
Altera / ahdl
.pdfНапример: B ”10x00”, H ”5ED0”.
Логические уравнения (Boolean Equation)
Логическое уравнение – логическое выражение с использованием логических или арифметических операторов, а также операторов сравнения для выполнения логических преобразований над входными и выходными портами и переменными.
Уравнения описываются в следующем виде:
__node_name = __node_name __operator __node_name;
где __node_name – обозначение порта или именованного вывода, а operator - логический, арифметический или оператор сравнения. Возможно применение скобок для выполнения нескольких логических преобразований в одном выражении.
В AHDL используются следующие логические операторы (Табл. 1).
Табл. 1. Логические операторы языка AHDL
Оператор |
Пример использования |
Описание |
! |
!fo |
Инверсия |
NOT |
NOT fo |
|
& |
fo & x4 |
И |
AND |
fo AND x4 |
|
!& |
a[3..1] !& b[5..3] |
И-НЕ |
NAND |
a[3..1] NAND b[5..3] |
|
# |
x2 # z1 |
ИЛИ |
OR |
x2 OR z1 |
|
!# |
a[3..1] !# b[5..3] |
ИЛИ-НЕ |
NOR |
a[3..1] NOR b[5..3] |
|
$ |
f_mux $ data[5] |
Исключающее ИЛИ |
XOR |
f_mux XOR data[5] |
|
!$ |
f_mux !$ data[5] |
Инверсия исключающего ИЛИ |
XNOR |
f_mux XNOR data[5] |
|
Арифметические операторы и операторы сравнения языка AHDL приведены в Табл. 2 и Табл. 3 соответственно.
Табл. 2. Арифметические операторы языка AHDL
Оператор |
Пример |
Описание |
+ (унарный) |
+1 |
Плюс |
- (унарный) |
-a[4..1] |
Минус |
+ |
count[7..0] + delta[7..0] |
Сложение |
- |
count[] - delta[] |
Вычитание |
! |
!a |
Отрицание |
^ |
a ^ 2 |
Степень |
MOD |
4 MOD 2 |
Модуль |
DIV |
4 DIV 2 |
Деление |
LOG2 |
LOG2(4-3) |
Логарифм по основанию 2 |
* |
a * 2 |
Умножение |
11
Табл. 3. Операторы сравнения языка AHDL
Оператор |
Пример |
Описание |
== (логическое) |
addr[19..4] == H”B800” |
Равно |
!= (логическое) |
b1 != b3 |
Не равно |
< (арифметическое) |
frame[] < power[] |
Меньше |
<= (арифметическое) |
money[] <= power[] |
Меньше или равно |
> (арифметическое) |
liv[] > max[] |
Больше |
>= (арифметическое) |
delta[] >= 0 |
Больше или равно |
Порядок использования логических уравнений может быть произвольным, поскольку, в отличие от языков программирования, компилятор осуществляет параллельное их выполнение.
Группы
Однотипные переменные или выводы могут быть объединены в одномерную, двумерную или временную группу.
Текстовое описание, иллюстрирующее использование одномерных и временных
групп:
SUBDESIGN Group |
|
|
( |
|
|
A[3..0]: |
INPUT; |
--одномерная группа с 4 членами |
B[4..1] : |
INPUT; |
-- одномерная группа с 4 членами |
c, d, e, f: |
INPUT; |
--одноразрядные входы |
E[2..1]: |
INPUT; |
-- одномерная группа с 3 членами |
OUT[5..2]: |
OUTPUT; |
-- одномерная группа с 4 членами |
R[1..0][2..1]: |
OUTPUT; |
--двумерная группа |
)
BEGIN
OUT[] = (A[] # B[1..4]) & !(c, d, e, f); R[][] = (E[1..2], E[]);
END;
Группы A[] и B[] имеют одинаковое число членов, поэтому возможно поразрядное применение оператора # (из примера).
Если в логическом уравнении используются все члены группы, причем в том же порядке, в котором они были заданы, то для ссылки на такую группу можно воспользоваться сокращенной формой записи: A[] вместо A[3..0]. При ссылке на группу B[4..1] ее индексы перечислены в обратном порядке B[1..4], поэтому указываются явно.
(c, d, e, f) – временная группа с 4 членами. Выражение !(c, d, e, f) задает поразрядное выполнение инвертирования.
Значение одной группы может быть присвоено другой группе (т.е. между ними можно поставить знак равенства) только в том случае, если они имеют одинаковое число разрядов.
Базовые значения логических функций (Defaults Statement)
Необходимость в задании базовых значений логических функций возникает тогда, когда они определены не на всех наборах аргументов. Базовые значения могут быть заданы:
неявно (по умолчанию);
12
явно.
Задаваемое по умолчанию базовое значение — логический нуль.
Для явного задания базовых значений логических функций применяется оператор
DEFAULTS:
DEFAULTS
__node_name = __constant_value; END DEFAULTS;
При описании логической функции с помощью операторов CASE и IF THEN целесообразно явное определение ее на всех наборах аргументов.
Константы (Constant Statement)
Использование в текстовом описании символических имен вместо фиксированных числовых значений (т. е. использование констант) позволяет:
сделать текстовое описание более наглядным;
упростить внесение изменений, связанных с изменением фиксированных числовых значений.
Константы задаются следующим образом:
CONSTANT __constant_name = __constant_value;
Пример использования констант приведен ниже:
CONSTANT у = 9;
CONSTANT IO_ADR = y-4;
CONSTANT ADC = IO_ADR+2;
Таблица истинности (Truth Table Statement)
Таблица истинности логической функции задается следующим образом:
TABLE |
|
__node_name,__node_name |
=> __node_name, |
__input_value, __input_value |
=> __output_value, |
__input_value, __input_value |
=> __output_value, |
__input_value, __input_value |
=> __output_value, |
END TABLE; |
|
__node_name;
__output_value; __output_value; __output_value;
Открывает таблицу ключевое слово TABLE, а закрывают ключевые слова END TABLE, за которыми следует точка с запятой (;).
Первая после слова TABLE строка определяет форму таблицы. В ней через запятую перечисляются аргументы (внутренние переменные, входы или выходы модуля) и имена формируемых логических функций (внутренние переменные или выходы модуля). Аргументы и функции разделяет символ стрелка (=>). В конце строки ставится точка с запятой. В следующих строках в соответствии с заданной формой указываются наборы аргументов и значения логических функций.
Ниже приведен пример использования таблицы истинности:
13
TABLE |
|
|
|
|
a0, |
f[4..1].q |
=> |
f[4..1].d, |
y_out; |
0, |
B"0000" |
=> |
H"1", |
1; |
0, |
B"0100" |
=> |
H"2", |
0; |
1, |
B"0XXX" |
=> |
H"4", |
0; |
X, |
B"1111" |
=> |
H"6", |
1; |
END TABLE; |
|
|
|
|
Оператор IF THEN (If Then Statement)
Оператор If then может использоваться в одной из следующих форм:
IF __expression THEN |
IF __expression THEN |
IF __expression THEN |
__statement; |
__statement; |
__statement; |
__statement; |
__statement; |
__statement; |
ELSIF __expression THEN |
ELSE |
END IF; |
__statement; |
__statement; |
|
__statement; |
__statement; |
|
ELSE |
END IF; |
|
__statement; |
|
|
__statement; |
|
|
END IF; |
|
|
Он, в общем случае, позволяет последовательно оценить истинность нескольких логических выражений и в соответствии с полученными результатами выполнить те или иные действия.
Оператор может быть и составным:
IF __expression THEN __statement; __statement;
ELSIF __expression THEN __statement; __statement;
ELSIF __expression THEN __statement; __statement;
ELSIF __expression THEN __statement; __statement;
ELSE
__statement; __statement;
END IF;
Отметим, что оператору IF THEN внутренне присущна приоритетность проверки условий.
Оператор CASE (Case Statement)
Этот оператор может использоваться в одной из следующих форм:
14
CASE __expression IS
WHEN __constant_value => __statement; __statement;
WHEN __constant_value => __statement; __statement;
WHEN OTHERS => __statement; __statement;
END CASE;
CASE __expression IS
WHEN __constant_value => __statement; __statement;
WHEN __constant_value => __statement; __statement;
END 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;
Оператор цикла (For Generate Statement)
Оператор цикла позволяет упростить запись последовательности сходных логических уравнений и операторов языка AHDL и имеет следующий вид:
FOR __index_variable IN __range GENERATE __statement;
__statement; END GENERATE;
Оператор задается следующим образом:
За ключевым словом FOR указывается символическое имя внутренней переменной оператора. Это имя не может совпадать с именем констант, параметров или переменных, используемых в текстовом описании.
Ключевые слова IN ... TO ... определяют границы изменения значений внутренней переменной оператора.
Границы задаются арифметическими выражениями. |
| |
За ключевым словом GENERATE следуют логические уравнения и операторы языка AHDL.
Оператор оканчивается ключевыми словами END GENERATE, за которыми следует точка с запятой (;).
Пример использования оператора:
CONSTANT NUM_OF_ADDERS = 8;
15
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;
Примитивы (Primitives)
Для использования в текстовом описании модуля примитива необходимо обратиться к встроенному в пакет функциональному описанию данного примитива и сопоставить его выводам числа, константы, переменили выводы модуля.
В языке AHDL определены два способа обращения к примитиву:
непосредственное обращение (In_Line Reference);
присвоение примитиву символического имени, т. е. объявление его переменной,
иобращение к нему как к переменной.
Непосредственное обращение к примитиву осуществляется следующим образом:
указывается выход (либо внутренняя переменная) модуля, на который передается сигнал с выхода примитива;
далее ставится знак равенства и имя примитива;
за именем примитива в круглых скобках, через запятую перечисляются передаваемые значения: числа, константы, переменные или выводы модуля, сопоставляемые входам примитива;
за круглыми скобками ставится точка с запятой.
Сопоставление входов примитива с передаваемыми значениями может осуществляться:
позиционно;
по именам.
При позиционном сопоставлении порядок перечисления передаваемых значений должен соответствовать порядку перечисления входов, использованному в описании прототипа примитива:
Вход модуля (внутренняя переменная) = Имя примитива (передаваемое значение, передаваемое значение,...)
16
Отметим, что прототипы примитивов встроены в пакет, и для их подключения к текстовому описанию оператор INCLUDE не используется.
Если некоторые из входов примитива не используются, то соответствующие позиции в списке передаваемых значений должны быть оставлены пустыми.
При сопоставлении передаваемых значений и входов примитива по именам в списке передаваемых значений через запятую перечисляются пары: вход, передаваемое значение. Формат записи:
Вход модуля (внутренняя переменная) = Имя примитива (.имя выхода=передаваемое значение, .имя выхода=передаваемое значение, ...);
Пары могут быть расположены в произвольном порядке, т. е. независимо от того, в какой последовательности перечислены входы в описании прототипа примитива. Неиспользованные входы примитива в списке передаваемых значений не указываются.
Другой способ обращения к примитиву — обращение к нему как переменной. При реализации этого способа примитив, прежде всего, следует объявить перемен-
ной. Для этого в разделе переменных (Variable Section) символическому имени или группе символических имен сопоставляется примитив. Объявленная таким образом переменная, а также каждая переменная из объявленной группы переменных, будет иметь тот же набор выводов, что и примитив.
Обращение к конкретному выводу примитива осуществляется путем указания имени переменной, разделяющей точки и имени вывода примитива.
Прототип модуля (Function Prototype Statement)
Язык AHDL позволяет при описании модуля использовать в качестве компонентов созданные ранее модули. Для этого текстовое описание верхнего уровня иерархии должно содержать описания прототипов этих модулей.
Прототип задается с помощью оператора Function Prototype Statement, который может быть расположен либо непосредственно в текстовом описании, либо в файле включения (Include File), содержимое которого подсоединяется к текстовому описанию на этапе компиляции.
Файл включения (Include File) с описанием прототипа модуля создается с помощью команды Create Default Include File (меню File), выполняемой в окне текстового редактора пакета MAX+plusII, содержащем описание модуля.
В языке AHDL определены два способа обращения к прототипу модуля:
Непосредственное обращение (In_Line Reference).
Присвоение прототипу символического имени, т. е. объявление его переменной,
иобращение к нему как к переменной.
Отметим, что указанные способы обращения к прототипу совпадают с описанными ранее способами обращения к примитиву. В языке AHDL определено два типа модулей:
Параметризированные (Parameterized).
Непараметризированные (Unparameterized).
При этом, как те, так и другие могут быть созданы либо самим разработчиком, либо фирмой Altera.
17