Изучение VHDL

       

Настроечная константа generic.


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

\объявление настроечных констант\::=

generic(\объявление настроечной константы\

             {; \объявление настроечной константы\});

\объявление настроечной константы\::=

                                \идентификатор\:\тип\[:=\начальное значение\]



Oбъекты языка VHDL


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

Сигнал.

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

signal : \идентификатор\{,\идентификатор\}:=[\начальное значение\];
где - \начальное значение\ - выражение, представляющее константу, значение которой принимает сигнал перед первым запуском процесса.

Константа.

Константой является объект, не изменяющий свое значение при вычислениях. После объявления константы присваивание ей значения запрещено (кроме случая отложенной константы). Пример объявления константы:
сonstant thousand: integer:=1000;

Переменная.

Переменной является объект, хранящий значение в пределах операторов процесса, функции или процедуры. В отличие от сигнала, присваивание переменной выполняется немедленно. Упрощенный синтаксис объявления переменной:
\объявление переменной\::=
[shared] variable \идентификатор\{,\идентификатор\}:\тип\[:=\начальное значение\];



Пример объявления переменной:
variable tmp: integer range -128 to 127:=0;

Порт.

В структуре программы VHDL выделяются объекты проекта, называемые entity. Не путать объекты языка с объектом проекта. Это связано с тем, что, во-первых, object и entity переводятся одинаково, во-вторых, в Language Reference Manual сигналы, переменные и др. в некоторых декларативных местах обзываются как entities. В этом слове есть что-то философское, как в афоризме: "Электрон неисчерпаем, как и атом".

Порт представляет собой интерфейсный сигнал объекта проекта. Как и в декларации сигнала, в декларации порта указывается его идентификатор, тип, начальное значение. Дополнительно указывается режим работы: in - прием, out - передача, inout - прием и передача, buffer - передача и использование как сигнал-операнд внутри объекта проекта и link – двунаправленное соединение с другим портом с таким же режимом. Упрощенный синтаксис объявления портов объекта проекта следующий:

\объявление портов\::=port (\объявление порта\ {; \объявление порта\}); \объявление порта\::=\идентификатор\: in |out|inout|buffer|link \тип\ [:=\начальное значение\]

Настроечная константа generic.

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

\объявление настроечных констант\::= generic( \объявление настроечной константы\ {; \объявление настроечной константы\}); \объявление настроечной константы\::= \идентификатор\:\тип\[:=\начальное значение\]

Переменная цикла.

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

Начальное значение объекта.

Начальное значение объекта в его объявлении - это то значение которое принимает объект перед первым циклом моделирования. Если начальное значение не присвоено, то симулятор присваивает наименьшее значение данного типа, если тип - числовой или самое левое значение, если тип - перечисляемый.

Например, многие вначале удивляются, почему проект, написаный с сигналами стандартного типа STD_LOGIC, отказывается вести себя как задумано - на всех выходах модели - значение U (не инициализировано). Объяснение простое: U - это самое левое значение перечисляемого типа STD_LOGIC, а каким-то сигналам в модели не дали ожидаемого начального значения или на них не распространился сигнал сброса. И значение U распространилось до выходов модели в согласии с логикой STD_LOGIC.

Начальное значение может быть выражением. Но значение выражения должно быть вычисленным до момента трансляции данного объявления. Например, первое объявление:
signal bb:bit:=aa;
signal aa:bit :='1';

неверно, так как при его рассмотрении компилятор еще не имеет сведений о идентификаторе аа.

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

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


Синтаксис объявления пакета:

\объявление пакета\::= package \идентификатор\ is

                                  {объявление в пакете}

                                    end [package][\идентификатор\];

В объявлении пакета могут быть объявленными объявление процедуры или функции, объявление типа и подтипа, объявление файла, псевдонима, константы, глобальной переменной, объявление и спецификация атрибута, объявление компонента, объявление группы, описание use.

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

Константам может быть не присвоено значение. Такие константы называются отложенными (deferred). Например, это могут быть заранее неопределенная  кодировка состояний или разрядность шин. Тогда эти константы должны получить значение  в теле пакета.

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

signal my_bit: IEEE.std_logic_1164.X01Z;



Объявление процедур и функций.


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

\объявление процедуры\::= procedure \имя процедуры\[(\список параметров\)];

\объявление функции\::=[pure | impure] function \имя функции\ |\знак функции\

                                     [(\список параметров\)] return \тип параметра\;



Однотактная синхронизация против двухтактной


В сентябре 1979 г. в лаборатории спец-ЭВМ кафедры вычислительной техники КПИ под руководством Ю.С.Каневского приступили к системной отладке самого скоростного в стране опытного образца процессора БПФ, собранного из 2000 микросхем серии К155. Отладка шла, в целом, успешно. Но процессор упорно отказывался работать стабильно. Как ни меняли конструкцию системы синхронизации, как не варьировали период и скважность синхросерии - данные нет-нет, да проскакивали лишний уровень регистров. Было принято кардинальное решение - заменить все асинхронные регистры ТМ5 на  синхронные ИР1. Т.е. заменить двухтактную синхронизацию на однотактную. Второе решение - никогда больше в лаборатории Ю.С.Каневского не применять двухтактную синхронизацию… А отлаженный и испытанный процессор еще несколько лет надежно работал где-то на Дальнем Востоке.

Проектирование микросхем и в частности, систем на кристалле (СНК) характеризуется тем, что ошибка в проекте обходится слишком дорого, а ее локализация в микро­схеме и выяснение ее причин очень затруднительны. Поэтому основным правилом проектирования является то, что поведение ВУ в кристалле должно быть предсказуемым.

В вычислительной технике используются, в основном, два принципа син­хро­низации вычислительных устройств (ВУ): двухтактной и однотактной синхронизации. Эти принципы обеспечивают различный уровень предсказуемости поведения ВУ и их необ­ходимо рассмотреть подробнее.

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


Благодаря двухтакт­ной синхронизации, триг­геры могут быть вы­полнены по простей­шей электрической схе­ме, т.е.
как асинхрон­ные, прини­мающие дан­ные по уров­ню син­хро­серии. Для пра­виль­ ной работы ВУ прием данных в сосед­них уров­нях триггеров дол­жен выполняться в раз­ных активных фазах синхросигналов CLK1 и CLK2. При перекрытии этих фаз (пример пере­крытия выделен цве­том на рис. 1) возмож­на ситуация непра­виль­ного прие­ма дан­но­го и даже прохож­дения данного через несколько уровней триг­ге­ров без запоминания. Поэтому фазы синхросерий выполняют с защитным времен­ным промежут­ком между ними.

Задержки в линиях соединений могут превосходить задержки в логичес­ких схемах и триггерах. Эти задержки трудно выполнить нормированными в заданных пределах, а при реализации в ПЛИС – это почти невозможно. Поэтому принцип двухтактной синхронизации применяется только тогда, когда защитный промежуток между фазами достаточно велик. А это приводит к существенному уменьшению быстродействия ВУ по сравнению с максимально возможным.

Если в ВУ применяются RS – триггеры и другие асинхронные триггеры, например, защелки, то такое ВУ необходимо отнести к схеме с двухтактной синхронизацией. Даже если в такой схеме используется один синхросигнал, то второй синхросигнал присутствует неявно. Например, его могут получать инвертированием первого синхросигнала.

При разработке проектов для ПЛИС двухтактная синхронизация практи­чески никогда не применяется, так как трудно получить проект с гарантиро­ванной работо­способностью. Но, например, в блоке распределенной памя­ти, выполнен­ном на LUT, такая синхронизация использована: по фронту синхро­сигнала записываются адрес и данное в защелки, а по его спаду – данное переписывается в триггер – защелку памяти. Но LUT разрабатывался с таким расчетом, чтоб его поведение было пред­ска­зу­емым при любой про­шивке ПЛИС, и чтобы пользователь воспринимал эту память как синхронную. Кстати, в первых ПЛИС эта память была асинхронной и необходимо было вводить дополнительные временные ограничения на сигналы, чтобы она работала корректно.



В некоторых ВУ используется асинхронный способ вычислений на логи­ческом уровне, благодаря чему понижается энергопотребление до мини­мума. Но разработка таких ВУ не поддерживается стандартными САПР и тем более - САПР для ПЛИС.


