Язык AHDL
Операторы и элементы языка аппаратуры фирмы Altera AHDL. Зарезервированные идентификаторы: шины, символы, строковые и символьные имена. Структура описания проекта на языке AHDL. Создание текстового выходного файла. Использование логики и констант.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | книга |
Язык | русский |
Дата добавления | 23.04.2015 |
Размер файла | 144,7 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
В левой части подставляемой ссылки выходы функции ставятся в соответствие переменным. В примере, показанном выше и демонстрирующем использование функции compare выходы less и greater поставлены в соответствие переменным clockwise и counterclockwise с использованием позиционного соответствия. Подобным же образом в примере для функции lpm_add_sub выходы result[] поставлены в соответствие группе sum[] с использованием позиционного соответствия.
Значения переменных, которые определены где-либо в разделе Logic, являются значениями связанными с соответствующими им входами и выходами. В примере, показанном выше для функции compare, значения position[] и target[] являются значениями, подаваемыми на соответствующие входы функции compare. Значения выходных портов less и greater связаны с clockwise и counterwise, соответственно. Эти переменные могут быть использованы в других выражениях раздела Logic.
3.12.9 Определение таблицы истинности (Truth Table)
Оператор Truth Table используется для определения комбинационной логики или для определения поведения автоматов. В таблицах истинности, используемых в AHDL каждая строка таблицы состоит из комбинации входных значений и соответствующих этой комбинации выходных значений. Эти выходные значения могут использоваться как обратные связи для определения переходов автоматов из одного состояния в другое, а также его выходов.
Следующий пример демонстрирует использование оператора Truth Table:
TABLE
a0,f[4..1].q => f[4..1].d,control;
0,B"0000" => B"0001",1;
0,B"0100" => B"0010",0;
1,B"0XXX" => B"0100",0;
X,B"1111" => B"0101",1;
END TABLE;
Оператор Truth Table имеет следующие характеристики:
Заголовок таблицы истинности состоит из ключевого слова TABLE, за которым следует разделенный запятыми список входов, символ (=>) и разделенный запятыми список выходов таблицы. Заголовок таблицы истинности заканчивается символом (;).
Входы таблицы истинности являются булевскими выражениями; выходы являются переменными. В примере, показанном выше, входными сигналами являются a0 и f[4..1].q; выходными сигналами являются f[4..1] и control.
Тело таблицы истинности состоит из одного или более компонентов, каждый из которых представляет одну или более строку и заканчивается символом (;).
Каждый компонент состоит из разделенного запятыми списка входов и разделенного запятыми списка выходов. Входы и выходы разделены символом (=>).
Каждый сигнал имеет однозначное соответствие с значениями в каждом компоненте тела таблицы истинности. Таким образом, первый компонент в примере, показанном выше, определяет, что когда a0 имеет значение 0, а f[4..1].q имеет значение B”0000”, то f[4..1].d примет значение B”0001”, а сигнал control примет значение 1.
Входные и выходные значения могут быть числами, предопределенными константами VCC и GND, символическими константами (т.е. символическими именами, используемыми как константы) или группами чисел или констант. Входные значения могут также иметь значение X (безразличное состояние).
Входные и выходные значения соответствуют входам и выходам, названия которых указаны в заголовке таблицы.
Описание таблицы истинности заканчивается ключевыми словами END TABLE, за которыми следует символ (;).
В отношении описания таблицы истинности необходимо соблюдать следующие правила:
Имена, используемые в заголовке таблицы истинности должны представлять собой либо одиночные узлы, либо группы.
Нет необходимости оговаривать в таблице истинности все возможные комбинации входных сигналов. Можно использовать символ “X” для определения того, что выходное значение не зависит от входного. Следующий пример определяет, что, если a0 имеет высокий уровень и f4 имеет низкий уровень, то логические уровни остальных входов не имеют значения. Таким образом, можно указать лишь общую часть нескольких комбинаций входных сигналов, а для всех остальных использовать символ “X”:
TABLE
a0,f[4..1].q => f[4..1].d,control;
0,B"0000" => B"0001",1;
0,B"0100" => B"0010",0;
1,B"0XXX" => B"0100",0;
X,B"1111" => B"0101",1;
END TABLE;
Количество разделенных запятыми элементов таблицы истинности должно в точности соответствовать количеству элементов в заголовке таблицы истинности. В противном случае в отношении выходных сигналов используются значения по умолчанию.
При использовании символа “X” для определения нескольких комбинаций значений входных сигналов необходимо внимательно следить за тем, чтобы определяемое таким образом подмножество комбинаций не перекрывалось ни с каким другим подмножеством в пределах данной таблицы истинности. В противном случае возможны непредсказуемые результаты.
4. Применение языка AHDL
В данном разделе описывается как разрабатывать проект на AHDL и предлагаются советы по созданию успешных проектов.
4.1 Использование шаблонов AHDL
Текстовой редактор позволяет Вам вставить шаблон любого из операторов или разделов AHDL в текущий файл. Шаблоны AHDL - это простой способ ввода синтаксических конструкций языка AHDL, увеличивающий скорость и точность ввода проекта.
Для вставки шаблона AHDL в текущую позицию ввода:
Откройте диалоговое окно AHDL Template с помощью команды меню Template.
Выберите имя в окне Template Section.
Нажмите OK.
После ввода шаблона в Ваш TDF файл, Вы должны заместить все переменные в шаблоне на Вашу собственную логику. Каждое ключевое слово AHDL выделено заглавными буквами, а каждое имя переменной начинается с двух символов подчеркивания (_ _) чтобы помочь Вам идентифицировать их.
4.2 Создание текстового выходного файла
Вы можете создать один или больше текстовых выходных файлов проекта (Text Design Output Files (.tdo)), которые содержат AHDL эквивалент полностью оптимизированной логики для устройства, применяющегося в проекте. Кроме того Компилятор создает также один или больше выходных файлов назначения и конфигурации (Assignment & Configuration Output Files (.aco)).
Вы можете сохранить TDO файл как текстовой файл проекта, отредактировать его, определить его как проект с помощью команд меню File: Project Name или Project Set Project to Current File и перекомпилировать проект (Вы должны также сохранить ACO файл как файл Assignment & Configuration File если Вы хотите сохранить распределения для устройства).
TDO файлы облегчают обратную аннотацию и сохраняют имеющийся логический синтез проекта. Для проекта с несколькими устройствами TDO файлы позволяют Вам зафиксировать проект и схему расположения выводов каждого устройства в проекте.
Для создания TDO файла для проекта:
Включите опцию Generate AHDL TDO File в команде меню Processing.
Для начала компиляции выберите кнопку Start в окне компилятора или одну из команд в меню File: Project Save & Compile или Project Save, Compile & Simulate в любом из приложений MAX+PLUS II.
4.3 Использование чисел
Числа применяются для определения значений констант в булевских выражениях и уравнениях, в арифметических выражениях, а также значения параметров. 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" определяет декодируемый адрес.
4.4 Использование констант и оценочных функций
Вы можете использовать константу в 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;
4.5 Использование итеративно-генерируемой логики
Когда Вы хотите использовать несколько схожих блоков логики, Вы можете использовать оператор 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, который раздельно управляет специальными случаями, например, в первом и последнем каскадах многокаскадного умножителя.
4.6 Использование условно-генерируемой логики
Вы можете создать логику условно с помощью оператора 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.
4.7 Выполнение контроля выражений с помощью оператора 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;
4.8 Управление логическим синтезом с помощью примитивов LCELL & SOFT
Вы можете ограничить размер (масштаб) логического синтеза путем изменения переменных NODE на SOFT и LCELL примитивы. NODE переменные и LCELL примитивы обеспечивают наибольшее управление всем логическим синтезом. SOFT примитивы не предусмотрены для управления всем логическим синтезом.
NODE переменные, объявленные с помощью объявления Node в разделе Variable налагают несколько ограничений на логический синтез. Во время синтеза логический синтезатор заменяет каждый экземпляр переменной NODE логикой, которая представляет переменную. Затем он минимизирует логику для подгонки в одну логическую ячейку. Обычно этот метод дает самую большую скорость, но может приводить к слишком сложной логике.
SOFT буферы обеспечивают больший контроль по использованию ресурсов, чем NODE переменные. Логический синтезатор выбирает, когда заместить экземпляры SOFT примитивов с помощью LCELL примитивов. SOFT буферы могут помочь в исключении слишком сложной логики и упрощении подгонки проекта, но могут увеличить использование логических ячеек и уменьшить быстродействие.
LCELL примитивы обеспечивают наибольшее управление. Логический синтезатор минимизирует всю логику, которая управляет LCELL примитивом, так что она занимает только одну логическую ячейку. LCELL примитивы всегда реализуются в логической ячейке и никогда не удаляются из проекту даже если они запитываются одним входом. В последнем случае Вы можете использовать SOFT примитив вместо LCELL примитива, который будет удаляться во время логического синтеза.
MAX+PLUS II обеспечивает несколько логических опций, которые автоматически вставляют или удаляют SOFT и LCELL буферы в соответствующих местах проекта.
Следующая иллюстрация демонстрирует два варианта TDF файла: один реализуется с помощью NODE переменных, а другой с SOFT примитивами. В nodevar переменная odd_parity объявлена как NODE и затем ей присвоено значение булева выражения d0 $ d1 $ ... $ d8. В softbuf компилятор замещает некоторые SOFT примитивы на LCELL примитивы во время обработки для улучшения использования устройства.
TDF с NODE переменными: TDF с SOFT примитивами:
SUBDESIGN nodevarSUBDESIGN softbuf
((
))
VARIABLEVARIABLE
odd_parity : NODE;odd_parity : NODE;
BEGINBEGIN
odd_parity =odd_parity =
d0 $ d1 $ d2$SOFT(d0 $ d1 $ d2) $
d3 $ d4 $ d5$SOFT(d3 $ d4 $ d5) $
d6 $ d7 $ d8;SOFT(d6 $ d7 $ d8);
END;END;
4.9 Реализация комбинационной логики
Комбинационная логика реализуется на языке AHDL с помощью булевых выражений и уравнений, таблиц истинности, и множества мега и макрофункций. Примеры комбинационных функций включают дешифраторы, мультиплексоры и сумматоры.
4.9.1 Реализация логических выражений и уравнений
Булевы выражения являются набором узлов, чисел, констант и других булевых выражений, разделенных операторами и/или компараторами и дополнительно сгруппированных с помощью скобок. Булево уравнение устанавливает узел или шину равной величине булевого выражения.
Файл boole1.tdf, приведенный ниже, демонстрирует два простых булевых выражения, представляющие два логических вентиля.
SUBDESIGN boole1
(
a0, a1, b : INPUT;
out1, out2 : OUTPUT;
)
BEGIN
out1 = a1 & !a0;
out2 = out1 # b;
END;
В этом файле выход out1 является логическим И входов а1 и инверсии а0, а выход out2 логическим ИЛИ out1 и b. Порядок следования их в файле не важен.
4.9.2 Именование логических операторов и компараторов
Именование логических операторов и компараторов позволяет облегчить ввод, присваивание ресурсов и интерпретацию раздела уравнений в файле отчета проекта.
Файл 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 номера цепей, и эти имена произвольно переназначаются при каждой компиляции.
4.9.3 Использование узлов
Узел, который объявляется с помощью объявления 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.
4.9.4 Использование шин
Шина, которая может включать до 256 членов (битов), трактуется как коллекция узлов и работает как одно целое. Имя шины можно определить с помощью имени с одним диапазоном, имени с двумя диапазонами или именем в последовательном формате.
В булевых уравнениях шина может приравниваться булеву выражению, другой шине, единственному узлу, VCC, GND, 1 или 0. В каждом из этих случаев значение шины различно. Оператор Options можно использовать для определения того, каким будет самый младший бит: наиболее значимым битом(MSB) или наименее значимым битом(LSB) или каким-либо другим.
Как только шина определена, скобки [ ] являются коротким способом определения всего диапазона. Например, a[4..1] можно также указать как a[]; b[5..4][3..2] можно представить как b[][].
Файл group1.tdf, приведенный ниже, демонстрирует булевы выражения, которые определяют несколько шин.
OPTIONS BIT0 = MSB;
CONSTANT MAX_WIDTH = 1+2+3-3-1;
% MAX_WIDTH = 2 %
SUBDESIGN group1
(
a[1..2], use_exp_in[1+2-2..MAX_WIDTH] : INPUT;
d[1..2],use_exp_out[1+2*2-4..MAX_WIDTH] : OUTPUT;
dual_range[5..4][3..2] : OUTPUT;
)
BEGIN
d[] = a[] + B"10";
use_exp_out[] = use_exp_in[];
dual_range[][] = VCC;
END;
В этом примере оператор Options используется для определения того, что самый правый бит шины будет MSB, а десятичная 1 прибавляется к шине a[]. Если ко входу a[] прикладывается 00, то результатом этой программы будет d[] == 1. Шины use_exp_in[] и use_exp_out[] показывают как константы и арифметические выражения можно использовать для ограничения диапазонов шин.
Следующие примеры иллюстрируют использование шин:
Когда шина приравнивается к другой шине того же самого размера, то каждый член справа приравнивается каждому члену слева в соответствующей позиции.
Когда шина приравнивается к VCC или GND, все биты шины соединяются с этим значением.
Когда шина приравнивается к 1, только наименее значимый бит шины соединяется со значением VCC. Остальные биты шины соединяются с GND.
Когда приравниваются шины не одинакового размера, количество битов шины с левой стороны уравнения должно точно делиться на количество битов шины с правой стороны уравнения. Например, уравнение
a[4..1] = b[2..1] правильно.
В этом уравнении биты отображаются следующим образом:
a4 = b2
a3 = b1
a2 = b2
a1 = b1
4.9.5 Реализация условной логики
Операторы If Then и Case идеально подходят для реализации условной логики. Операторы If Then оценивают одно или несколько булевых выражений и описывают поведение для различных значений выражения. Операторы Case являются списком альтернатив, которые доступны для каждого значения выражения. Они оценивают выражение, а затем выбирают направление действия на основе значения выражения.
Условную логику, реализуемую с помощью операторов If Then и Case, не следует путать с логикой, создаваемой условно оператором If 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.
Оператор 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
Оператор If Then против оператора Case
Операторы If Then и Case подобны. В некоторый случаях Вы можете использовать любой из двух операторов для получения того же самого результата.
Но между ними существует важное различие:
В операторе If Then можно использовать любые виды булевых выражений. Каждое выражение, следующее за IF или ELSIF областями, может быть несвязанно с другими выражениями в операторе. В операторе Case, напротив, только одно булево выражение сравнивается с константой в каждой WHEN области.
Использование ELSIF предложения может привести к логике, которая слишком сложна для компилятора, так как каждое следующее друг за другом предложение ELSIF должно еще проверять, ложность предыдущих IF/ELSIF предложений. Следующий пример показывает как компилятор интерпретирует оператор If Then. Если a и b сложные выражения, тогда инверсия этих выражений даст, возможно, даже более сложные выражения.
Оператор If Then Интерпретация компилятора
IF a THENIF a THEN
c = d;c = d;
END IF;
ELSIF b THENIF !a & b THEN
c = e;c = e;
END IF;
ELSE IF !a & !b THEN
c = f;c = f;
END IF;END IF;
4.9.6 Создание дешифраторов
В AHDL для создания дешифратора Вы можете использовать или оператор Truth Table или lpm_compare или lpm_decode функции.
Файл 7segment.tdf, приведенный ниже, является дешифратором для комбинации светоизлучающих диодов (LED). LED отображают шестнадцатеричные числа.
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;
В этом примере выходной набор для всех 16 возможных входных наборов i[3..0] описан в операторе Truth Table
Файл decode3.tdf, приведенный ниже, является дешифратором адреса для реализации 16-битной микропроцессорной системы.
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;
В этом примере существуют тысячи входных наборов и описывать их все в операторе Truth Table непрактично. Вместо этого Вы можете использовать логический уровень Х для указания того, что выход не зависит от соответствующего входа. Например, в первой строчке оператора TABLE выход rom должен быть высоким для всех 16,384 входных наборов addr[15..0], начинающихся с 00. Следовательно Вам необходимо точно определить только общую часть входного набора, а для остальных входов использовать символ Х.
При использовании символов Х Вы должны гарантировать отсутствие наложений между битовыми комбинациями в таблице истинности. Язык AHDL предполагает что одновременно только одно условие в таблице истинности может быть истинно.
Файл 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;
4.9.7 Использование значений переменных по умолчанию
Вы можете определить значение по умолчанию для узла или шины, который используете, когда его величина не указана где-нибудь в другом месте файла. 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.
4.9.8 Реализация логики с активными низкими уровнями
Активный низкий сигнал становится активным, когда его значение равно GND. Активные низкие сигналы могут быть полезны при управлении памятью, периферийными устройствами и микропроцессорными кристаллами.
Файл daisy.tdf, приведенный ниже, является модулем схемы арбитра по методу дейзи-цепочки. Он принимает запросы на доступ к шине от самого себя и от следующего модуля в цепочке. Доступ к шине предоставляется модулю с наивысшим приоритетом, запросившим его.
SUBDESIGN daisy
(
/local_request: INPUT;
/local_grant: OUTPUT;
/request_in: INPUT;% от младшего приоритета %
/request_out: OUTPUT; % к старшему приоритету %
/grant_in: INPUT;% от старшего приоритета %
/grant_out: OUTPUT;% к младшему приоритету %
)
BEGIN
DEFAULTS
/local_grant = VCC;% активные низкие выходы %
/request_out=VCC;
%должны быть равны по умолчанию %
/grant_out = VCC;% 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 рекомендует, чтобы Вы выбирали схему именования узлов, ясно указывающую имена активных низких сигналов, например, начальное "n" или слеш (/).
Операторы If Then используются для определения активности модулей, т.е. равен ли сигнал GND. Если сигнал активный, то активизируются уравнения, следующие за соответствующим оператором If Then.
4.9.9 Реализация двунаправленных выводов
MAX+PLUS II позволяет конфигурировать выводы I/O как двунаправленные. Двунаправленные выводы можно определить с помощью порта BIDIR, который соединяется с выходом примитива TRI. Сигнал между выводом и примитивом TRI является двунаправленным и может использоваться для управления другой логикой проекта.
Файлы bus_reg2.tdf и bus_reg3.tdf, приведенные ниже, оба реализуют регистр, который фиксирует значение, обнаруженное на тристабильной шине. Также они могут выдавать запомненное значение обратно на шину. Один файл реализует DFF и TRI функции с помощью ссылок на логические функции. Другой файл использует объявления Register и Instance, соответственно, в разделе Variable.
SUBDESIGN bus_reg2 SUBDESIGN bus_reg3
((
clk : INPUT; clk : INPUT;
oe : INPUT; oe : INPUT;
io : BIDIR; io : BIDIR;
))
VARIABLE VARIABLE
dff_out : NODE; my_dff : DFF;
my_tri : TRI;
BEGIN BEGIN
dff_out = DFF(io, clk, ,); my_dff.d = io;
io = TRI(dff_out, oe); my_dff.clk = clk;
my_tri.in = my_dff.q;
END; my_tri.oe = oe;
io = my_tri.out;
END;
Двунаправленный сигнал io, управляемый примитивом TRI, используется в качестве входа d триггера D (DFF).
Также Вы можете присоединить двунаправленный вывод из TDF файла нижнего уровня к выводу верхнего уровня. Двунаправленный выходной порт подпроекта должен соединяться с двунаправленным выводом с верхнего уровня иерархии. Прототип Function для 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.9.10 Реализация тристабильных шин
Примитивы TRI, которые управляют портами OUTPUT или BIDIR, имеют вход разрешения выхода (Output Enable), который переводит выход в высокоимпедансное состояние.
Вы можете создать тристабильную шину путем соединения примитивов TRI и портов OUTPUT или BIDIR вместе с помощью узла TRI_STATE_NODE типа. Схема управления должна обеспечивать разрешение не более одного выхода в одно и тоже время.
Файл tri_bus.tdf, приведенный ниже, реализует тристабильную шину, используя узел TRI_STATE_NODE типа, созданный в объявлении Node.
SUBDESIGN tri_bus
(
in[3..1], oe[3..1] : INPUT;
out1 : OUTPUT;
)
VARIABLE
tnode : TRI_STATE_NODE;
BEGIN
tnode = TRI(in1, oe1);
tnode = TRI(in2, oe2);
tnode = TRI(in3, oe3);
out1 = tnode;
END;
В этом примере несколько присваиваний узлу tnode, связывают сигналы вместе. Для реализации тристабильной шины требуется тип TRI_STATE_NODE, вместо типа NODE: для типа NODE сигналы связываются вместе с помощью проводного И или проводного ИЛИ, тогда как для типа TRI_STATE_NODE сигналы соединяются с тем же самым узлом. Однако, если только одна переменная присваивается узлу TRI_STATE_NODE, то она трактуется как переменная обычного типа NODE.
4.10 Реализация последовательностной логики
Последовательную логику в языке AHDL можно реализовать с помощью конечных автоматов, регистров и защелок или используя библиотеку параметрических модулей (LPM). Конечные автоматы особенно удобны для реализации последовательной логики. Другими примерами являются счетчики и контроллеры.
4.10.1 Объявление регистров
Регистры запоминают значения данных и синхронизируют их с помощью сигнала 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;
4.10.2 Объявление регистровых выходов
Вы можете объявить регистровые выходы 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). Поэтому, если Вы хотите протестировать регистр или использовать специфические для регистра логические опции, Вы должны по разному назвать регистры и порты.
4.10.3 Создание счетчиков
Счетчики можно определить с помощью D триггеров (DFF и DFFE) и операторов If Then или с помощью функции lpm_counter.
Файл 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 триггеров с имена count0 по count15. Оператор If Then определяет значение, которое загружается в триггеры на возрастающем фронте Clock.
Файл lpm_cnt.tdf, приведенный ниже, использует функцию lpm_counter для реализации той же функциональности, что и файл ahdlcnt.tdf.
INCLUDE "lpm_counter.inc";
SUBDESIGN lpm_cnt
(
clk, load, ena, clr, d[15..0] : INPUT;
q[15..0] : OUTPUT;
)
VARIABLE
my_cntr: lpm_counter WITH (LPM_WIDTH=16);
BEGIN
my_cntr.clock = clk;
my_cntr.aload = load;
my_cntr.cnt_en = ena;
my_cntr.aclr = clr;
my_cntr.data[] = d[];
q[] = my_cntr.q[];
END;
4.10.4 Конечные автоматы
В языке AHDL конечные автоматы реализуются также легко как таблицы истинности и булевы уравнения. Язык структурирован настолько, что Вы можете или сами присвоить значения состояниям или позволить компилятору MAX+PLUS II сделать эту работу за Вас.
Компилятор использует усовершенствованные эвристические алгоритмы автоматического присваивания состояний, которые минимизируют логические ресурсы, требующиеся для реализации конечных автоматов.
От Вас просто требуется нарисовать диаграмму состояний и построить таблицу следующих состояний. Затем компилятор автоматически выполнит следующие функции:
назначит биты, выбирая или T или D триггер (TFF или DFF) для каждого бита
присвоит значения состояниям
применит сложную технику логического синтеза для получения уравнений возбуждения
Для определения конечного автомата на языке AHDL, необходимо включить следующие элементы в TDF файл:
объявление конечного автомата (раздел Variable)
булевы уравнения управления (раздел Logic)
переходы между состояниями в операторе Table или Case (раздел Logic)
Также Вы можете импортировать и экспортировать конечные автоматы между TDF файлами и другими файлами проекта, определяя входные и выходные сигналы как автоматные порты в разделе Subdesign.
4.10.5 Реализация конечных автоматов
Вы можете создать конечный автомат, объявив его имя, состояния и, дополнительно, биты конечного автомата в объявлении конечного автомата в разделе Variable.
Файл simple.tdf, приведенный ниже, обладает такой же функциональностью как D триггер (DFF).
SUBDESIGN simple
(
clk, reset, 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;
В файле simple.tdf конечный автомат с именем ss объявлен в разделе Variable. Состояния автомата определены как s0 и s1, а биты состояния не объявлены.
Переходы конечного автомата определяют условия изменения к новому состоянию. Вы должны условно присвоить состояния в пределах одной поведенческой конструкции для определения переходов конечного автомата. Для этой цели рекомендуются операторы Case или Table. Например, в simple.tdf переходы из каждого состояния определяются в предложениях WHEN оператора Case.
Вы можете также определить выходное значение для состояния с помощью оператора If Then или Case. В операторах Case эти присваивания выполняются в предложениях WHEN. Например, в simple.tdf выход q присваивается GND, когда конечный автомат ss находится в состоянии s0 и VCC, когда автомат находится в состоянии s1.
Выходные значения можно также определить в таблицах истинности как описано в пункте 4.10.7 Присваивание состояний.
4.10.6 Управление записью, сбросом и разрешением (Clock, Reset & Enable)
Сигналы Clock, Reset, и Clock Enable управляют триггерами регистра состояний конечного автомата. Эти сигналы определяются с помощью булевых уравнений управления в разделе Logic.
В файле simple.tdf, приведенном ниже, Clock конечного автомата управляется входом clk. Сигнал асинхронного сброса конечного автомата Reset управляется сигналом reset, который является активным высоким. В этом файле проекта объявление входа ena в разделе Subdesign и булева уравнения ss.ena = ena в разделе Logic подсоединяет сигнал Clock Enable.
SUBDESIGN simple
(
clk, reset, ena, d : INPUT;
q : OUTPUT;
)
VARIABLE
ss: MACHINE WITH STATES (s0, s1);
BEGIN
ss.clk = clk;
ss.reset = reset;
ss.ena = ena;
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;
4.10.7 Присваивание состояний
Бит состояния - это выход триггера, который используется конечным автоматом для запоминания однобитного значения. В большинстве случаев Вы должны разрешить компилятору MAX+PLUS II присвоить биты состояния и значения для минимизации требующихся логических ресурсов: логический синтезатор автоматически минимизирует количество необходимых битов состояния, оптимизируя как использование устройства так и производительность.
Однако некоторые конечные автоматы могут работать быстрее, используя значения состояний, которые требуют больше чем минимальное количество битов состояния. Кроме того, Вы можете захотеть, чтобы определенные биты состояния являлись выходами конечного автомата. Для управления этими случаями Вы можете объявить биты конечного автомата и значения в объявлении конечного автомата.
Команда Global Project Logic Synthesis (меню Assign) включает опцию One-Hot State Machine Encoding (позиционное кодирование состояний), которая автоматически реализует этот тип кодирования для проекта. Кроме того, компилятор автоматически реализует позиционное кодирование для устройств FLEX 6000, FLEX 8000, и FLEX 10K, несмотря на то, включена или нет эта опция. Если Вы точно назначили биты состояния, в добавление к использованию автоматического позиционного кодирования, логика Вашего проекта может быть реализована неэффективно.
Файл stepper.tdf, приведенный ниже, реализует контроллер шагового двигателя.
SUBDESIGN stepper
(
clk, reset : INPUT;
ccw, cw : INPUT;
phase[3..0] : OUTPUT;
)
VARIABLE
ss: MACHINE OF BITS (phase[3..0])
WITH STATES (
s0 = B"0001",
s1 = B"0010",
s2 = B"0100",
s3 = B"1000");
BEGIN
ss.clk = clk;
ss.reset = reset;
TABLE
ss, ccw, cw => ss;
s0, 1, x => s3;
s0, x, 1 => s1;
s1, 1, x => s0;
s1, x, 1 => s2;
s2, 1, x => s1;
s2, x, 1 => s3;
s3, 1, x => s2;
s3, x, 1 => s0;
END TABLE;
END;
В этом примере выходы phase[3..0], объявленные в разделе Subdesign, также объявлены как биты конечного автомата ss в объявлении конечного автомата. Заметьте, что ccw и cw никогда не должны одновременно равняться 1 в одной и той же таблице. AHDL предполагает, что только одно условие в таблице истинности является истинным в одно и тоже время, следовательно, перекрытие комбинаций битов может привести к непредсказуемым результатам.
4.10.8 Конечные автоматы с синхронными выходами
Если выходы конечного автомата зависят только от состояний автомата, Вы можете определить его выходы в предложении 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, проект может использовать несколько логических ячеек, но логические ячейки могут требовать дополнительной логики для управления входами их триггеров. В этом случае модуль логического синтеза компилятора не сможет полностью минимизировать конечный автомат.
Другим способом проектирования конечного автомата с синхронными выходами является опускание присваиваний значений состояниям и точное объявление выходных триггеров. Файл 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
% состояние вход состояние выход %
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;
Вместо определения выхода с помощью присваиваний значений состояниям в объявлении конечного автомата, этот пример включает столбец `` следующий выход '', после столбца `` следующее состояние '' в операторе Table. Этот метод использует D триггер (DFF), вызванный с помощью ссылки, для синхронизации выходов с тактовой частотой.
4.10.9 Конечные автоматы с асинхронными выходами
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;
4.10.10 Выход из некорректных состояний
Логика, созданная для конечного автомата компилятором MAX+PLUS II, будет вести себя так, как Вы описали в файле TDF. Тем не менее проекты конечных автоматов, которые точно объявляют биты состояния, и которые не используют позиционного кодирования, часто допускают значения битов состояния, которые не связаны с действительными состояниями. Эти не присвоенные значения называются не корректными состояниями. Проект, который вводит некорректные состояния, например, в результате нарушений времени предустановки и удержания, может приводить к неверным выходам. Хотя Altera рекомендует, чтобы входы конечного автомата удовлетворяли всем временным требованиям, Вы можете заставить конечный автомат принудительно вернуться из некорректного состояния в известное состояние с помощью оператора Case.
...Подобные документы
Описание комбинационных и последовательностных логических устройств, групповых операций, цифровых таблиц истинности с учетом архитектурных особенностей. Особенности языка AHDL. Зарезервированные ключевые слова. Реализация иерархического проекта.
реферат [2,2 M], добавлен 23.01.2014Графический ввод схемы и симуляция в Quartus II. Основные логические элементы. Описание логических схем при помощи языка AHDL, его элементы. Зарезервированные ключевые слова. Моделирование цифровых схем с использованием параметрических элементов.
курсовая работа [1,7 M], добавлен 07.06.2015Разработка структурной схемы системы. Выбор и обоснование не указанных в задании элементов. Анализ временных параметров системы. Разработка файла конфигурации для системы сбора-обработки данных на языке AHDL. Моделирование цифровой части системы.
курсовая работа [1,1 M], добавлен 26.10.2014Элементы языка Object Pascal: идентификаторы, константы, переменные, выражения. Структура проекта Delphi. Операторы и метки. Типы данных языка OPascal. Статические и динамические массивы. Записи с вариантными полями. Совместимость и преобразование типов.
курс лекций [385,4 K], добавлен 18.02.2012Символьный тип данных как составляющая языка программирования: управляющие символы, лексемы и разделители. Разработка программного обеспечения для практической реализации решения задач, содержащих символьные величины языка программирования Turbo Pascal.
курсовая работа [37,7 K], добавлен 03.05.2012История разработки языка программирования Си. Программа на Си как одна или несколько единиц компиляции (файлов), стадии работы компилятора. Идентификаторы и ключевые слова, типы констант. Форма Бекуса-Наура описания синтаксиса формальных языков.
презентация [257,7 K], добавлен 05.01.2014Идентификаторы, объекты и операции языка VHDL. Последовательные и параллельные операторы. Описание интерфейса устройства. Синтез схем по описаниям на языке VHDL. Последовательность букв и цифр произвольной длины. Цифровое устройство и его модель.
курсовая работа [132,5 K], добавлен 28.06.2009Создание приложения по выбору варианта заполнения прямоугольной матрицы: случайными числами или из текстового файла. Идентификаторы метода "main". Расчет количества столбцов, содержащих хотя бы один нулевой элемент. Инструкция по работе с программой.
курсовая работа [563,8 K], добавлен 28.10.2014Создание программы для перевода кодов с языка Pascal на язык Си. Обработка программ операторами case, assign, rewrite и write. Способы объявления файла, комментария, переменных, логических и арифметических выражений. Виды синтаксических анализаторов.
курсовая работа [461,0 K], добавлен 03.07.2011Общая характеристика языков программирования. Описание языка Паскаль: основные субъекты языка; структура Паскаль-программы; типизация и объявление данных. Операторы присваивания и выражения. Структурные операторы, организация ветвлений и циклов.
дипломная работа [276,6 K], добавлен 26.01.2011Переменные и операции языка СИ: используемые символы, константы, идентификаторы и ключевые слова. Использование комментариев в тексте программы. Типы данных и их объявление. Приоритеты операций и порядок вычислений. Функции, переменные, макроподстановки.
учебное пособие [135,0 K], добавлен 17.02.2012История создания и применение языка Basic. Стандартные математические и строковые функции. Операции и выражения языка. Блоки данных и подпрограммы. Операторы управления, цикла, ввода-вывода и преобразования информации. Константы, переменные, массивы.
контрольная работа [2,3 M], добавлен 04.05.2015Ознакомление со структурой, комментариями, переменными и типами данных, константами, перечислениями, преобразованием типов языка программирования высокого уровня С++. Ключевые понятия языка, идентификаторы, ключевые слова, функции, операторы, выражения.
контрольная работа [31,2 K], добавлен 12.12.2009Главная идея LaTeX, возможности системы. Структура документа - текстового файла, содержащего специальные команды языка разметки. Формат текста и вспомогательные программы. Отображение математических и других формул, символы функций и исходные команды.
курсовая работа [704,6 K], добавлен 21.02.2015Стандартизированный процедурный язык программирования. Создание системного программного обеспечения и прикладных программ. Особенности языка Си, его основные недостатки. Передача параметров в функцию по значению. Стандартная библиотека языка Си.
презентация [396,3 K], добавлен 12.11.2012Рассмотрение принципа работы процессора и его практической реализации с использованием языка описания аппаратуры Verilog. Проектирование системы команд процессора. Выбор размера массива постоянной памяти. Подключение счетчика инструкций и файла регистра.
курсовая работа [1,2 M], добавлен 26.05.2022Создание приложения, исполняющего трансляцию программы из языка Паскаль в язык Си: разработка алгоритма реализации задачи, описание необходимых констант, переменных, функций и операторов, представление листинга программы и распечатка результатов.
курсовая работа [305,9 K], добавлен 03.07.2011Составление Win32 App проекта - простейшего текстового редактора, который позволяет выполнять такие операции: редактирование текста, копирование и вставку из одного окна проекта в другое окно проекта. Методы вызова диалогов сохранения и открытия файла.
курсовая работа [716,3 K], добавлен 09.11.2010Информационные технологии и защиты данных. Методы защиты информации. Виды информационной безопасности и умышленные угрозы. Программирование на языке Turbo Pascal. Типы числовых данных. Функции ввода и вывода. Логические операторы, символьные переменные.
курсовая работа [1,7 M], добавлен 16.05.2016Ознакомление со структурой языка программирования Turbo-Pascal 7.0, его алфавитом, выражениями и простейшими конструкциями (метками, идентификаторами). Способы описания арифметических, вещественных, логических и символьных операций в программной среде.
реферат [68,2 K], добавлен 07.02.2011