Введение в язык описания аппаратуры: начало работы с VHDL для проектирования цифровых схем
В данной статье рассматривается VHDL, язык описания аппаратного обеспечения, и то, как он структурируется при описании цифровых схем. Мы также рассмотрим некоторые вводные примеры описаний схем и коснемся различий между типами данных "std_logic
" и "bit
".
VHDL является одним из широко используемых языков описания аппаратуры (HDL, Hardware Description Language). VHDL означает язык описания аппаратуры VHSIC. В свою очередь, VHSIC означает высокоскоростная интегральная микросхема (Very-High-Speed Integrated Circuit).
Создание VHDL было инициировано Министерством обороны США в 1981 году. Сотрудничество таких компаний, как IBM и Texas Instruments, привело к выпуску первой версии VHDL в 1985 году. Xilinx, которая выпустила первую микросхему FPGA в 1984 году, вскоре поддержала VHDL в своих продуктах. С тех пор VHDL превратился в развитый язык в области проектирования, моделирования и синтеза цифровых схем.
В данной статье мы вкратце обсудим общую структуру кода VHDL при описании заданной схемы. С помощью некоторых вводных примеров мы также познакомимся с некоторыми широко используемыми типами данных, операторами и так далее.
Общая структура кода VHDL
Рассмотрим простую цифровую схему, показанную на рисунке 1.
На этом рисунке показано, что есть два входных порта (a и b) и один выходной порт (out1). На рисунке показано, что входные и выходные порты имеют ширину один бит. Функциональность схемы – это выполнение логической операции И двух входов и вывод результата на выходной порт.
VHDL использует похожее описание; однако он имеет свой собственный синтаксис. Например, для описания входных и выходных портов этой схемы используются следующие строки кода:
entity circuit_1 is
Port ( a : in STD_LOGIC;
b : in STD_LOGIC;
out1 : out STD_LOGIC);
end circuit_1;
Давайте по очереди разберемся, что это значит.
Строка 1. Первая строка указывает произвольное название для описываемой схемы. Слово «circuit_1
», которое находится между ключевыми словами «entity
» и «is
», определяет имя этого модуля.
Строки с 2 по 4. Эти строки определяют входные и выходные порты схемы. Сравнивая эти строки со схемой, изображенной на рисунке 1, мы видим, что порты схемы вместе со своими функциями перечислены после ключевого слова «port
». Например, в строке 3 говорится, что у нас есть порт под названием «b
». Этот порт является входом, как указано ключевым словом «in
» после двоеточия.
Что указывает ключевое слово «std_logic
»? Как мы обсудим далее в этой статье, std_logic
является в VHDL широко используемым типом данных. Его можно использовать для описания однобитового цифрового сигнала. Поскольку все порты входов/выходов на рисунке 1 передают единицу или ноль, мы можем использовать для этих портов тип данных std_logic
.
Строка 5. Эта строка определяет конец оператора «entity
».
Следовательно, фрагмент кода entity
определяет 1) название описываемой схемы и 2) порты схемы вместе со своими характеристиками, а именно: вход/выход и тип данных, которые должны передаваться этими портами. Фактически фрагмент кода entity
описывает интерфейс модуля с окружающей его средой. Функции схемы, указанные в обсуждаемом операторе «entity
», показаны на рисунке 1 зеленым цветом.
В дополнение к интерфейсу схемы с окружающей средой нам необходимо описать работу схемы. На рисунке 1 функциональность схемы – это выполнение логической операции И двух входов и вывод результата на выходной порт. Чтобы описать работу схемы, VHDL добавляет секцию «architecture
» и связывает её с circuit_1
, определенной оператором entity
. Код VHDL, описывающий архитектуру этой схемы, будет следующим.
architecture Behavioral of circuit_1 is
begin
out1 <= ( a and b );
end Behavioral;
Строка 6. Эта строка дает название, «Behavioral
», для архитектуры, которая будет описана в следующих строках. Это имя встречается между ключевыми словами «architecture
» и «of
». Данная строка также связывает эту архитектуру с «circuit_1
». Другими словами, эта архитектура будет описывать работу «circuit_1
».
Строка 8. Указывает начало описания архитектуры.
Строка 9. Строка 9 использует синтаксис VHDL для описания работы схемы. Логическая операция И (AND) двух входов находится в круглых скобках, а результат присваивается выходному порту с помощью оператора присваивания «<=
».
Строка 10. Указывает конец описания архитектуры. Как упоминалось выше, эти строки кода описывают внутреннюю работу схемы, которая здесь представляет простой логический элемент И (на рисунке 1 показан синим цветом).
Объединив то, что мы обсудили ранее, мы закончим описание «Circuit_1» в VHDL. Мы получим следующий код:
entity circuit_1 is
Port ( a : in STD_LOGIC;
b : in STD_LOGIC;
out1 : out STD_LOGIC);
end circuit_1;
-----------------------------------------------------
architecture Behavioral of circuit_1 is
begin
out1 <= ( a and b );
end Behavioral;
Однако нам еще нужно добавить еще несколько строк кода. Эти строки добавят библиотеку, содержащую некоторые важные определения, включая определения типов данных и операторов. Библиотека может состоять из нескольких пакетов (смотрите рисунок 2 ниже). Нам нужно сделать необходимый пакет(ы) данной библиотеки видимыми для проекта.
Поскольку в приведенном выше примере используется тип данных «std_logic
», нам нужно добавить в код пакет «std_logic_1164
» из библиотеки «ieee
». Обратите внимание, что логические операторы для типа данных std_logic
также определены в пакете «std_logic_1164
», иначе нам пришлось бы сделать соответствующий пакет видимым для кода. Окончательный код будет следующим:
library ieee;
use ieee.std_logic_1164.all
entity circuit_1 is
Port ( a : in STD_LOGIC;
b : in STD_LOGIC;
out1 : out STD_LOGIC);
end circuit_1;
architecture Behavioral of circuit_1 is
begin
out1 <= ( a and b );
end Behavioral;
Здесь мы добавляем две новые строки перед тем, что уже написали. Первая строка добавляет библиотеку «ieee
», а вторая строка указывает, что требуется пакет «std_logic_1164
» из данной библиотеки. Поскольку «std_logic
» является широко используемым типом данных, нам почти всегда нужно добавлять в VHDL код библиотеку «ieee
» и пакет «std_logic_1164
».
Для проверки приведенного выше VHDL кода мы можем использовать симулятор Xilinx ISE.
Теперь, когда мы познакомились с основными блоками кода VHDL, давайте рассмотрим один из самых важных типов данных VHDL, т.е. тип данных «std_logic
».
Тип данных «std_logic
» (против «bit
»)
Как упоминалось выше, тип данных «std_logic
» может использоваться для представления однобитового сигнала. Интересно, что существует еще один тип данных VHDL, «bit
», который может принимать логическую единицу или логический ноль.
Итак, зачем нам нужен тип данных std_logic
, если тип данных «bit
» уже охватывает высокое и низкое логические состояния цифрового сигнала? Ну, цифровой сигнал на самом деле не ограничивается высоким логическим уровнем и низким логическим уровнем. Рассмотрим инвертор с тремя состояниями, показанный на рисунке 3.
Когда на «включен» высокий логический уровень, «выход_данных» подключается либо к Vdd, либо к земле; однако, когда на «включен» низкий логический уровень, «выход данных» висит в воздухе, то есть он не имеет низкоимпедансного соединения с Vdd или землей, а вместо этого представляет для внешней схемы «высокий импеданс». Тип данных «std_logic
» позволяет нам описывать цифровой сигнал в режиме с высоким импедансом, присвоив ему значение 'Z
'.
Существует еще одно состояние, то есть к дополнение в высокому логическому уровню, низкому логическому уровню и высокому импедансу, которое может быть использовано при проектировании цифровых схем. Иногда нам неважно значение на конкретном входе. В этом случае представление значения сигнала с «неважным значением» может привести к более эффективному проектированию. Тип данных «std_logic
» поддерживает состояние «неважное значение». Это позволяет улучшить аппаратную оптимизацию для таблиц поиска.
Тип данных «std_logic
» также позволяет нам представить неинициализированный сигнал, присвоив ему значение 'U
'. Это может быть полезно при моделировании фрагмента VHDL кода. Оказывается, что тип данных «std_logic
» фактически может принимать девять значений:
- '
U
': не инициализировано; - '
1
': обычный индикатор высокого логического уровня, также известный как «принудительный высокий логический уровень»; - '
0
': обычный индикатор низкого логического уровня, также известный как «принудительный низкий логический уровень»; - '
Z
': высокий импеданс; - '
-
': неважное значение; - '
W
': слабое неизвестное; - '
X
': неизвестное; - '
H
': слабая '1
' (имеется в виду слабый ток); - '
L
': слабый '0
' (имеется в виду слабый ток).
Среди этих значений мы обычно используем ‘0
’, ‘1
’, ‘Z
’ и ‘-
’.
Давайте посмотрим пример.
Пример 1
Напишем VHDL код для схемы на рисунке 4.
Основная процедура почти такая же, как в предыдущем примере. Код будет выглядеть следующим образом:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity circuit_2 is
Port ( a : in STD_LOGIC;
b : in STD_LOGIC;
c : in STD_LOGIC;
d : in STD_LOGIC;
out1 : out STD_LOGIC;
out2 : out STD_LOGIC);
end circuit_2;
architecture Behavioral of circuit_2 is
signal sig1: std_logic;
begin
sig1 <= ( a and b );
out1 <= ( sig1 or c );
out2 <= (not d);
end Behavioral;
Строки 1 и 2. Эти строки добавляют в код необходимые библиотеку и пакет. Поскольку используется тип данных «std_logic
», мы должны добавить пакет «std_logic_1164
».
Строки 3-10. Эти строки определяют имя модуля вместе с его входными/выходными портами. Этот фрагмент кода соответствует частям зеленого цвета на рисунке 4.
Строки 11-17. Эта часть кода описывает работу схемы (т.е. части синего цвета на рисунке 4). Как вы могли заметить, на рисунке 4 есть один внутренний узел; он обозначен как «sig1
». Мы используем оператор «port
» из «entity
» для определения входных/выходных портов, но как мы можем определить внутренние узлы схемы? Для этого мы используем ключевое слово «signal
».
В строке 12 вышеприведенного кода ключевое слово «signal
» сообщает программному обеспечению, что в схеме есть узел, помеченный как «sig1
». Подобно определению портов, мы используем ключевое слово «std_logic
» после двоеточия, чтобы указать требуемый тип данных. Теперь мы можем присвоить значение этому узлу (строка 14) или использовать его значение (строка 15).
Пример 2
Напишем VHDL код для схемы на рисунке 5.
Данная схема представляет собой мультиплексор два-к-одному. Когда на «sel
» высокий логический уровень, выход нижнего логического элемента И будет в низком логическом состоянии независимо от значения на «b
». Мы можем сказать, что логический элемент И предотвращает распространение «b
» на «sig2
». С другой стороны, поскольку на «sel
» высокий логический уровень, выход верхнего логического элемента И будет соответствовать «a
». Или, что то же самое, «a
» достигнет «sig3
». Поскольку в этом случае «sig2
» равен логическому нулю, то на выходе логического элемента ИЛИ будет такое же состояние, как у «sig3
». Следовательно, когда на «sel
» высокий логический уровень, «out1
» будет таким же, как «a
».
Аналогичное обсуждение покажет, что, когда на «sel
» низкий логический уровень, «out1
» будет принимать значение «b
». Следовательно, исходя из значения «sel
», мы можем позволить значению на одном или другом входе достичь выхода. Это называется мультиплексированием, а схема называется мультиплексором.
Мы можем описать схему на рисунке 5, используя следующий код:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity circuit_3 is
Port ( a : in STD_LOGIC;
b : in STD_LOGIC;
sel : in STD_LOGIC;
out1 : out STD_LOGIC);
end circuit_3;
architecture Behavioral of circuit_3 is
signal sig1, sig2, sig3: std_logic;
begin
sig1 <= ( not sel );
sig2 <= ( b and sig1 );
sig3 <= ( a and sel );
out1 <= ( sig2 or sig3 );
end Behavioral;
Резюме
В данной статье мы обсудили, что такое VHDL, как структурируется его код, и представили некоторые примеры того, как он используется для описания цифровых схем. Теперь вы должны лучше понимать следующие моменты:
- Фрагмент кода «
entity
» определяет 1) название описываемой схемы и 2) порты схемы; он устанавливает интерфейс между модулем и его окружением. - Фрагмент кода «
architecture
» описывает внутреннюю работу схемы. - Библиотеки VHDL содержат важные определения, включая определения типов данных и операторов. Сама библиотека может состоять из нескольких пакетов.
- Нам почти всегда нужно добавлять в свой VHDL код библиотеку «
ieee
» и пакет «std_logic_1164
». - Среди возможных значений типа данных «
std_logic
» мы обычно используем ‘0
’, ‘1
’, ‘Z
’ и ‘-
’.