Язык AHDL

         

Арифметические операторы в булевых выражения


Арифметические операторы используются для арифметических операций сложения и вычитания над числами и шинами в булевых выражениях. В них используются следующие операторы:

Оператор:

Пример:

Описание:

+ (унарный)

+1

плюс

- (унарный)



-a[4..1]

минус

+

count[7..0] + delta[7..0]

сложение

-

rightmost_x[] - leftmost_x[]

вычитание

К бинарным операторам применимы следующие правила:

·   Операции выполняются между двумя операндами, которые должны быть шинами или числами.

·   Если оба операнда - шины, то они должны иметь один размер.

·   Если оба операнда числа, более короткое число расширяется до размеров другого операнда.

·   Если один оператор - число, а другой группа узлов, то число усекается или расширяется для согласования размеров операндов. Если отбрасываются любые значимые биты,  то компилятор MAX+PLUS II выдает сообщение об ошибке.

Þ   Когда Вы складываете две шины вместе с правой стороны булева уравнения с помощью оператора +, Вы можете поместить 0 с левой стороны группы для расширения ширины шины. Этот метод обеспечивает добавление дополнительного бита данных с левой стороны уравнения, который можно использовать как сигнал выходного переноса. Например, шины count[7..0] и delta[7..0] дополняются нулями для обеспечения информацией сигнала cout:

(cout, answer[7..0]) = (0, count[7..0]) + (0, delta[7..0])



Арифметические выражения


Арифметические выражения можно использовать для определения оцениваемых функций в операторах Define, констант в операторах Constant, значений параметров в операторах Parameters и в качестве ограничителей диапазонов шин. Например,

Диапазон, определенный с помощью арифметического выражения:

SUBDESIGN foo

(

            a[4..2+1-3+8] : INPUT;

)

Константа, определенная с помощью арифметического выражения:

CONSTANT foo = 1 + 2 DIV 3 + LOG2(256);

Оцениваемая функция, определенная с помощью арифметического выражения:

DEFINE MIN(a,b) = ((a < b) ? a : b);

Арифметические операторы и компараторы используются в этих выражениях для выполнения основных арифметических и сравнительных операций с числами в них. В арифметических выражениях используются следующие операторы и компараторы:

Оператор/ компаратор:

Пример:

Описание:

Приоритет:

+ (унарный)

+1

положительный

1

- (унарный)

-1

отрицательный

1

!

!a

NOT

1

^

a ^ 2

степень

1

MOD

4 MOD 2

модуль

2

DIV

4 DIV 2

деление

2

*

a * 2

умножение

2

LOG2

LOG2(4-3)

логарифм по основанию 2

2

+

1+1

сложение

3

-

1-1

вычитание

3

== (числовой)

5 == 5

числовое  равенство

4

== (строковый)

"a" == "b"

строковое равенство

4

!=

5 != 4

не равно

4

5 > 4

больше чем

4

>=

5 >= 5

больше чем или равно

4

a < b+2

меньше чем

4

<=

a <= b+2

меньше чем или равно

4

&

a & b

AND

5

AND

a AND b

!&

1 !& 0

NAND

5

NAND

1 NAND 0

$

1 $ 1

XOR

6

XOR

1 XOR 1

!$

1 !$ 1

XNOR

6

XNOR

1 XNOR 1

#

a # b

OR

7

OR

a OR b

!#

a !# b

NOR

7

NOR

a NOR b

?

(5<4) ? 3:4

тернарный

8

Ко всем арифметическим выражениям применяются следующие правила:

1.   Арифметические выражения должны давать не отрицательные числа.

2.   Когда результат LOG2 не целый, он автоматически округляется до следующего  целого. Например, LOG2(257) = 9.

Арифметические операторы, поддерживаемые в арифметических выражениях, являются надмножеством арифметических операторов, поддерживаемых в булевых выражениях, которые описываются в 1.3.9.2.



Булевские выражения


Булевские выражения используются в разделе Logic текстового файла  проекта на языке AHDL для представления соединений  узлов, входных и выходных потоков сигналов через входные и выходные выводы, примитивы, макро-  и мегафункции  и конечные автоматы.

Следующий пример демонстрирует сложное булевское выражение:

a[] = ((c[] & -B"001101") + e[6..1]) # (p, q, r, s, t, v);

Левая часть выражения может быть символическим именем, именем порта или именем группы. Для инвертирования выражения в левой части выражения можно пользоваться  операцией NOT (!). Правая часть равенства представлена булевским выражением, вычисляемым в порядке, описанном в разделе “Приоритеты булевских операторов и операций отношения”.

Символ эквивалентности (=) используется в булевских выражениях для индикации того, что результат булевского выражения, представленного в правой части, является источником сигнала для символического объекта или группы в левой части. Символ (=) отличается от символа (==), используемого как компаратор.

В примере, показанном выше, булевское выражение в правой части равенства вычисляется в соответствии со следующими правилами:

1.   Двоичное число B”001101” меняет знак и принимает вид B”110011”. Унарная операция (-) имеет наивысший приоритет.

2.   B”110011” объединяется по И с группой c[]. Эта операция имеет второй уровень приоритета, потому что она заключена в круглые скобки.

3.   Результат групповой операции, проведенной на втором шаге, прибавляется к группе e[6..1].

4.   Результат, полученный на третьем шаге, объединяется по ИЛИ с группой (p, q, r, s, t, v). Это выражение имеет наименьший уровень приоритета.

Результат операции присваивается группе a[ ].

Для корректного выполнения операций, показанных выше, необходимо, чтобы количество бит в группе в левой части выражения было равно или делилось нацело на число бит в группе в правой части выражения. Биты в левой части выражения отображаются на соответствующие биты в правой части выражения по порядку.




В отношении булевских выражений используются следующие правила:

