3.3. Язык описания аппаратуры VHDL 

  3.3.1.Общие сведения

Наиболее универсальным и распространенным языком описания аппаратуры является VHDL. На этом языке возможно как поведенческое, так структурное и потоковое описание цифровых схем.

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

С точки зрения программиста язык VHDL состоит как бы из двух компонент -общеалгоритмической и проблемно-ориентированной.

Общеалгоритмическая компонента VHDL - это язык, близкий по синтаксису и семантике к современным языкам программирования типа Паскаль, С и др. Язык относится к классу строго типизированных. Помимо встроенных (пакет STANDART) простых (скалярных) типов данных: целый, вещественный, булевский, битовый, данных типа время, данных типа ссылка (указатель) - пользователь может вводить свои типы данных (перечислимый, диапазонный и др.).

Помимо скалярных данных можно использовать агрегаты: массивы array, в том числе и битовые векторы bit_vector, и символьные строки string, записи record, файлы file. Последовательно выполняемые (последовательные) операторы VHDL могут использоваться в описании процессов, процедур и функций. Их состав включает: 

Язык поддерживает концепции пакетного и структурного программирования. Сложные операторы заключены в операторные скобки: if- end if; process- end process; case-end case; loop- end loop и т. д.

Различаются локальные и глобальные переменные. Область "видимости" локальных переменных ограничена пределами блока (процессного, процедурного, оператора блока, оператора описания архитектуры).

Фрагменты описаний, которые могут независимо анализироваться компилятором и при отсутствии ошибок помещаться в библиотеку проекта (рабочую библиотеку), называются пакетами проекта. Такими пакетами могут быть объявление интерфейса объекта проекта entity, объявление архитектуры architecture, объявление конфигурации configuration, объявление интерфейса пакета package и объявление тела пакета package body.

Модули проекта, в свою очередь, можно разбить на две категории: первичные и вторичные. К первичным пакетам относятся объявления пакета, объекта проекта, кон-

фигурации. К вторичным - объявление архитектуры, тела пакета. Один или несколько модулей проекта могут быть помещены в один файл, называемый файлом проекта (design file).

Каждый проанализированный модуль проекта помещается в библиотеку проекта (design library) и становится библиотечным модулем (library unit).

Каждая библиотека проекта в языке VHDL имеет логическое имя (идентификатор). По отношению к сеансу работы с VHDL-системой существует два класса рабочих библиотек проекта: рабочие библиотеки и библиотеки ресурсов.

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

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

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

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

Так же, как в описаниях проектируемых систем разделяются описания интерфейсов и тел, в VHDL у пакета разделяются описание интерфейса и тела пакета. По умолчанию предусмотрено подключение стандартных пакетов STANDART и TEXT 10. Пакет STANDART, в частности, содержит описание булевских операций над битовыми данными и битовыми векторами. Нестандартные пакеты реализуются пользователями, желающими более точно отобразить свойства описываемых ими объектов. Например, можно в пользовательском пакете переопределить логические операции И, ИЛИ и НЕ и перейти от булевского (О, 1) к многозначному (1, О, X, Z) алфавиту моделирования. Проблемно-ориентированная компонента позволяет описывать цифровые системы в привычных для разработчика понятиях и терминах. Сюда можно отнести: 

 

  3.3.2. Средства объявления объектов entity и их архитектур architecture

Если говорить об операторной части проблемно-ориентированной компоненты, то условно ее можно разделить на средства поведенческого описания аппаратуры (параллельные процессы и средства их взаимодействия); средства потокового описания (описание на уровне межрегистровых передач) - параллельные операторы назначения сигнала (<=) с транспортной transport или инерциальной задержкой передачи сигналов; средства структурного описания объектов (операторы конкретизации компонент с заданием карт портов port map и карт настройки generic map, объявление конфигурации и т. д.).

Параллельные операторы VHDL включают: 

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

Базовым элементом описания систем на языке VHDL является блок. Блок содержит раздел описаний данных и раздел параллельно исполняемых операторов. Частным случаем блока является описание архитектуры объекта. В рамках описания архитектуры могут использоваться внутренние, вложенные, блоки. Наряду со всеми преимуществами блочной структуры программы и ее соответствием естественному иерархическому представлению структуры проекта операторы блока языка VHDL позволяют устанавливать условия охраны (запреты) входа в блок. Только при истинности значения охранного выражения управление передается в блок и инициирует выполнение операторов его тела.

 

  3.3.3. Алфавит языка

Как и любой другой язык программирования, VHDL имеет свой алфавит - набор символов, разрешенных к использованию и воспринимаемых компилятором. В алфавит языка входят:

Из символов, перечисленных в пп, 1-3 (и только из них!) могут конструироваться идентификаторы в программе. Кроме того, написание идентификаторов должно подчиняться следующим правилам:

Примеры корректных идентификаторов: cont, clock2, full_add Примеры некорректных идентификаторов: Iclock, _adder, add_sub, entity

Следует отметить, что прописные и строчные буквы не различаются, т.е. идентификаторы clock и CLOCK являются эквивалентными.

Символ "пробел" (код 32), символ табуляции (код 9), символ новой строки (коды 10 и 13) являются разделителями слов в конструкциях языка. Количество разделителей не имеет значения. Таким образом, следующие выражения для компилятора будут эквивалентны:

count:=2+2; 

count := 2 + 2 ; 

count := 2

+

2;

Специальные символы, участвующие в построении конструкций языка:

+ -*/ = <>.,():;#'"|

Составные символы, воспринимаемые компилятором как один символ:

<= >= => := /=

Разделители между элементами составных символов недопустимы.

 

  3.3.3.1. Комментарии

Признаком комментария являются два символа тире («—»). Компилятор игнорирует текст, начиная с символов «—» до конца строки, т.е. комментарий может включать в себя символы, не входящие в алфавит языка (в частности русские буквы).

 

  3.3.3.2. Числа

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

К разновидности числовых значений можно отнести также битовые строки.

 

  3.3.3.3. Символы

Запись символа представляет собой собственно символ, заключенный в одиночные кавычки. Например:

'A', '*', ' '

В средствах синтеза ПЛИС область применения символов ограничена использованием их в качестве элементов перечислимых типов.

 

  3.3.3.4. Строки

Строки представляют собой набор символов, заключенных в двойные кавычки. Чтобы включить двойную кавычку в строку, необходимо ввести две двойных кавычки. Например:

"A string"

"A string in a string ""A string"" "

 

  3.3.4. Типы данных

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

Необходимо отметить, что в данном пособии рассматриваются не все типы данных, определенные в стандарте, а только те, которые поддерживаются средствами синтеза ПЛИС.

 

  3.3.4.1. Простые типы

Следующие простые типы являются предопределенными:

Примечание. В действительности тип STD_ULOG 1C является базовым типом для типа STD_LOGIC, т.е. объекты обоих типов могут принимать одно и то же множество значений и имеют одинаковый набор допустимых операций. Единственное различие между типами заключается в том, что для типа STDULOGIC не определена функция разрешения (resolving function). В языке VHDL функция разрешения используется для определения значения сигнала, имеющего несколько'источников (драйверов).

Пример: Выходы двух буферов с тремя состояниями подключены к одной цепи X. Пусть выход одного буфера установился в состояние "Z", а выход другого—в состояние "1". Функция разрешения определяет, что в этом случае значение сигнала X будет равно "1".

Поскольку для типа STDJJLOGIC не определена функция разрешения, сигналы этого типа могут иметь только один источник.

Далее рассматривается только тип STD_LOGIC, однако все сказанное будет справедливо и для типа STDJJLOGIC. На практике в подавляющем большинстве случаев достаточно использования типа STDJLOGIC.

 

  3.3.4.2. Сложные типы

Из всей совокупности сложных типов, определенных в стандарте языка, для синтеза логических схем используются только массивы (тип ARRAY) и записи (тип RECORD). Однако тип RECORD поддерживается не всеми средствами синтеза и в данном пособии рассмотрен не будет.

Следующие типы-массивы являются предопределенными:

BIT_VECTOR - одномерный массив элементов типа BIT;

STD_LOGIC_VECTOR - одномерный массив элементов типа STD LOGIC;

STD_ULOGIC_VECTOR - одномерный массив элементов типа STD ULOGIC;

STRING - одномерный массив элементов типа CHARACTER;

Направление и границы диапазона индексов не содержатся в определении указанных типов и должны быть указаны непосредственно при объявлении объектов данных типов.

 

  3.3.4.3. Описание простых типов

Тип 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 <='!';

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 ТО 127

Данная конструкция определяет X как 8-битное число.

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

TYPE имя_типа IS RANGE диапазон_индексов\

диапазон_индексов определяется следующим образом:

mTOw

п DOWNTO т

где т,п- целочисленные константы, т <= п.

Пример:

TYPE byte_int О ТО 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); если второй операнд является константой и его значение равно 2", где п = О, 1,2,3....

Применение операторов *, /, MOD, REM недопустимо, если оба операнда являются сигналами (SIGNAL) или переменными (VARIABLE).

Оператор возведения в степень (**), как правило, не поддерживается средствами синтеза,

Другие операторы

Другие операции над операндами типа INTEGER не определены.

Тип BIT

Объект данного типа может принимать значение "О" (логический 0) или "1" (логическая 1).

Примечание. Стандартом IEEE 1176 определена замена типа 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 значений: "О", "1", "Z", "-", "L", "Н", "U", "X", "W". Для синтеза логических схем используются только первые четыре: "О" - логический «О»; "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 не определены.

Перечислимый тип

Перечислимый тип - это такой тип данных, при котором количество всех возможных значений конечно. Строго говоря, все описанные выше типы являются перечислимыми.

Применение перечислимых типов преследует две цели:

1) улучшение смысловой читаемости программы;

2) более четкий и простой визуальный контроль значений.

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

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

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

Объявление перечислимого типа имеет вид:

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 и игнорируются при синтезе логических схем.

Переменные типа SEVERITYJLEVEL могут принимать следующие значения: NOTE, WARNING, ERROR и FAILURE.

Тип CHARACTER

