Язык описания аппаратуры AHDL разработан фирмой Altera и предназначен для описания комбинационных и последовательностных логических устройств, групповых операций, цифровых автоматов (state machine) и таблиц истинности с учетом архитектурных особенностей ПЛИС фирмы Altera. Он полностью интегрируется с системой автоматизированного проектирования ПЛИС MAX+PLUS II. Файлы описания аппаратуры, написанные на языке AHDL, имеют расширение *.TDF (Text design file). Для создания TDF-файла можно использовать как текстовый редактор системы MAX+PLUS II, так и любой другой. Проект, выполненный в виде TDF-файла, компилируется, отлаживается и используется для формирования файла программирования или загрузки ПЛИС фирмы Altera.

Операторы и элементы языка AHDL являются достаточно мощным и универсальным средством описания алгоритмов функционирования цифровых устройств, удобным в использовании. Язык описания аппаратуры AHDL дает возможность создавать иерархические проекты в рамках одного этого языка или же в иерархическом проекте использовать как TDF-файлы, разработанные на языке AHDL, так и другие типы файлов. Для создания проектов на AHDL можно, конечно, пользоваться любым текстовым редактором, но текстовый редактор системы MAX+PLUS II предоставляет ряд дополнительных возможностей для ввода, компиляции и отладки проектов.

Проекты, созданные на языке AHDL, легко внедряются в иерархическую структуру. Система MAX+PLUS II позволяет автоматически создать символ компонента, алгоритм функционирования которого описывается TDF-файлом, и затем вставить его в файл схемного описания (GDF-файл). Подобным же образом можно вводить собственные функции разработчика помимо порядка 300 макрофункций, разработанных фирмой Altera, в любой TDF-файл. Для всех функций, включенных в макробиблиотеку системы MAX+PLUS II, фирма Altera поставляет файлы с расширением *.inc, которые используются в операторе включения INCLUDE.

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

При работе с AHDL следует соблюдать так называемые "Золотые правила" (Golden Rules). Выполнение этих правил позволит эффективно применять язык AHDL и избежать многих ошибок:

 

         Соблюдайте форматы и правила присвоения имен, описанные в руководстве по стилям AHDL, чтобы программа была читаемой и содержала меньше ошибок;

         Несмотря на то, что язык AHDL не различает прописные и строчные буквы, Altera рекомендует для улучшения читаемости использовать прописные буквы для ключевых слов;

         Не применяйте вложенные конструкции условного оператора If, если можно использовать оператор выбора Case;

         Строка в TDF-файле может быть длиной до 255 символов. Однако следует стремится к длине строки, умещающейся на экране. Строки заканчиваются нажатием клавиши Enter;

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

         Ключевые слова, имена и числа должны разделяться соответствующими символами или операторами и/или одним или более пробелами;

         Комментарии должны быть заключены в символы процента (%). Комментарий может включать любой символ, кроме символа %, поскольку компилятор системы MAX+PLUS II игнорирует все, заключенное в символы процента. Комментарии не могут быть вложенными;

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

         Используйте только макрофункции EXPDFF, EXPLATCH, NANDLTCH и NORLTCH, входящие в макробиблиотеку системы MAX+PLUS II. Не создавайте свои собственные структуры перекрестных связей. Избегайте многократного связывания вместе EXPDFF, EXPLATCH, NANDLTCH и NORLTCH. Многочисленные примеры этих макрофункций должны всегда разделяться примитивами LCELL.

         Если многочисленные двунаправленные или выходные выводы связаны вместе, разработчик не может использовать оператор Pin Connection для соединения выводов при функциональном моделировании с аппаратной поддержкой или функциональном тестировании;

         Нет необходимости создавать прототипы функций для примитивов. Однако разработчик может переопределить примитивы в объявлениях прототипов функций для изменения порядка вызова входов в вашем TDF-ФАЙЛЕ;

         Не редактируйте файл Fit. Если разработчик желает отредактировать назначения для проекта, необходимо сохранить сначала файл Fit как TDF-файл или сделать обратное назначение с помощью команды Project Back-Annotate и отредактировать их с помощью команд Chip to Device, Pin/LC/Chip и Enter Assignments;

         Если разработчик хочет загрузить регистр по определенному фронту глобального тактового сигнала Clock, фирма Altera рекомендует, когда регистр загружен, использовать для управления вход Clock Enable одного из триггеров типа Enable: DFFE, TFFE, JKFFE или SRFFE;

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

         Используйте опцию Design Doctor для проверки надежности логики проекта во время компиляции.

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

 