¨    Множественные присваивания, осуществляемые в отношении переменной объединяются в соответствии с монтажным ИЛИ (#), исключая тот случай, когда значением по умолчанию для этой переменной является VCC.

¨    Узлы в левой части булевского выражения однозначно соответствуют узлам в правой части .

¨    Если значение одиночного узла, VCC или GND присваиваются группе, то  значение узла или константы копируется до размерности группы . Например, (a, b) = e эквивалентно  a = e и b = e.

¨    Если и левая и правая части выражения представляют собой группы одинакового размера, то каждый член группы, расположенной в правой части, соответствует тому члену группы в левой части, который расположен на той же позиции .Например, (a, b) = (c, d) эквивалентно a = c и b = d.

Þ   При сложении двух групп в правой части булевского выражения  с использованием операции (+) можно добавить символ “0” слева каждой группы для знакового расширения. Этот метод может быть использован для получения дополнительного бита сигнала переноса в группе, расположенной в левой части выражения. В следующем примере группы count[7..0] и delta[7..0] представлены в знакорасширенном формате для получения значения бита переноса, обозначенного символическим именем cout в левой части выражения:

 (cout, answer[7..0]) = (0, count[7..0]) + (0, delta[7..0])

¨    Если в левой и правой частях булевского выражения расположены группы разных размерностей, то количество бит в группе слева должно быть равно или делиться нацело на количество бит в правой части  выражения. Биты в левой части выражения отображаются на биты в правой части выражения по порядку. Следующая запись является корректной:

a[4..1] = b[2..1]

В данном выражении биты отображаются в следующем порядке:

a4 = b2

a3 = b1

a2 = b2

a1 = b1

¨    Группа узлов или чисел не может быть присвоена одиночному узлу.

¨    Если число в правой части выражения присваивается группе, расположенной в левой части выражения, то число усекается или расширяется путем распространения знака до соответствия размеру группы в левой части. Если при этом происходит усечение значащих битов, то  компилятор выдает сообщение об ошибке. Каждый член в правой части выражения присваивается соответствующему члену в левой части выражения по порядку. Например, (a, b) = 1 эквивалентно a = 0; b =1;

¨    Запятые могут использоваться для резервирования места под неупомянутые элементы группы в булевских выражениях Следующий пример демонстрирует использование запятых для резервирования места под отсутствующие элементы группы (a, b, c, d) :

 (a, , c, ) = B"1011";

В данном примере элементам a и c присваивается значение “1”.

¨    Каждое выражение заканчивается символом (;).


Булевы операторы, использующие AND, NAND, OR, NOR, XOR, и XNOR


С бинарными операторами существует пять сочетаний операндов. Каждое из этих сочетаний интерпретируется различно:

1.   Если оба операнда - одиночные узлы или константы GND и VCC, оператор выполняет логическую операцию над двумя элементами. Например, (a & b).

2.   Если оба операнда - группы узлов, оператор действует  на соответствующие узлы каждой группы, выполняя побитовые операции между группами. Группы должны иметь одинаковый размер. Например, (a, b, c) # (d, e, f) интерпретируется как (a # d, b # e, c # f).

3.   Если один операнд - одиночный узел, GND, или VCC, а другой группа узлов, одиночный узел или константа дублируется для создания группы такого же размера как другой оператор. Затем выражение трактуется как групповая операция. Например, a & b[4..1] интерпретируется как (a & b4, a & b3, a & b2, a & b1).

4.   Если оба операнда - числа, то более короткое число расширяется с учетом знака для согласования с размером другого числа и трактуется затем как групповая операция. Например, в выражении (3 # 8), 3 и 8 преобразуются в двоичные числа  B"0011" и B"1000", соответственно. Результатом будет B"1011".

5.   Если один операнд - число, а другой узел или группа узлов, то число разделяется на биты для согласования с размером группы и выражение рассматривается как групповая операция. Например, в выражении (a, b, c) & 1, 1 преобразуется к  B"001" и выражение  становится (a, b, c) & (0, 0, 1). Результатом будет (a & 0, b & 0, c & 1).

Выражение, которое использует VCC как операнд, интерпретируется в зависимости от выражения, которое использует 1 как операнд. Например, в первом выражении, 1 - число в знакорасширенном формате . Во втором выражении, узел VCC дублируется . Затем каждое выражение трактуется как групповая операция.

 (a, b, c) & 1   = (0, 0, c)

(a, b, c) & VCC = (a, b, c)



Булевы операторы, использующие NOT


Оператор НЕ является префиксом инвертора. Поведение оператора НЕ зависит от операнда, на который он воздействует.

С оператором НЕ можно использовать три типа операндов:

1.   Если операнд - одиночный узел, GND, или VCC, выполняется одиночная инверсия. Например, !a означает, что сигнал проходит через инвертор.

2.   Если операнд - группа узлов, то каждый член группы проходит через инвертор. Например, шина !a[4..1] интерпретируется как (!a4, !a3, !a2, !a1).

3.   Если операнд - число, он трактуется как двоичное число и каждый его бит инвертируется. Например, !9 интерпретируется как !B"1001", то есть B"0110".



Булевы выражения


Булевы выражения состоят из операндов, разделенных логическими и арифметическими операторами и компараторами и дополнительно сгруппированы с помощью круглых скобок. Выражения используются в булевых уравнениях также как и в других операторах таких как Case и If Then.

Булево выражение может быть одним из следующих:

1.   Операнд

Например, a, b[5..1], 7, VCC

2.   Подставляемая ссылка на логическую функцию

Например, out[15..0] = 16dmux(q[3..0]);

3.   Префиксный оператор (! или -), применяемый к булеву выражению

Например, !c

4.   Два булевых выражения, разделенных бинарным оператором

Например, d1 $ d3

5.   Булево выражение, заключенное в круглые скобки

     Например, (!foo & bar)

Вы можете именовать булевы операторы и компараторы в файлах AHDL для облегчения ввода присваиваний ресурсов и для интерпретации раздела Equations в файле отчета. За дополнительной информацией обратитесь к 1.2.5.2



Числа в AHDL


Вы можете использовать десятичные, двоичные, восьмеричные и шестнадцатеричные числа в любых сочетаниях. Синтаксис для каждого основания показывается ниже.

Основание:                 Значения:

 

Десятичное      <последовательность цифр от 0 до 9>

Двоичное         B"<последовательность 0-ей, 1-ц и

X-ов>" (где X = "безразличное состояние")

Восьмеричное O"<последовательность цифр от 0

до 7>" или Q"< последовательность цифр от 0 до 7>"

Шестнадцатеричное    X"< последовательность цифр

от 0 до 9, A до F>"

            H"< последовательность цифр

от 0 до 9, A до F >"

К числам применяются следующие правила:

1.   Компилятор MAX+PLUS II всегда интерпретирует числа в булевых выражениях как группы двоичных цифр; числа в диапазонах шин как десятичные значения.

2.   Числа нельзя присваивать одиночным узлам в булевых уравнениях. Вместо этого используйте VCC и GND.



Диапазоны и поддиапазоны шин


Диапазоны в именах шин могут состоять из чисел или арифметических выражений, разделенных двумя точками (..) и заключенных в скобки []. Например,

a[4..1]               шина с членами a4, a3, a2, и a1.

d[B"10"..B"00"]  шина с членами d2, d1, и d0.

b[2*2..2-1]                     шина с членами b4, b3, b2, и b1. Ограничителями диапазона являются арифметические выражения.

q[MAX..0]                      допустимая шина, если константа MAX была описана в операторе Constant.

c[MIN(a,b)..0]    допустимая шина, если оцениваемая функция MIN была описана в операторе Define.

t[WIDTH-1..0]    допустимая шина, если параметр WIDTH был описан в операторе Parameters.

Не зависимо от того является ли ограничитель диапазона числом или арифметическим выражением компилятор разделяет и интерпретирует ограничители как десятичные значения (целые числа).

Поддиапазоны содержат подмножество узлов, определенных в объявлении шины и могут описываться рядом способов. Запятые можно использовать как заменители только в шинах с левой стороны булева уравнения или подставляемой ссылки. Например,

Если Вы объявили шину c[5..1], то Вы можете использовать  следующие поддиапазоны этой шины:

c[3..1]

c[4..2]

c4

c[5]

(c2, , c4)

В поддиапазоне (c2, , c4), запятая используется для сохранения места не назначенному  члену шины.

 

Диапазоны обычно приводятся в убывающем порядке. Для указания диапазонов в возрастающем порядке или как  в убывающем так и в возрастающем порядке Вы должны определить опцию BIT0 с помощью оператора Options для предотвращения выдачи предупреждающих сообщений компилятором. В шинах с двумя диапазонами эта опция воздействует на оба диапазона.



Именование булевых операторов и компараторов


Вы можете именовать булевы операторы и компараторы для облегчения ввода присваивания ресурсов и интерпретации раздела уравнений в файле отчета проекта.

Файл boole3.tdf,  приведенный ниже, идентичен с файлом boole1.tdf, но использует именованные операторы. Имя оператора отделяется от оператора знаком двоеточия; имя может содержать до 32 символов.

SUBDESIGN boole3

(

   a0, a1, b  : INPUT;

   out1, out2 : OUTPUT;

)

BEGIN

   out1 = a1 tiger:& !a0;

   out2 = out1 panther:# b;

END;

Следующие отрывки из файла отчета показывают различие между boole3.rpt и boole1.rpt для первых двух уравнений.

-- boole3.rpt equations:

-- Node name is 'out1' from file "boole3.tdf" line 7, col 2

-- Equation name is 'out1', location is LC3_A1, type is output

out1 = tiger~0;

-- Node name is 'tiger~0' from file "boole3.tdf" line 7, column 18

-- Equation name is 'tiger~0', location is LC2_A1, type is buried

tiger~0 = LCELL( _EQ002);

  _EQ002 = !a0 &  a1;

-- boole1.rpt equations:

-- Node name is 'out1' from file "boole1.tdf" line 7, col 2

-- Equation name is 'out1', location is LC3_A1, type is output

out1 = _LC2_A1;

-- Node name is ':33' from file "boole1.tdf" line 7, col 12

-- Equation name is '_LC2_A1', type is buried

LC2_A1 = LCELL( _EQ001);

  _EQ001 = !a0 &  a1;

В зависимости от логики уравнения именованный оператор может представлять несколько имен узлов, однако, все имена относятся к имени оператора и, поэтому, узлы  легче распознаются в файле отчета. В файле boole3.rpt единственный узел, tiger~0, создается для первого уравнения. В файле boole1.tdf компилятор связывает  цепь ID :33 с тем же самым узлом.

После того, как Вы откомпилировали проект Вы можете использовать имена узлов, приведенные в файле отчета, для введения  присваивания ресурса для дальнейшей компиляции, даже если логика проекта изменена. Имена логических ячеек, созданные из именованных операторов, остаются постоянными, если Вы изменили несвязанную с ними логику в файле. Например, Вы можете ввести присваивание для узла tiger~0. В противоположность этому, если операторы неименованы, доступны только ID номера цепей, и эти имена произвольно переназначаются при каждой компиляции.



Импорт и экспорт конечных автоматов


Вы можете импортировать и экспортировать конечные автоматы между TDF файлами и другими файлами проекта, определяя входные и выходные порты как MACHINE INPUT или MACHINE OUTPUT в разделе Subdesign. Прототип функции, который представляет файл, содержащий конечный автомат, должен указывать, какие входы и выходы принадлежат конечному автомату с помощью предварения имен сигналов ключевым словом MACHINE.

Типы портов MACHINE INPUT и MACHINE OUTPUT нельзя использовать в файле проекта верхнего уровня. Хотя высокоуровневый файл с этими портами полностью не компилируется, Вы можете использовать команду Project Save & Check (меню File) для проверки его синтаксиса и команду Create Default Include File (меню File) для создания Include файла, который представляет текущий файл.

Вы можете переименовать конечный автомат с помощью временного имени, вводя объявление псевдоимени автомата в раздел Variable. Вы можете использовать это псевдоимя в файле, где создан этот автомат или в файле, который использует порт MACHINE INPUT для импорта конечного автомата. Затем Вы можете применить это имя вместо исходного имени автомата.

Файл ss_def.tdf, приведенный ниже, определяет и экспортирует конечный автомат ss с помощью порта ss_out.

SUBDESIGN ss_def

(

 clk, reset, count : INPUT;

ss_out    : MACHINE OUTPUT;

)

VARIABLE

   ss: MACHINE WITH STATES (s1, s2, s3, s4, s5);

BEGIN

   ss_out = ss;

   CASE ss IS

      WHEN s1=>

         IF count THEN ss = s2; ELSE ss = s1; END IF;

      WHEN s2=>

         IF count THEN ss = s3; ELSE ss = s2; END IF;

      WHEN s3=>

         IF count THEN ss = s4; ELSE ss = s3; END IF;

      WHEN s4=>

         IF count THEN ss = s5; ELSE ss = s4; END IF;

      WHEN s5=>

         IF count THEN ss = s1; ELSE ss = s5; END IF;

   END CASE;

   ss.(clk, reset) = (clk, reset);

END;

Файл ss_use.tdf, приведенный ниже, импортирует конечный автомат с помощью порта ss_in.

SUBDESIGN ss_use

(

   ss_in : MACHINE INPUT;




   out   : OUTPUT;

)

BEGIN

   out = (ss_in == s2) OR (ss_in == s4);

END;

Файл top1.tdf, приведенный ниже, использует ссылки для вставки экземпляров функций ss_def и ss_use. Прототипы функций для ss_def и ss_use содержат ключевые слова MACHINE, которые указывают какие входы и выходы являются автоматными.

FUNCTION ss_def (clk, reset, count)

 RETURNS (MACHINE ss_out);

FUNCTION ss_use (MACHINE ss_in)

 RETURNS (out);

SUBDESIGN top1

(

            sys_clk, /reset, hold : INPUT;

            sync_out              : OUTPUT;

)

VARIABLE

ss_ref: MACHINE; %объявление псевдоимени автомата  %

BEGIN

            ss_ref = ss_def(sys_clk, !/reset, !hold);

            sync_out = ss_use(ss_ref);

END;

Внешний конечный автомат можно также реализовать в TDF файле верхнего уровня с помощью объявления экземпляра в разделе Variable. Файл top2.tdf, приведенный ниже, имеет такую же функциональность, как и top1.tdf, но использует объявления экземпляров, вместо ссылок.

FUNCTION ss_def (clk, reset, count)

 RETURNS (MACHINE ss_out);

FUNCTION ss_use (MACHINE ss_in)

 RETURNS (out);

SUBDESIGN top2

(

sys_clk, /reset, hold : INPUT;

sync_out              : OUTPUT;

)

VARIABLE

            sm_macro : ss_def;

            sync     : ss_use;

BEGIN

sm_macro.(clk, reset, count) = (sys_clk, !/reset, !hold);

sync.ss_in = sm_macro.ss_out;

sync_out = sync.out;

END;


Использование чисел


Числа применяются для определения значений констант в булевских выражениях и уравнениях, в арифметических выражениях, а также значения параметров. AHDL поддерживает все комбинации десятичных, двоичных, восьмеричных и шестнадцатеричных чисел.

Файл decode1.tdf, приведенный ниже, описывает дешифратор адреса, который генерирует активный высокий сигнал разрешения кристалла, когда адрес равен 370 Hex.

SUBDESIGN decode1

(

   address[15..0] : INPUT;

   chip_enable    : OUTPUT;

)

BEGIN

   chip_enable = (address[15..0] == H"0370");

END;

 

В этом простом примере десятичные числа 15 и 0 используются для определения битов шины адреса. Шестнадцатеричное число H"0370" определяет декодируемый  адрес.



Использование для переменных значений по умолчанию


Вы можете определить значение по умолчанию для узла или шины, который используете, когда его величина не указана где-нибудь в другом месте файла. AHDL позволяет Вам также присваивать значение узлу или шине более одного раза в одном файле. Если эти присваивания конфликтуют, то значение по умолчанию используется для разрешения конфликтов. При отсутствии определения значения по умолчанию ему присваивается значение GND.

Значение по умолчанию определяется  с помощью оператора Defaults для переменных, использующихся в операторах Truth Table, If Then, и Case.

Вы не должны путать значения по умолчанию для переменных со значениями по умолчанию для портов, которые присваиваются в разделе Subdesign.

Файл default1.tdf, приведенный ниже, оценивает входы и выбирает один из пяти ASCII кодов, основываясь на входах.

SUBDESIGN default1

(

   i[3..0]             : INPUT;

   ascii_code[7..0] : OUTPUT;

)

BEGIN

   DEFAULTS

ascii_code[] = B"00111111"; % ASCII  код "?" %

   END DEFAULTS;

   TABLE

      i[3..0]    => ascii_code[];

      B"1000" => B"01100001"; % "a" %

      B"0100" => B"01100010"; % "b" %

      B"0010" => B"01100011"; % "c" %

      B"0001" => B"01100100"; % "d" %

   END TABLE;

END;

Когда входной набор совпадает с одним из наборов, приведенным с левой стороны оператора Truth Table, выходы устанавливаются в соответствии с комбинацией справа. Если совпадения не происходит, выходы принимают значения по умолчанию B"00111111".

Файл default2.tdf, приведенный ниже, иллюстрирует как возникают конфликты, когда одному узлу присваивается более одного значения и как эти конфликты разрешаются языком AHDL.

SUBDESIGN default2

(

a, b, c                           : INPUT;

select_a, select_b, select_c : INPUT;

wire_or, wire_and            : OUTPUT;

)

BEGIN

   DEFAULTS




      wire_or = GND;

      wire_and = VCC;

   END DEFAULTS;

   IF select_a THEN

      wire_or = a;

      wire_and = a;

   END IF;

   IF select_b THEN

      wire_or = b;

      wire_and = b;

   END IF;

   IF select_c THEN

      wire_or = c;

      wire_and = c;

   END IF;

END;

В этом примере wire_or присваиваются значения a, b, или c, в зависимости от значений сигналов select_a, select_b, и select_c. Если ни один из этих сигналов не равен VCC, тогда wire_or принимает значение GND.

Если больше одного из сигналов select_a, select_b, или select_c принимают значение VCC, тогда сигнал wire_or является логическим ИЛИ соответствующих входных значений .

Сигнал wire_and работает таким же образом, за исключением того, что по умолчанию он устанавливается в VCC, когда ни один из "select" сигналов не равен VCC и равен логическому И соответствующих входов, когда более одно сигнала принимает значение VCC.


Использование итеративно-генерируемой логики


Когда Вы хотите использовать несколько схожих блоков логики, Вы можете использовать оператор For Generate

для итеративно-генерируемой логики.

Файл iter_add.tdf, приведенный ниже, демонстрирует пример итеративного создания логики:

CONSTANT NUM_OF_ADDERS = 8;

SUBDESIGN iter_add

(

a[NUM_OF_ADDERS..1], [NUM_OF_ADDERS..1],

cin                               : INPUT;

c[NUM_OF_ADDERS..1], cout : OUTPUT;

)

VARIABLE

sum[NUM_OF_ADDERS..1], carryout[(NUM_OF_ADDERS+1)..1] : NODE;

BEGIN

   carryout[1] = cin;

   FOR i IN 1 TO NUM_OF_ADDERS GENERATE

   sum[i] = a[i] $ b[i] $ carryout[i];           % Полный суматор %

   carryout[i+1] = a[i] & b[i] # carryout[i] & (a[i] $ b[i]);

END GENERATE;

   cout = carryout[NUM_OF_ADDERS+1];

   c[] = sum[];

END;

В iter_add.tdf оператор For Generate используется для присваивания значений полным сумматорам. Выходной перенос carryout генерируется вместе с каждым полным сумматором.

Оператор If Generate

особенно полезен с оператором For Generate, который раздельно управляет специальными случаями, например, в первом и последнем каскадах многокаскадного умножителя.



Использование констант и оценочных функций


Вы можете использовать константу в AHDL файле, давая ей дескриптивное имя на число или текстовую строку. Аналогичным образом Вы можете использовать оценочную функцию, давая ей дескриптивное имя на арифметическое выражение. Это  имя, которое можно использовать по всему файлу, может быть более информативным и читаемым, чем число, строка или арифметическое выражение. Например, числовая константа UPPER_LIMIT более информативна, чем число 130.

Константы и оценочные функции особенно полезны, если одно и тоже число, строка или арифметическое выражение повторяются несколько раз в файле: если оно изменяется, то требуется изменить только один оператор. В AHDL константы реализуются с помощью оператора Constant, а оценочные функции с помощью оператора Define.

AHDL снабжен также предопределенными оценочными функциями USED, CEIL, и FLOOR.

Файл decode2.tdf, приведенный ниже, имеет туже самую функциональность как и decode1.tdf,  но использует константу IO_ADDRESS вместо числа H"0370".

CONSTANT IO_ADDRESS = H"0370";

SUBDESIGN decode2

(

   a[15..0] : INPUT;

   ce       : OUTPUT;

)

BEGIN

   ce = (a[15..0] == IO_ADDRESS);

END;

Вы можете определить константы и оценочные функции с помощью арифметических выражений. Компилятор оценивает арифметические операторы в арифметическом выражении и сокращает их до числовых значений. Логика для этих выражений не создается.

Файл strcmp.tdf,  приведенный ниже, определяет константу FAMILY и использует ее в операторе Assert для проверки того, является ли текущее семейство устройств FLEX 8000.

PARAMETERS

(

DEVICE_FAMILY

% DEVICE_FAMILY является предопределенным параметром %

);

CONSTANT FAMILY = "FLEX8000";

SUBDESIGN strcmp

(

   a : INPUT;

   b : OUTPUT;

)

BEGIN

   IF (DEVICE_FAMILY == FAMILY) GENERATE

      ASSERT

         REPORT "Обнаружена компиляция для FLEX8000 "

         SEVERITY INFO;

      b = a;

   ELSE GENERATE

      ASSERT

         REPORT " Обнаружена компиляция для % семейства"

            DEVICE_FAMILY

         SEVERITY ERROR;

      b = a;

   END GENERATE;

END;

Файл minport.tdf,  приведенный ниже, определяет оценочную функцию MAX,  которая гарантирует минимальную ширину порта в разделе Subdesign.

PARAMETERS (WIDTH);

DEFINE MAX(a,b) = (a > b) ? a : b;

SUBDESIGN minport

(

   dataA[MAX(WIDTH,0)..0] : INPUT;

   dataB[MAX(WIDTH,0)..0] : OUTPUT;

)

BEGIN

   dataB[] = dataA[];

END;



Использование непараметрических функций


MAX+PLUS II включает библиотеки примитивов и непараметрических макрофункций. Все логические функции MAX+PLUS II можно использовать для создания иерархических проектов. Мега и макрофункции  автоматически устанавливаются в подкаталогах каталога \maxplus2\max2lib, созданного во время инсталляции. Логика примитивов встроена в AHDL.

Существует два способа использовать (т.е. вставлять экземпляр) непараметрическую  функцию в языке AHDL:

·   Объявить переменную для функции, т.е. имя экземпляра, в разделе Variable объявления Instance и использовать порты экземпляра функции в разделе Logic.

·   Использовать ссылку на логическую функцию в разделе Logic TDF файла.

Объявления Instance

обеспечивают именование узлов, которые полезны для ввода присваиваний ресурсов и моделирования проекта. С другой стороны с помощью ссылок на логические функции, имена узлов, основанные на ID номерах, можно менять при изменениях логики проекта.

Входы и выходы мега и макрофункций должны объявляться с помощью оператора прототипа функции (Function Prototype). Прототипы функций не требуются для примитивов. MAX+PLUS II снабжена файлами включения (Include Files), которые содержат прототипы для всех мега и макрофункций MAX+PLUS II в каталогах \maxplus2\max2lib\mega_lpm и \maxplus2\max2inc, соответственно. С помощью оператора Include, Вы можете передавать содержимое Include файла в файл TDF, для объявления прототипа мега или макрофункции MAX+PLUS II.

Файл macro1.tdf, приведенный ниже, демонстрирует 4-битный счетчик, соединенный с дешифратором 4 в 16. Экземпляры этих функций создаются с помощью объявлений Instance в разделе Variable.

INCLUDE "4count";

INCLUDE "16dmux";

SUBDESIGN macro1

(

   clk        : INPUT;

   out[15..0] : OUTPUT;

)

VARIABLE

   counter : 4count;

   decoder : 16dmux;

BEGIN

   counter.clk = clk;

   counter.dnup = GND;

   decoder.(d,c,b,a) = counter.(qd,qc,qb,qa);

   out[15..0] = decoder.q[15..0];

END;




Этот файл использует операторы Include, для импортирования прототипов функций для двух макрофункций: 4count и 16dmux. В разделе Variable переменная counter объявлена как экземпляр функции 4count, а переменная decoder объявлена как экземпляр функции 16dmux. Входные порты функций, в формате <имя экземпляра>.<имя порта>, определены с левой стороны булевых уравнений в разделе Logic, а выходные порты с правой стороны.

Файл macro2.tdf, приведенный ниже, имеет такую же функциональность как и macro1.tdf, но создает экземпляры двух функций с помощью ссылок и узлов q[3..0]:

INCLUDE "4count";

INCLUDE "16dmux";

SUBDESIGN macro2

(

   clk         : INPUT;

   out[15..0]  : OUTPUT;

)

VARIABLE

   q[3..0]     : NODE;

BEGIN

   (q[3..0], ) = 4count (clk, , , , , GND, , , , );

% эквивалент подставляемой ссылки со связью по имени порта  %

%  (q[3..0], ) = 4count (.clk=clk, .dnup=GND);         %

% эквивалент подставляемой ссылки со связью по имени порта %

% и предложением RETURNS, определяющим требуемый выход %

%  q[3..0] = 4count (.clk=clk, .dnup=GND)              %

%                RETURNS (qd, qc, qb, qa);             %

   out[15..0]  = 16dmux (.(d, c, b, a)=q[3..0]);

% эквивалент подставляемой ссылки со связью по положению порта %

% out[15..0]  = 16dmux (q[3..0]); %

END;

Прототипы функций 4count.inc и 16dmux.inc приведены ниже:

FUNCTION 4count (clk, clrn, setn, ldn, cin, dnup, d, c, b, a)

   RETURNS (qd, qc, qb, qa, cout);

FUNCTION 16dmux (d, c, b, a)

   RETURNS (q[15..0]);

Ссылки на 4count и 16dmux появляются в первом и втором булевых уравнениях в разделе Logic, соответственно. Ссылка на 4count использует связь по положению порта, тогда как ссылка на 16dmux использует связь по имени порта. Входные порты обоих макрофункций определяются с правой стороны ссылки, а выходные порты с левой.

Комментарии демонстрируют эквивалентные ссылки для различных видов связи с портом.В ссылке порты с правой стороны символа равенства (=) можно перечислять с помощью или связи по положению или по имени порта. Порты с левой стороны символа равенства всегда используют связь по положению. При использовании связи по положению важен порядок портов, так как существует соответствие один в один между порядком портов в прототипе функции и портами, определенными в разделе Logic. В ссылке на 4count запятые используются как разделители для портов, которые не соединяются точно.

Предложение RETURNS является дополнительным с ссылке. RETURNS можно использовать для перечисления подмножества выходов функции, которые используются в экземпляре.

Примитивы и макрофункции всегда имеют значения по умолчанию для не подсоединенных входов. Напротив, мегафункции необязательно имеют их.  


Использование оператора Assert


Вы можете использовать оператор Assert для проверки действительности любого произвольного выражения, которое использует параметры, числа, вычисляемые функции или использует или не использует статус порта. Вы могли бы, например,   использовать оператор Assert для определения того, попадает ли значение дополнительного параметра в диапазон, определяемый значением второго параметра.

Когда Вы используете оператор Assert

с условиями, Вы приводите список приемлемых значений для устанавливаемых условий. Если значение не допустимо, активизируется оператор и выдается сообщение. Если Вы используете оператор Assert без условий, то оператор активизируется всегда.

Компилятор вычисляет каждое условие только один раз после того, как модуль экстрактора списка связей (Netlist Extractor) разрешил все значения параметров. Оператор не может зависеть от значения сигнала, который реализуется в устройстве. Например, если оператор Assert помещается после оператора If Then вида IF a = VCC THEN c = d, то условие оператора Assert не может зависеть от значения a.

Файл condlog2.tdf, приведенный ниже, имеет такую же функциональность как и condlog1.tdf, но использует операторы Assert в разделе Logic для сообщения какая логика сгенерирована оператором If Generate.

PARAMETERS (DEVICE_FAMILY);

SUBDESIGN condlog2

(

   input_a : INPUT;

   output_b : OUTPUT;

)

BEGIN

   IF DEVICE_FAMILY == "FLEX8000" GENERATE

      output_b = input_a;

ASSERT

         REPORT "Компиляция для семейства FLEX8000"

         SEVERITY INFO;

   ELSE GENERATE

      output_b = LCELL(input_a);

      ASSERT (DEVICE_FAMILY == "FLEX10K")

         REPORT "Компиляция для семейства %", DEVICE_FAMILY;

   END GENERATE;

END;



Использование параметрических функций


MAX+PLUS II содержит параметрические мегафункции, а также функции библиотеки параметрических модулей (LPM). Например, параметры используются для определения ширины порта или будет ли блок памяти RAM реализован как синхронный или асинхронный. Параметрические функции могут содержать другие подпроекты, которые в свою очередь могут быть параметрическими или непараметрическими. Параметры можно использовать с некоторыми макрофункциями, которые не являются параметрическими. (Примитивы не могут быть параметрическими). Все логические функции MAX+PLUS II можно использовать для создания иерархических проектов. Мега и макрофункции автоматически устанавливаются в подкаталоги каталога \maxplus2\max2lib, созданного во время инсталляции; логика примитивов встроена в язык AHDL.

Параметрические функции объявляются с помощью ссылки на функцию или объявления Instance таким же образом как для непараметрических функций, но с некоторыми дополнительными шагами:

·   Экземпляр логической функции должен содержать в себе предложение WITH, которое основано на предложении WITH в прототипе функции, в котором приводится список параметров, используемых экземпляром. Вы можете использовать предложение WITH для дополнительного присваивания значений параметрам экземпляра, однако, для всех необходимых параметров в функции, параметрическое значение должно прикладываться где-нибудь в пределах проекта. Если сам по себе экземпляр не содержит некоторых или всех значений для требуемых параметров, компилятор ищет их в порядке поиска значений параметров.

·   Так как параметрические функции не обязательно имеют начальные значения для не подсоединенных входов, Вы должны убедиться что все необходимые порты подсоединены. С другой стороны, примитивы и макрофункции всегда имеют начальные значения для не подсоединенных входов.

Файл lpm_add1.tdf, приведенный ниже, реализует 8-битный сумматор с помощью ссылки на параметрическую мегафункцию lpm_add_sub.

INCLUDE "lpm_add_sub.inc";




SUBDESIGN lpm_add1

(

аа a[8..1], b[8..1] : INPUT;

аа c[8..1]ааааааааа : OUTPUT;

аа carry_outааааааа : OUTPUT;

)

BEGIN

% ¦ъчхьяы Ё ьхурЇєэъЎшш ёю ёт ч№¦ яюЁЄр яю яюыюцхэш¦ %

аа (c[], carry_out, ) = lpm_add_sub(GND, a[], b[], GND,,)

аааааааааааааааааааааааааа WITH (LPM_WIDTH=8,

LPM_REPRESENTATION="unsigned");

%¦ътштрыхэЄэvщ ¤ъчхьяы Ё ёю ёт ч№¦ яю шьхэш %

--(c[],carry_out,)= lpm_add_sub(.dataa[]=a[],.datab[]=b[],

--ааааааааааааааааааааааааааа .cin=GND, .add_sub=GND)

-- WITH (LPM_WIDTH=8,

LPM_REPRESENTATION="unsigned");

END;

¦ЁюЄюЄшя ЇєэъЎшш фы  lpm_add_sub яЁштхфхэ эшцх:

FUNCTION lpm_add_sub(cin, dataa[LPM_WIDTH-1..0], datab[LPM_WIDTH-1..0],а add_sub)

аа WITH (LPM_WIDTH, LPM_REPRESENTATION, LPM_DIRECTION, ADDERTYPE,

ааааа ONE_INPUT_IS_CONSTANT)

аа RETURNS (result[LPM_WIDTH-1..0], cout, overflow);

¦фхё№ ЄЁхсєхЄё  Єюы№ъю ярЁрьхЄЁ LPM_WIDTH ш ¤ъчхьяы Ё ЇєэъЎшш lpm_add_sub т Їрщых lpm_add1.tdf юяЁхфхы хЄ чэрўхэш  ярЁрьхЄЁют Єюы№ъю фы  LPM_WIDTH ш LPM_REPRESENTATION.

Lрщы lpm_add2.tdf, яЁштхфхээvщ эшцх, шфхэЄшўхэ ё lpm_add1.tdf, эю ЁхрышчєхЄ 8-сшЄэvщ ёєььрЄюЁ ё яюью•№¦ юс· тыхэш  Instance.

INCLUDE "lpm_add_sub.inc";

SUBDESIGN lpm_add2

(

аа a[8..1], b[8..1] : INPUT;

аа c[8..1]ааааааааа : OUTPUT;

аа carry_outааааааа : OUTPUT;

)

VARIABLE

аа 8bitadder : lpm_add_sub WITH (LPM_WIDTH=8,

аааааааа аааааааааLPM_REPRESENTATION="unsigned");

BEGIN

аа 8bitadder.cin = GND

аа 8bitadder.dataa[] = a[]

аа 8bitadder.datab[] = b[]

аа 8bitadder.add_sub = GND

аа c[] = 8bitadder.result[]

аа carry_out = 8bitadder.cout

END;


Использование условно-генерируемой логики


Вы можете создать логику условно с помощью оператора If Generate, если, например, хотите реализовать различное поведение в зависимости от значения арифметического выражения. Оператор If Generate приводит список последовательностей операторов поведения, которые активизируются после положительной оценки одного или более арифметических выражений.

Файл condlog1.tdf, приведенный ниже, использует оператор If Generate для реализации различного поведения выхода output_b на основании текущего семейства устройств.

PARAMETERS (DEVICE_FAMILY);

SUBDESIGN condlog1

(

   input_a : INPUT;

   output_b : OUTPUT;

)

BEGIN

   IF DEVICE_FAMILY == "FLEX8K" GENERATE

      output_b = input_a;

   ELSE GENERATE

      output_b = LCELL(input_a);

   END GENERATE;

END;

Оператор If Generate

особенно полезен с оператором For Generate, который управляет специальными случаями различно.

MAX+PLUS II включает предопределенный параметр DEVICE_FAMILY, как показано в примере выше и предварительно вычисляемую функцию USED, которую можно использовать в арифметических выражениях. Параметр DEVICE_FAMILY можно использовать для проверки текущего семейства устройств для проекта, заданного с помощью команды Device (меню Assign). Функцию USED можно использовать для проверки того, использовался ли дополнительный порт в текущем экземпляре.

Вы можете найти многочисленные примеры операторов If Generate в TDF файлах, которые реализуют LPM функции в MAX+PLUS II. Эти файлы размещаются в подкаталоге mega_lpm каталога max2lib.



Использование заказных мега и макро функций


Вы можете легко создать и использовать заказные мега и макрофункции в TDF файле.

После того как Вы определили логику для заказной функции в файле проекта, необходимо выполнить несколько шагов при использовании функции в других TDF файлах или в других типах файлов проекта.

Чтобы подготовить заказную мега или макрофункцию к использованию в другом файле проекта требуется:

1.   Откомпилировать и при необходимости промоделировать файл проекта для обеспечения его правильного функционирования.

2.   Если Вы планируете использовать функцию в нескольких проектах, Вы должны назначить каталог для хранения файла проекта в качестве библиотеки пользователя с помощью команды User Libraries (меню Options) или сохранения копии файла в существующем каталоге пользовательской библиотеки. Или же сохраните копию файла в каталоге, содержащем проект, который будет использовать заказную функцию.

I.              С помощью открытия файла в окне текстового редактора создайте Include файл и  символ, который представляет текущий файл:

A.            Выберите команду Create Default Include File (меню File) для создания Include файла, который можно использовать в TDF файле верхнего уровня. С помощью оператора Include Вы можете импортировать содержимое Include файла в TDF файл, объявляя прототип мега или макрофункции.

B.            Выберите команду Choose Create Default Symbol (меню File) для создания символа, который можно использовать в GDF файле.

После того как Вы подготовили функцию для других файлов проекта, Вы можете создать новый TDF файл и вставить экземпляр функции с помощью объявления экземпляра или подставляемой ссылки. Вы можете использовать заказные функции таким же образом как и функции, поставляемые Altera.



Как пользоваться языком AHDL


В данном разделе описывается как разрабатывать проект на AHDL и предлагаются советы по созданию успешных проектов.



Комбинаторная логика


Комбинационная логика реализуется на языке AHDL с помощью булевых выражений и уравнений, таблиц истинности, и множества мега и макрофункций. Примеры комбинационных функций включают дешифраторы, мультиплексоры и сумматоры.



Компараторы


Для сравнения одиночных узлов или шин используются два типа компараторов: логические  и арифметические. В булевых выражениях можно использовать следующие компараторы.

Компаратор:

Пример:

Описание

== (логический)

addr[19..4] == B"B800"

равно

!=  (логический)

b1 != b3

не равно

<   (арифметический)

fame[] < power[]

меньше чем

<= (арифметический)

money[] <= power[]

меньше чем или равно

>   (арифметический)

love[] > money[]

больше чем

>= (арифметический)

delta[] >= 0

больше чем или равно

Логические компараторы могут сравнивать одиночные узлы, шины и числа без неопределенных (X)  значений. При сравнении шин или чисел, шины должны иметь одинаковый размер. Компилятор MAX+PLUS II выполняет побитовое сравнение шин, возвращая VCC, когда сравнение истинно, и GND, когда сравнение ложно.

Арифметические компараторы могут сравнивать только шины и числа; шины должны иметь одинаковый размер. Компилятор выполняет беззнаковое сравнение значений шин, т.е., каждая шина интерпретируется как положительное двоичное число и  сравнивается с другой шиной.



Конечные автоматы


В языке AHDL конечные автоматы реализуются также легко как таблицы истинности и булевы уравнения. Язык структурирован настолько, что Вы можете или сами присвоить значения состояниям или позволить компилятору MAX+PLUS II сделать эту работу за Вас.

Компилятор использует усовершенствованные эвристические алгоритмы автоматического присваивания состояний, которые минимизируют логические ресурсы, требующиеся для реализации конечных автоматов.

От Вас просто требуется нарисовать диаграмму состояний и построить таблицу следующих состояний. Затем компилятор автоматически выполнит следующие функции:

·   назначит биты, выбирая или T или D триггер (TFF или DFF) для каждого  бита

·   присвоит значения состояниям

·   применит сложную технику логического синтеза для получения уравнений возбуждения

 Для определения конечного автомата на языке AHDL, необходимо включить следующие элементы в TDF файл:

·   объявление конечного автомата (раздел Variable)

·   булевы уравнения управления (раздел Logic)

·   переходы между состояниями в операторе Table  или Case (раздел Logic)

Также Вы можете импортировать и экспортировать конечные автоматы между TDF файлами и другими файлами проекта, определяя входные и выходные сигналы как автоматные порты в разделе Subdesign.



Конечные автоматы с асинхронными выходами


AHDL поддерживает реализацию конечных автоматов с асинхронными выходами. Выходы этих типов конечных автоматов могут изменяться при изменении входов, несмотря на переходы сигнала Clock.

Файл mealy.tdf, приведенный ниже, реализует автомат Мили на 4 состояния с асинхронными выходами.

SUBDESIGN mealy

(

   clk   : INPUT;

   reset : INPUT;

   y     : INPUT;

   z     : OUTPUT;

)

VARIABLE

   ss: MACHINE WITH STATES (s0, s1, s2, s3);

BEGIN

   ss.clk = clk;

   ss.reset = reset;

   TABLE

%  состояние    вход       выход        состояние %

      ss,              y      =>  z,               ss;

      s0,              0     =>  0,               s0;

      s0,              1      =>  1,               s1;

      s1,              0      =>  1,               s1;

      s1,              1      =>  0,               s2;

      s2,              0      =>  0,               s2;

      s2,              1      =>  1,               s3;

      s3,              0      =>  0,               s3;

      s3,              1      =>  1,               s0;

   END TABLE;

END;



Конечные автоматы с синхронными выходами


Если выходы конечного автомата зависят только от состояний автомата, Вы можете определить его выходы в предложении WITH STATES объявления конечного автомата.

Файл moore1.tdf, приведенный ниже, реализует автомат Мура на четыре состояния.

SUBDESIGN moore1

(

   clk   : INPUT;

   reset : INPUT;

   y     : INPUT;

   z     : OUTPUT;

)

VARIABLE

ss: MACHINE OF BITS (z)

            WITH STATES (s0    =   0,

                                     s1    =   1,

                                     s2    =   1,

                                     s3    =   0);

BEGIN

   ss.clk   = clk;

   ss.reset = reset;

   TABLE

   %  текущее      текущий     следующее  %

   %  состояние    вход           состояние %

      ss,                           y      =>   ss;

      s0,                           0      =>   s0;

      s0,                           1      =>   s2;

      s1,                           0      =>   s0;

      s1,                           1      =>   s2;

      s2,                           0      =>   s2;

      s2,                           1      =>   s3;

      s3,                          0      =>   s3;

      s3,                           1      =>   s1;

   END TABLE;

END;

Этот пример определяет состояния конечного автомата с помощью объявления конечного автомата. Переходы между состояниями определены в таблице переходов, которая реализована с помощью оператора Table. В этом примере автомат ss имеет 4 состояния, но только один бит состояния (z). Компилятор автоматически добавляет другой бит и создает соответствующие присваивания для синтезированной переменной для представления автомата на 4 состояния. Этот автомат требует не менее 2 битов.

Когда значения состояний используются в качестве выходов, как в файле moore1.tdf, проект может использовать несколько логических ячеек, но логические ячейки могут требовать дополнительной логики для управления входами их триггеров. В этом случае модуль логического синтеза компилятора не сможет полностью минимизировать конечный автомат.



Контекстно-зависимая помощь


Для получения контекстно-зависимой помощи, Вы сперва должны сохранить Ваш текстовой файл с расширением .tdf.

Контекстно-зависимая помощь доступна для следующих элементов:

·   Арифметические операторы (в булевых выражениях)

·   Арифметические операторы (в арифметических выражениях)

·   Компараторы

·   Логические операторы

·   Мегафункции

·   Макрофункции

·   Примитивы

·   Зарезервированные идентификаторы

·   Зарезервированные ключевые слова

·   Символы

 [M1]

Процесс копирования присваиваний ресурсов, сделанных компилятором, из файла подгонки в ACF файл. Используется для сохранения текущей подгонки при дальнейших компиляциях.

 [M2]



Логические операторы


В булевых выражениях можно использовать следующие логические операторы:

Оператор:

Пример:

Описание:

!

!tob

дополнение до 1

NOT

NOT tob

&

bread & butter

И

AND

bread AND butter

!&

a[3..1] !& b[5..3]

И-НЕ

NAND

a[3..1] NAND b[5..3]

#

trick # treat

ИЛИ

OR

trick OR treat

!#

c[8..5] !# d[7..4]

ИЛИ-НЕ

NOR

c[8..5] NOR d[7..4]

$

foo $ bar

Исключающее ИЛИ

XOR

foo XOR bar

!$

x2 !$ x4

Исключающее ИЛИ-НЕ

XNOR

x2 XNOR x4

Каждый оператор представляет двухвходовый логический вентиль, за исключением оператора NOT (!), который является префиксом инвертирования одного узла. Вы можете использовать или имя или символ для представления логического оператора.

Выражения, которые используют эти операторы, интерпретируются различно в зависимости от того, являются ли операнды одиночными узлами, шинами или числами.

Вы можете позволить компилятору заменить И операторы и все компараторы в булевых выражениях на lpm_add_sub и lpm_compare функции, включая логическую опцию Use LPM for AHDL Operators.



Макрофункции


MAX+PLUS II предлагает свыше 300 макрофункций.

Имена шинных макрофункций оканчиваются на букву В. Они функционально идентичны с соответствующими не шинными макрофункциями, но имеют сгруппированные входные и/или выходные выводы.

Для просмотра схемы или AHDL файла, который содержит логику макрофункции, укажите символ макрофункции в графическом редакторе или имя макрофункции в текстовом редакторе и выберите Hierarchy Down (меню File).

Категории макрофункций:

Сумматоры      Защелки

АЛУ                  Умножители

Буферы                        Мультиплексоры

Компараторы   Генераторы четности

Конвертеры     Быстрые умножители

Счетчики          Регистры

Декодеры         Сдвиговые регистры

Цифровые        Регистры хранения

фильтры

EDAC                SSI функции

Шифраторы     Элементы ввода/вывода

Делители частоты



Мегафункции/LPM


MAX+PLUS II предлагает большое разнообразие мегафункций, включая LPM функции а также параметризуемые функции. Ниже приводится список мегафункций.

Вентили

 

lpm_and

lpm_inv

lpm_bustri

lpm_mux

lpm_clshift

lpm_or

lpm_constant

lpm_xor

lpm_decode

mux

busmux

Арифметические компоненты

 

lpm_abs

lpm_counter

lpm_add_sub

lpm_mult

lpm_compare

Запоминающие компоненты

 

csfifo

lpm_ram_dq

csdpram

lpm_ram_io

lpm_ff

lpm_rom

lpm_latch

lpm_dff

lpm_shiftreg

lpm_tff

Другие функции

 

clklock

pll

ntsc

Функции Мегаядра

 

a16450

a8255

a6402

fft

a6850

rgb2ycrcb

a8237

ycrcb2rgb

a8251

Мегафункция - сложный или высокоуровневый строительный блок, который можно использовать совместно с примитивами вентилей и триггеров и/или с макрофункциями старого типа в файлах проекта.

Altera поставляет библиотеку мегафункций, включая функции из библиотеки параметризуемых модулей (LPM) версии 2.1.0, в директории  \maxplus2\max2lib\mega_lpm, созданной во время инсталляции.

Для просмотра файла, содержащего логику мегафункции, укажите символ мегафункции в графическом редакторе или ее имя в текстовом редакторе и выберите Hierarchy Down  (меню File).

Библиотека параметризуемых функций (LPM) - технологически-независимая библиотека логических функций, параметризуемая для достижения масштабируемости и адаптируемости. Altera реализовала параметризуемые модули (называемые также параметризуемые функции) из LPM в версии 2.1.0, которые предлагают архитектурно-независимый ввод проекта для всех, поддерживаемых MAX+PLUS II устройств. Компилятор включает встроенную поддержку компиляции LPM  для функций, используемых во входных файлах (схемном, AHDL, VHDL, и EDIF).

Параметризуемая функция - логическая функция, использующая параметры для достижения масштабируемости, адаптируемости и эффективной реализации в кремнии.




Мегафункции Мегаядра - предварительно проверенные HDL файлы для сложных функций системного уровня, которые можно приобрести у Altera. Они оптимизированы под архитектуры FLEX 10K, FLEX 8000, FLEX 6000, MAX 9000, и MAX 7000 устройств. Мегафункции Мегаядра состоят из нескольких файлов. Файл для последующего синтеза используется для реализации проекта (подгонки) в заданном устройстве. Кроме этого прилагаются VHDL или  Verilog HDL функциональные модели для проектирования и отладки со стандартными EDA средствами моделирования.

Altera поставляет библиотеку мегафункций, включая любые приобретаемые мегафункции Мегаядра в директории  \maxplus2\max2lib\mega_lpm, созданной во время инсталляции.

Если Ваш код доступа для мегафункции Мегаядра содержит разрешение просмотра источника файла проекта, Вы можете просмотреть его, указывая символ мегафункции в графическом редакторе или имя в текстовом редакторе и выбирая Hierarchy Down (меню File).

Ниже приводится описание наиболее часто применяемых мегафункций. Полные сведения по всем мегафункциям можно найти в системе помощи (меню Help, команда Megafunctions/LPM).

lpm_and  (вентиль И)

Altera рекомендует использовать примитивы вентилей И или их операторы вместо lpm_and для более легкой реализации и улучшения времени компиляции. Тем не менее lpm_and могут быть полезны при необходимости иметь параметризуемые входы.

Прототип функции

FUNCTION lpm_and

(data[LPM_SIZE-1..0][LPM_WIDTH-1..0])

   WITH (LPM_WIDTH, LPM_SIZE)

   RETURNS (result[LPM_WIDTH-1..0])





Порты

:

ВХОДЫ


Имя порта


Необходим


Описание


Комментарии


data[][]


Да


Вход данных в вентиль И


Размер порта LPM_SIZE x LPM_WIDTH

ВЫХОДЫ


Имя порта


Необходим


Описание


Комментарии


result[]


Да


Побитовое И.


Размер порта LPM_WIDTH.

Параметры

:


Параметр


Тип


Необходим


Описание


LPM_WIDTH


Целый


Да


Ширина портов data[][] и result[]. Количество AND вентилей.


LPM_SIZE


Целый


Да


Количество входов в каждый AND вентиль. Количество входных шин.

<


Каждый вентиль И имеет следующую функцию:


Входы


Выходы


data[LPM_SIZE-1]_[LPM_WIDTH-1]


result[LPM_WIDTH-1]


0XXX...


0


X0XX...


0


XX0X...


0


...


...


1111...


1

Используемый ресурс:

Простые вентили lpm_and используют приблизительно одну логическую ячейку на вентиль.


Объявление конечных автоматов


Конечный автомат создается определением его имени, состояний и в необязательном порядке его битами в разделе описания переменных.

Следующий пример демонстрирует описание конечного автомата:

VARIABLE

            ss :       MACHINE

                                    OF BITS (q1, q2, q3)

                                    WITH STATES (

                                                s1 = B"000",

                                                s2 = B"010",

                                                s3 = B"111");

Имя конечного автомата в данном примере ss. Биты состояний q1, q2 и q3 являются выходами регистров данного автомата. Состояниями данного конечного автомата являются s1, s2 и s3, каждому из которых  присвоено числовое значение представленное битами q1, q2 и q3.

Процедура объявления конечного автомата имеет следующие характеристики:

¨    Конечный автомат имеет символическое имя. В примере, показанном выше, именем конечного автомата является ss.

¨    За именем конечного автомата следует двоеточие и далее ключевое слово MACHINE.

¨    Определение конечного автомата должно включать список состояний, а также может включать имена битов состояний.

¨    Необязательное указание имен битов состояний производится с использованием ключевого слова OF BITS, за которым следует список имен битов, отделенных друг от друга запятыми ;список должен быть заключен в круглые скобки. В примере, показанном выше, определены имена битов состояний q1, q2 и q3.

¨    Состояния определяются ключевыми словами WITH STATES, за которым следует список имен состояний отделенных друг от друга запятыми ;этот список также должен быть заключен в круглые скобки. В примере,  показанном выше определены имена состояний s1, s2 и s3.

¨    Первое состояние указанное в списке состояний за ключевыми словами WITH STATES является состоянием Reset для конечного автомата.

¨    В необязательном порядке именам состояний могут быть присвоены числовые значения, следующие за знаком (=) после соответствующего имени состояния. В примере, показанном выше, состоянию с именем s1 присвоено числовое значение B”000”, состоянию с именем s2 присвоено числовое значение B”001” и s3 присвоено значение B”010”.

¨    Предусмотрена возможность определения псевдонима имени конечного автомата, объявленного в данном текстовом файле проекта или импортируемого из другого файла.

¨    Символ (;) заканчивает конструкцию определения конечного автомата.

Þ   Каждое состояние конечного автомата представляется уникальным набором значений на выходах триггеров,  хранящих состояния конечного автомата. Количество состояний связано с количеством битов состояний конечного автомата следующим образом:

<количество состояний> = 2^<количество битов состояний>



Объявление регистров


Регистры запоминают значения данных и синхронизируют их с помощью сигнала Clock. Вы можете объявить экземпляр регистра с помощью объявления Register в разделе Variable. ( Вы можете также реализовать регистр используя ссылки на функции в разделе Logic). AHDL предлагает несколько примитивов регистров, а также поддерживает регистровые LPM функции.

После того как Вы объявили регистр, Вы можете соединить его с другой логикой в TDF файле, используя его порты. Порт экземпляра используется в следующем формате:

<имя экземпляра>.<имя порта>

Файл bur_reg.tdf, приведенный ниже, использует объявление Register для создания байтного регистра, который фиксирует значения входов d на переднем фронте Clock, когда вход загрузки высокий.

SUBDESIGN bur_reg

(

   clk, load, d[7..0] : INPUT;

   q[7..0]            : OUTPUT;

)

VARIABLE

   ff[7..0]           : DFFE;

BEGIN

   ff[].clk = clk;

   ff[].ena = load;

   ff[].d = d[];

   q[] = ff[].q;

END;

Регистры объявляются в разделе Variable как DFFE(D триггер с сигналом разрешения). Первое булево уравнение в разделе Logic соединяет вход clk с портами Clock триггеров ff[7..0].

Второе уравнение соединяет вход загрузки с портами разрешения тактовой частоты. Третье уравнение соединяет входы данных d[7..0] с входными портами триггеров ff[7..0]. И четвертое уравнение соединяет выходы с выходными портами триггеров. Все четыре уравнения оцениваются совместно.

Вы можете также объявить T, JK, и SR триггеры в разделе Variable, а затем использовать в разделе Logic.

Если Вы хотите загрузить регистр на определенном переднем фронте глобального сигнала Clock, Altera рекомендует использовать вход разрешения тактовой частоты одного из DFFE, TFFE, JKFFE, или SRFFE триггеров для управления загрузкой регистра.

Файл lpm_reg.tdf, приведенный ниже, использует ссылку для реализации экземпляра функции lpm_dff, который обладает такой же функциональностью, как и файл bur_reg.tdf.

INCLUDE "lpm_dff.inc";

SUBDESIGN lpm_reg

(

   clk, load, d[7..0] : INPUT;

   q[7..0]            : OUTPUT;

)

BEGIN

q[] = lpm_dff (.clock=clk, .enable=load, .data[]=d[])

      WITH (LPM_WIDTH=8)

   RETURNS (.q[]);

END;



Объявление регистров


Объявление регистров используется для определения регистров, включая D, T, JK и SR триггеры (DFF, DFFE, TFF, TFFE, JKFF, JKFFE, SRFF и SRFFE)  и защелки (LATCH). Следующий пример демонстрирует описание регистра:

VARIABLE

            ff : TFF;

Именем объекта, представляющего собой Т - триггер, является ff. После данного объявления можно использовать входной и выходной порты объекта ff с использованием следующего формата:

ff.t

ff.clk

ff.clrn

ff.prn

ff.q

Поскольку все примитивы имеют только один выход можно использовать имя примитива без указания имени его выходного порта (например, без .q или .out) в правой части выражений. Аналогично, если примитив имеет лишь один вход (т.е. все примитивы за исключением примитивов JKFF, JKFFE, SRFF и SRFFE), то можно использовать имя примитива без указания имени его входного порта в левой части выражений (т.е., без .d, .t или .in).

Например, прототип функции для примитива DFF имеет вид : FUNCTION DFF(d, clk, clr, prn) RETURNS (q); . В следующем текстовом файле проекта выражение a = b эквивалентно a.d = b.q:

VARIABLE

            a, b : DFF;

BEGIN

            a = b;

END;



Объявление регистровых выходов


Вы можете объявить регистровые выходы TDF файла путем объявления выходных портов как триггеров в разделе Variable. Файл reg_out.tdf,  приведенный ниже, имеет туже самую функциональность,  что и файл bur_reg.tdf, но обладает регистровыми выходами.

SUBDESIGN reg_out

(

   clk, load, d[7..0] : INPUT;

   q[7..0]            : OUTPUT;

)

VARIABLE

q[7..0] : DFFE; % также объявлены как регистровые %

BEGIN

   q[].clk = clk;

   q[].ena = load;

   q[] = d[];

END;

Когда Вы присваиваете значение регистровым выходам в разделе Logic, то значение с d входов направляется в регистр. Выходы регистра не изменяются до тех пор, пока не появится возрастающий фронт сигнала Clock. Для определения тактового входа регистра используйте конструкцию <имя регистра>.clk в разделе Logic. Вы можете реализовать глобальный тактовый сигнал Clock, используя примитив GLOBAL

с помощью логической опции Global Signal

в диалоговом окне Individual Logic Options, которое Вы можете открыть из окна Logic Options ( меню Assign), или с помощью опции Automatic Global Clock из диалогового окна Global Project Logic Synthesis( меню Assign).

В файле,  приведенном ниже, каждый DFFE триггер, объявленный в разделе Variable, запитывает выход с тем же именем, поэтому Вы можете обратиться к выходам q триггеров без использования порта q.

В TDF файле высокого уровня выходные порты синхронизируются с выходными выводами. Когда Вы объявляете одинаковое имя для выходного порта и регистра, присваивания опций probe и logic применяются к выводу, а не регистру (за исключением логической опции Fast I/O). Поэтому, если Вы хотите протестировать регистр или использовать специфические для регистра логические опции, Вы должны по разному назвать регистры и порты.



Объявление узлов


Узел, который объявляется с помощью объявления Node в разделе Variable, можно использовать для хранения значения промежуточного выражения.

Объявления узлов особенно полезны, когда булево выражение используется повторно. Булево выражение можно заменить дескриптивным именем узла, которое легче читается.

Файл boole2.tdf,  приведенный ниже, содержит ту же самую логику что и файл boole1.tdf, но имеет только один выход.

SUBDESIGN boole2

(

   a0, a1, b   : INPUT;

   out         : OUTPUT;

)

VARIABLE

   a_equals_2  : NODE;

BEGIN

   a_equals_2 = a1 & !a0;

   out = a_equals_2 # b;

END;

Этот файл объявляет узел a_equals_2 и связывает его с выражением a1 & !a0. При использовании узлов можно сохранять ресурсы устройства, когда узел используется в нескольких выражениях.

Можно использовать как обычные узлы (NODE), так и тристабильные узлы (TRI_STATE_NODE). NODE и TRI_STATE_NODE различаются в том, что несколько присваиваний на них дают различные результаты.

Присваивания на узлы типа NODE связывают сигналы вместе с помощью функций ПРОВОДНОЕ-И или ПРОВОДНОЕ-ИЛИ. Значения по умолчанию, объявленные в операторах Defaults, определяют поведение: VCC представляет функцию ПРОВОДНОЕ-И, а GND представляет функцию ПРОВОДНОЕ-ИЛИ.

Присваивания на TRI_STATE_NODE привязывают сигналы к одному и тому же узлу.

Если только одной  переменной назначается тип TRI_STATE_NODE, то она трактуется как NODE.



Объявления псевдоимен конечных автоматов


Используя процедуру объявления псевдоимени конечного автомата в разделе описания переменных, можно описать псевдоимя для данного, описанного или импортированного из другого файла конечного автомата. После указанной процедуры можно пользоваться псевдоименем конечного автомата наравне с его исходным. Например:

FUNCTION ss_def (clock, reset, count)

            RETURNS (MACHINE ss_out);

VARIABLE

            ss : MACHINE;

BEGIN

            ss = ss_def (sys_clk, reset, !hold);

            IF ss == s0 THEN

            ELSIF ss == s1 THEN

END;

Процедура объявления псевдоимени конечного автомата имеет следующие характеристики:

¨    Псевдоним представляет собой символическое имя. За псевдонимом следует символ двоеточия и далее ключевое слово MACHINE. В примере, показанном выше, символическое имя ss является псевдонимом конечного автомата.

¨    Предусмотрена возможность импортирования и экспортирования конечных автоматов между текстовыми файлами проектов, а также другими файлами проектов путем определения входных и выходных портов с использованием ключевых слов MACHINE INPUT или MACHINE OUTPUT в разделе Subdesign.

¨    При импортировании и экспортировании конечных автоматов прототип функции, представляющий файл описания конечного автомата должен определять какие входы и выходы являются конечными автоматами. В примере, показанном выше, ss_out является именем конечного автомата.

¨    Декларация псевдонима конечного автомата заканчивается символом (;).

Þ   Порты типов MACHINE INPUT и MACHINE OUTPUT не могут использоваться в  файлах проектов верхнего уровня.



Обзор


Текстовый файл проекта на языке AHDL должен содержать, как минимум, два раздела: Subdesign и Logic. Все остальные разделы и операторы являются необязательными. В предлагаемом к ознакомлению разделе ‘Структура проекта’ информация об операторах и разделах языка AHDL дается в том порядке, в котором они следуют в текстовом файле проекта (TDF - Text Design File).



Оператор Assert


Оператор Assert позволяет проверять действительность выражений арбитражного характера, в которых используются параметры, числа, оценочные функции, а также статусные состояния портов (используется порт или не используется)

Следующий пример демонстрирует использование оператора Assert:

ASSERT (WIDTH > 0)

            REPORT           "Ширина (%) должна быть положительным целым" WIDTH

            SEVERITY                     ERROR

            HELP_ID                       INTVALUE;       

-- for internal Altera use only

Оператор Assert имеет следующие характеристики:

За ключевым словом ASSERT следует  арифметическое выражение, в необязательном порядке заключенное в круглые скобки. Когда выражение принимает значение ‘ложь’, строка - сообщение, следующая за ключевым словом REPORT, выводится в текстовом процессоре .При отсутствии условного выражения  строка сообщения выводится безусловно.

За ключевым словом REPORT следует строка сообщения и необязательные параметры, представленные переменными. Строка сообщения заключается в двойные кавычки и может содержать символы  %  , которые замещаются  значениями соответствующих переменных. Если ключевое слово REPORT не используется  и при этом  значение выражения арбитражного характера  принимает значение ‘ложь’, то  в текстовом процессоре выдается следующее сообщение:

<severity>: Line <line number>, File <filename>: Assertion failed

Необязательные переменные, включаемые в сообщение состоят из одного или более параметров, оценочных функций или арифметических выражений. Переменные, включаемые в сообщение отделяются друг от друга запятыми. Значения переменных  подставляются  в порядке появления в сообщении символов  % .В примере, показанном выше, значение переменной WIDTH заменяет символ %  в строке сообщения.

За необязательным ключевым словом SEVERITY следует уровень  строгости ERROR, WARNING или INFO. По умолчанию предполагается уровень строгости ERROR.

Ключевое слово HELP_ID и строка - подсказка поддерживается в некоторых поставляемых фирмой Altera функциях и зарезервировано для внутреннего использования фирмой Altera.

Оператор Assert заканчивается символом (;).

Оператор Assert может использоваться внутри раздела Logic или за пределами других разделов языка AHDL.



Оператор Case


Файл decoder.tdf, приведенный ниже, описывает дешифратор 2 в 4 бита. Он преобразует 2-битный код в унарный код.

SUBDESIGN decoder

(

            code[1..0]         : INPUT;

            out[3..0]            : OUTPUT;

)

BEGIN

            CASE code[] IS

                        WHEN 0 => out[] = B"0001";

                        WHEN 1 => out[] = B"0010";

                        WHEN 2 => out[] = B"0100";

                        WHEN 3 => out[] = B"1000";

            END CASE;

END;

В этом примере входной код шины имеет значения 0, 1, 2 или 3. В операторе Case за символом => следует активизируемое уравнение. Например, если code[] равен 1, то выход out1 устанавливается в B"0010". Поскольку все значения выражения различны, в одно время можно активизировать только одну область WHEN



Оператор Case


Оператор Case определяет список альтернативных вариантов, которые могут быть активизированы в зависимости от значения переменной, группы или выражения, следующего за ключевым словом CASE.

Следующий пример демонстрирует использование оператора Case:

CASE f[].q IS

            WHEN H"00" =>

                        addr[] = 0;

                        s = a & b;

            WHEN H"01" =>

                        count[].d = count[].q + 1;

            WHEN H"02", H"03", H"04" =>

                        f[3..0].d = addr[4..1];

            WHEN OTHERS =>

                        f[].d = f[].q;

END CASE;

Оператор Case имеет следующие характеристики:

¨    Булевское выражение, группа или конечный автомат  располагаются между ключевыми словами CASE и IS (в примере, показанном выше,  это f[ ].q).

¨    Оператор Case завершается ключевыми словами END CASE за которыми следует символ (;).

¨    Телом оператора Case является список из одного или более неповторяющихся альтернативных вариантов, следующих за ключевым словом WHEN. Каждому альтернативному варианту предшествует ключевое слово WHEN.

¨    Каждый альтернативный вариант представляет собой одно или более отделенных друг от друга запятыми значений констант, за  которыми следует символ (=>).

¨    Если значение булевского выражения, стоящего за ключевым словом CASE, соответствует какому - либо альтернативному варианту, то все операторы, следующие за соответствующим символом (=>) активизируются. В примере, приведенном выше, если f[ ].q равно h”01”, то активизируется булевское выражение count[ ].d = count[ ].q + 1.

¨    Если значение булевского выражения, стоящего за ключевым словом CASE не равно ни одному из альтернативных вариантов, то активизируется  альтернативный вариант, стоящий за ключевыми словами WHEN OTHERS. В примере, показанном выше, если значение f[ ].q не равно H”00”, H’01” или H”CF”, то активизируется выражение f[ ].d = f[].q.

¨    Оператор Defaults  определяет значение по умолчанию для тех случаев, когда ключевые слова WHEN OTHERS не используются.

¨    Если оператор Case используется для определения переходов конечного автомата, то ключевые слова WHEN OTHERS не могут использоваться для выхода из недопустимых состояний. Если состояния конечного автомата определяются n -мерным кодом и при этом автомат имеет 2^n состояний, то использование ключевых слов WHEN OTHERS является допустимым.

¨    Каждый альтернативный вариант должен заканчиваться символом (;).



Оператор Constant


Оператор Constant позволяет ввести в применение информативное символическое имя для числа или арифметического выражения. Следующие примеры демонстрируют использование оператора Constant:

CONSTANT UPPER_LIMIT = 130;

CONSTANT BAR = 1 + 2 DIV 3 + LOG2(256);

CONSTANT FOO = 1;

CONSTANT FOO_PLUS_ONE = FOO + 1;

Оператор Constant имеет следующие характеристики:

¨    Оператор Constant начинается с ключевого слова CONSTANT, за которым следует символическое имя, затем символ (=) и далее число (при необходимости, включая его основание) или арифметическое выражение.

¨    Оператор Constant заканчивается символом (;).

¨    После того, как константа была определена,  она может быть использована в пределах всего текстового файла проекта (TDF). В примере, приведенном выше, в разделе Logic можно использовать константу UPPER_LIMIT для представления десятичного числа 130.

¨    Константы могут быть определены посредством арифметических выражений. В эти арифметические выражения могут входить константы определенные ранее.

¨    Компилятор вычисляет арифметические выражения,  используемые в операторе Constant и упрощает их до числовых значений. При этом не производится  генерация логических схем.

При использовании оператора Constant необходимо соблюдать следующие правила:

¨    Константа может быть использована лишь после того, как она определена.

¨    Имена констант должны быть уникальными.

¨    Имя константы не должно содержать пробелов. Для разделения слов в имени константы и улучшения восприятия имен констант  следует пользоваться символом подчеркивания.

¨    Оператор Constant может использоваться произвольное количество раз в рамках одного текстового файла проекта.

¨    Oператор Constant должен быть расположен за пределами других разделов  языка AHDL.

¨    Константы, используемые для определения других констант, должны быть определены ранее.

¨    Использование циклических ссылок недопустимо. Следующий пример демонстрирует использование недопустимой циклической ссылки:

CONSTANT FOO = BAR;

CONSTANT BAR = FOO;



Оператор Defaults


Оператор Defaults  позволяет определять значения по умолчанию,  применяемые в таблицах истинности, а также в операторах If Then и Case. Поскольку активно- высокие сигналы автоматически имеют значения по умолчанию GND, то оператор Default необходим лишь в случае использования активно-низких сигналов.

Þ   Не следует путать значения по умолчанию, присваиваемые переменным со значениями по умолчанию, присваиваемыми портам в разделе Subdesign.

Следующий пример демонстрирует использование оператора Defaults:

BEGIN

            DEFAULTS

                        a = VCC;

            END DEFAULTS;

            IF y & z THEN

            a = GND;           % a активный низкий %

            END IF;

END;

Оператор Defaults имеет следующие характеристики:

¨    Значения по умолчанию заключаются в ключевые слова DEFAULTS и END DEFAULTS. Оператор заканчивается символом (;).

¨    Тело оператора Defaults  состоит из одного или более логических выражений, присваиваемых константам или переменным. В примере, показанном выше, значение по умолчанию VCC присваивается переменной a.

¨    Каждое выражение заканчивается символом (;).

¨    Оператор Default активизируется в том случае, когда какая-либо переменная, включенная в список оператора Default в каком-либо из операторов, оказывается неопределенной. В примере, показанном выше, переменная a оказывается неопределенной, если y и z

имеют значения логического нуля; таким образом активизируется выражение (a = VCC) в операторе Default.

При использовании оператора Default необходимо соблюдать следующие правила:

¨    В разделе Logic допускается использовать не более одного оператора Default и кроме того при его использовании он должен располагаться  сразу за ключевым словом BEGIN.

¨    Если в операторе Default в отношении одной и той же переменной  производятся многократные присваивания, то все присваивания за исключением последней игнорируются.



Оператор Define


Оператор Define позволяет определить оценочную функцию (evaluated function), представляющую собой математическую функцию,  возращающую значение, вычисленное на основе необязательных входных аргументов.

В следующем примере описывается оценочная функция MAX, предопределяющая существование по меньшей мере одного порта в разделе Subdesign:

DEFINE MAX(a,b) = (a > b) ? a : b;

SUBDESIGN

(

   dataa[MAX(WIDTH,0)..0]: INPUT;

   datab[MAX(WIDTH,0)..0]: OUTPUT;

)

BEGIN

   datab[] = dataa[];

END;

Оператор Define имеет следующие характеристики:

¨    Оператор Define начинается с ключевого слова DEFINE, за  которым следует символическое имя и список из одного или более аргументов, заключенных в круглые скобки.

¨    Аргументы отделяются друг от друга запятыми. Символ (=) отделяет список аргументов от арифметического выражения

Þ   При отсутствии аргументов оценочная функция эквивалентна константе.

Þ   Компилятор производит вычисления арифметических выражений приведенных в операторе Define и упрощает их до числовых значений. Генерации логических схем при этом не производится.

¨    Оператор заканчивается символом (;).

¨    Один раз определенная оценочная функция может использоваться затем в пределах всего текстового файла проекта (TDF).

¨    Для определения оценочных функций могут использоваться ранее определенные оценочные функции. Например, приведенная ниже оценочная функция MIN_ARRAY_BOUND вычисляется на основе значения оценочной функции MAX:

DEFINE MAX(a,b) = (a > b) ? a : b;

DEFINE MIN_ARRAY_BOUND(x) = MAX(0, x) + 1;

При использовании оператора Define необходимо соблюдать следующие правила:

¨    Оценочная функция может быть использована только после того как она была определена.

¨    Имена оценочных функций должны быть уникальными.

¨    Имена оценочных функций не должны содержать пробелов. Для разделения слов в имени оценочной функции и улучшения ее восприятия следует пользоваться символом подчеркивания.

¨    Оператор Define может использоваться произвольное количество раз в рамках одного текстового файла проекта.

¨    Oператор Define должен быть расположен за пределами других разделов  языка AHDL.



Оператор For Generate


Следующий пример показывает использование итерационного оператора For Generate:

CONSTANT NUM_OF_ADDERS = 8;

SUBDESIGN 4gentst

(

a[NUM_OF_ADDERS..1], b[NUM_OF_ADDERS..1],

 cin                                          : INPUT;

c[NUM_OF_ADDERS..1], cout    : OUTPUT;

)

VARIABLE

            carry_out[(NUM_OF_ADDERS+1)..1] : NODE;

BEGIN

carry_out[1] = cin;

            FOR i IN 1 TO NUM_OF_ADDERS GENERATE

                        c[i] = a[i] $ b[i] $ carry_out[i];                % Полный сумматор %

carry_out[i+1] = a[i] & b[i] # carry_out[i] & (a[i] $ b[i]);

            END GENERATE;

cout = carry_out[NUM_OF_ADDERS+1];

END;

Оператор For Generate имеет следующие характеристики:

¨    Между ключевыми словами FOR и GENERATE  заключаются следующие параметры:

1.   Временная переменная, представляющая собой символическое имя. Эта переменная используется лишь в пределах оператора For Generate и заканчивает свое существование после того, как компилятор обработает этот оператор. В примере, показанном выше такой переменной является переменная i. Это имя не может использоваться в качестве имени константы, параметра или узла в пределах данного проекта.

2.   За ключевым словом IN следует диапазон, ограниченный двумя арифметическими выражениями. Арифметические выражения разделяются между собой ключевым словом TO. В примере, показанном выше арифметическими выражениями являются 1 и NUM_OF_ADDRESS. Границы диапазона могут  содержать выражения, состоящие только из констант и параметров; использование переменных при этом недопустимо.

¨    За ключевым словом GENERATE следует один или более логических операторов, каждый из которых заканчивается символом (;).

¨    Оператор If Generate заканчивается ключевыми словами END GENERATE, за которыми следует символ (;).  



Оператор Function Prototype


Операторы Function Prototype имеют ту же функцию, что и символы в графических файлах проектов. И те и другие представляют собой краткое описание функции, описывая ее имя, а также входные, выходные и двунаправленные порты. Для функций, импортирующих и экспортирующих конечные автоматы,  могут использоваться порты автомата.

Входные порты мега- и макрофункций не имеют значений по умолчанию, как это имеет место в файлах графического редактора MAX+PLUSII. Поэтому входные значения неиспользуемых портов должны быть указаны явно. Кроме того в секции Subdesign могут быть указаны значения по умолчанию для двунаправленных портов. Заметим, что для выходных портов нельзя определить значения по умолчанию.

 Перед созданием объекта (an instance) мега- или макрофункции  необходимо убедиться в существовании соответствующего ей  файла проекта, описывающего ее логическое функционирование. Затем с помощью оператора Function Prototype  описываются порты функции  и создается экземпляр (an instance) логической функции путем объявления объекта (Instance Declaration) или подставляемой ссылки (in-line reference),

Следующие примеры демонстрируют использование операторов Function Prototype. Первый пример демонстрирует описание параметризируемой функции, а второй - не параметризируемой функции:

FUNCTION lpm_add_sub (cin, dataa[LPM_WIDTH-1..0], datab[LPM_WIDTH-1..0],   add_sub)

   WITH (LPM_WIDTH, LPM_REPRESENTATION, LPM_DIRECTION, ADDERTYPE,    

      ONE_INPUT_IS_CONSTANT)

   RETURNS (result[LPM_WIDTH-1..0], cout, overflow);

FUNCTION compare (a[3..0], b[3..0])

            RETURNS (less, equal, greater);

Оператор Function Prototype имеет следующие характеристики:

¨    За ключевым словом FUNCTION следует имя функции. В примерах показанных выше использованы имена функций  lpm_add_sub и compare.

¨    За именем функции следует список входных портов. В первом примере, показанном выше, входными портами являются cin, dataa[LPM_WIDTH-1..0] и datab[LPM_WIDTH-1..0]; во втором примере входными портами являются a3,a2,a1,a0,b3,b2,b1 и b0.




¨    В параметризируемой функции за списком параметров следует ключевое слово WIDTH и список имен параметров. Список заключен в круглые скобки; имена отделены друг от друга запятыми.

¨    За списком выходных и двунаправленных портов функции следует ключевое слово RETURNS.В первом  примере, показанном выше, выходными портами являются result[LPM_WIDTH-1..0], count и overflow ;во втором примере - less, equal и greater.

¨    Список входных и выходных портов заключается в круглые скобки. Имена отделяются друг от друга запятыми.

¨    При импортировании и экспортировании конечных автоматов, используемый файлом оператор Function Prototype должен использовать автоматный порт (определяемый ключевым словом MACHINE) для указания того, какие входы и выходы являются конечными автоматами. Пример:

FUNCTION ss_def (clock, reset, count)

   RETURNS (MACHINE ss_out);

¨    Оператор Function Prototype заканчивается символом (;).

¨    Oператор Function Prototype должен быть расположен за пределами других разделов  языка AHDL и кроме того он должен располагаться до экземпляра логической функции созданной путем объявления объекта или подставляемой ссылки (in-line reference).

Для экземпляра примитива

также следует использовать механизм  объявления объекта (Instance Declaration) или подставляемую ссылку (in-line reference). Однако, в отличие от мега- и макрофункций логика функционирования примитива предопределена, таким образом нет необходимости определять логику функционирования примитива в отдельном файле проекта. Кроме того нет необходимости использовать оператор Function Prototype, за исключением тех случаев, когда нужно изменить порядок следования портов примитива.

Следующий пример демонстрирует прототип функции, существующий по умолчанию для примитива JKFF:

FUNCTION JKFF (j, k, clk, clrn, prn)

            RETURNS (q);

Данный пример показывает модифицированный прототип функции для примитива JKFF:

FUNCTION JKFF (k, j, clk, clrn, prn)

            RETURNS (q);

Альтернативой использования оператора Function Prototype в файле проекта является применение оператора Include для подключения файлов с расширением .inc, содержащих прототипы используемых функций. Кроме того MAX+PLUSII имеет в своем составе команду Create Default Include File в меню File, которая автоматически создает файл с расширением .inc, содержащий прототип функции для текущего файла проекта.

Прототипы функций для всех мега- и макрофункций  хранятся в файлах с расширением .inc в директориях \maxplus2\max2lib\mega_lpm и \maxplus2\max2inc соответственно. Контекстно-зависимая подсказка для всех поставляемых фирмой Altera мега-, макрофункций и примитивов, выводит содержимое соответствующих им прототипов функций.


Оператор If Generate


Оператор If Generate содержит список операторов, активизирующийся в случае положительного результата оценки арифметического выражения.

Следующий пример демонстрирует использование оператора If Generate:

IF DEVICE_FAMILY == "FLEX8K" GENERATE

            c[] = 8kadder(a[], b[], cin);

ELSE GENERATE

            c[] = otheradder(a[], b[], cin);

END GENERATE;

Оператор If Generate имеет следующие характеристики:

¨    Между ключевыми словами If  Generate заключается арифметическое выражение, значение которого подвергается оценке. За ключевым словом GENERATE следует список операторов, каждый из которых заканчивается символом (;). Операторы активизируются в том случае, если арифметическое выражение принимает истинное значение.

¨    За ключевыми словами ELSE GENERATE следует один или более операторов, которые активизируются в случае, если арифметическое выражение принимает ложное значение.

¨    Оператор If Generate заканчивается ключевыми словами END GENERATE, за которыми следует символ (;).

¨    Оператор If Generate может использоваться в разделе Logic и в  разделе Variable.

Þ   В отличие от операторов If Then, которые могут оценивать лишь значения булевских выражений, операторы If Generate могут оценивать значения наборов арифметических выражений. Основное различие между операторами If Then и If Generate состоит в том, что в первом случае значение булевского выражения оценивается аппаратным способом (в кремнии), а во втором случае значение набора арифметических выражений оценивается на этапе компиляции.

Þ   Оператор If Generate особенно часто используется с операторами For Generate, что позволяет различным образом обрабатывать особые ситуации, например, младший значащий бит в многокаскадном умножителе. Этот  оператор может также использоваться для тестирования значений параметров, как показано в последнем примере.



Оператор If Then


Файл priority.tdf,  приведенный ниже, демонстрирует приоритетный шифратор, который преобразует уровень активного входа с наивысшим приоритетом в значение.

SUBDESIGN priority

(

   low, middle, high   : INPUT;

   highest_level[1..0] : OUTPUT;

)

BEGIN

   IF high THEN

      highest_level[] = 3;

   ELSIF middle THEN

      highest_level[] = 2;

   ELSIF low THEN

      highest_level[] = 1;

   ELSE

      highest_level[] = 0;

   END IF;

END;

В этом примере входы high, middle, и low оцениваются для определения того, является ли их уровни равными VCC. Оператор If Then активизирует уравнения, которые следуют за активной IF или ELSE областями и, если  вход high высокий, то highest_level[] равен 3.

Если активизируется более одного входа, то оператор If Then оценивает приоритет входов в порядке следования областей IF и ELSIF ( первая область имеет наивысший приоритет).

Если ни один из входов не активизирован, по срабатывает уравнение, следующие за ключевым словом ELSE.



Оператор If Then


Оператор If Then содержит список операторов, выполняемых в том случае, если булевское выражение, расположенное между ключевыми словами IF и THEN, принимает истинное значение .

Следующий пример демонстрирует использование оператора If Then:

IF a[] == b[] THEN

            c[8..1] = H "77";

            addr[3..1] = f[3..1].q;

            f[].d = addr[] + 1;

ELSIF g3 $ g4 THEN

            f[].d = addr[];

ELSE

            d = VCC;

END IF;

Оператор If Then имеет следующие характеристики:

¨    Между ключевыми словами IF и THEN располагается булевское выражение, в зависимости от значения которого выполняется или не выполняется список операторов, располагающийся за ключевым словом THEN. Каждый оператор в этом списке оканчивается символом (;).

¨    Между ключевыми словами ELSEIF и THEN располагается дополнительное булевское выражение а за ключевым словом THEN также располагается список операторов, выполняемых в зависимости от значения булевского выражения. Эти необязательные ключевые слова и операторы могут повторяться многократно.

¨    Оператор(ы), следующий за ключевым словом THEN, активизируется в том случае, если соответствующее ему булевское выражение принимает истинное значение. При этом последующие конструкции ELSEIF THEN игнорируются.

¨    Ключевое слово ELSE, за которым следует один или более операторов, схоже по своему значению с ключевыми словами WHEN OTHERS  в операторе Case. Если ни одно из булевских выражений не приняло истинное значение, то выполняются операторы, следующие за ключевым словом ELSE. В примере, показанном выше, если ни одно из булевских выражений не приняло истинного значения, то выполняется оператор d = VCC. Использование ключевого слова ELSE не является обязательным.

¨    Значения булевских выражений, следующих за ключевыми словами IF и ELSEIF оцениваются последовательно.

¨    Оператор If Then заканчивается ключевыми словами END IF за которыми следует символ (;).