Двухтактная синхронизация относится к асинхронному управлению. Другим случаем такого управления является асинхронная начальная уста­новка или сброс триггеров ВУ. Если сигнал сброса не согласован по вре­мени с синхросигналом или если в схеме используются несколько сигналов сброса, то она может функциони­ровать некорректно. Например, после сбро­са, состояние управляющего автомата, следующее за начальным, может быть случайным, если за­держка между сигналом сброса и фронтом синхро­серии слишком мала. Для избежания этого в ПЛИС ор­ганизована ши­на гло­баль­ного сброса, под­во­дящая сигнал сбро­са-ус­та­новки ко всем тригге­рам поч­ти одно­вре­менно.

При однотактной син­хро­низации все триггеры ВУ выпол­нены как син­хрон­ные и тактиру­ются фрон­том од­ного син­хро­сигнала (рис. 2). При этом усло­вием пра­виль­ности функци­о­ни­ро­ва­ния ВУ яв­ля­ется неравен­ство кри­ти­ческой задержки:

max(TTi+TDi,j + TПj ± ?TCi,j) < TC,                                          (1)

i,j

где TTi – задержка от фронта синхросигнала до выхода i-го триггера, TDi,j – задержка сигнала в логических схемах и линиях связи между i –м и j – м триггером, TПj – время предустановки сигнала на входе j-го триггера относи­тельно фронта синхросигнала, ?TCi,j - относительная задержка между син­хро­сигналами, приходящими на эти триггеры, называемая перекосом фазы (clock skew), TC – заданный период синхросигнала, при условии, что время удержания сигнала на входе триггера ТУ  удовлетворяет заданным ограниче­ниям.

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

max(TTi+TDi,j + TПj ) < TC .                                              (2)

i,j

Временной анализ проектов микросхем

Предсказание правильности поведения ВУ с однотактной синхрониза­ци­ей во всех САПР микросхем основано, прежде всего, на времен­ном анализе задержек схемы ВУ, который выполняет программа временного анализа. Эта программа по известным задержкам между всеми элементами проекта ВУ, включая задержки в проводниках, выполняет проверку условия (2). Также вычисляются задержки от входных выводов микросхемы до входов тригге­ров и от выходов триггеров до выходных выводов микросхем.

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

Если в ВУ существует перекос фаз, то временной анализ усложняется, так как он выполняется по более сложной формуле (1). Во многих САПР автоматический учет перекоса фаз не выполняется или проводится только для отдельно выбранных маршрутов. Если ВУ состоит из нескольких связан­ных между собой модулей, в пределах которых действуют разные синхросе­рии, то дополнительно проверяется условие (1), в котором ?TCi,j - относи­тельная задержка между фронтами двух синхро­серий, а задержки опреде­ля­ются по маршрутам сигналов между парами блоков.

Часто, операнд за­пи­­сыва­ется в триггер i и хранится в нем несколько так­тов, в течение кото­рых сигнал операнда распространяется через логическую схему до триггера j, в который операнд записывается также через несколько тактов. Очевидно, что такой маршрут желатель­но удалить из временного ана­ли­за или анализи­ровать отдельно, так как через него практически никог­да не проходит крити­ческая задержка. Такие маршруты выделяют в виде множества много­так­товых маршрутов (multicycle paths), называемых также ложными маршрута­ми (false paths).

В результате временного анализа подтверждается, что схема ВУ работа­ет с однотактной синхронизацией, что в ней отсутствуют кри­тические пе­реко­сы фаз, а также фиксируются критический путь и его задерж­ка, которые ха­рак­­теризуют быстродействие ВУ. Это быстродействие обычно вы­ража­ется ве­личи­ной минимального тактового периода TCmin, определяе­мо­го ле­вой час­тью формулы (1) или максимальной тактовой частотой fmax = 1/TCmin.

Стадия размещения вентилей логической схемы по площади кристалла и трассировки межсоединений является ответственным этапом проектирова­ния микросхемы и прошивки ПЛИС, так как от нее зависят все основные характеристики СНК. В то же время, это одна из самых трудоемких стадий. Она сводится к серии последовательных приближений к эффективному ва­рианту размещения в плоскости микросхемы графа соединения вентилей (рис. 27).

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

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

Исходя из вышеизложенных особенностей проектирования микросхем, разработчики фирм – производителей микросхем предлагают следующие рекомендации :

Þ       Применять только однотактную синхронизацию и желательно, только один синхросигнал.

Þ       Если в ВУ используется несколько синхросигналов, в том числе один сигнал, но со срабатыванием по фронту и спаду, то минимизировать их число, а их распространение ограничить отдельными модулями – по одному синхросигналу на модуль; синхросигналы генерировать в одном, предназна­ченном для этого модуле.

Þ       Не допускать существенных перекосов фаз.

Þ       Минимизировать количество проверяемых маршрутов, в частности, вы­де­лением множества многоцикловых маршрутов и конвейеризацией ВУ.

Þ       Отделять быстродействующие блоки от медленных блоков и оптими­зи­ровать их раздельно.

Þ       Обеспечить запоминание в регистрах модулей ВУ выходных сигналов, а еще лучше – и входных сигналов. Благодаря этому, не только ускоряется временной анализ, повышается максимальная тактовая частота, но и упро­щается стыковка модулей между собой, упрощаются условия повторного использования модулей (вычислительных заготовок).

Þ       Реализовать преимущественно синхронные начальные установку или сброс триггеров, особенно в схемах управления.

Þ       При реализации в ПЛИС желательно все триггеры выполнить с асин­хронным сбросом или установкой по одному сигналу.





Анатолий Сергиенко
< a href = "mailto:%20kvantn@ukrpack.net"> E-mail: aser@comsys.ntu-kpi.kiev.ua

Операции в выражениях


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

Операции VHDL перечислены в таблице 1 в порядке их приоритета.

Таблица 1 - Операции VHDL.

Тип операции Символ или ключевое слово
Логические
Сравнения
Сдвига
Сложения
Унарные (знак)
Умножения
Различные
and, or, nand, nor, xor, xnor
=, /=, , >=
sll, srl, sla, sra, rol, ror
+, -, & (конкатенация)
+, -
*, /, mod, rem
**, abs, not

Логические операции имеют самый низкий приоритет. Операнды логических операций должны быть одного типа bit или boolean, или одномерного регулярного типа (векторы) из элементов типа bit или boolean. Для однозначной компиляции логических выражений необходимо использовать скобки, например:
(a or b) and C and (d or c).

Операции сравнения выполняются над операндами одинакового типа и возвращают тип boolean. Операции равенства "=" и неравенства "/=" выполняются над всеми типами. Остальные операции сравнения выполняются над перечисляемыми типами, целыми типами и одномерными регулярными типами (векторами) из элементов такого типа.

Операции сравнения выполняются над операндами одинакового типа и возвращают тип boolean.

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

При сравнении перечисляемых типов элемент, стоящий в ряду правее (старший), считается бо'льшим. При сравнении векторов сравниваются пары элементов векторов, начиная с самых левых. Если пара элементов неодинакова, то вектор с более старшим элементом считается бо'льшим. Если пара элементов одинакова то рассматривается следующая пара элементов. Например, в сравнении векторов битов "0111" >="01011" результат будет true.

Операции сдвига выполняют сдвиг вектора битов на число разрядов типа integer. Например, результатом выражения ("100110" sra 3) является вектор "111100" , т.е. происходит арифметический сдвиг вправо на 3 разряда.

Операции сложения - вычитания "+", "-" предопределены для целых чисел и чисел с плавающей запятой. Операция конкатенции "&" применяется со всеми одномерными регулярными типами или с их элементами. С помощью этой операции векторы - операнды объединяются в более длинные векторы. Например, выражение "101" & '1' & "10" даст результат "101110".

Унарные операторы применяются к одиночным операндам. Оператор ми-нус инвертирует значение операнда. Операторы умножения "*", деления "/" приме-ня-ют-ся с целыми операндами и операндами с плавающей запятой. Операторы mod (модуль), rem (остаток) применяются с целыми числами. Операции абсолютного значения abs и возведения в степень "**" определены для целых чисел и чисел с плавающей запятой, причем показатель степени должен быть целым.

Для многих операций языка существуют функции с таким же обозначением. Эти функции выполняют аналогичные действия, что и операции, но над другими типами. Например, функция "+" из пакета numeric_bit библиотеки IEEE выполняет сложение векторов битов, которые кодируют целые числа. Такие функции перезагружают операции в зависимости от типа операндов.

При программировании для синтеза следует учесть, что правый операнд для операций "/", mod, rem может быть равным только степени двойки, а левый операнд операции "**" должен быть равен 2, так что эти операции будут означать сдвиг двоичного кода.