Перечислимый тип. Значением объекта данного типа может быть любой символ из набора ASCII (128 первых символов).

Массивы

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

Несмотря на то, что стандартом языка допускается использование массивов любой размерности, для синтеза ПЛИС используются только одномерные (поддерживаются всеми средствами синтеза) и двумерные (поддерживаются ограниченным числом средств синтеза) массивы.

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

Существуют две разновидности типа «массив»: ограниченный (constrained) и неограниченный (unconstrained).

Объявление ограниченного типа определяет границы диапазона индексов (число элементов массива) в каждом измерении при определении типа.

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

Объявление ограниченного типа «массив» имеет вид:

TYPE имя__типа IS

ARRAY (диапазон_индексов [ , диапазон_индексов] ) OF тип_элемента;

диапазон_индексов может определяться двумя способами:

1) явным заданием границ диапазона

тТОп

п DOWNTO от

где тп,п- целочисленные константы, m <= п.

2) с использованием идентификатора ограниченного подтипа. В этом случае значения границ подтипа являются значениями границ индекса массива. Описание подтипов см. далее.

Объявление неограниченного типа «массив» имеет вид:

TYPE имя_типа IS

ARRAY (тип_индекса [ , тмп_индекса] )

OF тип_элемента;

тип_индекса определяется следующим образом: подтип RANGE О

где подтип может быть:

INTEGER - индекс находится в диапазоне -<231-1). . . 231-1; NATURAL - индекс находится в диапазоне 0 . .. 231-1; POSITIVE - индекс находится в диапазоне 1 ... 231-1;

Примеры:

1) Объявление ограниченного массивного типа:

TYPE word IS ARRAY (31 DOWNTO 0) OF STD_LOGIC;

TYPE register_barik IS ARRAY (byte RANGE 0 TO 132) OF INTEGER;

TYPE memory IS ARRAY (address) OF word; — двумерный массив

2) Объявление неограниченного массивного типа:

TYPE logic IS ARRAY (INTEGER RANGE <>) OF BOOLEAN;

3) Объявление двумерного массива:

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 STDJJLOGIC;

Объявление объекта типа «неограниченный массив» должно содержать ограничения на индекс. Диапазон изменения индексов может быть ограничен: путем использования ключевых слов ТО или 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";

 

  3.3.4.4. Строки, битовые строки и агрегаты

Строки, битовые строки, агрегаты (strings, bit strings, aggregates) применяются для конструирования значений обьектов массивных типов. Они могут использоваться в любом месте, где допускается значение типа "массив", например - как начальное значение константы или операнд в выражении.

Строковая запись может быть использована для представления значений как объектов некоторых предопределенных типов (string, bit_vector, std_logic_vector), так и для любого одномерного массива, элементы которого имеют тип character, например:

TYPE bit6 IS ("U", "О", "1", "F", "H", "X");

TYPE bit6_data IS ARRAY (POSITIVE RANGEO) OF bit6;

SIGNAL datajDus : bit6_data(15 DOWNTO 0);

data_bus <= «UUUUUUUUFFFFFFFF»;

VHDL позволяет компактно описывать битовые строки (значение типа bit_vector или std_logic_vector) в базисе 2, 8 и 16. Например:

CONSTANT clear : bit_vector := В»00_101_010";

CONSTANT empty : bit__vector := O»052";

CONSTANT null : bit_vector := X»2A»;

Все три константы имеют одно и то же значение. Отметим, что символы подчеркивания могут использоваться в любом месте битовой строки для облегчения чтения. Расширенными цифрами (extended digits) для шестнадцатеричного представления являются буквы от А до F, причем могут использоваться как прописные, так и строчные буквы.

Массивные агрегаты используются для присвоения объектам типа "массив" значений. Массивные агрегаты формируются при помощи позиционной (positional) записи, поименованной (named) записи или комбинации этих двух форм. Рассмотрим пример.

Предположим, что имеются следующие описания:

TYPE ArayType IS ARRAY (I TO 4) OF CHARACTER; VARIABLE Test : ArrayType;

Требуется, чтобы переменная Test содержала элементы "f', "о", "о", "d" в указанном порядке.

Позиционная запись имеет вид:

Test := ("f", "о", "о", "d") ;

Агрегат в данном случае записывается как список значений элементов, разделенных запятыми. Первое значение назначается элементу с наименьшим значением индекса (крайнему левому).

Поименованная запись имеет вид:

Test := (l=>'f, 3=>'o', 4=>'d', 2=>'o');

В этом случае агрегат также является списком, элементы которого разделены запятыми, однако элементы списка имеют формат:

позиция => значение

Порядок перечисления элементов при поименованной записи не имеет значения. Комбинированная запись имеет вид:

Test := ('"f", "о", 4=>'d', 3=>'о');

В этом случае сначала записываются элементы, присваиваемые с применением позиционной записи, а оставшиеся элементы присваиваются с использованием поименованной записи.

При формировании агрегата с использованием поименованной (или комбинированной) записи вместо номера позиции можно указывать ключевое слово OTHERS, которое определяет значение для всех элементов, которые еще не были описаны в аг- • регате. Например:

Test := ("f", 4=>'сГ, OTHERS=>'0');

 

  3.3.4.5. Подтипы

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

1) Подтип может ограничить диапазон значений базового скалярного типа (ограничение по диапазону). В этом случае объявление подтипа выглядит следующим образом:

SUBTYPE имя_подтипа IS имя__базового_типа RANGE диапазон_индексов;

диапазон_индексов определяется следующим образом:

m TO л

л DOWNTO m

где m,n- целочисленные константы, m <= «.

Пример:

Предположим, что разработчик желает создать сигнал Л типа .sever/fv и что Л может принимать значения только OKAY, NOTE и WARNING.

TYPE sevirity IS (OKAY, NOTE, WARNING, ERROR, FAILURE); 

SUBTYPE go_status IS severity RANGE OKAY TO WARNING; 

SIGNAL A : go_status;

Базовый тип и ограничение диапазона могут быть включены непосредственно в объявление объекта. Объявление сигнала А, эквивалентное приведенному выше, будет выглядеть следующим образом:

SIGNAL A : severity RANGE OKAY TO WARNING; Другие примеры:

SUBTYPE pin_count IS INTEGER RANGE 0 TO 400; SUBYUPE digits IS character range "0" TO "9";

Подтипы, объявленные таким образом, могут также участвовать в описании ограниченных массивных типов (см. «Массивы))).

2) Подтип может определить границы диапазона индексов для неограниченного (unconstrained) массивного типа. В этом случае объявление подтипа выглядит следующим образом:

SUBTHE имя_подапазон IS тя_базового_ттз (диапазон_индексов [ , диапазон_ивдексов]) ;

диапазон индексов определяется следующим образом:

m ТО n

n DOWNTO m

где т,п- целочисленные константы, т <= п.

Такое использование подтипа может быть удобно при наличии большого числа объектов некоторого типа с одинаковыми ограничениями на индексы. Пример:

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 О ТО highest_integer; SUBTYPE POSITIVE IS INTEGER RANGE 1 TO highest_integer;

 

  3.3.5. Операторы VHDL

  3.3.5.1. Основы синтаксиса

Исходный текст описания на VHDL состоит из последовательностей операторов, записанных с учетом следующих правил:

Комментарии могут быть включены в текст программы с помощью двух подряд идущих символов "—". После появления этих символов весь текст до конца строки считается комментарием.

Для указания системы счисления для констант могут быть применены спецификаторы: 

 

  3.3.5.2. Объекты

Объекты являются контейнерами для хранения различных значений в рамках модели. Идентификаторы объектов содержат буквы, цифры и знаки подчеркивания. Идентификаторы должны начинаться с буквы, не должны заканчиваться знаком подчеркивания, и знаки подчеркивания не могут идти подряд. Прописные и строчные буквы в VHDL не различаются. Все объекты должны быть явно объявлены перед использованием, за исключением переменной цикла в операторе./}?/1, которая объявляется по умолчанию.

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

Constant { name [, name] } : Type [ ( indexjrange [ , indexjrange ] ) ] := initial_value;

Variable { name [, name] ) : Type [ ( indexjrange [ , indexjrange ])][:= initialj/alue ];

Signal { name [, name] } : Type [ ( indexjrange ) ];

Диапазон значений индексов задается в виде int_value to int_value или int^yalue down to int_value,

 

  3.3.5.3. Атрибуты

