AHDL () — комп'ютерна мова опису апаратних засобів, розроблена компанією Altera, що призначена для опису комбінаційних логічних пристроїв, цифрових автоматів і таблиць істинності з врахуванням архітектурних особливостей ПЛІС цієї фірми. Мова має Ada-подібний синтаксис; порівнюючи AHDL з Verilog можна зазначити, що це наче мова асемблера та мова високого рівня: перша має більше контролю, проте немає високорівневої підтримки.
AHDL, природно, сумісний з компіляторами фірми Altera: Quartus та Max+PLUS та дає можливість створювати ієрархічні проєкти в рамках цієї мови чи комбінувати різні типи файлів в один проєкт.
Структура програми Програма на мові AHDL має визначену структуру. Її розділи повинні слідувати в такому порядку: + Назва Призначення Особливості Заголовок () Дає назву модулю Починається з ключевого слова TITLE, за яким слідує назва модуля. Оператор включення () Включає вміст вказаного у в текст програми Починається з ключевого слова INCLUDE, за яким слідує ім'я файлу, без шляху до нього. Оголошення константи () Присвоює імені константи число Починається з ключевого слова CONSTANT, за яким слідує ім'я, символ (=), а далі число чи арифметичний вираз. Оператор визначення () Присвоює арифметичним виразам символьні імена Починається з ключевого слова DEFINE, за яким слідує ім'я зі списком аргументів, за яким ставиться символ (=), а далі арифметичний вираз. Оголошення параметрів () Оголошує параметри модуля Починається з ключевого слова PARAMETERS, за яким слідує список параметрів. Значення параметру за замовчуванням вказується після символу (=). Опис прототипу () Описує параметри модулів, що використовуються Починається з ключевого слова FUNCTION, за яким слідує ім'я, а потім список входів. Якщо модуль параметризований, далі йде ключове слово WITH і список параметрів. Потім вказується ключове слово RETURNS і список виходів модуля. Оператор опцій () Визначає елемент з меншим індексом Починається з ключевого слова OPTIONS, за яким слідує ключове слово BITO, символ (=), а далі одне з ключевих слів: LSB (молодший розряд), MSB (старший розряд) чи ANY (будь-який). Оператор контролю () Перевіряє істинність логічного виразу Починається з ключевого слова ASSERT, за яким в дужках слідує арифметичний вираз. Якщо значення виразу false, на екран виводиться повідомлення, записане після ключевого слова REPORT. Опис модуля () Задає ім'я модуля й перераховує його порти Починається з ключевого слова SUBDESIGN, за яким слідує назва модуля та список виводів в дужках. В кінці списку однотипних виводів вказується їх тип. Розділ змінних () Задає внутрішні змінні Починається з ключевого слова VARIABLE, за яким слідують імена однотипних змінних, а далі тип змінних. Розділ може містити оператор IF GENERATE, що керує створення змінних залежно від результату арифметичного виразу. Опис логіки () Описує функціонал модуля Починається з ключевого слова BEGIN, закінчується ключевим словом END. З усіх названих, лише розділи опису модуля та логіки є обов'язковими; заголовок, оператор опцій, розділи змінних, опису модуля та логіки можуть вживатися в програмі лише раз.
Конструкції мови
Множина символів мови До множини символів мови відносять букви, цифри та спеціальні символи, призначення яких наведено в таблиці нижче. + Символ Функція -- Коментар в стилі VHDL, що продовжується до кінця рядка % Ставляться з обох боків коментаря в стилі AHDL () Використовуються для підвищення пріоритету в операціях, оточують порти в іменах модуля та списки параметрів [] Використовуються для створення діапазону значень '' Використовуються для створення символічних імен "" Використовуються в заголовку, для вказування файлу для включення, оточують цифри в недесяткових константах . Відділяє ім'я файлу від розширення .. Розділяє найбільші та найменші значення в діапазонах ; Закінчує розділи і секції мови , Розділяє елементи списків та груп : Відділяє символьні імена від типів = Присвоює значення в операціях => Відділяє входи і виходи в таблицях істинності та операторі CASE
З символів складаються імена, що в мові AHDL можуть даватися: портам, шинам; константам; змінним кінцевих автоматів, бітам та іменам станів; екземплярам; параметрам; функціям; іменованим операторам; сегментам пам'яті; підпроєктам.
Синтаксис імен в AHDL схожий на синтаксис імен в інших комп'ютерних мовах: ім'я може містити букви, цифри, символ підкреслення та не може бути зарезервованим словом; зарезервовані слова можна використовувати як символічні імена лише коли вони вживаються в одинарних лапках або в коментарях; великі та малі літери не розрізняються; ім'я повинне починатися з букви і не може закінчуватися знаком підкреслення.
Зарезервовані слова В документації компанії Altera вказано, що для поліпшення прочитності програми зарезервовані слова варто писати великими літерами. До ключевих слів належать наступні: AND ASSERT BEGIN BIDIR BITS BURIED CASE CLIQUE CONNECTED_PINS CONSTANT DEFAULTS DEFINE DESIGN DEVICE DIV ELSE ELSEIF END FOR FUNCTION GENERATE GND HELP_ID IF INCLUDE INPUT IS LOG2 MACHINE MOD NAND NODE NOR NOT OF OPTIONS OR OTHERS OUTPUT PARAMETERS REPORT RETURNS SEGMENTS SEVERITY STATES SUBDESIGN TABLE THEN TITLE TO TRI_STATE_NODE VARIABLE VCC WHEN WITH XNOR XOR До службових імен належать: CARRY CASCADE CEIL DFFE DFF EXP FLOOR GLOBAL JKFFE JKFF LATCH LCELL MCELL MEMORY OPENDRN SOFT SRFFE SRFF TFFE TFF TRI USED WIRE X
Змінні Змінні використовуються для збереження проміжних результатів обчислень. Допустимими типами змінних є: NODE; TRI_STATE_NODE; імена примітивів, мегафункцій, макрофункцій та машин станів.
Кілька провідників, що несуть однакове смислове навантаження можна об'єднати в шину. Кожна з них може мати до 255 біт і працює як одне ціле. Визначити шину можна наступними способами, після чого [] стануть еквівалентними звертанню до всієї шини: a[1..5] b[7..0] (c, d, e)
Порти Порт — це вхід чи вихід логічної функції. Може мати один з наступних типів: INPUT — вхід; OUTPUT — вихід; BIDIR — двонаправлений вивід; MACHINE INPUT — вхід станів автомата; MACHINE OUTPUT — вихід станів автомата.
Мова AHDL дає можливість описати двонаправлений порт, що корисно для зменшення кількості провідників. На прикладі нижче, двонаправлений сигнал io, що запускається примітивом TRI, використовується як вхід та вихід для D-тригера (DFF). Варто відмітити, що входи тригера clrn та prn не підключені, що видно з відділених комами місць. SUBDESIGN bus_register ( clk, oe : INPUT; io : BIDIR; ) BEGIN io = TRI(DFF(io, clk, , ), oe); END;
Числа Мова AHDL підтримує запис чисел в десятковій, двійковій, вісімковій та шістнадцятковій системах числення. Таблиця нижче ілюструє формат запису чисел. + Основа системи Формат 10 <послідовність цифр 0..9> 2 B"<послідовність цифр 0, 1, X>" 8 O"<послідовність цифр 0..7>" чи Q"<послідовність цифр 0..7>" 16 X"<послідовність цифр 0..9, A..F>" чи H"<послідовність цифр 0..9, A..F>" Константи можна використати для того, щоб надати конкретному числу більше інформативності. Окрім підвищення прочитності програми, їх застосування стає корисним тоді, коли це число неодноразово повторюється. Нижче наведено приклад селектора адреси, що забезпечує підключення певного пристрою до шини лише за умови подання на його вхід адреси 21 в шістнадцятковій системі числення. CONSTANT io_address = H"21"; SUBDESIGN address_selector ( a[15..0] : INPUT; select : OUTPUT; ) BEGIN select = (a[15..0] == io_adress); END;
Арифметичні і булеві вирази Арифметичні вирази — це засіб формування конструкцій мови, що обраховуються компілятором і не займають ресурсів ПЛІС. Їх результатом завжди є ціле додатне число, для його отримання є функції явного задання правил округлення: CEIL (до більшого цілого) та FLOOR (до меншого цілого).
Операції, що можуть використовуватись в арифметичних виразах наведені в таблиці: + Операція Опис Пріоритет + (унарний) Плюс 1 — (унарний) Мінус 1 ! (NOT) Заперечення 1 ^ Степінь 1 MOD Залишок від ділення 2 DIV Ділення 2 * Множення 2 LOG2 Двійковий логарифм 2 + Додавання 3 — Віднімання 3 == (numeric) Рівність чисел 4 == (string) Рівність рядків 4 != Не рівно 4 > Більше 4 >= Більше рівно 4 < Менше 4 <= Менше рівно 4 & (AND) Кон'юнкція 5 !& (NAND) Штрих Шефера 5 $ (XOR) Виключна диз'юнкція 6 !$ (XNOR) Заперечення виключної диз'юнкції, еквівалентність 6 # (OR) Диз'юнкція 7 !# (NOR) Стрілка Пірса 7 ? Умовна операція 8
Булеві вирази — це операнди, розділені знаками арифметичних, логічних операцій та операторами порівняння, згруповані дужками. Варто зазначити, що порядок слідування булевих рівнянь в програмі не важливий, оскільки логічні стани встановлюються одночасно.
Операції, що можуть використовуватись в булевих виразах наведені в таблиці: + Операція Опис Пріоритет — Доповнення до 2 1 ! Інверсія 1 + Додавання 2 — Віднімання 2 == Рівно 3 != Не рівно 3 > Більше 3 >= Більше рівно 3 < Менше 3 <= Менше рівно 3 & (AND) Елемент «І» 4 !& (NAND) Елемент «І-НЕ» 4 $ (XOR) Елемент «ВИКЛЮЧНЕ АБО» 5 !$ (XNOR) Елемент «ВИКЛЮЧНЕ АБО-НЕ» 5 # (OR) Елемент «АБО» 6 !# (NOR) Елемент «АБО-НЕ» 6
Приклади використання Комбінаційна логіка Комбінаційна логіка — це кінцеві автомати без пам'яті, що реалізуються за допомогою булевих виразів та таблиць істинності.
Таблична логіка Таблична логіка в мові AHDL реалізується за допомогою наступного синтаксису: оператор починається ключевим словом TABLE, за яким йде заголовок таблиці; в заголовку перераховуються список входів, символ (=>) та список виходів; наступні рядки таблиці містять списки значень входів і виходів, розділені символом (=>). Вхідні значення можуть бути в неважливому стані X, проте варто слідкувати, щоб діапазони значень не перекривались в межах однієї таблиці; оператор закінчується ключевими словами END TABLE. На прикладі нижче наведено контролер, що формує управляючі сигнали для відображення цифр в шістнадцятковій системі числення на семисегментному індикаторі. % -a- % % f| |b % % -g- % % e| |c % % -d- % SUBDESIGN segment7 ( 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;
Умовна логіка Умовна логіка в мові реалізується операторами IF та CASE.
Оператор CASE, як і в більшості комп'ютерних мовах, визначає вписок альтернативних варіантів, один з яких виконується при певному значенні селектора. Його синтаксис наступний: оператор починається ключевим словом CASE, за яким записується селектор, а потім — ключове слово IS; кожен альтернативний варіант починається ключевим словом WHEN, після якого йде константа, потім символ (=>) та набір операторів; на відміну від інших, останній альтернативний варіант може починатися з WHEN OTHERS; якщо селектор рівний одній з констант, виконується блок її операторів, якщо ж така константа не передбачена — виконується блок з WHEN OTHERS; завершується оператор ключевими словами END CASE. Нижче наведено приклад дешифратора, що перетворює двохрозрядний код на вході в код «one hot» (чотири значення, кожне має одну одиницю): SUBDESIGN decoder2x4 ( 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;
Послідовна логіка Регістр Регістр необхідний для збереження інформації і створюється після його оголошення в розділі змінних. На прикладі нижче сформовано восьмирозрядний регістр, що використовує виходи як D-тригери, що дає економію ресурсів мікросхеми. SUBDESIGN register8 ( clk, load, d[7..0] : INPUT; q[7..0] : OUTPUT; )