Для большинства операций найдутся эквивалентные функции с таким же названием, определеные в таких стандартных пакетах, как IEEE.std_arith, IEEE.numeric_std. Основным свойством этих функций является то, что они подставляются вместо операций (перезагружают их), если операнды имеют тип integer, а также std_logic_vector, signed, unsigned и другие типы, производные от std_ulogic.

Анатолий Сергиенко
E-mail: aser@comsys.ntu-kpi.kiev.ua

Операнды в выражениях.


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

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

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

Агрегат. Агрегатом называется операция, которая объединяет одно или несколько значений в значение составного типа, т.е. регулярного или комбинированного типа. Его упрощенный синтаксис:
\агрегат\::=(\связывание элементов\ {,\связывание элементов\})
\связывание элементов\::=[\альтернативы\ =>] \выражение\
\альтернативы\::=\альтернатива\ {,\ альтернатива\}
\альтернатива\::=\простое выражение\|\диапазон\|\имя элемента\| others .

Связывание элементов означает подстановку одного выражения в одно или несколько заданных полей или элементов значений составного типа. Связывание элементов может происходить в порядке нумерации элементов cсоставного типа. Тогда оно называется позиционированным связыванием. Например, в объявлении:
variable v_5: bit_vector (0 to 4):=('0', '0', '0', '1', '1');
битам 0, 1 и 2 присвоено начальное значение 0, а битам 2,3 - значение 1. Если каждый элемент связывается со своим значением по имени, то такое связывание называется поименованным. Например, для той же переменной v_5:
(3 |4 => '1' , others => '0'); или (0 to 2 => '0'; 3 to 4 => '1');

Здесь ключевое слово others означает остальные элементы значения и должно стоять последним в списке связываний. Возможны и комбинированные агрегаты, в которых первые представляют собой позиционное связывание, а остальные поименованное связывание, например,
('0', '0',3 to 4 => '1' , others => '0').

Такая альтернатива, как простое выражение, применяется только для регулярных типов и должна определять номер элемента из диапазона этого типа, например, агрегат (i => '1', others => '0') задает вектор в котором на i-м месте стоит 1, а остальные биты - нулевые.

Альтернатива \имя элемента\ применяется только для комбинированных типов, например:

type complex is record ( Re : integer; Im : integer ); end record; variable X is complex:=(Re => 1000, Im => 0);

Атрибут. У объектов языка имеется некоторое множество свойств и особенных значений. Атрибут объекта - это специальная функция, которая возвращает его особенное значение. Например, атрибут object1'left возвращает значение самого левого элемента объекта object1 перечисляемого типа. Подробнее об атрибутах будет рассмотрено в разделе, посвященном атрибутам.

Вызов функции. При вызове функции выполняется функция с заданными значениями параметров. Упрощенный синтасис вызова функции:

\вызов функции\::=\имя функции\ ([\имя параметра =>\] \выражение\ {,[\имя параметра\ => ] \выражение\});

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

Например, в пакете IEEE.Math_Real определена функция синуса:
function SIN (X : in REAL ) return REAL;
Ее вызов по аргументу вещественного типа выглядит как:
SIN(X=>MATH_2_PI* angle) или SIN(MATH_2_PI *angle) ,
где MATH_2_PI – константа, равная 2&#960, определенная в этом пакете.

Имя с индексом дает значение элемента регулярного ти-па, номер которого задается выражением в скобках. Например, vect(4) означает 4-й бит вектора vect, arr(i, j) означает элемент (i, j) двумерного массива arr.

Квалифицированное выражение. Результат выражения может принадле-жать нескольким типам одновременно. Если необходимо, чтобы этот результат принадлежал к конкретному типу, то его необходимо обозначить как квалифицированный с заданным типом. Синтаксис такого выражения:
\квалифицированное выражение\::=\имя типа\'(\выражение\)
Например, если объявлено
type vect is bit_vector(0 to 9); var X: vect;
то выражение ('1', others => '0') может принадлежать к типу векторов любой длины. Поэтому для присваивания переменной этого выражения необходимо сделать его квалифицированным:
X:=vect'('1', others => '0');
Имя-вырезка задает цепочку элементов объекта регулярного типа. Его упрощенный синтаксис:
\имя-вырезка\::=\имя\(\выражение\ to | downto \выражение\)
\выражение\ - должно вычислять значение, не превосходящее диапазон индексов объекта регулярного типа с именем \имя\. Направление изменения индекса to или downto должно совпадать с направлением, заданным в объявлении типа. Например, если объявлен сигнал:
signal A: bit_vector(15 downto 0);
то A(15 downto 8) - старший байт сигнала А.

Поле комбинированного типа. Чтобы оперировать с полем объекта комбинированного типа его вставляют в выражение согласно синтаксису:
\поле комбинированного типа\::=\имя комбинированного типа\.\имя поля\
где \имя поля\ - может представлять поле любого типа, а также его имя с индексом, имя - вырезку, агрегат. Например, если объявлены тип и сигнал:

type comp_vect is record (Re: bit_vector(0 to 15); Im:bit_vector(0 to 15)); end record; signal A: comp_vect; то A.Re(0 to 7) - старший байт поля Re сигнала A типа cоmp_vect.

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

Различают два вида преобразования типа: переход типа и вызов функции преобразования типа. Переход типа применяется для преобразования тесно связанных типов или подтипов. Такими парами типов являются, например, real и integer, integer и natural, регулярные типы с одинаковым числом элементов того же самого типа с одинаковыми диапазонами индексов. Например, при переходе из значения с плавающей запятой к целому значению:
С:=integer (123.5);
результат С округляется до ближайшего целого, т.е. до 124.

Если типы не тесно связанные, то необходимо выполнить вызов функции пре-обра-зо-ва-ния типа. Например, типы boolean и bit - не тесно связанные т.к. при-над-ле-жат к перечисляемым типам с различными множествами элементов. По-это-му, например, преобразование переменной Х типа boolean в переменную Y типа bit может выполняться функцией преобразования типов, которая включает оператор:
if Х then Y:='1'; else Y:='0'; end if;

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

Оператор цикла.


Этот оператор несколько раз выполняет последовательность операторов. Его синтаксис:

\оператор цикла\::=[\метка\:][\схема итерации\]loop

       {\последовательный оператор\}

       {next[\метка\][when \условие\];}

       {exit[\метка\][when \условие\];}

end loop [\метка\];

\схема итерации\::=while \условие\

                             | for \переменная цикла \ in \диапазон\

Метка \метка\ необязательна, она отмечает начало цикла и используется для организации вложенных циклов или для указания в каком цикле начать новую итерацию по оператору next или из какого цикла выйти по оператору exit.

По первой схеме итераций цикл, ограниченный ключевыми словами loop и end loop будет выполняться, пока условие \условие\ не примет значение false. Причем, это условие проверяется до выполнения цикла и если оно равно false, то цикл не выполняется. В примере:

variable vec: bit_vector(1 to n);

variable or_vec:bit;

variable i:natural;

i:=1; 

or_vec:='0';

while i<=n loop

          or_vec:= or_vec or vec(i);

           i:=i+1;

end loop;

вычисляется переменная or_vec, равная функции ИЛИ от всех разрядов вектора vec длины n. Если n = 0, то цикл не вычисляется. Этот пример можно записать с помощью второй схемы итерации как:

variable vec: bit_vector(1 to n);

variable or_vec:bit;

       ….

     or_vec:='0';

for i in 1 to n loop

          or_vec:= or_vec or vec(i);

     end loop;

Здесь переменная цикла i последовательно принимает значения 1,2,… из диапазона 1 to n. Если необходим обратный порядок изменения переменной цикла: n, n-1,… то этот диапазон может быть задан как:  n downto 1 . Следует отметить, что переменную цикла не нужно объявлять, как другие переменные и ей нельзя выполнять присваивания.

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

variable vec: bit_vector(1 to n);

variable numb:natural;

numb:=0;

for i in 1 to n loop

    next when vec(i)='0';

    numb:=numb+1;


end loop;

вычисляется число единиц в векторе vec.

При необходимости закончить оператор цикла до завершения всех итераций применяют оператор exit выхода из цикла. В примере

variable vec: bit_vector(1 to n);

variable numb:natural;



numb:=0;

for i in 1 to n loop

    exit when vec(i)='1';

    numb:=numb+1;

end loop;

благодаря оператору exit, находится номер самой левой единицы в векторе vec, т.е. реализована функция приоритетного шифратора.

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