Атрибуты определяют характеристики объектов, к которым они относятся. Стандарт VHDL предусматривает как предопределенные, так и определяемые пользователем атрибуты, однако современные инструментальные средства в большинстве своем поддерживают только предопределенные атрибуты. Для обращения к атрибутам объекта используется символ "'" (например, Al 'left),

В VHDL определены следующие атрибуты, относящиеся к массивам:

'left - левая граница диапазона индексов массива 'right - правая граница диапазона индексов массива 'low - нижняя граница диапазона индексов массива 'high - верхняя граница диапазона индексов массива 'range - диапазон индексов массива 'reversejrange - обращенный диапазон индексов массива 'length - ширина диапазона индексов массива

 

  3.3.5.4. Компоненты

Объявление компонента определяет интерфейс к модели на VHDL (entity и architecture), описанной в другом файле. Обычно объявление компонента совпадает с соответствующим объявлением entity. Они могут различаться только значениями по умолчанию. Эти значения используются, когда какой-либо из отводов компонента остается не присоединенным (ключевое слово open) при установке компонента в схему.

Оператор объявления компонента может находиться внутри объявления architecture или в заголовке пакета (package). Соответствующие компоненту объявления entity и architecture не обязательно должны существовать в момент анализа схемы. В момент моделирования или синтеза должны существовать объявления entity и architecture для компонентов, которые не только объявлены, но и установлены в схему. Это позволяет, например,

конструктору задать объявления библиотечных элементов, а реальное их описание (объявления entity и architecture) задавать по мере использования этих элементов в конструкции. Объявление компонента записывается следующим образом:

Component name

[ port( port_list } ; ] end component;

 

  3.3.5.5. Выражения

Выражения могут содержать следующие операторы: преобразование типа and, or, nand, nor, xor, =, /=, <, <=, >, >=, +, -, &, *, /, mod, rem, abs, not.

В зависимости от избранной САПР при синтезе может поддерживаться подмножество приведенных выше операторов. Порядок вычисления выражений определяется приоритетом операторов:

and, or, nand, nor, xor - самый низкий приоритет

-, /-, <, <=, >,>-+, -, & (бинарные) +, - (унарные)

*, /, mod, rem

abs, not — высший приоритет

Операторы с более высоким приоритетом выполняются раньше. Чтобы изменить такой порядок используются скобки. При моделировании (но не при синтезе) схемы возможно также описание формы сигнала в виде выражения. Записывается оно следующим образом:

Value_expression [ after time_expression ]

{ , value_expression [ after time__expression ] }

С помощью операторов описывается алгоритм, определяющий функционирование схемы. Они могут находиться в теле функции, процедуры или процесса.

Wait until condition;

Приостанавливает выполнение процесса, содержащего данный оператор до момента выполнения условия.

Signal <= expression

Оператор присваивания сигнала устанавливает его значение равным выражению справа.

Variable: = expression

Оператор присваивания устанавливает значение переменной равным выражению справа.

Procedure_пате (parameter {, parameter } )

Оператор вызова процедуры состоит из имени процедуры и списка фактических параметров.

If condition then

Sequence_of_statements { Elsif condition then

Sequence_of_statements } [ else

sequence_of_statements ] end if ;

Оператор if используется для ветвления алгоритма по различным условиям,

Case expression is

When choices_list => sequence_of_statements;

{ When choices_list => sequence_of_statements; }

When others => sequence_of_statements; End case;

Оператор case., подобно оператору if, задает ветвление алгоритма. Значения в списках разделяются символом "("• Когда значение выражения встречается в одном из списков значений, выполняется соответствующая последовательность операторов. Если значение выражения не присутствует ни в одном из списков, то выполняется список операторов, соответствующий ветви when others.

[ loop_label : ]

for loop_index_variable in range loop

sequence_of_statements end loop [ loop_label ] ;

Оператор цикла позволяет многократно выполнить последовательность операторов. Диапазон значений задается в виде valuel to valm2 или value! downto valne2. Переменная цикла последовательно принимает значения из заданного диапазона. Количество итераций равно количеству значений в диапазоне.

Return expression ;

Этот оператор возвращает значение из функции.

Null

Пустой оператор, не выполняет никаких действий.

 

  3.3.6. Интерфейс и тело объекта

Полное VHDL-описание объекта состоит как минимум из двух отдельных описаний: описания интерфейса объекта и описания тела объекта (описание архитектуры).

Интерфейс описывается в объявлении объекта entity declaration и определяет входы и выходы объекта, его входные и выходные порты ports и параметры настройки generic. Параметры настройки отражают тот факт, что некоторые объекты могут иметь управляющие входы, с помощью которых может производиться настройка экземпляров объектов, в частности, могут задаваться времена задержки.

Например, у объекта Q1 три входных порта XI, Х2, ХЗ и два выхода У1, У2. Описание его интерфейса на VHDL имеет вид:

Entity Ql is

Port (XI, Х2, ХЗ: in real; Yl, Y2: out real); 

End Ql.

Порты объекта характеризуются направлением потока информации. Они могут быть: 

А также имеют тип, характеризующий значения поступающих на них сигналов: 

Тело объекта специфицирует его структуру или поведение. Его описание по терминологии VHDL содержится в описании его архитектуры architecture.

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

Средства VHDL для отображения структур цифровых систем базируются на представлении о том, что описываемый объект entity представляет собой структуру из компонент component, соединяемых друг с другом линиями связи. Каждая компонента, в свою очередь, является объектом и может состоять из компонент низшего уровня (иерархия объектов). Взаимодействуют объекты путем передачи сигналов signal по линиям связи. Линии связи подключаются к входным и выходным портам компонент. В VHDL сигналы отождествляются с линиями связи.

Имена сигналов и имена линий связи совпадают (они отождествляются). Для сигналов (линий), связывающих компоненты друг с другом, необходимо указывать индивидуальные имена.

Описание структуры объекта строится как описание связей конкретных компонент, каждая из которых имеет имя, тип и карты портов. Карта портов port map определяет соответствие портов компонент поступающим на них сигналам, можно интерпретировать карту портов как разъем, на который приходят сигналы и в который вставляется объект-компонента.

Принятая в VHDL форма описания связей конкретных компонент имеет следующий вид:

Имя: тип связи (сигнал, порт).

Например, описание связей объекта Q1 выглядит следующим образом:

Kl: SM port map {XI, X2, S);

КЗ: M port map (S, Yl) ;

K2: SM port map (S, X3, Y2) ;

Здесь Kl, K2, КЗ - имена компонент; SM, M - типы компонент; XI, X2, X3, S, Yl, Y2 — имена сигналов, связанных с портами,

Полное VHDL-описание архитектуры STRUCTURA объекта Q1 имеет вид:

Architecture STRUCTURA of Q1 is

Component SM port (A, B: in real; C: out real); 

End component;

Component M port (E: in real; D: out real); 

End component; 

Signal S: real; 

Begin

Kl: SM port map (XI, X2., S); 

КЗ: M 'port map (S, Yl); 

K2: SM port map (S, X3, Y2); 

End STRUCTURA;

Средства VHDL для отображения поведения описываемых архитектур строятся на представлении их как совокупности параллельно взаимодействующих процессов. Понятие процесса process относится к базовым понятиям языка VHDL.

Архитектура включает в себя описание одного или нескольких параллельных процессов. Описание процесса состоит из последовательности операторов, отображающих действия по переработке информации. Все операторы внутри процесса выполняются последовательно. Процесс может находиться в одном из двух состояний - либо пассивном, когда процесс ожидает прихода сигналов запуска или наступления соответствующего момента времени, либо активном, когда процесс исполняется.

Процессы взаимодействуют путем обмена сигналами.

В общем случае в поведенческом описании состав процессов не обязательно соответствует составу компонент, как это имеет место в структурном описании.

Поведение VHDL-объектов приходится учитывать с особенностями воспроизведения параллельных процессов на однопроцессорной ЭВМ. Особая роль в синхронизации процессов отводится механизму событийного воспроизведения модельного времени now.

Когда процесс вырабатывает новое значение сигнала перед его посылкой на линию связи, говорят, что он вырабатывает будущее сообщение transaction. С каждой линией связи (сигналом) может быть связано множество будущих сообщений. Множество сообщений для сигнала называется его драйвером driver.

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

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

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

В случае дельта-задержек новый цикл моделирования не связан с увеличением модельного времени. В приведенном выше примере новое значение сигнала У1 вырабатывается через дельта-задержку после изменения сигнала S.

Другая способность VHDL-процессов связана с так называемыми разрешенными resolved сигналами. Если несколько процессов изменяют один и тот же сигнал (сигнал имеет несколько драйверов), в описании объектов может указываться функция разрешения. Эта функция объединяет значения из разных драйверов и вырабатывает одно.

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

Полное описание архитектуры POVEDENIE объекта Q1 в этом случае имеет следующий вид:

Architecture POVEDENIE of Ql is Signal S: real;

Begin

YK=S;

Y2<=S+X3 after 10 ns;

S<=X3+X2 after 10 ns; End POVEDENIE;

 

  3.3.7. Описание простого объекта

Для иллюстрации возможностей VHDL рассмотрим пример проектирования про-, стой комбинационной схемы, назовем ее объект F. Объект проекта F имеет два входа -А1 и А2, и два выхода - В1 и В2.

Объявление объекта проекта F.

Entity F is

Port (Al, A2: in BIT; Bl, B2: out BIT)

Сигналы принимают значения 1 или 0 в соответствии с таблицей истинности.

Входы

Выходы

А1

А2

В1

В2

0

0

0

1

0

1

0

1

1

0

0

1

1

1

1

0

 

  3.3.7.1. Поведенческое описание архитектуры

Вариант описания архитектуры BEHAVIOR объекта F использует условный оператор if языка VHDL и учитывает, что только при обоих входах А1 и А2, равных I, выходы В 1=1 и В2=0. В остальных случаях, наоборот, В 1=0 и В2=1.

Architecture BEHAVIOR of F is Begin Process Begin

Wait on (Al, A2)

If (Al='l') and (A2='l')

Then B1<='1'; B2<='0'; End if; End process; End;

В каждом процессе может быть только 1 оператор wait on. Второй вариант поведенческого описания архитектуры объекта F, назовем его BEHAVIOR_F, использует выбор case языка VHDL и учитывает то свойство функции F, что для первых трех строк ее значение не меняется. В заголовке процесса указан список чувствительности процесса process (Al, A2). Это указание эквивалентно оператору wait on (Al, A2) в начале описания процесса.

Architecture BEHAVIOR_F of F is

Begin

Process (Al,A2);

Begin

—&-операция 

case (A1& A2) is

—первые три строки таблицы

when "00"/ "01"/ "10"=> В1<='0'; В2<='1'

—последняя строка таблицы 

when "11" => В1='1'; В2<='0' 

end case 

end process 

end BEHAVIOR_F;

 

  3.3.7.2. Потоковое описание

В процессе проектирования объекта F могут быть предложены различные варианты его функциональных схем.

Описание архитектуры объекта F может быть таким:

Architecture F_A of F is Begin

—каждому вентилю сопоставлен оператор назначения сигнала

Bl<= Al and А2;

В2<= not (Al and A2);

End;

Здесь каждому элементу сопоставлен процесс, отображающий последовательность преобразования входной информации и передачи ее на выход. Процесс представлен в форме оператора параллельного назначения сигнала. Операторы назначения сигнала (<=) срабатывают параллельно при изменении хотя бы одного из сигналов в своих правых частях.

Другой вариант описания архитектуры F_B. Здесь вентили включены последовательно.

Architecture F_B of F is

Signal X: bit

Begin

B2<= not (X);

X <= Al and A2;

Bl <= X; End;

Промежуточный сигнал X введен в описание архитектуры F_B объекта F потому, что в описании интерфейса объекта F порт В1 объявлен выходным, то есть с него нельзя считывать сигнал, и запись В2<= not(Bl) была бы некорректной.

Сигнал В2 вырабатывается только после изменения сигнала X. Оператор В2<= not(X) сработает только тогда, когда изменится сигнал X, то есть после оператора Х<= Al and A2, т. к. он реагирует только на изменение сигнала в своей правой части. С учетом задержки Е1=10 не., а Е2=5 не. описание архитектуры будет иметь вид:

Architecture F_B_TIME of F is

Signal X: bit

Begin

—задержка на В1- 10 не.

—задержка на В2- 5 не.

ВК=Х;

В2<= not (X) after 5 ns;

Х<= Al and A2 after 10 ns;

End;

Через 10 не. после изменения одного из входных сигналов (А1 или А2) может измениться выходной сигнал В1, и с задержкой 5 не. после него изменится В2.

 

  3.3.7.3. Структурное описание архитектуры

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

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

Library work; use work.all

—подключение рабочей библиотеки work, содержащей описание

—объекта соответствующего компоненте INE2

Architecture CXEM_F_C of F is

—ниже интерфейсы компоненты INE2

Component INE2

Port (XI, X2: in bit; Y: out bit);

End component;

—ниже описание связей экземпляров компонент 

Signal X: bit;

Begin

El: INE2 port map (Al, A2, X);

E2: INE2 port map (X, X, Bl);

B2<= X; End;

В описании архитектуры CXEM_F_C объекта F сначала указан интерфейс компонент, из которых строится схема. Это компоненты типа INE2 с двумя входными и одним выходным портом. Затем после begin идут операторы конкретизации компонент. Для каждого экземпляра компоненты следуют: ее имя или карта портов, указывающая соответствие портов экземпляра компоненты поступающим на них сигналам. Например, для компоненты по имени Е1 типа INE2 на порт XI подан сигнал А1, на порт Х2-сигнал А2. Порядок конкретизации безразличен, так как это параллельные операторы. Для того чтобы описание F было полным, в данном случае в рабочей библиотеке проекта work необходимо иметь описание интерфейса и архитектуры некоторого объекта, сопоставляемого компоненте INE2. Обозначим этот объект в библиотеке как LA3. Его описание:

Entity LA3 is

Port (X, Y: in bit; Z: out bit); End LA3;

Architecture DF_LA3 of LA3 is Begin

Z<= not (X and Y) after 10ns; End;

У объекта LA3 может быть насколько архитектур. В примерах дан вариант потокового описания архитектуры DF LA3 объекта LA3, который содержит оператор назначения сигналу Z инверсного значения конъюнкции сигналов X и Y с задержкой 10 не.

 

  3.3.8. Описание конфигурации

Конфигурацию можно рассматривать как аналог списка компонентов для проекта. Оператор конфигурации (идентифицируемый ключевым словом "configuration") определяет, какие реализации должны быть использованы, и позволяет изменять связи компонентов в вашем проекте во время моделирования и синтеза.

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

Обозначение типа компоненты в описании архитектуры CXEM_F_C объекта F и обозначение соответствующего объекта проекта в библиотеке могут не соответствовать друг другу. Связывание обозначений осуществляется в форме объявления конфигурации. Для того чтобы задать информацию о том, что использованная при описании архитектуры CXEM_F_C объекта F компонента INE2 соответствует библиотечному объекту LA3 и варианту его архитектуры под названием DF_LA3, необходимо объявить конфигурацию configuration. Конфигурация VI указывает, что из рабочей библиотеки проекта library work для архитектуры СХЕМ F С объекта F для компонент с именами Е1 и Е2 типа INE2 следует использовать архитектуру DF_LA3 объекта LA3.

Library WORK

—подключается рабочая библиотека проекта 

configuration VI of F is

—конфигурация по имени VI объекта F 

use WORK. all;

—используются все (all) компоненты библиотеки WORK 

for CXEM_F_C

—для архитектуры CXEM_F_C

—компоненты El, E2 соответствуют объекту LA3 с архитектурой 

DF_LA3 из библиотеки WORK 

for E1,E2: INE2 

use entity LA3 ,(DF_LA3); 

end for; 

end for; 

end V1;

 

  3.3.9. Векторные сигналы и регулярные структуры

Одним из средств повышения компактности описаний цифровых устройств является использование векторных представлений сигналов и операций над ними. Например, пусть некоторый объект FV выполняет ту же функцию, что и объект F, но над 20-разрядными двоичными векторами AV1 и AV2.

Его описание определяет порты как двоичные векторы:

Entity FV is

Port (AVI, AV2: in bit_vector (1 to 20);

BV1, BV2: out bit_vector (1 to 20)); End FV1;

Поведенческое описание архитектуры FV в потоковой форме использует операции над битовыми векторами,

Architecture BECHAV_FV of FV is

Begin

BV2<= not (AVI and AV2) ;

BV1<= AVI and AV2;

End ВЕСНАV_FV;

Структурное описание архитектуры FV для варианта реализации объекта FV как совокупности объектов F, представленное ниже, выполнено с использованием оператора генерации конкретизации. Это позволяет повысить компактность описаний регулярных фрагментов схем.

Architecture STRUCT_FV of FV is

Component F port (XI, X2: in bit; Yl, Y2: out bit);

End component;

Begin

— первая компонента конкретизирована обычным способом с использованием позиционного соответствия сигналов портам Kl: F port map (AVI (1), AV2 (1), BV1 (1), BV2 (!});

— вторая компонента конкретизирована с использованием ключевого способа указания соответствия сигналов ее портам К2: F port map (AVI (2)=>X1, BV1 {2)=>Y1, AV2 (2)=>Х2, BV2 (2) =>Y2 );

— компоненты КЗ - К20 конкретизированы с использованием оператора генерации, позволяющего компактно описывать регулярные фрагменты схем

for I in 3 to 20 generate

K( I ): F port map ("AVI (1.), AV2 (1), BV1 (1), BV2 (1) );

End generate;

End STRUCT_FV;

 

  3.3.10. Задержки сигналов и параметры настройки

Объект с задержкой можно представить как бы состоящим из двух элементов -идеального элемента и элемента задержки.

В языке VHDL встроены две модели задержек - инерциальная и транспортная.

Инерциальная модель предполагает, что элемент не реагирует на сигналы, длительность которых меньше порога, равного времени задержки элемента. Транспортная модель лишена этого ограничения.

Инерциальная модель по умолчанию встроена в оператор назначения сигнала языка VHDL. Например, оператор назначения Y<=X1 andX2 after 10 ns; описывает работу вентиля 2И и соответствует инерциальной модели. Указание на использование транспортной модели обеспечивается ключевым словом transport в правой части оператора назначения. Например, оператор YT< =tramport XI andX2 after 10 ns; отображает транспортную модель задержки вентиля.

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

Приведенное ниже описание объекта 12 включает описание интерфейса и тела 12 с инерциальной задержкой, заданной как параметр настройки:

Entity 12 is

—параметр настройки Т по умолчанию равен 10 не.

Generic (Т: time = 10 ns);

Port ( XI, Х2: in bit; Y: out bit );

End 12;

Architecture Al_inert of 12 is Begin

Y<= XI and X2 after T; End Al_inert;

Architecture Al_transport of 12 is Begin

Y<= transport Xland X2 after 10 ns; End;

Ниже представлен вариант описания архитектуры, иллюстрирующей возможность использования параметра настройки (задержка Е1 равна 5 не., Е2 - 20 не.) и возможность совмещения структурного и поведенческого описаний в одной архитектуре:

Architecture MIX_8_a of F is

Component 12

Generic (Т: time);

Port (X1, X2: in bit; Y: out bit );

End component;

Begin

El: 12 generic map (5 ns );

Port map (Al, A2, Bl);

E2: B2<= not ( Al and A2 ) after 20 ns; End;

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

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

Architecture INERT of 12 is Begin

Process ( XI, X2 );

Variable Z: bit; Begin

—выход идеального вентиля Z=X1 and X2; if Z=' 1' and Z'DELAYED=' 0' then

—срез

Y<=' 0' after 3 ns End if; End process; End;

Атрибут Z'DELAYED дает предыдущее значение сигнала.

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

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

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

 

  3.3.11. Атрибуты сигналов и контроль запрещенных ситуаций

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

длительностях или частотах импульсов и т.п. Например, в вентиле 2И возникает риск сбоя в ситуациях, когда фронт одного сигнала перекрывает срез другого.

Входные сигналы X1 и Х2 изменяются в противоположном направлении, и время их перекрытия меньше необходимого, допустим - равного 10 не.

Средством отображения информации о запрещенных ситуациях в языке VHDL является оператор утверждения (оператор контроля, оператор аномалии) assert. В нем, помимо контролируемого условия, которое не должно быть нарушено, т.е. должно быть истинным, записывается сообщение report о нарушении и уровень серьезности ошибки severity.

Для приведенного примера в описании архитектуры вентиля 2И может быть вставлено утверждение о том, что все будет нормально, если внутренний сигнал Z будет "равен 1 не менее чем 10 не., иначе идет сообщение об ошибке.

Для этого необходимо, чтобы в момент среза сигнала его задержанное на 10 не. значение было равно 1. Если оно равно 0, то длительность сигнала меньше 10 не.

Время предыдущего события в сигнале Z можно получить атрибутом LAST_EVENT.

Architecture Cl of 12 is

Signal Z: bit ='0'; Begin Process ( XI, X2 );

Z<= XI and X2;

Assert not (Z='0' and not Z'STABLE and Z'DELAYED (10 ns)= '0')

Report "риск сбоя в 1 в вентиле 12"

Severity worning;

Y<= transport Z after 10 ns; End Cl;

Более полное представление о предопределенных атрибутах сигналов можно получить из таблицы 3.1. Помимо предопределенных, пользователь может вводить дополнительные атрибуты для сигналов и других типов данных.

Таблица 3.1. Предопределенные атрибуты сигналов

Пример

Тип результата

Пояснения

S'QUIET(T)

Boolean

TRUE, если сигнал S пассивен на интервале Т.

S'TRANSACTION

Bit

Инвертируется S каждый раз, когда S активен (изменяется).

S'STABLE(T)

Boolean

TRUE, если не было событий за интервал Т.

S'DELAYED(T)

Signal

Предыдущее значение S в момент NOW- Т.

S' ACTIVE

Boolean

TRUE, если сигнал активен.

S'LAST ACTIVE

Time

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

S 'EVENT

Boolean

TRUE, если происходит событие в S.

S'LAST VALUE

Signal

Значение сигнала перед последним событием в нем.

S'LAST EVENT

Time

Время последнего события в S.

 

  3.3.12. Алфавит моделирования и пакеты

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

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

Пункты, появляющиеся в пределах описания пакета, могут стать видимыми в других проектах с помощью оператора включения.

Если пакет содержит описания подпрограмм (функций или процедур) или определяет одну или более задерживаемых констант (константы, чья величина не задана), то в дополнение к описанию необходимо тело пакета. Тело пакета (которое определяется с использованием комбинации ключевых слов "package body") должно иметь то же имя, что и соответствующее описание пакета, но может располагаться в любом месте проекта (оно не обязательно должно располагаться немедленно после описания пакета).

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

Приведенные выше описания объекта F базировались на стандартных средствах языка VHDL - сигналы представлялись в алфавите ' Г,' 0 ', логические операции И, ИЛИ, НЕ также определялись в этом алфавите. Во многих случаях приходится описывать поведение объектов в других алфавитах. Например, в реальных схемах сигнал, кроме значений' 1' и '0', может принимать значение высокого импеданса 'Z' (на выходе буферных элементов) и неопределенное значение 'X', например, отражая неизвестное начальное состояние триггеров. Переход к другим алфавитам осуществляется в VHDL с помощью пакетов. У пакета, как и у объекта проекта, различают объявление интерфейса package и объявление тела объекта package body.

Ниже приводится пример пакета Р4 для описания объектов в четырехзначном алфавите представления сигналов ('X', 'О', 'Г, 'Z'), X - значение не определено, Z -высокий импеданс. В этом пакете приводится тип KONTAKT для представления сигналов в четырехзначном алфавите и определяются функции NOT и AND над ними.

В ТТЛ логике высокий импеданс на входе воспринимается как 1, что учитывается в таблице функции AND.

Ниже следует объявление пакета Р4:

Package P4 is

—перечислимый тип

type KONTAKT is ( ЧХ', Л0', Ч', XZ' );

function "NOT" (X: in KONTAKT) return KONTAKT;

function "AND" (XI, X2: in KONTAKT} return KONTAKT;

end P4;

Объявление тела пакета Р4 имеет вид:

Package body P4 is

Function "NOT" (A: in KONTAKT} return^ KONTAKT is

Begin

If A='X' then return 'X' Else if A='l' then return Л0' Else if A='0' then return 4' Else return 'Z' End if; End "NOT";

Function "AND" ( Al, A2: in KONTAKT ) return KONTAKT is Begin

If (Al='0' ) or (A2='X' ) then return to '0' Else if (Al= VX' ) or (A2='0' ) or (A2= 'X') and (Al='0' ) then return ЛХ'

Else return to'l' End if; End "AND"; End P4;

Пример использования пакета Р4 при описании объекта F_P4. Этот объект отличается от F, т. к. у него другой интерфейс.

—подключается ( use) пакет Р4, все-его функции (ALL)

use P4.ALL;

entity F_P4 is

port (Al, A2: in KONTAKT; Bl, B2: out KONTAKT )

end F_P4;

Описание архитектуры F_P4_a '

Architecture F_P4_a of F is

Begin

B2<= not { Al and A2 );

Bl<= Al and A2;

End F_P4_a;

Из этого примера видно, что в ряде случаев изменение алфавита моделирования не требует внесения изменений в описания объектов.

Например, переход к семизначному алфавиту ('О', 'Г, 'X', 'Z', 'F', 'S', 'R'), где тип KONTAKT имеет дополнительные значения: F - фронт, S - срез, R - риск сбоя, потребует только создания нового пакета и подключения его к объявлению объекта F_P4. Изменение в других частях описаний объекта проекта не потребуется.

 

  3.3.13. Задание монтажного "или" и общей шины

Рассмотрим реализацию монтажных операций ИЛИ (И) и двунаправленные шины на элементах с тремя состояниями выхода.

Монтажное ИЛИ:

Signal Y: WIRED_OR bit;

Kl: process

Begin

Y<= XI and X2

End process Kl;

K2 : process

Y<= X3 and X4;

End process K2;

Общая шина на элементах с тремя стабильными выходами:

Туре A3 is { 'О', Ч', XZ' ); Signal D: CHIN A3; Cl: process Begin

If El='0' then D<=' Z' Else D<= XI and X2 End if;

End process Cl; C2: process

If E2='0' then D<='Z' Else D<= X3 and X4 End process C2;

Если каждой компоненте (Kl, K2) схемы сопоставить процесс, то имеем два параллельных процесса, каждый из которых вырабатывает свой выходной сигнал.

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

обычно описывается в пакете, а ее имя указывается при описании соответствующего сигнала. Например, тело функции разрешения WIRED_OR (монтажное ИЛИ) имеет следующий вид:

Function WIRED_OR (INPUTS: bit_vector) return bit is Begin

For I in INPUTS'RANGE loop

If INPUTS( I ) = 4' then

Return 4' ; End if; End loop; Return '0'; End;

Драйверы сигнала INPUTS неявно рассматриваются как массив, границы которого определяются атрибутом RANGE.

Функция сканирует драйверы сигнала и, если хоть один из них равен Т. возвращает значение Ч', иначе 'О'.

Функция разрешения SHIN для шины на элементах с тремя состояниями выходов может быть такой:

Туре A3 is ('0' , '1' , 'Z' );

Type VA3 is array ( integer range <> of A3 ); 

Function SHIN (signal X: VA3 ) return A3 is 

Variable VIXOD: A3:= 'Z'; Begin

For I in X'RANGE loop

If X ( I) /= *Z' then 

VIXOD:= X ( I); 

Exit; 

End if; 

End loop; 

Return VIXOD; 

End SHIN;

Предполагается, что может быть включен (то есть - не равен 'Z') только один из драйверов входных сигналов.

 

  3.4. Язык описания аппартуры Verilog

  3.4.1. Общие сведения

Как известно [45], язык описания аппаратуры Verilog был разработан фирмой Gateway Design Automation в 1984 году. После поглощения последней таким монстром, как Caddence, язык стал получать все более широкое распространение среди разработчиков, и стал не менее популярен, чем VHDL.

В отличие от VHDL, структура и синтаксис которого напоминают такие "сложные" языки, как АДА или АЛГОЛ, синтаксис Verilog напоминает очень популярный в среде как программистов, так и разработчиков встроенных систем и систем ЦОС старый добрый С. Verilog позволяет достаточно эффективно выполнить описание и провести моделирование (simulate) и синтез цифровых схем благодаря применению встроенных (built-in primitives) примитивов, примитивов пользователя (user-defined primitives), средствам временного контроля (timing checks), моделированию задержки распространения от входа до выхода (pin-to-pin delay simulation), возможности задания внешних тестовых сигналов (external stimulus).

Как и VHDL, Verilog изначально предназначался для моделирования цифровых систем, и как средство описания синтезируемых проектов стал использоваться с 1987 года. В настоящее время ведущие пакеты синтеза систем на ПЛИС, такие как продукты фирм Synopsis, Caddence, Mentor Graphics, многих производителей ПЛИС поддерживают синтез с описаниями на языке Verilog. В языке Verilog поддерживается набор типов логических вентилей (Gate Types). Для логических вентилей определены ключевые слова (Keywords): and (И), nand (И-НЕ), or (ИЛИ), nor (ИЛИ-НЕ), хог (Исключающее ИЛИ), хпог (Исключающее ИЛИ-НЕ), buf (Буферный элемент), not (Отрицание, НЕ). В Verilog при использовании вентилей необходимо задать входы и выходы элемента, а также (не обязательно) имя вентиля. Например, вентили and и or должны иметь один выход и два и более входов. Так, для вентиля И (and) имеем:

and <name><list of arguments>

and myand(out, inl, in2, in3);

and (out, inl, In2

Вентили buf и not могут иметь один вход и один и более выходов. Имя вентиля является необязательным. Примеры использования приведены ниже:

buf mybuf(outl, out2, out3, in); not (out, in);

Говоря о синтаксисе языка Verilog, следует помнить, что он является контекстно-зависимым языком, то есть строчные и прописные буквы различаются. Все ключевые слова (keywords) задаются в нижнем регистре (строчные буквы).

Для обозначения пустого пространства (White Space) используются символы пробела, табуляции и новой строки.

В Verilog поддерживаются два типа комментариев. Они аналогичны принятым в C++ - если надо закомментировать одну строку, то используются две косые черты в ее начале:

// это комментарий 

Чтобы закомментировать несколько строк, используется следующая конструкция:

/* Это

комментарии... */

Очевидно, что комментарии не могут быть вложенными.

 

  3.4.2. Операторы

В Verilog существует три типа операторов - с одним, двумя и тремя операндами. Унарные операторы располагаются слева от операнда, бинарные - между операндами, тернарный оператор разделяет три операнда двумя операторами.

Примеры операторов:

clock = ~clock; // унарный оператор отрицания

// clock - опреранд

с = а || Ь; // II - бинарный оператор ИЛИ, а и b операнды г = s ? t : u; // ?: - тернарный оператор, читается как

// г = [if s is true then t else u]

Как правило, при написании описаний на верилоге комментарии одной строкой (/ /) используются для ввода текстовых комментариев к коду, а конструкцию /* */ используют при отладке для "закомментирована" фрагментов кода.

 

  3.4.3. Числа в Verilog

  3.4.3.1. Целые числа (Integers)

Целые числа могут быть двоичными (binary), обозначаются b или В, десятичными (decimal, d или D), шестнадцатеричными (hexidecimal, h или Н) или восьмеричными (octal, о или О), Для определения чисел используются следующие форматы:

1. <разрядность>'<основание><число> - полное описание числа.

2. <основание><число> - используется разрядность представления, заданная в системе по определению, но не менее 32 бит.

3. <число> - используется, когда по умолчанию десятичное основание. Разрядность определяет число бит под представление числа. Например:

8"Ы0100010 // 8-битное число в двоичной системе 

8"hA2 // 8-битное число в шестнадцатеричной системе

 

  3.4.3.2. Неопределенное и высокоимпедансное состояния (X and Z values)

Символ х используется для задания неопределенного состояния, символ z показывает третье (высокоимпедансное). При использовании в качестве цифры в числах вместо символа z можно использовать ? . Это рекомендуется делать в операторах выбора (case expressions) для улучшения читаемости кода. Ниже приведены примеры использования символов х и z в числах.

4"b1ОхО

4"bl01z

12"dz

12"d?

8"h4x

 

  3.4.3.4. Отрицательные числа (Negative numbers)

Отрицательное число задается с помощью знака минус перед разрядностью числа. Примеры отрицательных чисел:

-8"d5 8"b-5 // неправильно, знак минус перед числом, а не разорядностью!

 

  3.4.3.5. Символ подчеркивания (Underscore)

Знак подчеркивания (_, underscores) может быть записан в любом месте числа, что позволяет использовать его как разделитель разрядов, улучшающий читабельность.

16"Ь0001_1010_1000_1111 // использование подчеркивания 

8"Ь_0001_1010 // некорректное использование подчеркивания

 

  3.4.3.6. Действительные числа (Real)

Действительные числа (Real numbers) могут быть представлены либо в десятичном виде, либо в стандартной форме с плавающей точкой (scientific format). Примеры действительных чисел:

1.8

3_2387.3398_3047

3.8е10 // е или Е для обозначения порядка

2.1е-9

3. // неправильно!

 

  3.4.3.7. Строки (Strings)

Строка заключается в кавычки « ... « и не может занимать более одной линии. Примеры использования строк:

«hello world»; // правильное использование строк «good b

У

е

wo 

rid»; // неправильное использование строк

 

  3.4.4.Цепи в Verilog (Nets)

Для обозначения цепей используются следующие ключевые слова: wire, supplyO, supply 1. Величина по умолчанию (default value): z. Разрядность по умолчанию (default size): 1 бит.

По своему назначению цепь (Net) в Verilog сходна с сигналом в VHDL. Цепи обеспечивают непрерывное модифицирование сигналов на выходах цифровой схемы относительно изменения сигналов на ее входах.

Если драйвер (источник) сигнала цепи имеет некоторое значение, то и цепь принимает то же значение. Если драйверы (drivers) цепи принимают различные значения, цепь принимает значение наиболее "сильного" сигнала (strongest), если же "сила" каждого сигнала равнозначна, то цепь принимает неопределенное состояние (х).

Для обозначения цепи наиболее часто применяется ключевое слово wire, ключевые слова supplyO и supplyl используются для моделирования источников питания (power supplies) в схеме.

 

  3.4.5. Регистры (Registers)

Для обозначения регистров используются следующие ключевые слова reg. Величина по умолчанию: х. Разрядность по умолчанию: 1 бит.

Основное различие между цепями (nets) и регистрами (registers) состоит в том, что значение регистра должно быть назначено явно. Эта величина сохраняется до тех пор, пока не сделано новое назначение. Рассмотрим использование этого свойства на примере триггера с разрешением (защелки, E-type flipflop).

module E__ff{q, data, enable, reset, clock); output q;

input data, enable, reset, clock; reg q;

always @ (posedge clock) if (reset == 0)

q = l"bO; else if (enable==l)

q = data; endmodule

Регистр q хранит записанную в него величину до тех пор, пока не произойдет новое назначение сигнала.

Для того чтобы провести моделирование этого примера, напишем модуль верхнего уровня (higher level module), который формирует тестовый сигнал и позволяет провести наблюдение за выходами триггера. В этом случае сигнал q является цепью, драйвером (источником) которой служит модуль E_ff.

module stimulus; reg data, enable, clock, reset; wire q;'

initial begin

clock = l"bO;

forever #5 clock = -clock; end

E_ff effO(q, data, enable, reset, clock);

initial begin reset = l"bO;

#10 reset = l"bl; data = l"bl;

#20 enable = 1;

#10 data = l"bO;

#10 data = l"bl;

#10 enable = 0;

#10 data = l"bO;

#10 data = l"bl;

#10 enable - 1;

#10 reset = l"bO;

#30 $finish; end

initial $monitor($time, « q = %d», q);

endmodule

 

  3.4.6. Векторы (Vectors)

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

reg [3:0] output; // выход 4-разрядного регистра wire [31:0] data; // 32-битная цепь reg [7:0] а;

data [3:0] = output; // частичное назначение output = 4"Ь0101; // Назначение на целый регистр

Важным является порядок назначения элементов в векторе. Первый элемент регистра является 'наиболее значимым (most significant).

reg [3:0] а; // аЗ - старший бит 

reg [0:3] b; // ЬО- старший бит.

 

  3.4.7. Массивы (Arrays)

Регистры (Registers), целые числа (integers) и временные (time) типы данных можно объявлять как массивы, как это показано в нижеследующем примере:

Объявление 

<data_type_spec> {size} <variable_name> {array_size}

Использование 

<variable_name> (array_reference} {bit_reference}

reg data [7:0]; // 8 1-разрядных элементов 

integer [3:0] out [31:0]; // 32 4-битных элемента 

data [5]; // 5 8-битных элементов

 

  3.4.8. Регистровые файлы (Memories)

Регистровый файл (Memories) представляет собой массив регистров (array of registers). Ниже представлен синтаксис объявления регистрового файла.

reg [15:0] mem!6_1024 [1023:01; // регистровый файл 1К X 16 

mem16_1024 [489] ; // 489 элемент файла meml6__1024

Желательно для обозначения регистровых файлов использовать информативные имена, например meml6_1024 чтобы избежать путаницы.

 

  3.4.9. Элементы с третьим состоянием (Tri-state)

Как уже упоминалось, в языке Verilog ситуация, когда драйверами одной цепи являются более одного источника с разными значениями, разрешается в пользу источника, имеющего большую "силу" (signal «strengths»). Наименьшую "силу" имеет сигнал z, обозначающий третье, или высокоимпедансное (high-impedance), состояние. Правда, эти рассуждения актуальны именно на этапе моделирования, но никак не синтеза ПЛИС, о них следует помнить при разработке тестов. Таким образом, драйвер в третьем состоянии не влияет на итоговое значение сигнала цепи. Пример драйвера с третьим состоянием приведен ниже:

module triDriver(bus, drive, value); inout [3:0] bus; input drive; input [3:0] value;

assign #2 bus = (drive ==1) ? value : 4"bz; endmodule // triDriver

В данном примере, когда управляющий сигнал принимает высокий уровень, шина принимает значение входной величины, в противном случае шина переходит в третье состояние.

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

module myTest;

wire [3:0] bus;

reg driveO, drivel, drive2;

integer i;

triDriver modi (bus, ciriveO, i[3:0]);

triDriver mod2 (bus, drivel, 4"hf);

triDriver mod3 {bus, drive2, 4"hO);

initial begin

for (i = 0; i < 12; i = i + 1) begin

#5 {drive2, drivel, driveO} = i;

#5 $display {$time,>> %b %b %d», i[2:0], bus, bus); end

$finish; end

endmodule 

Результаты прогона модели имеют вид:

10 000 zzzz z

20 001 0001 1

30 010 1111 15

40 Oil xxll X

50 100 0000 О

60 101 ОхОх X

70 110 хххх х

80 111 хххх х

90 000 zzzz z 100 001 1001 9 110 010 1111 15 120 011 1x11 X

 

  3.4.10. Арифметические операторы (Arithmetic operators)

Символы (keysymbols): *, /, +, -, %.

Бинарные операторы умножения, деления, сложения, вычитания, определения остатка от деления представлены в нижеследующем примере:

module arithTest; 

reg [3:0] a, b;

initial begin 

a = 4"bllOO; // 12 

b = 4"b0011; // 3

$displayb(a * b); // умножение - 4"blOOO

// 4 МСБ

$display(a / b); // деление 4 

$display(a + b); // сложение 15

$display(a - b); // вычитание 9 

$display((a + l"bl) % b)/ // остаток 1

end 

endmodule // arithTest

Унарные плюс и минус имеют более высокий приоритет (precedance), чем бинарные операторы.

Следует заметить, что если хотя бы один бит в одном из операндов неопределен (равен х), то и результат операции также будет неопределен.

 

  3.4.11. Логические операторы (Logical Operators)

Ключевые символы: &&, ||,!.

К логическим операциям относятся И (and), ИЛИ (or) и НЕ (not).

Результат логической операции может принимать значения: истинно (true, 1) или ложно (false, 0), а также иметь неопределенное состояние (unknown, х).

При выполнении логического оператора все неопределенные величины, как и операнды в третьем состоянии, принимаются как имеющие низкий логический уровень (false).

В качестве операнда может выступать как переменная (variable), так и логическое выражение (expression). Пример работы логических операторов приведен ниже:

module logicalTest; reg [3:0] a, b, с;

initial begin a = 2; b = 0; с •= 4"hx;

$display(a && b); // И О

$display(a I| b); // ИЛИ 1

$display(!a); // HE 0

$display(a || c); // 1, unknown j| 1 (=1)

$display(!c); // unknown

end

endmodule // logicalTest

 

  3.4.12. Операторы отношения (Relational Operators)

Ключевые символы: >, <, >=, <=.

К операторам отношения относятся операторы "больше", "меньше", "больше или равно", "меньше или равно". Результат операции - истина или ложь. Если хотя бы один операнд неопределен, то и результат операции будет неопределен.

module relatTest;

reg [3:0] a, b, c, d;

initial begin 

a=2; 

b=5; 

c=2; 

d=4"hx;

$display(a < b); // true, 1 

$display(a > b); false, 0 

$display(a >= c); // true, 1 

$display(d <= a); unknown 

end 

endmodule // relatTest

 

  3.4.13. Операторы эквивалентности (Equality)

Ключевые символы: ==, !=, ===, !==.

К операторам эквивалентности (equality operators) относятся: оператор логического равенства (logical equality), логического неравенства (logical inequality), выборочного равенства (case equality) и неравенства (inequality). Эти операторы сравнивают операнды побитно. Логические операторы возвращают неопределенный результат, если операнд содержит неопределенные биты, в отличие от выборочных операторов. В случае неравной длины операндов, более короткий дополняется нулями.

Ниже приведен пример использования операторов эквивалентности:

module equTest;

reg [3:0] a, b, с, d, e, f;

initial begin

a = 4; ь = 7; // these default to decimal bases 

с = 4"b010; 

d = 4"bxlO; 

e = 4"bxl01; 

f = 4"bxx01;

$displayb(c); // outputs 0010 

$displayb(d); // outputs xxlO

$display(a == b); // logical equality, evaluates to 0

$display(c != d); // logical inequality, evaluates to x

$display(c != f); // logical inequality, evaluates to 1

$display(d ==== e) ; // case equality, evaluates to 0

$display(c !== d); // case inequality, evaluates to 1

end

endmodule // equTest

Ну и, наверное, понятно, что операторы эквивалентности и присваивания - совершенно различные операторы.

 

  3.4.14. Поразрядные операторы (Bitwise Operators)

Ключевые символы: ~, &, |, л, (~л, л~).

К поразрядным операторам относятся: поразрядное отрицание, поразрядные логические И, ИЛИ, исключающее ИЛИ, исключающее И Л И-НЕ. Поразрядные операторы выполняются только над операндами, имеющими одинаковую разрядность. В том случае, если разрядность одного операнда меньше другого, недостающие разряды дополняются нулями. Ниже приведен пример использования поразрядных операторов:

module bitTest;

reg [3:0] a, b, с;

initial begin

a = 4"bllOO; b = 4"Ь0011; с = 4"b0101;

$displayb(~a) ; // bitwise negation, evaluates to 4"b0011

$displayb(a & c); // bitwise and, evaluates to 4"b0100

$displayb(a | b); // bitwise or, evaluates to 4"bllll

$displayb(b л с); // bitwise xor, evaluates to 4"b0110

$displayb(a ~л с); // bitwise xnor, evaluates to 4"b0110

end

endmodule // bitTest

 

  3.4.15.Операторы приведения (Reduction Operator)

Key symbols: &, ~&, |, ~|, л, ~л, л~.

Операторы приведения - И, ИЛИ, И-НЕ, ИЛИ-НЕ, исключающее ИЛИ, исключающее ИЛИ-НЕ (два варианта). Они выполняются над многоразрядным операндом пошагово, бит за битом, начиная с двух крайних левых разрядов, выдавая на выходе одноразрядный результат. Очевидно, что такой подход позволяет реализовать проверку на четность (нечетность). Ниже приведены примеры использования операторов приведения:

module reductTest; 

reg 13:0] a, b, c;

initial begin 

a = 4"bllll; 

b = 4'"b0101; 

с = 4"b0011;

$displayb(& а};//, (то же l&l&l&l), равен 1 1 

$displayb(f b); // (same as 0|1|0|1), evaluates to 1 

$displayb(A b); // искл.ИЛИ (same as 0Л1Л0Л1), evaluates to 0 

end

endmodule // reductTest

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

 

  3.4.16.Операторы сдвига (Shift Operator)

Ключевые символы: »,«.

Операторы сдвига позволяют осуществить сдвиг операнда как вправо, так и влево. Пример их использования приведен ниже:

module shiftTest; 

reg [3:0] а;

initial begin 

a = 4"b1010;

$displayb(a « 1); // shift left by 1, evaluates to 4"b0100 

$displayb(a » 2); // shift right by 2, evaluates to 4"b0010 

end

endmodule // shiftTest

Этот оператор часто применяют для реализации регистров сдвига, длинных алгоритмов перемножения и т.п.

 

  3.4.17. Конкатенация (объединение, Concatenation)

Ключевой символ: {,}

Объединение позволяет увеличить разрядность (size) цепей (nets), регистров (registers) и т.д.

module concatTest; 

reg a; 

reg [1:0] b; 

reg [5:0] с;

initial begin 

a = l"bl; 

b = 2"bOO; 

с = 6"b101001;

$displayb({a, b}); // produces a 3-bit number 3"blOO 

$displayb({c[5:3], a}}; // produces 4-bit number 4"bl011

end endmodule // concatTest

 

  3.4.18. Повторение (Replication)

Повторение (Replication) может быть использовано для многократного повторения объединения (concatenation), как показано в нижеследующем примере:

module replicTest; 

reg а; 

reg [1:0] b; 

reg [5:0] с;

initial begin 

a = l"bl; 

b - 2"bOO;

$displayb({4{a}}); // результат - 1111 

с = {4{a}};

$displayb(c); // результат -001111 

end

endmodule // replicTest

 

  3.4.19. Системные директивы (System Tasks)

Наверное, этот раздел не будет интересен тем, кто пишет только синтезируемые описания на Verilog. Но поскольку язык является не только средством описания проекта, но и довольно мощным инструментом для поведенческого моделирования систем, то следует сказать несколько слов о встроенных директивах компилятора, позволяющих выполнить моделирование и произвести анализ его результатов.

Директивы вывода результатов моделирования (Writing to Standard Output) Ключевые слова: Sdisplay, $displayb, Sdisplayh, Sdisplayo, Swrite, $writeb, Swriteh, Swriteo.

Наиболее часто применяется директива Sdisplay. Она может быть использована для вывода на экран строк, выражений или переменных. Ниже приведен пример использования директивы Sdisplay:

$display(«Hello Dr Blair»);

— output: Hello Dr Blair

$display($time) // current simulation time.

— output: 460

counter = 4"blO;

$display(« The count is %b», counter.);

— output: The count is 0010

Синтакс определения формата вывода аналогичен синтаксису printf в языке программирования С. Ниже приведено его описание для директивы Sdisplay:

Формат

Описание

%d or %D

Decimal

%b or %B

Binary

%h or %H

Hexadecimal

%o or %O

Octal

%m or %M

Hierarchical name

%t or %T

Time format

%e or %E

Real in scientific format

%for%F

Real in decimal formal

%g or %G

Real in shorter of above two

 

  3.4.20. Контроль процесса моделирования (Monitoring a Simulation)

Ключевые слова: Smonitor, Smonitoron, Smonitproff

Формат директивы Smonitor практически аналогичен формату Sdisplay. Разница заключается в том, что выход формируется при любом изменении переменных, которое произойдет в опердеденное время. Наблюдение может быть включено или отключено с помощью директив Smonitoron или Smonitoroff соответственно. По умолчанию в начале моделирования наблюдение за его ходом включено. Ниже приведен пример наблюдения за моделированием:

module myTest; 

integer a,b;

initial begin 

a = 2; 

b = 4; 

forever begin

#5 a = a + b;

#5 b = a - 1; 

end // forever begin 

end // initial begin 

initial #40 $finish;

initial begin

$rnonitor ($time, « a = %d, b = %d», a, b) ; 

end // initial begin

endmodule // myTest 

Результат прогона:

О а - 2, b = 4

5 a = 6, b = 4

10 a = 6, b = 5

15 a - 11, b = 5

20 a = 11, b - 10

25 a = 21, b = 10

30 a = 21, b = 20

35 a = 41, b = 20

 

  3.4.21. Окончание моделирования (Ending a simulation)

Ключевые слова: Sstop, $fmish.

Директива Sfmish завершает симуляцию и передает управление операционной системе. Директива. $stop приостанавливает моделирование и переводит систему с Verilog в интерактивный режим (см. пример ниже).

Для специальных символов используются следующие эскейп-по следовательно с-ти (escape sequence).

\n

новая строка

\t

табуляция

\\

\

V

и

%%

%

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

Если спецификация вывода не определена, то по умолчанию используются следующие форматы:

Директива

Формат по умолчанию

Sdisplay

decimal

Sdisplayb

binary

Sdisplayh

hexadecimal

Sdisplayo

octal

Swrite

decimal

Swriteb

binary

Swriteh

hexadecimal

Swriteo

octal

Так, например, следующий фрагмент кода ...

$write(5"b01101); $writeb(« «, 5"Ь01101); $writeh(« «, 5"b01101); $writeo(« «, 5"b01101,»\n»);

... и результат его работы:

13 01101 Od 15

14

initial begin clock = l"bO;

#200 $stop

#500 $finish End

 

  3.4.22. Проектирование комбинационных схем: пример проектирования мультиплексора 4 в 1

Рассмотрим проектирование комбинационных логических устройств на примере мультиплексора 4 в 1. При проектировании мультиплексора рассмотрим различные методы его построения.

 

  3.4.22.1. Реализация на уровне логических вентилей (Gate Level Implementation)

Рассмотрим пример реализации нашего мультиплексора 4 в 1 на уровне логических вентилей.

module multiplexor4_1(out, inl, in2, in3, in4, cntrll, cntr!2);

output out;

input inl, in2, in3, in4, cntrll, cntr!2;

wire notcntlrl, notcntr!2, w, x, y, z;

not (notcntrll, cntrll); not (notcntr!2, cntrl2);

and (w, inl, notcntrll, notcntr!2);

and (x, in2, notcntrll, cntr!2);

and (y, in3, cntrll, notcntr!2);

and (z, in4, cntrll, cntr!2);

or (out, w, x, y, z) ; endmodule

Начнем подробное построчное рассмотрение этого примера. Итак, "в первых строках" у нас ...

module multiplexor4_1 (out, inl, in2, in3, in4, cntrll, cntr!2) ;

Первая строка - описание модуля, ключевое слово module используется вместе с именем модуля, по которму осуществляется ссылка на модуль. В скобках приведен список портов модуля (port list), причем вначале перечисляются выходы, затем входы. Каждая строка завершается точкой с запятой - это, как известно, святое для многих языков высокого уровня.

output out;

input inl, in2, in3, in4, cntrll, cntr!2;

Все порты в списке должны быть объявлены как входы (input), выходы (output) или двунаправленые выводы (inout), в этом случае они по умолчанию назначаются типом цепь (wire), если нет других указаний. Когда назначено имя цепи, система моделирования на базе Verilog ожидает неявное назначение выходного сигнала, оценивая его, чтобы осуществлять передачу этого сигнала к внешним модулям.

wire notcntrll, notcntr!2, w, x, у, z;

В данной строке определяются внутренние цепи, осуществляющие объединение узлов мультиплексора. Как видим, понятия цепи в Verilog и сигнала в VHDL очень схожи.

not (notcntrll, cntrll); not (notcntr!2, cntr!2);

В этих строчках описываются вентили НЕ с входами cntrll и cntr!2 и выходами notcntrll и notcntr!2 соответственно. Следует помнить, что в описании портов вентиля всегда вначале идут выходы, затем входы.

and (w, inl, notcntrll, notcntr!2);

and (x, in2, notcntrll, cntr!2);

and (y, in3, cntrll, notcntr!2);

and (z, in4, cntrll, cntr!2);

or (out, w, x, y, z) ; Аналогично описываются и вентили И и ИЛИ endmodule Конец модуля завершается ключевым словом endmodule.

 

  3.4.22.2. Реализация мультиплексора с помощью логических операторов (Logic Statement Implementation)

Реализация мультиплексора с использованием логических операторов имеет вид:

module multiplexor4_l (out, inl, in2, in3, in4, cntrll, cntr!2); output out; input inl, in2, in3, in4, cntrll, cntr!2;

assign out = (inl & -cntrll & ~cntr!2) | (in2 & -cntrll & cntr!2) | (in3 & cntrll & ~cntr!2) | (in4 & cntrll & cntr!2); endmodule

Ну, в начале все понятно - имя проекта, порты ...

module multiplexor4_1 (out, inl, in2, in3, in4, cntrll, cntr!2); output out; input inl, in2, in3, in4, cntrll, cntr!2;

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

assign out = (inl & -cntrll & ~cntr!2) |

(in2 & -cntrll & cntr!2) |

(in3 & cntrll & ~cntr!2) |

(in4 & cntrll & cntr!2); endmodule

С помощью конструкции assign осуществляется непрерывное назначение (continuous assignment) цепи out. В этом случае ее значение заново вычисляется каждый раз, когда меняется хоть один из операндов.

 

  3.4.22.3. Реализация с помощью оператора выбора (Case Statement Implementation)

Рассмотрим использование оператора выбора (case statement) для реализации мультиплексора. Следует заметить, что этот способ, наверное, наиболее прост и наименее трудоемок.

module multiplexor4_l (out, inl, in2, in3, in4, cntrll, cntr!2) ; output out;

input inl, in2, in3, in4, cntrll, cntr!2; reg out;

always @(inl or in2 or in3 or in4 or cntrll or cntr!2) case ({cntrll, cntrl'2}) 2"bOO : out = inl; 2"b01 : out = in2; 2"ЫО : out = in3; 2wbll : out = in4;

default : $display(«Please check control bits»); endcase endmodule

Первые три строки до боли знакомы - добавить к сказанному ранее практически нечего.

module multiplexor4_l (out, inl, in2, in3, in4, cntrll, cntr!2); output out;

input inl, in2, in3, in4, cntrll, cntr!2; reg out;

Единственное отличие - выход out определен как регистр (register), это сделано для того, чтобы назначать его значения явно и не управлять ими. Такое назначение сигнала называется процедурным назначением (procedural assignment). Данные типа "цепь" (wire) не могут быть назначены явно, они нуждаются в сигнале драйвере, такое назначение называется непрерывным назначением (continuous assignment).

always @(inl or in2 or in3 or in4 or cntrll or cntr!2)

Эта конструкция читается так же, как и пишется, то есть значение вычисляется всегда при изменении хотя бы одного операнда - система постоянно их отслеживает. Несколько забегая вперед, следует отметить, что данная конструкция является синтезируемой во многих системах проектирования, в частности и в MAX+PLUS фирмы Altera. Список переменных называется списком чувствительности (sensitivity list), поскольку данная конструкция чувствительна к их изменениям. Данный термин нам уже известен из описания языка VHDL.

Ключевое слово - always @( expr or expr ... );

case ({cntr!2, cntrll}) 2"bOO : out = inl; 2"b01 : out - in2; 2"blO : out = in3; 2"bll : out = in4;

default : $display(«Please check control bits»); endcase endmodule

Синтакс оператора выбора case в Verilog сходен с синтаксисом оператора выбора в языке С. Условием является контатенация или объединение переменных cntr2 и cntrl в двухразрядное число. Завершает оператор выбора ключевое слово endcase.

Здесь нелишне напомнить, что следует различать процедурное и непрерывное назначение сигналов, что и иллюстрируют вышеприведенные примеры.

 

  3.4.22.4. Реализация с использованием условного оператора (Conditional Operator Implementation)

В принципе ничего нового мы уже не видим - ясно, что в нашем случае условный оператор проигрывает оператору case в наглядности представления (хотя для большинства систем проектирования синтезируемые реализации окажутся идентичными):

module multiplexor4_l (out, inl, in2, in3, in4, cntrll, cntr!2); output out; input inl, in2, in3, in4, cntrll, cntr!2;

assign out = cntrll ? (cntr!2 ? in4 : in3) : (cntrl2 ? in2 : inl); endmodule

 

  3.4.22.5. Тестовый модуль (The Stimulus Module)

Вообще говоря, первоначально язык Verilog задумывался как язык верификации цифровых устройств (Verify Logic). Поэтому одной из мощных возможностей языка является наличие средств для задания тестовых сигналов. Ниже приводится пример такого модуля для нашего мультиплексора 4 в 1:

module muxstimulus;

reg INI, IN2, IN3, IN4, CNTRLl, CNTRL2;

wire OUT;

multiplexor4_l muxl_4(OUT, INI, IN2, IN3, IN4, CNTRLl, CNTRL2);

initial begin

INI = 1; IN2 = 0; INS = 1; IN4 = 0;

$display(«Initial arbitrary values»);

#0 $display(«input 1 = %b, input2 = %b, inputs = %b, input4 = %b\n», INI, IN2, INS, IN4);

{CNTRLl, CNTRL2} - 2"bOO;

#1 $display(«cntrll=%b, cntr!2=%b, output is %b», CNTRLl, CNTRL2, OUT) ;

{CNTRLl, CNTRL2} = 2"b01;

#1 $display(«cntrll=%b, cntr!2=%b output is %b», CNTRLl, CNTRL2, OUT);

{CNTRLl, CNTRL2} = 2"blO;

#1 $display(«cntrll=%b/ cntr!2=%b output is %b», CNTRLl, CNTRL2, OUT) ;

{CNTRLl, CNTRL2} - 2"bll;

#1 $display(«cntrll=%b, cntrl2=%b output is %b», CNTRLl, CNTRL2, OUT);

end

endmodule

Рассмотрим данный пример подробнее.

module muxstimulus;

Поскольку наш генератор тестов является модулем верхнего уровня иерархии (top level module), то в его описании отсутствует список портов. Для задания модуля используется ключевое слово module.

reg INI, IN2, INS, IN4, CNTRLl, CNTRL2; wire OUT;

В данном случае мы обеспечиваем подачу тестовых сигналов на входы нашего мультиплексора и снятие сигнала с его выхода, следовательно, мы должны назначить сигналы для входов мультиплексора и сигнал, который управляется (driven) его выходом. Поэтому и использованы данные типа reg для входов и wire для выхода.

multiplexor4_l muxl_4(OUT, INI, IN2, INS, IN4, CNTRLl, CNTRL2);

В этой строке происходит обращение к тестируемому модулю multiplexor4_l, в таких случаях принят следующий синтакс:

<module_name> <instance_name> (port list);

Имя экземпляра (instance name) очень похоже на понятие языка VHDL и является необходимым при обращении к определяемым пользователем модулям (user defined modules), дабы не нарушать иерархие проекта.

Список портов (port list) устанавливает соответствие между сигналами тестового и тестируемого модулей, при этом порядок переменных в списке портов должен соответствовать порядку их объявления в тестовом модуле.

initial begin

-INI = 1; IN2 = 0; INS = 1; IN4 = 0; $display(«Initial arbitrary values»);

#0 $display («input 1 = %b, input2 = %b, inputs = %b, input4 = %b\n», INI, IN2, INS, IN4);

Собственно моделирование (simulation) осуществляется конструкцией, определяемой ключевыми словами initial begin ... end. Она предназначена для объединения инструкций, которые могут выполняться одновременно.

Перед инициализацией процесса моделирования сообщение об этом выводится с помощью Sdisplay. Конструкция #0 перед директивой вывода означает, что вывод на экран осуществляется после назначения сигналов на входы. Синтакс директивы Sdisplay подобен синтаксису функции printf в языке С:

$display(exprl, expr2, ...., exprN);

Expr N может быть переменной, выражением или строкой.

{CNTRLl, CNTRL2} = 2"ЬОО;

#1 $display(«cntrll=%b, cntr!2=%b, output is %b», CNTRLl, CNTRL2, OUT) ;

Здесь осуществляется назначение сигналов управления.

CNTRLl = 0; CNTRL2 = 0;

Оператор конкатенации (concatenation operator) { } может быть использован для группового назначения. Следует помнить, что число разрядов в числе и переменной должно совпадать.

{CNTRLl, CNTRL2} = 2"Ь01;

#1 $display(«cntrll=%b, cntr!2=%b output is %b», CNTRLl, CNTRL2, OUT) ;

{CNTRLl, CNTRL2} = 2"blO;

#1 $display(«cnt:rll=%b, cntr!2=%b output is %b», CNTRLl, CNTRL2, OUT);

{CNTRL1, CNTRL2} = 2"b11;

#1 $display(«cntrll=%b, cntr!2=%b output is %b», CNTRL1, CNTRL2, OUT);

end endmodule

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

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