Владимир Стешенко
Школа схемотехнического
проектирования устройств обработки сигналов
Занятие 9.
Языки описания аппаратуры: синтаксис и особенности применения
Возвышенное может быть выражено на любом языке,
но то, что понимается под возвышенным, не может
быть выражено ни на каком.
Маймонид
Язык описания аппаратуры (Hardware Description Language) является формальной записью, которая может быть использована на всех этапах разработки цифровых электронных систем. Это возможно вследствие того, что язык легко воспринимается как машиной, так и человеком. Он может использоваться на стадиях проектирования, верификации, синтеза и тестирования аппаратуры, а также в целях передачи данных о проекте, его модификации и сопровождения. Языки описания аппаратуры долгое время были прерогативой довольно узкого класса разработчиков специализированных интегральных схем. С появлением такой элементной базы, как ПЛИС, резко расширился круг пользователей, заинтересованных в использовании современых способов описания проекта. С другой стороны, наблюдается некоторый недостаток литературы, особенно русскоязычной, в которой бы достаточно подробно излагались как основы синтаксиса языков описания аппаратуры, так и примеры их применения при реализации устройств на ПЛИС. В данной главе делается скромная попытка восполнить этот пробел.
Прежде чем приступить к рассмотрению синтаксиса некоторых языков описания аппаратуры, следует определить основные понятия, касающиеся их применения при проектировании цифровых систем.
Как известно, цифровая система может быть описана на поведенческом, структурном и потоковом уровнях.
Структурное описание представляет собой описание системы в виде совокупности компонентов и связей между ними. Как следует из названия, оно отражает структуру системы и может быть реализовано «в железе» с использованием соответствующего программного и аппаратного обеспечения.
Поведенческое описание представляет собой описание системы при помощи задания зависимости вход/выход. Оно используется для функциональной верификации (моделирования) системы и не всегда может быть синтезировано в ПЛИС.
Потоковое описание не всегда выделяется в отдельный класс. По сути оно представляет собой описание межрегистровых передач и обмена данными. Такой тип описания удобен для проектирования систем, имеющих шинную архитектуру.
Языки описания аппаратуры можно весьма условно разделить на языки высокого и низкого уровня. К первым принято относить VHDL и Verilog HDL, ко вторым — AHDL, Abel HDL и ряд других. Языки высокого уровня позволяют обеспечить определенную мобильность описания при миграции на другую элементную базу, в то время как языки низкого уровня ориентированы на использование архитектурных особенностей ПЛИС конкретных производителей.
Одним из универсальных и распространенных языков описания аппаратуры является VHDL. На этом языке возможно как поведенческое, так и структурное и потоковое описание цифровых схем. Язык VHDL используется во многих системах для моделирования цифровых схем, проектирования программируемых логических интегральных микросхем, базовых матричных кристаллов, заказных интегральных микросхем.
С точки зрения программиста, язык VHDL состоит как бы из двух компонентов — общеалгоритмического и проблемно-ориентированного. Общеалгоритмический компонент VHDL — это язык, близкий по синтаксису и семантике к современным языкам программирования типа Паскаль, C и др. Язык относится к классу строго типизированных. Помимо встроенных простых (скалярных) типов данных (пакет STANDART), таких как целый, вещественный, булевский, битовый, данные типа время, данные типа ссылка или указатель, пользователь может вводить свои типы данных (перечислимый, диапазонный и др.). Помимо скалярных данных можно использовать агрегаты: массивы array, в том числе и битовые векторы bit_vector, а также символьные строки string, записи record, файлы file.
Последовательно выполняемые (последовательные) операторы VHDL могут использоваться в описании процессов, процедур и функций. Их состав включает:
- оператор присваивания переменной (:=);
- последовательный оператор назначения сигналу (<=);
- последовательный оператор утверждения (assert);
- условный оператор (if);
- оператор выбора (case);
- оператор цикла (loop);
- пустой оператор (null);
- оператор возврата процедуры — функции (return);
- оператор последовательного вызова процедуры.
Язык поддерживает концепции пакетного и структурного программирования. Сложные операторы заключены в операторные скобки: if — end if; process — end process; case — end case; loop — end loop и т. д.
Различаются локальные и глобальные переменные. Область «видимости» локальных переменных ограничена пределами блока (процессного, процедурного, оператора блока, оператора описания архитектуры).
Фрагменты описаний, которые могут независимо анализироваться компилятором и при отсутствии ошибок помещаться в библиотеку проекта (рабочую библиотеку Work), называются проектными пакетами design unit. Такими пакетами могут быть объявление интерфейса объекта проекта entity, объявление архитектуры architecture, объявление конфигурации configuration, объявление интерфейса пакета package и объявление тела пакета package body.
Модули проекта, в свою очередь, можно разбить на две категории: первичные и вторичные. К первичным пакетам относятся объявления пакета, объекта проекта, конфигурации. Ко вторичным — объявление архитектуры, тела пакета. Один или несколько модулей проекта могут быть помещены в один файл, называемый файлом проекта (design file).
Каждый проанализированный модуль проекта помещается в библиотеку проекта (design library) и становится библиотечным модулем (library unit). Каждая библиотека проекта в языке VHDL имеет логическое имя (идентификатор). По отношению к сеансу работы с VHDL-системой существуют два класса рабочих библиотек проекта: рабочие библиотеки и библиотеки ресурсов.
Рабочая библиотека — это библиотека WORK, с которой в данном сеансе работает пользователь, и в которую помещается пакет, полученный в результате анализа пакета проекта. Библиотека ресурсов — это библиотека, содержащая библиотечные модули, ссылка на которые имеется в анализируемом модуле проекта. В каждый конкретный момент времени пользователь работает с одной рабочей библиотекой и произвольным количеством библиотек ресурсов.
Модули, как и в обычных алгоритмических языках, являются средством выделения из ряда программ и подпрограмм общих типов данных, переменных, процедур и функций, позволяющим упростить, в частности, процесс их замены.
Так же как в описаниях проектируемых систем разделяются описания интерфейсов и тел, в VHDL у пакета разделяются описание интерфейса и тела пакета. По умолчанию предусмотрено подключение стандартных пакетов STANDART и TEXT 10. Пакет STANDART, в частности, содержит описание булевских операций над битовыми данными и битовыми векторами. Нестандартные пакеты реализуются пользователями, желающими более точно отобразить свойства описываемых ими объектов. Например, можно в пользовательском пакете переопределить логические операции И, ИЛИ и НЕ и перейти от булевского (0, 1) к многозначному (1, 0, X, Z) алфавиту моделирования.
Проблемно-ориентированная компонента позволяет описывать цифровые системы в привычных разработчику понятиях и терминах.
Сюда можно отнести:
- понятие модельного времени now;
- данные типа time, позволяющие указывать время задержки в физических единицах;
- данные вида сигнал signal, значение которых изменяется не мгновенно, как у обычных переменных, а с указанной задержкой, а также специальные операции и функции над ними;
- средства объявления объектов entity и их архитектур architecture.
Если говорить про операторную часть проблемно-ориентированной компоненты, то условно ее можно разделить на средства поведенческого описания аппаратуры (параллельные процессы и средства их взаимодействия); средства потокового описания (описание на уровне межрегистровых передач) — параллельные операторы назначения сигнала (<=) с транспортной transport или инерциальной задержкой передачи сигналов, и средства структурного описания объектов (операторы конкретизации компонентов с заданием карт портов port map и карт настройки generic map, объявление конфигурации и т. д.).
Параллельные операторы VHDL включают:
- оператор процесса process;
- оператор блока block;
- параллельный оператор назначения сигнала <=;
- оператор условного назначения сигнала when;
- оператор селективного назначения сигнала select;
- параллельный оператор утверждения assert;
- параллельный оператор вызова процедуры;
- оператор конкретизации компоненты port map;
- оператор генерации конкретизации generate.
Как видно из этого перечня, последовательные и параллельные операции назначения, вызова процедуры и утверждения различаются контекстно, то есть внутри процессов и процедур они последовательные, вне — параллельные.
Базовым элементом описания систем на языке VHDL является блок. Блок содержит раздел описаний данных и раздел параллельно исполняемых операторов. Частным случаем блока является описание архитектуры объекта. В рамках описания архитектуры могут использоваться внутренние вложенные блоки. Наряду со всеми преимуществами блочной структуры программы и ее соответствия естественному иерархическому представлению структуры проекта операторы блока языка VHDL позволяют устанавливать условия охраны (запреты) входа в блок. Только при истинности значения охранного выражения управление передается в блок и инициирует выполнение операторов его тела.
Алфавит языка
Как и любой другой язык программирования, VHDL имеет свой алфавит — набор символов, разрешенных к использованию и воспринимаемых компилятором. В алфавит языка входят:
- Латинские строчные и прописные буквы: A, B,..., Z, a, b,..., z.
- Цифры от 0 до 9.
- Символ подчеркивания «_» (код ASCII: 95).
Из символов, перечисленных в пп. 1–3 (и только из них!), могут конструироваться идентификаторы в программе. Кроме того, написание идентификаторов должно подчиняться следующим правилам:
- идентификатор не может быть зарезервированным словом языка;
- идентификатор должен начинаться с буквы;
- идентификатор не может заканчиваться символом подчеркивания «_»;
- идентификатор не может содержать двух последовательных символов подчеркивания «__»;
Примеры корректных идентификаторов:
cont, clock2, full_add
Примеры некорректных идентификаторов:
1clock, _adder, add__sub, entity
Следует отметить, что прописные и строчные буквы не различаются, то есть идентификаторы clock и CLOCK являются эквивалентными.
- Символ «пробел» (код 32), символ табуляции (код 9), символ новой строки (коды 10 и 13).
Данные символы являются разделителями слов в конструкциях языка. Количество разделителей не имеет значения. Таким образом, следующие выражения для компилятора будут эквивалентны:
count: = 2 + 2;
count := 2 + 2 ;
count := 2 + 2;
- Специальные символы, участвующие в построении конструкций языка:
+ — * / = < >., ( ): ; # ' « |
- Составные символы, воспринимаемые компилятором как один символ:
<= >= =>:= /=
- Разделители между элементами составных символов недопустимы.
Комментарии
Признаком комментария являются два символа тире («--»). Компилятор игнорирует текст, начиная с символов «--» до конца строки, то есть комментарий может включать в себя символы, не входящие в алфавит языка (в частности русские буквы).
Числа
В стандарте языка определены числа как целого, так и вещественного типа. Однако средства синтеза ПЛИС допускают применение только целых чисел. Целое число в VHDL может быть представлено в одной из четырех систем счисления: двоичной, десятичной, восьмеричной и шестнадцатеричной. Конкретные форматы написания числовых значений будут описаны далее при рассмотрении различных типов языка.
К разновидности числовых значений можно отнести также битовые строки.
Символы
Запись символа представляет собой собственно символ, заключенный в одиночные кавычки. Например:
'A', '*', ' '
В средствах синтеза ПЛИС область применения символов ограничена использованием их в качестве элементов перечислимых типов.
Строки
Строки представляют собой набор символов, заключенных в двойные кавычки. Чтобы включить двойную кавычку в строку, необходимо ввести две двойных кавычки. Например:
« A string»
«A string in a string «»A string»» «
Типы данных
Подобно высокоуровневым языкам программирования, VHDL является языком со строгой типизацией. Каждый тип данных в VHDL имеет определенный набор принимаемых значений и набор допустимых операций. В языке предопределено достаточное количество простых и сложных типов, а также имеются средства для образования типов, определяемых пользователем.
Необходимо отметить, что в данной статье рассматриваются не все типы данных, определенные в стандарте, а только те, которые поддерживаются средствами синтеза ПЛИС.
Простые типы
Следующие простые типы являются пред-определенными:
- BOOLEAN (логический) — объекты данного типа могут принимать значения FALSE (ложь) и TRUE (истина).
- INTEGER (целый) — значения данного типа представляют собой 32-разрядные числа со знаком. Объекты типа INTEGER могут содержать значения из диапазона -(231-1)…231-1 (-2147483647 … 2147483647).
- BIT (битовый) — представляет один логический бит. Объекты данного типа могут содержать значение '0' или '1'.
- STD_LOGIC (битовый) — представляет один бит данных. Объекты данного типа могут принимать 9 состояний. Данный тип определен стандартом IEEE 1164 для замены типа BIT.
- STD_ULOGIC (битовый) — представляет один бит данных. Объекты данного типа могут принимать 9 состояний. Данный тип определен стандартом IEEE 1164 для замены типа BIT (см. примечание).
- ENUMERATED (перечислимый) — используется для задания пользовательских типов.
- SEVERITY_LEVEL — перечислимый тип, используется только в операторе ASSERT.
- CHARACTER — символьный тип.
Примечание
В действительности тип STD_ULOGIC является базовым для типа STD_LOGIC, то есть объекты обоих типов могут принимать одно и то же множество значений и имеют одинаковый набор допустимых операций. Единственное различие между типами заключается в том, что для типа STD_ULOGIC не определена функция разрешения (resolving function). В языке VHDL функция разрешения используется для определения значения сигнала, имеющего несколько источников (драйверов).
Пример
Выходы двух буферов с тремя состояниями подключены к одной цепи X. Пусть выход одного буфера установился в состояние 'Z', а выход другого — в состояние '1'. Функция разрешения определяет, что в этом случае значение сигнала X будет равняться '1'.
Поскольку для типа STD_ULOGIC не определена функция разрешения, сигналы этого типа могут иметь только один источник.
Далее рассматривается только тип STD_LOGIC, однако все сказанное будет справедливо и для типа STD_ULOGIC. На практике, в подавляющем большинстве случаев достаточно использования типа STD_LOGIC.
Сложные типы
Из всей совокупности сложных типов, определенных в стандарте языка, для синтеза логических схем используются только массивы (тип ARRAY) и записи (тип RECORD). Однако тип RECORD поддерживается не всеми средствами синтеза и в данной статье рассмотрен не будет.
Следующие типы-массивы являются предопределенными:
- BIT_VECTOR — одномерный массив элементов типа BIT;
- STD_LOGIC_VECTOR — одномерный массив элементов типа STD_LOGIC;
- STD_ULOGIC_VECTOR — одномерный массив элементов типа STD_ULOGIC;
- STRING — одномерный массив элементов типа CHARACTER.
Направление и границы диапазона индексов не содержатся в определении указанных типов и должны быть указаны непосредственно при объявлении объектов данных типов.
Описание простых типов
Тип BOOLEAN
Тип BOOLEAN является перечислимым типом. Объект данного типа может принимать значения FALSE (ложь) и TRUE (истина), причем FALSE эквивалентно 0, а TRUE эквивалентно 1.
Все три типа объектов в VHDL (константы, переменные и сигналы) могут иметь тип BOOLEAN. Таким объектам может быть присвоено только значение типа BOOLEAN.
Пример
PROCESS (a, b)
VARIABLE cond: BOOLEAN;
BEGIN
cond:= a > b;
IF cond THEN
output <= '1';
ELSE
output <= '0';
END IF;
END PROCESS;
Допустимое использование
Операторы отношения
Значения типа BOOLEAN могут участвовать в выражениях. Операторы отношения (=, /=, <, <=, >, >=) определены для операндов типа BOOLEAN и одномерных массивов, содержащих элементы типа BOOLEAN.
Результат выражения также имеет тип BOOLEAN.
Как для всех перечислимых типов, операции сравнения над одномерными массивами типа BOOLEAN производятся поэлементно, начиная с крайнего левого элемента.
Логические операторы
Для операндов типа BOOLEAN и одномерных массивов, содержащих элементы типа BOOLEAN, определены все логические операции (AND, OR, NAND, NOR, XOR и NOT). Тип и размер операндов должны быть одинаковыми. Тип и размер результата такой же, как тип и размер операндов.
Оператор конкатенации
Оператор конкатенации также определен для операндов типа BOOLEAN и одномерных массивов, содержащих элементы типа BOOLEAN. Результат выражения представляет собой одномерный массив, содержащий элементы типа BOOLEAN; размер массива равен сумме размеров операндов.
Другие операторы
Другие операции над операндами типа BOOLEAN не определены.
Тип INTEGER
Стандарт VHDL определяет тип INTEGER для использования в арифметических выражениях. По умолчанию объекты типа INTEGER имеют размерность 32 бита и представляют целое число в интервале — (231–1)... 231–1 (–2147483647... 2147483647). Стандарт языка позволяет также объявлять объекты типа INTEGER, имеющие размер меньше 32 бит, используя ключевое слово RANGE, ограничивающее диапазон возможных значений:
SIGNAL X: INTEGER RANGE -127 TO 127
Данная конструкция определяет X как 8-битное число.
Кроме того, можно определить ограниченный целый тип, используя следующую конструкцию:
TYPE имя_типа IS RANGE диапазон_индексов;
диапазон индексов определяется следующим образом:
m TO n
n DOWNTO m
где m, n — целочисленные константы, m <= n.
Пример
TYPE byte_int 0 TO 255;
TYPE signed_word_int is range -32768 TO 32768;
TYPE bit_index is range 31 DOWNTO 0;
Значения типа INTGER записываются в следующей форме:
[ основание # ] разряд { [_ ] разряд} [ # ]
По умолчанию «основание» принимается равным 10. Допустимыми также являются значения 2, 8, 16.
При записи числа допускается использование одиночных символов подчеркивания, которые не влияют на результирующее значение.
Пример
CONSTANT min: INTEGER:= 0;
CONSTANT group: INTEGER:= 13_452; — эквивалентно 13452
CONSTANT max: INTEGER:= 16#FF#;
Допустимое использование
Операторы отношения
Значения типа INTEGER могут участвовать в выражениях. Операторы отношения (=, /=, <, <=, >, >=) определены для операндов типа INTEGER и одномерных массивов, содержащих элементы типа INTEGER. Результат выражения имеет тип BOOLEAN.
Арифметические операторы
Операторы +, –, ABS допустимы для операндов типа INTEGER. Результат выражения имеет тип INTEGER.
Операторы *, /, MOD, REM допустимы в следующих случаях:
- если оба операнда являются константами (CONSTANT);
- если второй операнд является константой и его значение равно 2n, где n = 0, 1, 2, 3….
Применение операторов *, /, MOD, REM недопустимо, если оба операнда являются сигналами (SIGNAL) или переменными (VARIABLE).
Оператор возведения в степень (**), как правило, не поддерживается средствами синтеза.
Другие операторы
Другие операции над операндами типа INTEGER не определены.
Тип BIT
Объект данного типа может принимать значение '0' (логический 0) или '1' (логическая 1).
Примечание
Стандартом IEEE 1164 определена замена типа BIT на более гибкий тип STD_LOGIC. Поэтому использование типа BIT в новых разработках не рекомендуется.
Допустимое использование
Операторы отношения
Значения типа BIT могут участвовать в выражениях. Операторы отношения (=, /=, <, <=, >, >=) определены для операндов типа BIT и одномерных массивов, содержащих элементы типа BIT. Результат выражения имеет тип BOOLEAN.
(Как для всех перечислимых типов, операции сравнения над одномерными массивами типа BIT производятся поэлементно, начиная с крайнего левого элемента.)
Логические операторы
Для операндов типа BIT и одномерных массивов, содержащих элементы типа BIT, определены все логические операции (AND, OR, NAND, NOR, XOR и NOT). Тип и размер операндов должны быть одинаковыми. Тип и размер результата такие же, как тип и размер операндов.
Оператор конкатенации
Оператор конкатенации также определен для операндов типа BIT и одномерных массивов, содержащих элементы типа BIT. Результат выражения представляет собой одномерный массив, содержащий элементы типа BIT; размер массива равен сумме размеров операндов.
Другие операторы
Другие операции над операндами типа BIT не определены.
Тип STD_LOGIC
Тип STD_LOGIC является перечислимым типом. Объекты типа STD_LOGIC могут принимать 9 значений: '0', '1', 'Z', '-', 'L', 'H', 'U', 'X', 'W'.
Для синтеза логических схем используются только первые четыре:
'0' — логический «0»;
'1' — логическая «1»;
'Z' — третье состояние;
'-' — не подключен.
Допустимое использование
Операторы отношения
Значения типа STD_LOGIC могут участвовать в выражениях. Операторы отношения (=, /=, <, <=, >, >=) определены для операндов типа STD_LOGIC и одномерных массивов, содержащих элементы типа STD_LOGIC. Результат выражения имеет тип BOOLEAN.
(Как для всех перечислимых типов, операции сравнения над одномерными массивами типа STD_LOGIC производятся поэлементно, начиная с крайнего левого элемента.)
Логические операторы
Для операндов типа STD_LOGIC и одномерных массивов, содержащих элементы типа STD_LOGIC, определены все логические операции (AND, OR, NAND, NOR, XOR и NOT). Тип и размер операндов должны быть одинаковыми. Тип и размер результата такой же, как тип и размер операндов.
Оператор конкатенации
Оператор конкатенации также определен для операндов типа STD_LOGIC и одномерных массивов, содержащих элементы типа STD_LOGIC. Результат выражения представляет собой одномерный массив, содержащий элементы типа STD_LOGIC; размер массива равен сумме размеров операндов.
Другие операторы
Другие операции над операндами типа STD_LOGIC не определены.
Перечислимый тип
Перечислимый тип — это такой тип данных, при котором количество всех возможных значений конечно. Строго говоря, все описанные выше типы являются перечислимыми.
Применение перечислимых типов преследует две цели: улучшение смысловой читаемости программы и более четкий и простой визуальный контроль значений. Наиболее часто перечислимый тип используется для обозначения состояний конечных автоматов.
Перечислимый тип объявляется путем перечисления названий элементов-значений. Объекты, тип которых объявлен как перечислимый, могут содержать только те значения, которые указаны при перечислении.
Элементы перечислимого типа должны быть идентификаторами или символами, которые должны быть уникальными в пределах одного типа. Повторное использование названий элементов в других перечислимых типах разрешается.
Объявление перечислимого типа имеет вид:
TYPE имя_типа IS (название_элемента [, название_элемента]);
Пример:
Type State_type IS (stateA, stateB, stateC);
VARIABLE State: State_type;
.
.
.
State:= stateB
В данном примере объявляется переменная State, допустимыми значениями которой являются stateA, stateB, stateC.
Примеры предопределенных перечислимых типов:
TYPE SEVERITY_LEVEL IS (NOTE, WARNING, ERROR, FAILURE);
TYPE BOOLEAN IS (FALSE, TRUE);
TYPE BIT IS ('0', '1');
TYPE STD_LOGIC IS ('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-');
Любой перечислимый тип имеет внутреннюю нумерацию: первый элемент всегда имеет номер 0, второй — номер 1 и т. д. Порядок нумерации соответствует порядку перечисления.
Допустимое использование
Операторы отношения
Значения определенных пользователем перечислимых типов могут участвовать в выражениях. Операторы отношения (=, /=, <, <=, >, >=) определены как для перечислимых типов, так и для одномерных массивов, содержащих элементы этих типов. Результат выражения имеет тип BOOLEAN.
Оператор конкатенации
Оператор конкатенации определен для операндов, имеющих перечислимый тип, и одномерных массивов, содержащих элементы перечислимого типа. При этом оба операнда должны быть одного типа. Результат выражения представляет собой одномерный массив, тип элементов которого равен типу операндов; размер массива равен сумме размеров операндов.
Другие операторы
К операндами перечислимых типов применим оператор указания типа. Данный оператор используется для уточнения типа объекта в том случае, если одно и то же название элемента используется различными типами.
Пример:
TYPE COLOR IS (green, red, tellow, orange);
TYPE FRUIT IS (orange, apple, pear);
VARIABLE VC: COLOR;
VARIABLE VF: FRUIT;
VC:= COLOR'orange;
VF:= FRUIT'orange;
Другие операции над операндами перечислимых типов, определенных пользователем, не определены.
Тип SEVERITY_LEVEL
Переменные этого типа используются только в операторе ASSERT и игнорируются при синтезе логических схем. Переменные типа SEVERITY_LEVEL могут принимать следующие значения: NOTE, WARNING, ERROR и FAILURE.
Тип CHARACTER
Относится к перечислимым типам. Значением объекта данного типа может быть любой символ из набора ASCII (128 первых символов).
Массивы
Массив (тип «массив») является сложным типом. Массив представляет собой упорядоченную структуру однотипных данных. Массив имеет диапазон индексов, который может быть возрастающим либо убывающим. На любой элемент массива можно сослаться, используя его индекс. Несмотря на то что стандартом языка допускается использование массивов любой размерности, для синтеза ПЛИС используются только одномерные (поддерживаются всеми средствами синтеза) и двумерные (поддерживаются ограниченным числом средств синтеза) массивы. Также можно сослаться на часть одномерного массива, используя вместо индекса диапазон индексов.
Существуют две разновидности типа «массив»: ограниченный (constrained) и неограниченный (unconstrained). Объявление ограниченного типа определяет границы диапазона индексов (число элементов массива) в каждом измерении при определении типа. Объявление неограниченного типа не определяет
границы диапазона индексов. В этом случае границы диапазона устанавливаются при объявлении конкретного экземпляра объекта данного типа.
Объявление ограниченного типа «массив» имеет вид:
TYPE имя_типа IS
ARRAY (диапазон_индексов [, диапазон_индексов] )
OF тип_элемента;
Диапазон_индексов может определяться двумя способами:
- явным заданием границ диапазона
m TO n
n DOWNTO m
где m, n — целочисленные константы, m <= n.
- с использованием идентификатора ограниченного подтипа. В этом случае значения границ подтипа являются значениями границ индекса массива. Описание подтипов см. далее.
Объявление неограниченного типа «массив» имеет вид:
TYPE имя_типа IS
ARRAY (тип_индекса
[, тип_индекса] )
OF тип_элемента;
Тип_индекса определяется следующим образом:
подтип RANGE <>
где подтип может быть:
INTEGER — индекс находится в диапазоне -(231–1)... 231–1;
NATURAL — индекс находится в диапазоне 0... 231–1;
POSITIVE — индекс находится в диапазоне 1... 231– 1;
Примеры:
- Объявление ограниченного массивного типа:
TYPE word IS ARRAY (31 DOWNTO 0) OF STD_LOGIC;
TYPE register_bank IS ARRAY (byte RANGE 0 TO 132) OF INTEGER;
TYPE memory IS ARRAY (address) OF word; – двумерный массив
- Объявление неограниченного массивного типа:
TYPE logic IS ARRAY (INTEGER RANGE <>) OF BOOLEAN;
- Объявление двумерного массива:
TYPE Reg IS ARRAY (3 DOWNTO 0) OF STD_LOGIC_VECTOR(7 DOWNTO 0);
TYPE transform IS ARRAY (1 TO 4, 1 TO 4)
OF BIT;
Как было сказано, в языке имеется несколько предопределенных типов «массив». Их объявления выглядят следующим образом:
TYPE STRING IS ARRAY (POSITIVE RANGE <>) OF CHARACTER;
TYPE BIT_VECTOR IS ARRAY (NATURAL RANGE <>) OF BIT;
TYPE STD_LOGIC_VECTOR IS ARRAY (NATURAL RANGE <>) OF STD_LOGIC;
TYPE STD_ULOGIC_VECTOR IS ARRAY (NATURAL RANGE <>) OF STD_ULOGIC;
Объявление объекта типа «неограниченный массив» должно содержать ограничения на индекс. Диапазон изменения индексов может быть ограничен:
- путем использованием ключевых слов TO или DOWNTO:
TYPE data_memory_type IS ARRAY (INTEGER RANGE <>) OF BIT;
...
VARIABLE data_ memory: data_memory_type (0 TO 255);
- либо путем использования диапазона начального значения:
CONSTANT part_id: STRING:='M38006';
Строки, битовые строки и агрегаты
Строки, битовые строки, агрегаты (strings, bit strings, aggregates) используются для конструирования значений обьектов массивных типов. Они могут использоваться в любом месте, где допускается значение типа массив, например, как начальное значение константы или операнд в выражении.
Строковая запись может быть использована для представления значений как объектов некоторых предопределенных типов (string, bit_vector, std_logic_vector), так и для любого одномерного массива, элементы которого имеют тип character; например:
TYPE bit6 IS ('U', '0', '1', 'F', 'R', 'X');
TYPE bit6_data IS ARRAY (POSITIVE RANGE<>) OF bit6;
...
SIGNAL data_bus: bit6_data(15 DOWNTO 0);
.
.
data_bus <= 'UUUUUUUUFFFFFFFF';
VHDL позволяет компактно описывать битовые строки (значение типа bit_vector или std_logic_vector) в базисе 2, 8 и 16. Например:
CONSTANT clear: bit_vector:= B'00_101_010';
CONSTANT empty: bit_vector:= O'052';
CONSTANT null: bit_vector:= X'2A';
Все три константы имеют одно и то же значение. Отметим, что символы подчеркивания могут использоваться в любом месте битовой строки для облегчения чтения. Расширенными цифрами (extended digits) для шестнадцатеричного представления являются буквы от A до F, причем могут использоваться как прописные, так и строчные буквы.
Массивные агрегаты используются для присваивания объектам типа массив значений. Они формируются при помощи позиционной (positional) записи, поименованной (named) записи или комбинации этих двух форм. Рассмотрим пример. Предположим, что имеются следующие описания:
TYPE ArayType IS ARRAY (1 TO 4) OF CHARACTER;
...
VARIABLE Test: ArrayType;
и требуется, чтобы переменная Test содержала элементы 'f', 'o', 'o', 'd' в указанном порядке.
Позиционная запись имеет вид:
Test:= ('f', 'o', 'o', 'd');
Агрегат в данном случае записывается как список значений элементов, разделенных запятыми. Первое значение назначается элементу с наименьшим значением индекса (крайнему левому). Поименованная запись имеет вид:
Test:= (1=>'f', 3=>'o', 4=>'d', 2=>'o');
В этом случае агрегат также является списком, элементы которого разделены запятыми, однако элементы списка имеют формат:
позиция => значение
Порядок перечисления элементов при поименованной записи не имеет значения.
Комбинированная запись имеет вид:
Test:= ('f', 'o', 4=>'d', 3=>'o');
В этом случае сначала записываются элементы, присваиваемые с использованием позиционной записи, а оставшиеся элементы присваиваются с использованием поименованной записи.
При формировании агрегата с использованием поименованной (или комбинированной) записи вместо номера позиции можно указывать ключевое слово OTHERS, определяющее значение для всех элементов, которые еще не были описаны в агрегате.
Например:
Test:= ('f', 4=>'d', OTHERS=>'0');
Подтипы
Использование подтипов позволяет объявлять объекты, принимающие ограниченный набор значений из диапазона, допустимого для базового типа. Подтипы применяются в двух случаях. Во-первых, подтип может ограничить диапазон значений базового скалярного типа (ограничение по диапазону). В этом случае объявление подтипа выглядит следующим образом:
SUBTYPE имя_подтипа IS имя_базового_типа RANGE диапазон_индексов;
диапазон_индексов определяется следующим образом:
m TO n
n DOWNTO m
где m, n — целочисленные константы, m <= n.
Пример:
Предположим, что разработчик желает создать сигнал A типа severity и что A может принимать значения только OKAY, NOTE и WARNING.
TYPE severity IS (OKAY, NOTE, WARNING, ERROR, FAILURE);
SUBTYPE go_status IS severity RANGE OKAY TO WARNING;
SIGNAL A: go_status;
Базовый тип и ограничение диапазона могут быть включены непосредственно в объявление объекта. Объявление сигнала A, эквивалентное приведенному выше, будет выглядеть следующим образом:
SIGNAL A: severity RANGE OKAY TO WARNING;
Другие примеры:
SUBTYPE pin_count IS INTEGER RANGE 0 TO 400;
SUBTYPE digits IS character range '0' TO '9';
Подтипы, объявленные таким образом, могут также участвовать в описании ограниченных массивных типов (см. «Массивы»).
Во-вторых, подтип может определить границы диапазона индексов для неограниченного (unconstrained) массивного типа. В этом случае объявление подтипа выглядит следующим образом:
SUBTYPE имя_подтипа IS имя_базового_типа (диапазон_индексов [, диапазон_индексов] );
диапазон_индексов определяется следующим образом:
m TO n
n DOWNTO m
где m, n — целочисленные константы, m <= n.
Такое использование подтипа может быть удобно при наличии большого числа объектов некоторого типа с одинаковыми ограничениями на индексы.
Пример:
TYPE bit6_data IS ARRAY (POSITIVE RANGE <>) OF bit6;
SUBTYPE data_store IS bit6_data (63 DOWNTO 0);
SIGNAL A_reg, B_reg,C_reg: data_store;
VARIABLE temp: data_store;
В языке имеются два предопределенных числовых подтипа natural и positive, которые определены как:
SUBTYPE NATURAL IS INTEGER RANGE 0 TO highest_integer;
SUBTYPE POSITIVE IS INTEGER RANGE 1 TO highest_integer;
В следующем занятии мы продолжим разговор о языке описания аппаратуры VHDL.
Литература
- Стешенко В. ПЛИС фирмы ALTERA: проектирование устройств обработки сигналов -М.: «Додека», 2000.
- Стешенко В. Школа схемотехнического проектирования устройств обработки сигналов. — Компоненты и технологии, №3–8, 2000, №1, 2, 2001.
- Стешенко В. Школа разработки аппаратуры цифровой обработки сигналов на ПЛИС. — Chip News,, №8-10, 1999 г., №1, 3–5, 2000.
- Дж. Р. Армстронг. Моделирование цифровых систем на языке VHDL. Пер. с англ./ — М.: Мир, 1992.
steshenk@sm.bmstu.ru
|