signal clk: bit;

signal numb:natural;



numb<=0;

loop

    wait until clk='1';

    numb<=numb+1;

end loop;


Оператор if.


 Этот условный оператор в зависимости от заданных условий выполняет цепочки последовательных операторов, причем от условия зависит, которая из цепочек операторов выполняется. Упрощенный синтаксис оператора:

\оператор if\::=if \условие 1\ then

{\последовательный оператор 1\}

[ { elsif  \условие 2\ then

{\последовательный оператор 2\}]

[else

{\последовательный оператор 3\}]

end if;

Каждое из условий должно быть выражением, вычисляющим результат булевского типа. При выполнении этого оператора условия проверяются последовательно друг за другом пока результат условия не будет true. Тогда выполняется соответствующая этому условию цепочка операторов и выполнение данного оператора if прекращается.

Оператор case.

Этот оператор разрешает выполнение одной из цепочек последовательных операторов в зависимости от значения выражения селектора. Его упрощенный синтаксис:

\оператор case\::=case \простое выражение\ is

        when \альтернативы\ => {\последовательный оператор\}

       {when \альтернативы\ => {\последовательный оператор\}}

end case ;

\альтернативы\:= \альтернативa\{ | \альтернатива\}

В выражении селектора \простое выражение\ должен вычисляться целый резуль­тат или значение перечисляемого или регулярного типа. Это должно быть простое выражение, а не, например, конкатенация. Каждая из альтернатив \альтернатива\ должна быть такого же типа, что и \выражение\ и представлена статичес­ким выражением или диапазо­ном, например, 0 to 4. Никакие два значения, получаемые  из выражений альтернатив, не должны быть равны друг другу, т.е. множества альтернатив не перекрываются. Последней альтернативой может быть ключевое слово others, которое указывает на не перечисленные альтернативы. Если слово others не применяется, то в альтернативах должны быть перечислены все возможные значения, принимаемые в селекторе \выражение\.  

Пример оператора case:

variable sel, a: integer 0 to 9;

………….

case sel is

when 0 => a <= 0;

when 1½2½3 => a <= 1;

when 4 to 7  => a <= 2;

when  others  => a <= 3;

end case;

Пустой оператор – оператор null – не выполняет никаких действий и может быть вставлен в любом месте программы как последовательный оператор. Например, если в операторе case по каким-то альтернативам не нужно ничего выполнять, то ставится этот оператор:

case sel is

when 0 => a <= 0;

when 1 to 9 => a <= b;

when  others  => null;

end case;



Оператор ожидания события wait.


На этом операторе выполнение процесса останавливается, в момент остановки выполняются присваивания сигналам и процесс продолжает исполнение при появлении события, которое выбирается этим оператором. Синтаксис оператора wait:

\оператор wait\::=wait [on \имя сигнала\ {,\имя сигнала\}]

         [until \булевское выражение\] [for \выражение времени\];

где ключевое слово on начинает список чувствительности, until - условие ожидания, а for - задержку ожидания. По оператору

wait on CLK, RST;

продолжение выполнения процесса начнется по событию изменения сигналов CLK или RST. По оператору

wait until CLK='1';

продолжение начнется в момент изменения состояния CLK из '0' в '1', т.е. по фронту этого сигнала. Оператор

wait for CLK_PERIOD;

остановит процесс на время, заданное переменной CLK_PERIOD типа time.

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



Описание use.


Объекты языка, объявленные в подпрограмме, процессе, пакете и объекте проекта видимы только в границах этих структурных единиц программы. Для того, чтобы в данной структурной единице был видимый объект, объявленный в другом месте, используется описание use. Его синтаксис:

\описание use\::= use \селективное имя\ {, \селективное имя\ };

\селективное имя\::= \имя1\. \имя2\

\имя2\::= \идентификатор\ | \символьный литерал\ |all

Здесь \имя1\ представляет собой обозначение места, где находится объект, который должен быть видимым. Это идентификатор библиотеки и идентификатор пакета в ней, разделенные точкой. Идентификатор – название объекта, который должен быть видимым, символьный литерал – символьное имя функции, например, "*".  Ключевое слово all означает, что видимы все бъекты, объявленные в указанном месте. Например, чтобы были видимы функции сложения и вычитания из пакета std_logic_arith библиотеки IEEE используют

use IEEE.std_logic_arith."-",  IEEE.std_logic_arith."+" ;

а если все объявления из этого пакета должны быть видимыми то используют

use IEEE.std_logic_arith.all;



ОЗУ в ПЛИС


Для реализации в ПЛИС модулей ОЗУ предусмотрено две возможности. Первую возможность предоставляет каждая ЛТ, которая может быть сконфигурирована как 16-битовое синхронное ОЗУ. Две соседних ЛТ могут быть сконфигурированы как 16-битовое двухпортовое ОЗУ с записью и чтением по одному адресу и чтением по другому адресу, как показано на рис. При этом для реализации синхронного режима записи входной бит данного, сигнал записи и адрес запоминаются в триггерах - защелках, а для чтения по второму адресу из блока второй ЛТ используется только мультиплексор чтения.

Для наращивания емкости памяти выходы нескольких КЛБ с модулями ОЗУ через тристабильные буферы подключаются к общим шинам. При этом требуется дополнительное оборудование только для построения схемы дешифрации адреса, которая выдает сигналы выборки той или иной ЛТ для записи, а также того или другого тристабильного буфера для чтения. Такое ОЗУ распределено по площади кристалла и поэтому названо Distributed RAM.

Если ЛТ запрограммировать как примитив SRL16, то из ее триггеров будет реализован 16-разрядный сдвиговый регистр с однобитовым входом и программируемым номером выходного разряда, т.е. память FIFO регулируемой длины.

Вторую возможность предоставляют отдельные блоки памяти BlockRAM. В ПЛИС серии Virtex они могут быть сконфигурированы как ОЗУ объемом 256 16-разрядных слов, 512 8-разрядных слов, и т.д. Эта память может быть запрограммирована как однопортовая или как полностью двухпортовая память. Начальное состояние этой памяти задается при ее конфигурировании, поэтому она может быть использована также как ПЗУ.



Параллельный оператор assert.


Этот оператор имеет такой же синтаксис, как и соответствующий ему последователь­ный оператор. Он выполняется точно так же, как и процесс, в исполнительной части которого стоит последовательный оператор assert  с таким  же содержанием.

Объект проекта описывается набором составных частей проекта, таких как: объявление объекта, тело архитектуры объекта. Не все знают, что в исполнительной части объекта проекта, которая открывается словом begin, вставляются параллельные операторы, которые не выполняют присваиваний сигналам, т.е. не влияют на поведение объекта. Это, так называемые, пассивные вызовы процедуры и процессы. Наиболее частое применение этих операторов – проверка соответствия входных сигналов, поступающих через порты, заданным требованиям или соответствие включения объекта в окружение, задаваемое ограничениями на настроечные константы generic. Например, проверяется время предустановки сигнала относительно фронта синхросерии, соответствие его уровней, разрядность входных данных и т.п. Так вот, при несоответствии сигналов или настроечных констант, оператор assert выдает сообщение об ошибке.  

Рассмотрим пример объявления объекта RS-триггера:

entity RS_FF is

   generic(delay:time);

   port(R, S: in bit;

        Q: out bit:='0';

        nQ: out bit:='1');

begin

      assert (R and S) /='1' report" In RS_FF R=S=1" severity error;

end entity RS_FF;

В нем настроечная константа delay задает параметр задержки, например, от входа до выхода, который будет подставлен при компиляции на этапе связывания компонентов.  Порты R,S имеют режим ввода in, а порты Q, nQ – режим вывода out. При единичных сигналах на обоих входах, т.е. когда RS – триггер функционирует неправильно, оператор assert выдает сообщение об ошибке.

Перезагрузка процедур и функций.


 В языке VHDL допускается определять несколько процедур и функций с одинаковыми названиями. При вызове функции или процедуры из числа функций или процедур с одинаковым названием выбирается такая, которая подходит по типам и числу входных и выходных параметров. Такая функция перезагружает (overloads) остальные функции. Перезагрузка процедур и функций удобна при вычислениях с различными типами. Например, над типами integer, real, подтипами signed, unsigned определены одни и те же арифметические функции, но имеющие различное сочетание типов аргументов и результатов.

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

function "and"(x1,x2:bit) return boolean is  

begin 

             return (x1 and x2) ='1';

      end;

Если эта функция объявлена, то теперь транслятор не выдаст сообщения об ошибке при выполнении оператора if, вызывающего эту функцию:

variable a,b,c: bit;

if (a and b and c) then

end if;

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

По каким причинам VHDL используется в современных САПР микроэлектроники?


Исторически сложилось, что в микроэлектронной индустрии наибольшее распространение получил язык Verilog. Полтора десятилетия назад этот язык выиграл конкурентную борьбу с другими языками задания ВУ, благодаря небольшим требуемым вычислительным ресурсам прежних рабочих станций и достаточно точным результатам моделирования СБИС. VHDL - более универсальный и гибкий язык, но он проигрывал в быстродействии языку Verilog, особенно при моделировании на уровне вентилей и транзисторов. VHDL получил широкое распространение в университетах и исследовательских учреждениях, так как это строгий, стройный, универсальный и расширяемый язык. Так, например, появились пакеты VHDL для аналогового моделирования, моделирования многозначной логики. Кроме того, симуляторы VHDL были гораздо дешевле симуляторов Verilog.

Все современные САПР микроэлектроники имеют компиляторы как с Verilog, так и с VHDL. Программист, освоивший VHDL, без особого труда может перейти к программированию на языке Verilog. В отличие от обратного.



Порт.


 Порт представляет собой интерфейсный сигнал объекта проекта. Как и в декларации сигнала, в декларации порта указывается его идентификатор, тип, начальное значение. Дополнительно указывается режим работы: in - прием, out - передача, inout - прием и передача, buffer - передача и использование  как сигнал-операнд внутри объекта проекта и link – двунаправленное соединение с другим портом с таким же режимом. Сразу укажем, что режим link - анахронизм, введенный на заре VHDL с целью дать возможность моделировать аналоговые схемы. Сейчас аналоговый VHDL для описания схем использует другие средства. Упрощенный синтаксис объявления портов объекта проекта следующий:

\объявление портов объекта\::=port (\объявление порта\

                                                {; \объявление порта\});

       \объявление порта\::=\идентификатор\: in |out|inout|buffer|link \тип\

                                [:=\начальное значение\]      .



Последовательный оператор присваивания


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

Здесь результат \приемник\ может быть имя (идентификатор), например, var, имя с индексом, как var(1), вырезка, как var (0 to 1), поле, как rec.var или агрегат, как (Re, Im).

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

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

При присваивании части элементов сигнала составного типа или перечисляемого типа, например, имени с индексом, вырезке считается, что выполнено присваивание всем элементам сигнала, причем те элементы, которые не указаны в операции присваивания, принимают старое значение. Например, по фрагменту программы
signal d:bit_vector(0 to 7);
………….. d others => '0');
d(0 to 3) d(4 to 5) wait
сигналу d будет присвоено значение "00111100".

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