2. Использование чисел и констант в языке AHDL

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

Ниже приведен файл decode1.tdf, который представляет собой дешифратор адреса, генерирующий высокий активный уровень сигнала разрешения доступа к шине, если адрес равен шестнадцатеричному числу 370h.

SUBDESIGNdecode1
(
address[15..0]:INPUT;
chip_enable:OUTPUT;
)
BEGIN
chip_enable=(address[15..0]==H"0370");
END;

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

В файле AHDL можно использовать константы для описательных имен разных чисел. Такое имя, используемое на протяжении всего файла, может быть более информативным, чем число; например, имя UPPER_LI несет больше информации, чем число 103. В языке AHDL константы вводятся объявлением CONSTANT.

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

3. Комбинационная логика

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

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

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

SUBDESIGNboole1
(
a0,a1,b:INPUT;
out1,out2:OUTPUT;
)
BEGIN
out1=a1&!a0;
out2=out1#b;
END;

Здесь выход out1 получается в результате логической операции И, примененной ко входу а1 и инвертированному входу а0, а выход out2 получается в результате применения логической операции ИЛИ к выходу out1 и входу b. Поскольку эти уравнения обрабатываются одновременно, последовательность их следования в файле не важна.

Узел, который объявляется в секции переменных VARIABLE в объявлении NODE, можно использовать для хранения промежуточных выражений.

Это полезно делать, если булево выражение повторяется несколько раз и его целесообразно заменить именем узла. Приведенный выше файл boole1.tdf можно переписать по-другому:


SUBDESIGNboole2
(
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. Использование узлов помогает экономить ресурсы устройств, если узел используется в нескольких выражениях.

Важным понятием AHDL является группа. Группа может включать в себя до 256 элементов (бит), рассматривается как совокупность узлов и участвует в различных действиях как единое целое. В булевых уравнениях группа может быть приравнена булевому выражению, другой группе, одному узлу, VCC, GND,1 или 0. В каждом случае значения группы разные.

Если группа определена, для краткого указания всего диапазона ставят две квадратные скобки [ ]. Например, группу а[4..1] можно кратко записать как а[ ].

Условная логика делает выбор между режимами в зависимости от логических входов. Для реализации условной логики используются операторы IF или CASE:

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

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

Логика оператора IF. В качестве примера рассмотрим файл priority.tdf, в котором описан кодировщик приоритета, который преобразует уровень самого приоритетного активного входа в значение. Он генерирует двухразрядный код, показывающий вход с наивысшим приоритетом, запускаемый VCC.


SUBDESIGNpriority
(
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;

Здесь оцениваются входы low, middle и high, чтобы определить, запущены ли они VCC. На выходе получится код, соответствующий приоритету того входа, который был запущен VCC. Если ни один вход не запущен, значение кода будет равно 0.

Логика оператора CASE. В качестве примера рассмотрим файл decoder.tdf, реализующий функции Дешифратора, преобразующего код из двухразрядного в четырехразрядный. В результате его работы два двухразрядных двоичных входа преобразуются в один "горячий код", который так называется потому, что четыре его допустимых значения содержат по одной единице: 0001, 0010, 0100, 1000.


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;

Здесь группа входа code [1..2] может принимать значения 0, 1, 2, 3. В зависимости от реального кода активизируется соответствующая ветвь оператора и только она одна в данный момент времени. Например, если на входе code [] равен 1, на выходе out устанавливается значение В"0010".

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

 

         В операторе IF можно использовать любое булево выражение. Каждое выражение, записываемое в предложении, следующем за IF или ELSEIF, может не быть связанным с другими выражениями в операторе. В операторе CASE одно единственное выражение сравнивается с проверяемым значением.

         В результате интерпретации оператора IF может быть сгенерирована логика, слишком сложная для компилятора системы MAX+PLUS II. В приведенном ниже примере показано, как компилятор интерпретирует оператор IF. Если а и b - сложные выражения, то инверсия каждого из них даст еще более сложное выражение.

 

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

Ниже приведен файл 7segment.tdf, представляющий собой дешифратор, который задает логику схемы светодиодов. Светодиоды отображают на семисегментном дисплее шестнадцатеричные цифры (от 0 до 9 и буквы от A до F).

SUBDESIGN 7segment
(
i[3..0] : INPUT;
a, b, c, d, e, f, g : OUTPUT;
)
BEGIN
TABLE
i[3..0] => a, b, c, d, e, f, g;
H"0" => 1, 1, 1, 1, 1, 1, 0;
H"1" => 0, 1, 1, 0, 0, 0, 0;
H"2" => 1, 1, 0, 1, 1, 0, 1;
H"3" => 1, 1, 1, 1, 0, 0, 1;
H"4" => 0, 1, 1, 0, 0, 1, 1;
H"5" => 1, 0, 1, 1, 0, 1, 1;
H"6" => 1, 0, 1, 1, 1, 1, 1;
H"7" => 1, 1, 1, 0, 0, 0, 0;
H"8" => 1, 1, 1, 1, 1, 1, 1;
H"9" => 1, 1, 1, 1, 0, 1, 1;
H"A" => 1, 1, 1, 0, 1, 1, 1;
H"B" => 0, 0, 1, 1, 1, 1, 1;
H"C" => 1, 0, 0, 1, 1, 1, 0;
H"D" => 0, 1, 1, 1, 1, 0, 1;
H"E" => 1, 0, 0, 1, 1, 1, 1;
H"F" => 1, 0, 0, 0, 1, 1, 1;
END TABLE;
END;

В этом примере все возможные шестнадцатиричные цифры (i[3..0]) и соответствующие состояния светодиодов (a, b, c, d, e, f, g), которые обеспечивают "начертание" цифры на дисплее. Изображение светодиодов на дисплее дано в виде комментария перед файлом.

Ниже приведен файл дешифратора адреса decode3.tdf для шестнадцатиразрядной микропроцессорной системы.

 

SUBDESIGN decode3

(
addr[15..0], m/io : INPUT;
rom, ram, print, sp[2..1] : OUTPUT;
)
BEGIN
TABLE
m/io, addr[15..0] => rom, ram, print, sp[];
1, B"00XXXXXXXXXXXXXX" => 1, 0, 0, B"00";
1, B"100XXXXXXXXXXXXX" => 0, 1, 0, B"00";
0, B"0000001010101110" => 0, 0, 1, B"00";
0, B"0000001011011110" => 0, 0, 0, B"01";
0, B"0000001101110000" => 0, 0, 0, B"10";
END TABLE;
END;

В данном примере существуют тысячи возможных вариантов входа (адреса), поэтому было бы непрактично сводить их все в таблицу. Вместо этого, можно пометить символом "Х" несущественные, не влияющие на выход, разряды. Например, выходной сигнал rom (ПЗУ) будет высоким для всех 16384 вариантов адреса addr[15..0], которые начинаются с 00. Поэтому вам нужно только указать общую для всех вариантов часть кода, т.е. 00, а в остальных разрядах кода поставить "Х". Такой прием позволит сделать проект, требующий меньше устройств и ресурсов.

Приведенный ниже пример decode4.tdf показывает использование стандартной параметризируемой функции lpm_decode в задаче разработки дешифратора, аналогичной примеру decode1.tdf

INCLUDE "lpm_decode.inc";

SUBDESIGN decode4
(
address[15..0] : INPUT;
chip_enable : OUTPUT;
)
BEGIN
chip_enable = lpm_decode(.data[]=address[])
WITH (LPM_WIDTH=16, LPM_DECODES=2^10)
RETURNS (.eq[H"0370"]);
END;

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

Объявление значений по умолчанию DEFAULTS можно использовать для задания переменных в таблице истинности, операторах IF и CASE.

Ниже приводится файл default1.tdf, в котором происходит оценка входов и выбор соответствующего ASCII кода.

 

SUBDESIGN default1

(
i[3..0] : INPUT;
ascii_code[7..0] : OUTPUT;
)
BEGIN
DEFAULTS
ascii_code[] = B"00111111";% ASCII question mark"?" % 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;

Если значение входа совпадает с одним из значений в левой части таблицы, код на выходе приобретает соответствующее значение ASCII кода в правой части таблицы. Если входное значение не совпадает ни с одним из (левых) табличных, выходу будет присвоено значение по умолчанию 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, или с в зависимости от входных сигналов select_a, select_b и select_c. Если ни один из них не равен VCC, то выход wire_or принимает значение по умолчанию, равное GND.

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

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

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

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

SUBDESIGN daisy
(
/local_request : INPUT;
/local_grant : OUTPUT;
/request_in : INPUT; % from lower priority % /request_out : OUTPUT; % to higher priority % /grant_in : INPUT; % from higher priority % /grant_out : OUTPUT; % to lower priority %
)
BEGIN
DEFAULTS
/local_grant = VCC; % active-low output % /request_out = VCC; % signals should default % /grant_out = VCC; % to VCC %
END DEFAULTS;
IF /request_in == GND # /local_request == GND THEN
/request_out = GND;
END IF;
IF /grant_in == GND THEN
IF /local_request == GND THEN
/local_grant = GND;
ELSIF /request_in == GND THEN
/grant_out = GND;
END IF;
END IF;
END;

Все сигналы в данном файлы имеют активный низкий уровень. Фирма Altera рекомендует помечать как-нибудь имена сигналов с низким активным уровнем, например, первым символом в имени ставить символ "/", который не является оператором, и использовать его постоянно.

В операторе IF проверяется, является ли модуль активным, т.е. равен ли он GND. Если модуль оказывается активным, реализуются действия, записанные в операторе IF.

В объявлении по умолчанию DEFAULTS считается, что сигналу присваивается значение VCC, если он не активен.

Система MAX+PLUS II позволяет конфигурировать порты ввода/вывода (I/O) в устройствах Altera как двунаправленные порты. Двунаправленный вывод задается как порт BIDIR, который подсоединяется к выходу примитива TRI. Сигнал между этим выводом и буфером с тремя состояниями является двунаправленным, и его можно использовать в проекте для запуска других логических схем.

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

SUBDESIGN bus_reg2
(
clk : INPUT;
oe : INPUT;
io : BIDIR;
)
BEGIN
io = TRI(DFF(io, clk,, ), oe);
END;

Двунаправленный сигнал io, запускаемый примитивом TRI, используется в качестве входа d для D-триггера (DFF). Запятые в конце списка параметров отделяют места для сигналов триггера clrn и prn. Эти сигналы по умолчанию установлены в неактивное состояние.

Двунаправленный вывод можно также использовать для подсоединения TDF-ФАЙЛа более низкого уровня к выводу с высоким уровнем. Прототип функции для TDF-ФАЙЛа более низкого уровня должен содержать двунаправленный вывод в предложении RETURNS. В приведенном ниже файле bidir1.tdf даны четыре примера использования макрофункции bus_reg2.

FUNCTION bus_reg2 (clk, oe) RETURNS (io);

SUBDESIGN bidir1
(
clk, oe : INPUT;
io[3..0] : BIDIR;
)
BEGIN
io0 = bus_reg2(clk, oe);
io1 = bus_reg2(clk, oe);
io2 = bus_reg2(clk, oe);
io3 = bus_reg2(clk, oe);
END;

 

4. Последовательностная логика в AHDL.

Логическая схема называется последовательностной, если выходы в заданный момент времени являются функцией входов не только в тот же момент, но и во все предыдущие моменты времени. Таким образом, в последовательностную схему должны входить некоторые элементы памяти (триггеры). В языке AHDL последовательностная логика реализована цифровыми автоматами с памятью (state machines), регистрами и триггерами. При этом средства описания цифровых автоматов занимают особое место. Кроме того, к последовательностным логическим схемам относятся различные счетчики и контроллеры.

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

Для подсоединения примера примитива, макрофункции или цифрового автомата к другой логике в TDF-файле можно использовать порты. Порт примера описывается в следующем формате: <имя примера>.<имя порта>.

Имя порта - это вход или выход примитива, макрофункции или цифрового автомата, что является синонимом имени вывода в файлах проектов (GDF-файл), *.WDF и других.

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

 

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 как D-триггер с разрешением (DFFE). В первом булевом уравнении в логической секции происходит соединение входа тактового сигнала подпроекта к портам тактового сигнала триггеров ff[7..0]. Во втором уравнении отпирающий тактовый сигнал соединяется с загрузкой. В третьем уравнении входы данных подпроекта соединяются с портами данных триггеров ff[7..0]. В четвертом уравнении выходы подпроекта соединяются с выходами триггеров. Все четыре уравнения оцениваются одновременно.

Можно также в секции VARIABLE объявить T-, JK- и SR-триггеры и затем использовать их в логической секции. При использовании T-триггеров придется в третьем уравнении изменить порт d на t. При использовании JK- и SR-триггеров вместо третьего уравнения придется записать два уравнения, в которых происходит соединение портов j и k или s и r с сигналами.

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

Можно объявить регистровые выходы, если объявить выходы подпроекта как D-триггеры в секции 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;

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

Каждый отпирающий D-тригер, объявленный в секции VARIABLE, возбуждает выход с таким же именем, поэтому можно обращаться к q выходам объявленных триггеров без использования q порта этих триггеров.

Создание счетчиков. Счетчиками называются последовательностные логические схемы для счета тактовых импульсов. В некоторых счетчиках реализован счет вперед и назад (реверсивные счетчики), в некоторые счетчики можно загружать данные, а также обнулять их. Счетчики обычно определяют как D-триггеры (DFF и DFFE) и используют операторы IF.

Ниже приведен файл ahdlcnt.tdf, который реализует 16-битовый загружаемый счетчик со сбросом.

 

SUBDESIGN ahdlcnt

(
clk, load, ena, clr, d[15..0] : INPUT;
q[15..0] : OUTPUT;
)
VARIABLE
count[15..0] : DFF;
BEGIN
count[].clk = clk;
count[].clrn = !clr;
IF load THEN
count[].d = d[];
ELSIF ena THEN
count[].d = count[].q + 1;
ELSE
count[].d = count[].q;
END IF;
q[] = count[];
END;

В данном файле в секции VARIABLE объявлены 16 D-триггеров и им присвоены имена от count0 до count15. В операторе IF определяется значение, загружаемое в триггеры по фронту синхросигнала (например, если загрузка запускается VCC, то триггерам присваивается значение d[ ]).

 

5. Цифровые автоматы с памятью (state mashine)

 

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

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

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

  назначает биты, выбирая для каждого бита либо T-триггер, либо D-триггер;

  присваивает значения состояний;

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

По желанию пользователя можно задать в TDF-файле переходы в машине состояний с помощью объявления таблицы истинности.

В языке AHDL для задания цифрового автомата нужно включить в TDF-файл следующие элементы:

  объявление цифрового автомата (в секции VARIABLE);

  булевы уравнения управления (в логической секции);

  переходы между состояниями (в логической секции).

Цифровые автоматы в языке AHDL можно также экспортировать и импортировать, совершая обмен между файлами типа TDF и (GDF-файл) или *.WDF; при этом входной или выходной сигнал задается как порт цифрового автомата в секции SUBDESIGN.

Цифровой автомат задают в секции VARIABLE путем объявления имени цифрового автомата, его состояний и, возможно, выходных битов.

Ниже приведен файл simple.tdf, который реализует функцию D-триггера.

 

SUBDESIGN simple

(
clk : INPUT;
reset : INPUT;
d : INPUT;
q : OUTPUT;
)
VARIABLE
ss : MACHINE WITH STATES (s0, s1);
BEGIN
ss.clk = clk;
ss.reset = reset;
CASE ss IS
WHEN s0 =>
q = GND;
IF d THEN
ss = s1;
END IF;
WHEN s1 =>
q = VCC;
IF !d THEN
ss = s0;
END IF;
END CASE;
END;

В данном файле в секции VARIABLE объявлен цифровой автомат (state machine) ss. Состояния автомата определяются как s0 и s1. Биты состояний не определены.

Сигналы Clock, Reset и Enable управляют триггерами регистра состояний в цифровом автомате. Эти сигналы задаются булевыми уравнениями управления в логической секции.

В предыдущем примере (файл simple.tdf) синхросигнал цифрового автомата (Clock) формируется входом clk. Асинхронный сигнал сброса цифрового автомата (Reset) формируется входом reset, имеющим высокий активный уровень. Для подключения сигнала отпирания (Enable) нужно добавить в данный файл проекта строку "ena : INPUT;" в секцию SUBDESIGN, а также добавить в логическую секцию булево уравнение "ss.ena = ena;".

Для задания выходных значений можно использовать операторы IF и CASE. В приведенном выше примере (файл simple.tdf) значение выхода q устанавливается равным GND, если цифровой автомат ss находится в состоянии s0, и равным VCC, когда она находится в состоянии s1. Эти присваивания делаются в предложениях WHEN оператора CASE.

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

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

В приведенном выше примере (файл simple.tdf) переходы для каждого состояния определены в предложениях WHEN оператора CASE.

Бит состояния - это выход триггера, используемый для хранения одного бита значений цифрового автомата. В большинстве случаев для минимизации логических ресурсов следует предоставить компилятору системы MAX+PLUS II присвоение битов и значений состояния. Однако пользователь может сделать это самостоятельно в объявлении цифрового автомата, если, например, он хочет, чтобы определенные биты были выходами цифрового автомата.

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

Ниже приведен пример, в котором реализован автомат Мура с четырьмя состояниями.

 

SUBDESIGN moore1

>(
clk : INPUT;
reset : INPUT;
y : INPUT;
z : OUTPUT;
)
VARIABLE % current current %
% state output %
ss :MACHINE OF BITS (z)
WITH STATES (s0 = 0,
s1 = 1,
s2 = 1,
s3 = 0);
BEGIN
ss.clk = clk;
ss.reset = reset;
TABLE
% current current next %
% state input state %
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;

В данном примере состояния определены в объявлении цифрового автомата. Переходы между состояниями определены в таблице next_state, которая задана в объявлении таблицы истинности. В данном примере машина имеет четыре состояния и только один бит состояния z. Компилятор системы MAX+PLUS II автоматически добавляет еще один бит и делает соответствующие присвоения этой синтезированной переменной для того, чтобы получилась машина с четырьмя состояниями. Такой цифровой автомат (state machine) требует, по крайней мере, двух битов.

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

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

Этот альтернативный метод использован в приведенном ниже файле moore2.tdf.

 

SUBDESIGN moore2

(
clk : INPUT;
reset : INPUT;
y : INPUT;
z : OUTPUT;
)
VARIABLE
ss : MACHINE WITH STATES (s0, s1, s2, s3);
zd : NODE;
BEGIN
ss.clk = clk;
ss.reset = reset;
z = DFF(zd, clk, VCC, VCC);
TABLE
% current current next next %
% state input state output %
ss, y => ss, zd;
s0, 0 => s0, 0;
s0, 1 => s2, 1;
s1, 0 => s0, 0;
s1, 1 => s2, 1;
s2, 0 => s2, 1;
s2, 1 => s3, 0;
s3, 0 => s3, 0;
s3, 1 => s1, 1;
END TABLE;
END;

В данном примере вместо того, чтобы задать выходы присвоением значений состояниям в объявлении цифрового автомата, в объявление таблицы истинности добавлен один столбец под названием "next output (следующий выход)". В этом методе для синхронизации выходов синхросигналом используется D-триггер, вызов которого записан с помощью непосредственной ссылки.

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

В приведенном ниже фале mealy.tdf реализован автомат Мили с четырьмя состояниями и асинхронными выходами.

 

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
% current current current next %
% state input output state %
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;

6. Реализация иерархического проекта

 

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

В системе MAX+PLUS II есть большая библиотека, которая представляет собой блоки высокого уровня, используемые для создания проекта с иерархической логикой.

В языке AHDL существуют два способа макрофункции:

         объявить переменную типа <macrofunction> в объявлении примеров INSTANCE в секции VARIABLE и использовать порты примера макрофункции в логической секции. В этом способе важное значение имеют имена портов;

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

Входы и выходы макрофункций перечисляются в описании прототипов функций (FUNCTION PROTOTYPE). Прототипы функций можно записать в отдельный файл и указать его в своем файле с помощью директивы INCLUDE. Такие Include-файлы создаются автоматически для данного проекта с помощью команды Create Default Include File. Include-файл вставляется вместо вызывающей его директивы INCLUDE. Для всех макрофункций системы MAX+PLUS II Include-файлы должны находиться в каталоге \maxplus2 \max2inc.

Ниже приведен файл macro1.tdf, который реализует четырех битовый счетчик, подсоединенный к дешифратору 4бит -> 16 бит. Соответствующие макрофункции вызываются объявлениями примеров в секции 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 для импортирования прототипов функций для двух макроофункций фирмы Altera: 4count и 16dmux. В секции VARIABLE объявляются две переменные: counter и decoder как примеры этих макрофункций. В логической секции определяются входные порты для обеих макрофункций в формате <имя переменной-примера>.<имя порта>. (Они ставятся в левой части булевых уравнений, а выходные порты - справа.) Порядок портов в прототипе функции не важен, так как имена портов в логической секции перечисляются явно.

Ниже приведен файл macro2.tdf, выполняющий те же функции, что и предыдущий, но макрофункции в нем вызываются непосредственной ссылкой.

 

 
INCLUDE "4count";
INCLUDE "16dmux";
SUBDESIGN macro2
(
clk : INPUT;
out[15..0] : OUTPUT;
)
VARIABLE
q[3..0] : NODE;
BEGIN
(q[3..0], ) = 4count (clk, , , , , GND, , , , );
%
out[15..0] = 16dmux (.(d, c, b, a)=q[3..0]);
% equivalent in-line ref. with positional port association %
% out[15..0] = 16dmux (q[3..0]); %
>END;

Вызов макрофункций 4count и 16dmux осуществляется в логической секции непосредственной ссылкой (в правой части булевых уравнений).

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

         Создать логику для макрофункции в файле проекта.

         Определить порты макрофункции в объявлении прототипа функции.

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

Объявление прототипов функций может быть размещено в Include-файле, который вызывается в пользовательском файле. Используя команду Create Default Include File, можно автоматически создавать Include-файл с прототипом функции для любого файла проекта.

         Вставить в файл пример макрофункции с помощью объявления примера в секции VARIABLE или с помощью непосредственной ссылки в тексте.

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

Для использования макрофункции ее нужно либо включить в описание прототипа функции в TDF-файле, либо указать в директиве INCLUDE файла TDF имя Include-файла, содержащего прототип этой макрофункции

7. Управление синтезом

 

Можно ограничить логический синтез с помощью замены переменных типа узел (NODE) примитивами SOFT и LCELL. Переменные NODE и примитивы LCELL обеспечивают наилучшее управление логическим синтезом. Примитивы SOFT обеспечивают более слабый управление логическим синтезом.

Переменные NODE, которые объявляются в секции VARIABLE, накладывают слабые ограничения на логический синтез. Во время синтеза модуль логического синтеза компилятора системы MAX+PLUS II заменяет каждый пример использования переменной NODE логикой, которую она представляет. Затем происходит минимизация логики до одной логической ячейки. Этот метод обычно приводит к ускорению работы схемы, но в результате может получиться слишком сложная логика или же ее трудно свести к одной ячейке.

Буферы SOFT обеспечивают лучшее управление использованием ресурсов, чем переменные NODE. Модуль логического синтезатора выбирает, когда заменить примеры использования примитивов SOFT примитивами LCELL

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

Наиболее сильное управление процессом логического синтеза обеспечивается примитивами LCELL. Модуль логического синтезатора минимизирует всю логику, которая запускает примитив LCELL, таким образом, чтобы можно было свести ее к одной логической ячейке. Примитивы LCELL реализуются в виде одной логической ячейки (их нельзя убрать из проекта, даже если они имеют единственный вход). Если проект минимизирован до такой степени, что один примитив LCELL имеет единственный вход, в этом случае вместо примитивов LCELL можно использовать примитивы SOFT, которые убираются в процессе логического синтеза.

 

 

 

 

Хостинг от uCoz