Если пользоваться пакетом IEEE.STD_LOGIC_1164, то сигнал, объявленный как std_logic, можно присваивать в разных процессах, так как в этом пакете есть функция разрешения для такого типа сигналов.

Присваивание сигналу при моделировании.

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

\присваивание сигналу\::=\приемник\ transport |[reject \выражение времени\] inertial \график\::= \выражение\ [after \выражение времени\] {, \выражение\ [after \выражение времени\] }

Здесь график (waveform) представляет собой запись, состоящую из одной или нескольких пар: величина сигнала – задержка сигнала. В первой паре задержка может не указываться, подразумевается, что она нулевая.

Cпособ задержки transport означает, что при присваивании сигналы, представленные в графике, будут задержаны подобно тому, как сигнал задерживается в линии задержки или проводниках. Величина задержки отсчитывается относительно момента остановки процесса и задается выражением \выражение времени\, имеющем тип time.

Способ задержки inertial реализует поведение задержки в источнике сигнала, который не реагируют на слишком короткие входные импульсы. При этом фразой reject задается минимальная ширина импульса, которая выдается источником. Если этой фразы нет, то минимальная ширина импульса задается в фразе after. По умолчанию в операторе применяется способ задержки inertial. Действие оператора иллюстрируют следующий ряд примеров.
Yafter 10 ns;
- значение сигнала X на момент запуска процесса присвоится сигналу Y с задержкой 10 нс, при этом импульсы шириной менее 10 нс будут подавлены.
Yafter 10 ns, '0' after 20 ns, '1' after 30 ns;
- сигналу Y сначала присвоится 0, через 10 нс – 1, через 20 нс – 0, и через 30 нс – 1, например, это задание тестовой последовательности сигнала.
Yafter delay_sum;
- сигналу Y сначала присвоится А, а через задержку, определяемую статическим выражением delay_sum – сумма сигналов А и В.
Ytransport X after 1000 ns;
- модель линии задержки сигнала Х с задержкой 1 мкс.
Yreject t_rej inertial А and B after t_d;
- моделирует вентиль "И" с задержкой t_d , который не пропускает импульсы короче t_rej.

Программистская модель вычислителя VHDL


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

Он знает, что VHDL - это язык программирования. Но у него возникает вопрос, программирования чего? При программировании на Си программист должен представлять, что он с помощью этого языка описывает задуманный алгоритм для его реализации на неймановской модели ЭВМ, содержащей, АЛУ, регистровую, оперативную, дисковую память и т.д., что существуют определенные типы данных и механизмы доступа к ним. Другими словами, он программирует некоторую программистскую модель вычислителя для реализации данного языка. Безусловно, для успешного программирования на этом языке необходимо досконально знать программистскую модель соответствующего вычислителя, т.е. его архитектуру.

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

Наиболее полно программистская модель вычислителя VHDL описана в руководстве к стандарту языка (VHDL'93. IEEE Standard VHDL Language Reference Manual или сокращенно - LRM) . В нем параллельно с описанием синтаксиса и семантики всех языковых конструкций приводятся объяснения их реализации в модели вычислителя. Но, изучая это руководство, с первого раза, трудно постичь основы этой модели. LRM предполагает, что читатель будет его листать из начала - в конец, из конца - в середину, из середины - вперед и т.д. несколько итераций, пока не возникнет понимание целостной картины языка. Наверное, за это VHDL и не любят, так как такая методика его освоения вызывает к нему отвращение. С другой стороны, тот, кто постиг основы VHDL, чувствует себя более свободным в обращении с ним.

Ниже описывается упрощенная модель вычислителя VHDL, которая содержит основные особенности этой модели и не противоречит модели, описываемой в LRM.

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

Структура ВПЭ состоит из арифметико-логического устройства (АЛУ), ОЗУ данных (ОЗУД), ОЗУ программы (ОЗУП) и определенного количества источников (ИС) и приемников (ПС) сигналов.

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

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

В ОЗУ программы хранится программа в виде цепочки операторов. Операторы, включая условные операторы, выполняются последовательно друг за другом, как в обычных языках программирования. Но на операторах wait выполнение программы останавливается.

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

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

Такая программа записывается в VHDL-программе как один параллельный оператор, называемый процессом, а ВПЭ выполняет его как вычислительный процесс.

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

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

Верхний уровень программистской модели составляет множество ВПЭ, объе­ди­нен­ных линиями связи, по которым передаются сигналы. Общи­ми для всех ВПЭ являются консоль для связи с оператором-программистом (клавиатура и дисплей), дисковая память и ОЗУ глобальных переменных.

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

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

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

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

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

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

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

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

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

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

Реализация выражения в аппаратной модели VHDL


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

Логические операции реализуются в соответствующих элементах: and - в элементе "И", not - элементе "НЕ" и т.д. При операциях над битовыми или булевскими данными реализуются одиночные логические элементы. При выполнении операции над операндами регулярного типа каждому элементу операнда ставится в соответствие один логический элемент.

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

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

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

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

Операция конкатенации пары операндов регулярного типа соответствует объединению двух шин, пересылающих эти операнды, в одну, состоящую из исходных шин.

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

Если операнды объявлены как тип integer без диапазона, то им соответствуют 32-разрядные типы и соответствующие 32-разрядные схемы реализации операций. Для минимизации оборудования рекомендуется принять объявление переменной с диапазоном: например, если переменные объявлены как :
variable a, b: integer range (-128 to 127);
то выражение a+b выполняется на 8-разрядном сумматоре.

Сложное выражение от нескольких операндов при отсутствии скобок и с равноприоритетными операциями выполняется последовательно слева направо. Ему соответствует схема из цепочки модулей, выполняющих эти операции. Вставка скобок в это выражение задает приоритет выполнения операций, который отображается в аппаратную схему. Благодаря этому результирующая схема имеет вид дерева из модулей, задержка логических схем которого может быть намного меньше, чем в исходной схеме. На рис. показаны аппаратные схемы, соответствующие выражениям a+b+c+d и (a+b)+(c+d).

">

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

Схемы для ускорения арифметических операций


В ЭКЛБ две ЛТ и два триггера соединены вместе через схему ускоренного переноса и два однобитных полусумматора. Эти схемы позволяют эффективно реализовать многоразрядные параллельные сумматоры, а на их основе - всевозможные счетчики и АЛУ.

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

Следует добавить, что в новой серии VirtexII аппаратно реализованы умножители 18 на 18 разрядов.



Шины с тремя состояниями


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

Несмотря на это, в ПЛИС фирмы Xilinx всё-таки широко применяются шины с тремя состояниями, хотя это существенно повышает их себестоимость. Зато, во-первых, проще выполнить переход от проекта схемы на плате к проекту системы на кристалле. Во-вторых, ВУ с общими шинами, к которым подключено несколько десятков модулей, имеет аппаратные затраты в несколько раз меньше, чем такое же ВУ, в котором шины заменены на эквивалентную схему из системы мультиплексоров. В-третьих, с помощью общих шин эффективно реализовать встроенное распределенное ОЗУ, о котором пойдет речь ниже.

Для реализации общей шины каждый КЛБ имеет два буфера с тремя состояниями BUFT , которые через транзисторы-перемычки могут подключаться к общим шинам, проходящим вдоль всего кристалла. В обычных шинах третье состояние характеризуется уровнем, находящимся между уровнями логической 1 и логического 0. Но если такую шину реализовать внутри микросхемы, то в случае, когда все тристабильные буферы будут в третьем (закрытом) состоянии, их выходные транзисторы будут полуоткрытыми и могут выйти из строя. Для исключения такого электрического режима в ПЛИС общая шина нагружена на концах специальной триггерной схемой - Weak Keeper , которая выводит уровень шины или к уровню H, или к уровню L (слабые 1 или 0), если все буферы закрыты.

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



Система синхронизации


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

Для надежного функционирования ПЛИС синхросигнал должен подаваться через вывод GCLKPAD и попадать в сеть синхросерии через буфер GCLKBUF. В ПЛИС предусмотрено 4 вывода GCLKPAD, размещенных на противоположных сторонах ее корпуса. Синхросигнал может вырабатываться и внутри ПЛИС, но в этом случае его следует завести в сеть синхросерии через глобальный буфер BUFG.

С помощью спроектированного синхронного автомата, сконфигурированного в ПЛИС, можно изменять частоту и фазу синхросерии. Но в этом случае ее временные параметры будут недостаточно стабильными и поэтому такой подход обычно не применяется. Для надежного регулирования частоты синхросерии в ПЛИС включают делители частоты синхросерии с автоподстройкой - блоки CLKDLL. На рис. показана типичная схема его включения. Блок CLKDLL обеспечивает умножение частоты синхросерии в 2 раза, сдвиг ее фазы на 90, 180 и 270 градусов, деление на 1.5, 2, 2.5, 3, 4.5, 8 и 16.



Спецификация функции.


Спецификация функции имеет следующий синтаксис:

\спецификация функции\::=[pure | impure] function \имя функции\ |\знак функции\

                                     [(\список параметров\)] return \тип параметра\ is

        {\объявление в подпрограме\}

begin

       {\последовательный оператор\}

        return \выражение\;

end [function][\имя функции\];

В ней знак функции – символ в кавычках, например, "+", список параметров – такой же, как в процедуре за исключением того, что режимы параметров out и inout не допускаются. После ключевого слова return в объявлении функции указывается тип возвращаемого параметра. Объявления в функции могут быть такими же, как в процедуре. Выполнение функции должно оканчиваться оператором return, вычисляющим выражение возвращаемого параметра.



Спецификация процедуры.


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

\спецификация процедуры\::=procedure \имя процедуры\[(\список параметров\)] is

{\объявление в подпрограме\}

begin

{\последовательный оператор\}

end [procedure][\имя процедуры\];

\список параметров\::=(\элемент списка\ {; \элемент списка\})

\элемент списка\::=[constant | variable | signal ]

          \идентификатор\{,\идентификатор\}: [in | out | inout] \тип параметра\

           [ := \статическое выражение\]

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

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

Объявленными в процессе могут быть: объявление и тело другой процедуры или функции, объявление типа и подтипа, объявление константы, переменной, файла, псевдонима, объявление и спецификация атрибута, объявление группы, описание use.

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

       process(a1,a2,a3)

          variable b1,b2,b3:integer; 

          procedure sort2(variable x1,x2:inout integer) is  

                variable t:integer;

          begin

                if x1>x2 then

                   return;

                else

                   t:=x1; x1:=x2; x2:=t;

                end if;   

          end procedure;

        begin                

          b1:=a1; b2:=a2; b3:=a3;

          sort2(b2,b3);

          sort2(b1,b2);

          sort2(b2,b3);

          c1<=b1; c2<=b2; c3<=b3;           

       end process;

Здесь процедура sort2 выполняет сортировку двух переменных х1, х2, которые являются входными – выходными формальными параметрами процедуры. Вызов процедуры выполняется с позиционным связыванием.

Оператор return досрочно прерывает исполнение процедуры. Последовательный оператор return -оператор возврата из подпрограммы – немедленно прерывает выполнение процедуры или вызова функции и возвращает управление в программу, вызвавшую процедуру.



Статические выражения


Структура виртуальной параллельной вычислительной системы и ее параметры формируются при компиляции программы VHDL и остаются неизменными в процессе ее исполнения. Точнее, это происходит на последнем этапе – этапе связывания объектов (elaboration). В программах часто встречаются выражения, от результатов которых зависят структура и параметры системы. Это например, настроечные переменные (generic), определяющие порядок включения блоков, их разрядность. Результаты этих выражений должны иметь конкретные значения перед исполнением программы и не должны зависеть от входных данных. Такие выражение получили название статических. Другими словами, непосредственно перед моделированием статическое выражение должно быть вычислено до константы или приведено к идентификатору . Некоторые операторы, например, case, вставки компонента, требуют, чтобы в них входили статические выражения. Например, если объявлены сигналы
signal n: integer;
signal A: bit_vector(16 downto n+1);
то на момент начала моделирования операнд n неизвестен и симулятор будет пытаться подставить n= -2147483647, что вызывает аварийную остановку симулятора при размещении сигнала А в памяти, т.е. здесь выражение n+1 – не статическое.

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

В предыдущем примере симулятор может работать, если у сигнала n было задано начальное нулевое значение. Но для синтеза такая программа не годится, так как, во-первых, присваивание начального значения при синтезе игнорируется или запрещается, во-вторых, в аппаратуре должны быть четко заданы разрядность регистров и шин, объем памяти.

Структура КЛБ


В базовой серии ПЛИС XC4000 фирмы Xilinx основной единицей оборудования считается КЛБ, состоящий из двух триггеров и двух ЛТ. В новых сериях ПЛИС количество триггеров и ЛТ увеличилось вдвое и вчетверо. Чтобы оставить для всех серий одну и ту же единицу оборудования, условились называть КЛБ из двух триггеров и двух ЛТ эквивалентным КЛБ (ЭКЛБ) или CLB slice. Таким образом, КЛБ серии Virtex состоит из двух ЭКЛБ, а серии VirtexII - из четырех ЭКЛБ .



Технология разработки систем на кристалле


Согласно известному закону Мора, количество транзисторов на кристалле СБИС с каждым годом увеличивается приблизительно на 60%. С определенного момента времени то оборудование, которое размещалось на одной печатной плате, стало возможным поместить на одном кристалле (рис.2). Причем это становится выгодным, благодаря уменьшению общей стоимости, числа необходимых микросхем, энергопотребления, повышению надежности. Таким образом, на одном кристалле размещается не только конкретное функциональное устройство, например, центральный микропроцессор, но и другие, такие как АЦП, ОЗУ, ПЗУ, блоки цифровой обработки сигналов, интерфейсные узлы и т.п., дополняющие его до законченной системы блоков. Поэтому такое ВУ принято называть System On the Chip (SOC) - системой на кристалле (СНК).

СНК это, как правило, заказная СБИС. Чтобы разработка СНК себя окупила, необходимо реализовать десятки и сотни тысяч СБИС. Проект ВС, реализованный на ПЛИС, может быть выгодным при партиях в десятки и сотни экземпляров, благодаря дешевизне разработки и производстава такой ВС. Разработка такой ВС как минимум в 2 раза длится быстрее, чем проектирование СБИС. Это обусловило бурное распространение ПЛИС как элементной базы СНК.

Наиболее трудоемкими и ответственными этапами разработки СНК выступают этапы структурного проектирования и верификации соответствия ВС заданным алгоритмам функционирования. Поэтому эффективность САПРов микросхем и производительность разработчиков, выполняющих проектирование на уровне регистровых передач, постоянно растет приблизительно на 20% в год. Но начиная с середины 90-х годов, производительность разработчиков стала заметно отставать от роста сложности СНК .

Первым направлением улучшения технологии разработки СНК, направленным на уменьшение зазора между ростом производительности проектирования на уровне регистровых передач и ростом сложности СНК, является применение крупных библиотечных вычислительных модулей (Intellectual Property Cores). Эти модули должны быть надежно повторяемыми и настраиваемыми под решаемые задачи в ряде проектов СНК.
Повторное применение таких модулей (IP Core reuse), которые можно назвать вычислительными заготовками за их функциональную и технологическую адаптируемость, позволяет уменьшить трудозатраты и сроки проектирования СНК.

Второе направление - это разработка САПР совместного проектирования аппаратно-программного обеспечения (Hardware - Software Codesign). Архитектура СНК, как правило, включает в себя микропроцессорное ядро с периферийными устройствами в различном сочетании. Обычно процесс разработки ВУ с такой архитектурой состоит из трех последовательных этапов: разработки матобеспечения микропроцессора, проектирования электрической схемы аппаратуры и стыковки матобеспечения с аппаратурой. Для ускорения проектирования разрабатывают САПР, которая не только обеспечивает совместное выполнение этих этапов, но и моделирование работы СНК и ее верификацию в комплексе.

Наибольшее ускорение разработки СНК может дать внедрение САПР непосредственного отображения алгоритмов в аппаратуру, т.е. САПР системного проектирования. Например, такая САПР может включать в себя трансляцию программы с языка высокого уровня, например, С++ , с автоматическим разделением вычислительных задач между микропроцессорным ядром и спецпроцессорами и другими периферийными устройствами.


Тело пакета.


Тело пакета необходимо приводить в паре с объявлением пакета, если в последнем объявлены подпрограммы или отложенные константы. Оно имеет синтаксис:

\объявление пакета\::= package body \идентификатор\ is

                                  {объявление в теле пакета}

                                    end [package body][\идентификатор\];

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

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

package short_boolean is

    constant b0:boolean:=false;

    constant b1:boolean:=true;

   function b(x:bit) return boolean ;

   function "not"(x:bit) return boolean ;

   function "and"(x1,x2:bit) return boolean ;

   function "or"(x1,x2:bit) return boolean ;

end package;

package body short_boolean is

   function b(x:bit) return boolean is

   begin 

             return x ='1';

   end;

   function "not"(x:bit) return boolean is  

   begin 

             return x ='0';

   end;

   function "and"(x1,x2:bit) return boolean is  

   begin 

             return (x1 and x2) ='1';

   end;

   function "or"(x1,x2:bit) return boolean is  

   begin 

             return (x1 or x2) ='1';

        end;

   end package body;

Теперь, если данный пакет присоединить к объекту проекта с помощью описаний library и  use, то подстановка констант и функций этого пакета во многих местах, например, в операторах if , when сокращает запись программы.

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

Типы


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

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

Перечисляемый тип определяется как список (перечисление) всех возможных значений данного типа. Объявления этого типа выглядит как: type \имя типа\ is (\перечисляемый литерал\ {,\ перечисляемый литерал\});

Здесь текст в фигурных скобках может повторяться 0,1,2,… раз.

Элементы списка литералов нумеруются при компиляции слева - направо, начиная с нуля. Например, объявление
type \направление\ is (\налево\,\прямо\,\направо\);

означает, что состояния идентификатора \направление\ будут кодироваться так, что \налево\ соответствует 0, \направо\ - 2.

Целый тип. Объявление этого типа выглядит как:
type \имя типа\ is range \диапазон целых\;

где \диапазон целых\::=\выражение\ to\выражение\
|\выражение\downto\выражение\ .

Выражение целого типа в диапазоне должно быть вычислимо в период компиляции. Максимальный диапазон целых задается как:
-2147483647 to 2147483647.

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

Регулярный тип представляет собой множество элементов одинакового типа. Различают неограниченные и ограниченные регулярные типы. Неограниченный тип объявляется как:

type \имя регулярного типа\ is array (\имя типа диапазона\range<>) of \имя типа элемента\; где \имя типа диапазона\ - имя типа integer или какого-либо подтипа от integer.

Ограниченный регулярный тип объявляется как:

type \имя регулярного типа\ is array (\диапазон целых\ of \имя типа элемента\);

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

Представителя одномерного регулярного типа обычно называют вектором. VHDL допускает многомерные регулярные типы или многомерные массивы. В их определениях диапазоны индексов перечисляются через запятую, например:
type matrix is array (integer range <>, integer range <>) of integer.

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

type \имя комбинированного типа\ is record \имя элемента\:\тип элемента\; {\имя элемента\:\тип элемента\;} end record[\имя комбинированного типа\];

Физический тип представляется целым числом, единица которого имеет вес единицы измерения некоторой физической величины. Наиболее распространенным физическим типом в VHDL является время tіme, которое измеряется в фемтосекундах (fs), пикосекундах (ps), наносекундах (ns) и т.д. Объекты физического типа, как правило, не синтезируются, но они могут участвовать как операнды в вычислениях констант других типов.

Другие типы объектов.

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

Подтип.

Подтипом называется тип с дополнительными ограничениями. Объявление подтипа имеет следующий упрощенный синтаксис:
\подтип\::=subtype \имя подтипа\ is \базовый тип\ [\ограничение\];

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

Предопределенные типы данных.

Основные типы данных VHDL определены в пакете STANDARD, который подключается к проекту по умолчанию. Вот так в нем определены некоторые стандартные типы объектов:

type boolean is (false, true); type bit is ('0', '1'); type integer is range -2147483647 to 2147483647; subtype natural is integer range 0 to 2147483647; type bit_vector is array (natural range <>) of bit;

Следует заметить, что тип integer покрывает все значения, представляемые 32-битовыми словами, кроме одного: -231 .

Также определены подтип positive, включающий положительные значения типа integer, тип character, как набор букв, цифр и знаков, включая буквы альтернативного алфавита,тип string, как одномерный регулярный тип из элементов типа character.

Топология ПЛИС


На площади кристалла ПЛИС размещены матрица конфигурируемых логических блоков (КЛБ или CLB), матрица отрезков линий межсоединений, покрытых матрицами из полевых транзисторов - перемычек. По краям кристалла размешены блоки настраиваемых ОЗУ - BlockRAM. По периметру кристалла размещены блоки ввода-вывода сигналов (IOBs), а также периферийный канал линий межсоединений, называемый Versaring, предназначеный для соединения КЛБ с произвольным IOB линией связи с малой задержкой.



Триггер


В ПЛИС используются программируемые D-триггеры. При конфигурировании можно задать такие режимы работы триггера, как триггер с начальным сбросом (R) или начальной установкой (S), с записью по фронту или спаду синхросерии, с разрешением или без разрешения записи.

После окончания конфигурирования ПЛИС выдает сигнал общего сброса GSR, который устанавливает все триггеры в 0 или 1.



В чем преимущества VHDL над схемным проектированием?


Проектирование больших вычислительных устройств (ВУ) - С помощью VHDL проще и быстрее ввести и проверить большой проект. Десятью строками VHDL можно описать как 1, так и 100000 триггеров. Микросхему с интеграцией более 10000 вентилей разработать только с помощью электрических схем очень трудно по причине громоздскости схем.

Проект на VHDL -объединение структуры ВУ и алгоритма его функционирования. Для ВУ, описанного на VHDL, необязательно выполнять проверку правильности его функционирования, например, путем его макетирования. Чтобы определить, правильно ли ВУ выполняет заданный алгоритм, достаточно его VHDL -программу запустить на исполнение в симуляторе VHDL. Соответствующие САПР преобразуют VHDL-описание в комплект документации для изготовления работоспособного устройства.

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

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

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

Проект на VHDL - портативный проект. Разработанный для одной элементной базы, проект ВУ без труда переносится на другую элементную базу, напр. СБИС с различной технологией.

Проект на VHDL - долгоживущий проект. Электрическая схема всегда разрабатывается под конкретные элементную базу и интерфейс. Так как элементная база сменяется за период 2-5 лет, за этот же период устаревают и электрические схемы, ее использующие. Проект ВУ на VHDL может быть повторно использован через несколько лет. Хорошее техническое решение (напр., изобретение), описанное на VHDL, может быть востребованным в течение десятилетий.

VHDL - универсальное средство описания ВУ на уровнях: алгоритмическом, структурном, регистровых передач (RTL) и потоков данных (dataflow), логическом, аналоговых схем.

Важнейшими качествами VHDL в САПР выступают следующие:


Гибкость. Проект, описанный на VHDL, может быть легко настроен под конкретные задачи потребителя. Универсальный язык. VHDL - общепринятый язык для всех основных фирм - изготовителей микросхем ПЛИС, ПЛМ, заказных СБИС как стандартный язык для задания сложных проектов. Проектирование с VHDL - устойчивая тенденция в инженерной технологии. Существуют компиляторы, транслирующие VHDL- программы в эквивалентные им Verilog - программы.

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

Стандартное подключение блоков. Конструкции языка, такие как entity, port map, configuration, обеспечивают надежную и быструю стыковку блоков, разработанных разными фирмами и разработчиками, в различном сочетании.

Стандартное тестирование. На всех этапах разработки выполняется тестирование по одной методике одними и теми же тестами.

VHDL - стандарт будущего. Все новые САПР основаны на технологии трансляции описания ВУ на языке описания аппаратуры. Использование VHDL - гарантия того, что через 5 и 10 лет найдется САПР, поддерживающая старые разработки.

VHDL для синтеза (new)





VHDL - хобби


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

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

Как только я познакомился с языком VHDL и ПЛИСами, я понял, что это как раз то, чего мне с детства не хватало. Было сделано несколько проектов, пришел опыт. Но интерес к языку всё возрастал. Интерес толкал жонглировать операторами языка при реализации разных штучек, не нужных в работе, но оригинальных в исполнении и эффектных в функционировании. VHDL и ПЛИС - это как кисти и мольберт для художника. VHDL стал моим хобби. Хорошо, когда работа - хобби, а хобби - работа.

Информация о VHDL и ПЛИС занимает достойное место в интернете. Это: конференция comp.arch.fpga, конференция comp.lang.vhdl, конференция http://server.vhdl.org/viuf/ журнал VHDL Times On-Line: http://vhdl.org/vhdl_intl/vltimes/ журнал Programmable Logic News & Views: http://www.plnv.com/ http://www.vhdl-online.de http://www.stefanVHDL.com http://www.opencores.org http://www.free-ip.com http://www.aldec.com.ua и по многим другим адресам.

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

Возврат из процедуры или функции.


Оператор возврата из подпрограммы – последовательный оператор return – немедленно прерывает выполнение процедуры или вызова функции и возвращает управление в программу, вызвавшую процедуру.



Вычислительные заготовки


В крупных фирмах, долгие годы занимающихся разработкой СБИС, а теперь и СНК, наработаны большие библиотеки стандартных модулей, как-то: ОЗУ, АЛУ, периферийные устройства. В новых проектах СНК некоторые блоки приходится разрабатывать заново, а остальные - берутся из библиотеки. При этом если модуль неясно описан, не имеет хорошего интерфейса, документации, комментариев, испытательного стенда с надежными тестами, то он повторно применяться не будет. Если такой модуль изначально оформлен в виде вычислительной заготовки, то он будет без лишних проблем вставляться в любой новый проект. Более того, лицензию на него можно предлагать другим фирмам - разработчикам СНК. Рисунок иллюстрируют суть вычислительной заготовки (IP core).

Вычислительные заготовки различаются по степени гибкости своей настройки под условия потребителя как:

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

Гибкие заготовки обычно подстраиваются к условиям нового проекта в широких пределах и независимы от его технологии (серия ПЛИС, технология СБИС). Минимизация аппаратурных затрат вычислительных заготовок обеспечивает не только уменьшение стоимости СНК, но и уменьшение его энергопотребления, что является важным фактором для портативных и энергонезависимых приложений.

Чтобы проект ВУ был принят как гибкая вычислительная заготовка, он должен иметь:

исчерпывающую и ясную документацию; текст описания на VHDL или Verilog в хорошем стиле для синтеза, заготовка должна быть настраиваемой под технические условия потребителя; хорошие средства верификации в виде испытательных стендов, исчерпывающих тестов, возможно, опытных макетов; четкую методику того, как ВУ вставлять в СНК, включающую надежные скрипты (программы на макроязыке САПР, автоматизирующие тестирование и создание жесткой или твердой заготовки) [1].

В сегодняшних условиях, чтоб быстрее перейти от идеи к "железу", эффективнее провести проектирование новой СНК, необходимо эту СНК "собрать" из имеющихся вычислительных заготовок , а отсутствующие - приобрести на рынке IP cores, который бурно развивается в последние годы. Если приобрести не удастся или если проект - исследовательский, то необходимую заготовку можно поискать, например, в банке бесплатных IP cores, что на сайте www.opencores.org. Этот банк создан по инициативе организаций, содействующих развитию технологии СНК, а также инженеров, желающих поделиться своими результатами. Если оба этих пути не устраивают, то прийдется ВУ проектировать самостоятельно и данная книга может этому помочь.

Вызов функции.


При вызове функции выполняется функция с заданными значениями параметров. Упрощенный синтасис вызова функции:

\вызов функции\::=\имя функции\ ([\имя параметра\ =>] \выражение\

                                   {,[\имя параметра\ => ] \выражение\});

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

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

function BIT_TO_INT(x:bit_vector) return natural is                      

   variable t, j:integer:=0;   

 begin 

    for I in x'reverse_range loop

         if ( x(I)='1') then

              t:=t + 2**j;

         end if;  

              j:=j+1;

         end loop;  

         return t;

       end function BIT_TO_INT;

преобразует вектор битов в целое. При этом атрибут x'reverse_range возвращает диапазон, обратный диапазону представления входного параметра. Например, если входной параметр – bit_vector(7 downto 0), то в оператор цикла подставится диапазон 0 to 7. Таким образом, получается функция, универсальная для множества различных параметров – операндов.

Ключевые слова pure и impure  обозначают идеальную и неидеальную функции. В отличие от идеальной функции, неидеальная функция может возвращать различные результаты для одинаковых наборов  входных параметров. Например, если входной параметр – глобальная переменная, то она может измениться в момент вызова функции и результат будет отличаться от ожидаемого. Поэтому глобальные переменные не могут быть операндами в идеальных функциях. Примером неидеальной функции является функция Now из пакета STANDARD, которая при вызове возвращает переменную предопределенного типа delay_length, равную текущему моменту времени моделирования. Естественно, что при различных вызовах этой функции она возвращает различные значения.



Вызов процедуры.


Вызов процедуры также представляет собой последовательный оператор. Его упрощенный синтаксис:

\вызов процедуры\::=\имя процедуры\[([\имя параметра =>\] \выражение\

                    {,[\имя параметра\ => ] \выражение\})];

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

В пакете IEEE.Math_Real определена процедура генерации случайных чисел:

 procedure UNIFORM(variable SEED1,SEED2:inout POSITIVE; variable X:out real);

Она может быть вызвана со связыванием параметров:

variable s1,s2:natural:=12345;

variable Random:real;

UNIFORM(X=> Random, SEED1=>s1,SEED2=>s2);

или без связывания параметров:

UNIFORM(s1,s2, Random);

Вызов процедуры без параметров – это просто написанное ее имя. 


  Входные параметры сигналов представляются как ссылки на сигналы. Параметру сигнала нельзя присваивать начальное значение, так как источник этого сигнала недоступен. Поэтому нельзя также использовать такие атрибуты сигнала, как  'delayed, 'stable, 'quiet или 'transaction. Выходной параметр сигнала передается в процедуру вместе с источником сигнала, в котором происходит присваивание сигналу. Это эквивалентно тому, что цепочка последовательных операторов тела процедуры копируется в процесс на место вызова процедуры с соответствующей подстановкой параметров. В отличие от вызова процедуры в обычных алгоритмических языках, в которых используется одно тело процедуры, в VHDL каждый вычислительный процесс, вызывающий процедуру, использует свой собственный экземпляр тела процедуры.

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

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