Основы программирования на VHDL
Модели вычислителей VHDL
Начинающий программист VHDL легко осваивает структурный пчшь программирования, которым формально описывается структура ВУ. Без трудностей он программирует стилем потоков данных, пыражая операторами параллельного присваивания прохождение данных через некоторую комбинационную схему. Но при переходе к поведенческому стилю, основанному на операторах процессов, нередко возникают сложности с пониманием выполнения этих опера-1оров, программированием желаемого поведения системы и отладкой составленной программы.
Он знает, что VHDL — это язык программирования. Но у него возникает вопрос, программирования чего? При программировании на Он программист представляет, что он с помощью языка описывает ипдуманный алгоритм для его реализации на модели ЭВМ, содер-жмщей АЛУ, регистровую, оперативную, дисковую память и т.д., что существуют определенные типы данных и механизмы доступа к ним. Другими словами, он программирует некоторую программистскую модель вычислителя для реализации данного языка.
Алгоритм, описанный на VHDL, как и любой другой параллельный алгоритм, представляет собой определенное множество вычислительных процессов, организованных на строго заданной модели иычислителя (рис. 17).
Составление программы VHDL означает программирование этой модели. Поэтому далее рассмотрим программистскую модель вычислителя для реализации языка VHDL. Для понимания реализации VHDL в симуляторах будет также рассмотрена модель вычислителя с точки зрения разработчика симуляторов. Наконец, будет приведена аппаратная модель реализации VHDL, т.е. модель, реализуемая в СБИС или ПЛИС.
Модель вычислителя для программирования на VHDL
Наиболее полно программистская модель вычислителя VHDL описана в руководстве к стандарту языка [1]. В нем параллельно с описанием синтаксиса и семантики всех языковых конструкций приводятся объяснения их реализации в модели некоторого виртуального симулятора. Но, изучая это руководство, с первого раза трудно постичь основы этой модели. Ниже описывается упрощенная модель вычислителя VHDL, которая не противоречит модели, описываемой в [1].
В отличие от большинства современных языков программирования, язык VHDL основан на параллельной многопроцессорной модели. Нижний уровень модели образует архитектура виртуального процессорного элемента (ВПЭ), а верхний уровень - множество ВПЭ, объединенных некоторой запрограммированной системой межпроцессорных связей.
Структура ВПЭ состоит из арифметико-логического устройства (АЛУ), ОЗУ данных (ОЗУД), ОЗУ программы (ОЗУП) и определенного количества источников (ИС) и приемников (ПС) сигналов (рис. 18).
ЛЛУ выполняет такой же набор операций, какой требуется для Iтипизации большинства языков программирования, как, например, сложение, умножение, деление с фиксированной и плавающей запя-и>И. логические операции и т.д. Кроме того, АЛУ выполняет многие друие операции, специфические для VHDL, такие как операции над днимими с заданной разрядностью, функции с многозначным логическим представлением разрядов. При выполнении операций постоянно проверяется корректность результата, и фиксируются ошибки, как-то: выход за заданный диапазон представления числа, деление на ноль и т.п.
П ОЗУ данных хранятся переменные, участвующие в вычислениях. Переменные имеют статические адреса, но можно реализовать и динамический доступ к переменным. Источники и приемники сиг-мнмов служат, в основном, для связи ВПЭ с внешним миром. При поступлении сигнала приемник фиксирует это событие. В приемнике хранится как текущее, так и предыдущее состояние сигнала. При и i.i иол нении операции с идентификатором сигнала, как с операндом, выполняется чтение приемника или источника сигнала. Источник генерирует сигнал не сразу после выполнения оператора присва-шищия, а в момент остановки ВПЭ.
li ОЗУ программы хранится программа в виде цепочки оператором. Операторы, включая условные операторы, выполняются после-допптельно друг за другом, как в обычных языках программировании. Но на операторах wait выполнение программы останавливает-с и. Такая программа записывается в VHDL-программе как один пираллельный оператор, называемый процессом, а ВПЭ выполняет его как вычислительный процесс.
Операнды оператора wait - это набор входных сигналов, назы-иасмый списком чувствительности, заданный промежуток времени пидоржки или булевское выражение. Оператор wait ожидает появления внешнего события: прихода сигналов или истечения срока заданной задержки. После появления внешнего события программа продолжает выполнение со следующего оператора. Только при выполнении оператора wait в источниках сигналов генерируются сиг-пимы, которым в программе было присвоено новое значение. После исполнения последнего оператора программа переходит к своему первому оператору.
Отдельным входом-выходом ВПЭ является шина передачи гло-шшьных (shared) переменных. Глобальная переменная может прини-
маться (участвовать как операнд) или передаваться из ПЭ (как результат операции присваивания) в произвольные моменты времени.
К ВПЭ можно подключать дисковую память. При этом операторы открытия, чтения, записи, закрытия файлов используются аналогично, как в других языках.
Верхний уровень программистской модели составляет множество ВПЭ, объединенных линиями связи, по которым передаются сигналы (рис. 19). Консоль для связи с программистом (клавиатура и дисплей), дисковая память и ОЗУ глобальных переменных используются всеми ВПЭ как обшие.
Количество ВПЭ в системе равно числу процессов в программе VHDL после ее компиляции. В структуре параллельного вычислителя столько линий межпроцессорной связи, сколько необходимо для исполнения VHDL-программы.
Как и в других языках параллельного программирования, в VHDL сигнал используется одним вычислительным процессом для сообщения другим вычислительным процессам факта исполнения некоторого события. Кроме того, сигнал используется для передачи исходных и промежуточных данных между процессами. Наконец, выбранные сигналы при исполнении VHDL-программы можно записать в своем развитии и затем воспроизвести в виде временных графиков или таблиц.
При запуске скомпилированной программы сперва все переменные принимают заданное начальное значение. Затем во всех ВПЭ начинают выполняться вычислительные процессы со своих первых операторов. При достижении операторов wait ВПЭ генерируют новые значения сигналов и останавливаются. Эти сигналы, пройдя через соответствующие им линии связи до других ВПЭ, запускают в них продолжение вычислительных процессов. Такое функционирование вычислительной системы может продолжаться неопределенно долго, пока оно не будет остановлено с консоли или не выполнится оператор assert, требующий останова. В большинстве программ VHDL один из процессов является ведущим и задает поток возбуждающих состояний сигнала для других процессов. Например, этот процесс моделирует источник исходных данных или генератор синхросигнала. Тогда ВПЭ — генератор возбуждающего сигнала — запускает смежные с ним ВПЭ. Эти ВПЭ запускают ВПЭ следующие за ними и т.д. Таким образом, по вычислительной системе проходят волны запусков. Поэтому модель вычислителя для реализации VHDL можно трактовать как волновой процессор со специализированной топологией.
Если в процессе не использованы операторы wait с установленной задержкой, то цикл запуска-остановки этого процесса выполняется почти мгновенно, а точнее — с дельта-задержкой. Здесь дельта-задержка - исчезающе малый промежуток времени, одинаковый для всех таких процессов.
Основное назначение консоли - это запуск программы на исполнение и вывод сообщений на экран, которые генерируются специальными операторами assert и report.
ВПЭ могут иметь произвольный доступ записи-чтения к памяти глобальных переменных. Эти переменные служат дополнительным средством связи между ВПЭ, так как внутренние переменные в ВПЭ недоступны для других элементов вычислительной системы. ВПЭ функционируют асинхронно относительно друг друга и поэтому невозможно задать однозначный порядок доступа к глобальной переменной от нескольких ВПЭ без искусственного введения механизмов синхронизации. Поэтому корректное использование глобальной переменной возможно, если она используется как константа или запись в нее выполняется только одним ВПЭ, причем в случае, если момент записи переменной безразличен относительно вычислительных процессов в других ВПЭ.
При программировании на VHDL необходимо учитывать следующее.
Все процессы исполняются параллельно.
а Одновременно исполняемые процессы образуют фронт волны запусков процессов. Этот фронт может передвигаться с временным шагом, равным дельта-задержке.
а Все параллельные операторы языка VHDL преобразуются в функционально эквивалентные операторы процессов, поэтому данная вычислительная модель годится для произвольной VHDL-программы.
а Структура вычислительной модели остается неизменной после компиляции программы, т.е. после своего формирования. Эта структура не зависит от сигналов и переменных, изменяемых в процессе выполнения программы, т.е. она не может перестраиваться динамически.
Область действия всех переменных (кроме глобальных) огра
ничена рамками операторов процесса. Вне процессов перемен
ные невидимы.
а Порядок доступа к глобальным переменным непредсказуем. Следует с осторожностью программировать с этими переменными.
Вычислительная модель си муля тор a VHDL
Модель вычислителя с точки зрения программиста не может быть реализована в виде реальной многопроцессорной вычислительной системы из-за чрезмерно высоких аппаратурных затрат. С другой стороны, язык VHDL разрабатывался с целью реализации в симуля-торах дискретных систем. Такой симулятор, как правило, исполняется на однопроцессорной ЭВМ. Рассмотрим архитектуру вычислителя VHDL с точки зрения разработчика симулятора.
На рис. 20 условно показана архитектура симулятора VHDL. В данной модели каждый ВПЭ реализован как отдельный вычислительный процесс (ВП). Все вычислительные процессы разделяют во времени один и тот же аппаратный ресурс - центральный процессорный элемент (ЦПЭ) микропроцессора ПЭВМ.
Все ВП разделены на три подмножества - очередь спящих процессов, очередь готовых процессов и исполняемый процесс. Большинство ВП относится к числу спящих, т.е. к ВП, для исполнения которых нет готовых входных данных. Например, такой ВП ожидает какой-либо входной сигнал из списка чувствительности его one-
ратора wait. При поступлении сигнала этот ВП переносится в очередь готовых к исполнению ВП. Один из готовых ВП, выбранный произвольно, пересылается в кэш-ОЗУ микропроцессора для исполнения. Исполняемый ВП выполняет свои операторы в соответствии с семантикой функционирования ВПЭ на ресурсах ЦПЭ микропроцессора и с использованием соответствующих библиотек процедур. При достижении оператора wait ВП останавливается. Выработанные им сигналы запоминаются и пересылаются другим ВП, которые являются приемниками этих сигналов. Затем остановленный ВП пересылается в очередь спящих процессов.
Один особенный исполняемый ВП служит диспетчером для остальных процессов. Он называется ядром симулятора и формирует очереди спящих ВП и готовых к исполнению ВП, а также выбирает ВП для исполнения. Он также рассылает сигналы от исполняемого ВП к другим ВП. Кроме того, он ведет счетчик времени моделирования Тс, выполняет связь с консолью, обслуживает обращение к дисковой памяти и памяти глобальных переменных.
Для моделирования программист создает проект — каталог с файлами VHDL, имеющий название проекта. После компиляции в проекте создается библиотека проекта, которая имеет название проекта и содержит все скомпилированные объекты проекта. После запуска программы на моделирование выполняется связывание объектов
проекта и назначение начальных значений переменным и сигналам (elaboration).
Затем запускается собственно моделирование. При этом выбранные программистом сигналы записываются в отдельной области памяти в своем развитии и могут быть отображены на дисплее в виде таблиц или графиков.
Для того чтобы сохранить семантику исполнения множества параллельных процессов, такую же, как у системы из ВПЭ, симулятор в каждом цикле моделирования выполняет следующие шаги:
1. Каждый остановленный ВП, для которого произошло новое событие, т.е. пришло новое значение сигнала, который ожидается соответствующим оператором wait,запускается на исполнение; в ВП, остановленных для ожидания задержки, проверяется окончание этой задержки и если задержка истекла, эти ВП также запускаются.
2. Каждый запущенный ВП исполняется до своей остановки на операторе wait,при этом вычисляются новые значения сигналов в операторах присваивания сигналам.
3. Вычисляется новое значение текущего времени Тв как ближайший момент времени, в который будет запущен какой-либо ВП, остановленный на операторе waitожидания окончания задержки или момент времени следующей активации источников сигнала.
4. Счетчик времени принимает новое значение Тс = Тв.
5. Каждому сигналу, для которого было вычислено новое значение, присваивается это значение, т.е. источники сигналов активизируются; эти изменения сигналов проверяются, являются ли они событиями для каких-либо ВП.
Если в следующем цикле моделирования не запускается ВП по окончанию заданной задержки или активация источников сигнала происходит без задержки, то в данном цикле счетчик времени Тс сохраняет свое прежнее значение, измеряемое в фемта-, пико- или наносекундах. В этом случае считается, что время моделирования увеличилось на дельта-задержку.
Моделирование имеет такую особенность, что серия, включающая от нуля до нескольких циклов (обычно не более 1000)с дельта-задержкой сменяется одним циклом с конкретной задержкой. Допустим, что в модели находятся два процесса, обменивающихся одной глобальной переменной. Тогда порядок обмена этой переменной
не контролируется программистом, так как он не может определить, какой из этих процессов сработает первым в серии циклов с дельта-задержкой. Для того чтобы эти процессы были запущены не в произвольном, а именно в последнем цикле с дельта-задержкой из серии циклов, причем после всех процессов, такие процессы обозначаются как отложенные (postponed).
Описанная модель симулятора является приближенной. В реальных симуляторах упомянутые процессы не имеют ничего общего с процессами и потоками, исполняемыми под управлением операционной системы. Обычно каждая новая версия симулятора отличается повышенным быстродействием. Например, для увеличения быстродействия, по результатам компиляции VHDL-программы строится ациклический граф потоков данных, вершинами которого являются процессы программы и который соответствует алгоритму, исполняемому за один главный цикл моделирования. Тогда моделирование сводится к обходу вершин этого графа.
Другой метод предполагает предсказание тех процессов, которые будут исполняться в следующем цикле моделирования. Тогда моделирование ускоряется за счет того, что проверяется готовность к исполнению не всех процессов, а только предсказанных [4].
При составлении VHDL-программ желательно иметь в виду следующее,
Даже небольшой процесс занимает в памяти несколько килобайт. Максимальное количество процессов в скомпилированной программе определяется объемом динамической памяти компьютера.
D Смена одного ВП другим ВП представляет собой смену контекста в работе ЦПЭ, которая может длиться несколько тысяч тактов ЦПЭ.
D Наибольшую долю времени занимает исполнение ВП ядра симулятора, которая возрастает нелинейно с увеличением числа ВП и числа сигналов в списках чувствительности их операторов wait. Поэтому, чем меньше процессов в скомпилированной программе и сигналов в списках чувствительности - тем быстрее выполняется эта программа в симуляторе.
D Нельзя программировать процесс без оператора wait (или без списка чувствительности), т.к. после того, как этот процесс станет активным, он монопольно захватит ресурсы ЦПЭ.
Аппаратная модель реализации VHDL
Одним из важнейших назначений VHDL является описание проектов дискретных устройств при автоматизированном проектировании микросхем. В основе технологии разработки микросхем (заказных СБИС или ПЛИС) лежит автоматическая трансляция VHDL-описания дискретного устройства в схему на логическом уровне, которая выполняется с помощью компилятора-синтезатора. Здесь под синтезом понимается получение аппаратной модели, которая исполняет исходную VHDL-программу и преобразование её в схему на логическом уровне. Причем подбор структуры модели и её логическая оптимизация по критериям минимума аппаратуры и максимума быстродействия с учетом элементного базиса целевой микросхемы выполняются автоматически.
Работа компилятора-синтезатора основана на взаимно-однозначном инъективном отображении программистской модели, отвечающей исходной VHDL-программе, в аппаратную модель. Это означает, что каждому из ВПЭ с его программой ставится в соответствие некоторый специализированный процессорный элемент (СПЭ) (рис.21), причем ПС, ИС и ИС/ПС отвечают входам, выходам и входам-выходам ВПЭ. В свою очередь, граф линий связи между ВПЭ и граф соединений между СПЭ - изоморфны (рис. 22). Так как отображение инъективно, то одна VHDL-программа может дать большое множество функционально эквивалентных схем, отличающихся по степени оптимальности и элементному базису.
Различают два типа СПЭ: СПЭ с памятью и СПЭ без неё. СПЭ без памяти представляют собой комбинационную схему, состояние выходов которой (источников сигнала) представляет собой некоторую логическую функцию от состояния её входов (приемников сигнала).
Если по семантике оператора процесса предполагается, что не все его переменные и сигналы выполняют присваивания при некотором запуске процесса, то это означает, что такие переменные и сигналы должны хранить свое предыдущее состояние при этом запуске. Поэтому эти процессы отображаются в СПЭ с памятью.
СПЭ с памятью имеют в своей структуре комбинационную схему, а также триггеры и регистры для хранения результатов и промежуточных операндов. Состояние выходов СПЭ представляет собой логическую функцию не только от состояния входов, но и от состояния регистров. Регистры могут запоминать операнды как по уровню синхросигнала (защелка), так и по его фронту (триггер).
В отличие от ВПЭ, задержка от входов СПЭ до его выходов равна величине, определяемой характеристиками элементного базиса, а не дельта-задержке или задержке, заданной оператором wait.
При отображении в аппаратуру вместо оператора каждого типа подставляется соответствующая ему логическая схема. Так, операции and ставится в соответствие логическое "И", а операции "*" -комбинационный умножитель.
На аппаратную модель реализации VHDL налагается ряд ограничений, связанных с особенностями элементной базы СБИС или ПЛИС. Эти ограничения имеют прообразы в программистской модели. В основном, они образуют множество объектов и операторов языка, которые не могут быть отображены в аппаратуру, так как не имеют в ней соответствующего эквивалента.
Например, на сегодняшний день не могут быть автоматически отображены в аппаратуру сигналы и переменные типа с плавающей запятой, динамического, файлового типа, операция деления, операторы wait с параметром задержки, операторы вывода на консоль
assert и report. Также в большинстве случаев глобальные переменные не находят своего отображения.
Некоторые значения перечисляемого типа, например, стандартного типа stcLlogic, такие как "и" - не инициализированное, "X" -неизвестное, "-" - безразличное, также не могут быть отображены в аппаратуру, а другие, как например, "н" - слабая единица или "L" -слабый ноль, отображаются, соответственно, в 1 и 0.
Не могут быть синтезированы такие языковые конструкции, для которых невозможно определить конкретную комбинационную схему или ее разрядность на период компиляции. Например, оператор цикла отображается в многоуровневую комбинационную схему, в которой число уровней равно количеству итераций. И если количество итераций неизвестно на период компиляции, т.е. не задается статическим выражением, (например, если параметр итераций вычисляется в процессе), то такую схему можно смоделировать, но построить невозможно,
Говорят, что VHDL-программа, в которой отсутствуют несинтези-руемые объекты, операторы и конструкции, написана стилем для синтеза. При составлении программы стилем для синтеза желательно принять во внимание следующее.
а Существует несколько распространенных компиляторов-синтезаторов от разных фирм-поставщиков. Эти компиляторы различаются, в частности, списком несинтезируемых элементов языка VHDL. Причем с появлением новых версий компиляторов этот список обычно сокращается.
Компиляторы-синтезаторы также существенно различаются по возможностям оптимизации отображения, набором атрибутов, управляющих синтезом, библиотеками процедур и функций, возможностями распознавания идиом языка, которые эффективно отображаются в СПЭ и адаптированы к целевой элементной базе. Например, не все компиляторы выполняют эффективно минимизацию оборудования путем разделения ресурсов. Поэтому для умелого написания программ для синтеза желательно накопить опыт работы с тем или иным компилятором.
Объекты и типы языка
Объекты и типы языка
Сигналы, переменные, константы и другие объекты языка VHDL служат для содержания некоторых значений. Эти значения могут быть присвоены объектам в одном месте и затем использованы в другом месте программы, как операнды в выражениях, функциях и т.п. Прежде чем остановиться на описании объектов, необходимо рассмотреть комментарии, литералы языка, а затем описать типы, которые бывают у объектов.
В приведенных ниже описаниях синтаксиса текст в квадратных скобках означает необязательный элемент, фигурными скобками выделяется текст, который может повторяться 0,1,2,... раз, вертикальными линиями разделяются альтернативы. Ключевые слова языка выделены полужирным шрифтом.
Комментарии
В языке VHDL комментарии начинаются двумя дефисами и продолжаются до конца строки. В книге комментарии выделены курсивом, как и во многих редакторах языка VHDL.
Литералы
В языке литералом задается такой лексический элемент, который остается постоянным в программе и принимает определенное числовое значение после компиляции. Константы, операнды в выражениях, идентификаторы представляются литералами. То, что синтаксис литерала отображает признак типа соответствующего ему объекта, является одной из особенностей VHDL.
Числовой литералпредставляет собой целое или вещественное число.
Десятичный литерал- это числовой литерал в системе счисления по основанию (базису) 10, например, 120.
Вещественный литералотличает обязательное наличие точки, отделяющей целую часть от дробной, например, 120.0, 1.20е2.
Базисный литерал- это число в системе счисления с заданным базисом от 0 до 16. Его условный синтаксис:
\базисный литерал\::=\базис\#\число в базисе\#[\экспонента\], например, 10#112# = 1б#70# = 5#422# = 2#1110000# = 2#111#е4.
Символьный литералиспользуется как значение для операторов или как элемент перечисляемого типа, например, бит. Он записывается как символ в одиночных кавычках, например, 'Г, 'F*, '@'.
Идентификатор.Идентификатор используется как имя константы, переменной, функции, сигнала, порта, подпрограммы, объекта проекта, а также как метка. Он содержит латинские буквы, с которых начинается, цифры и некоторые символы, например, однократный символ подчеркивания. Идентификаторы с одинаковым названием, но с различными заглавными и строчными буквами считаются одним идентификатором, т.е. они "нечувствительны" к высоте букв. Ключевое слово языка не может быть идентификатором.
Идентификатор может состоять из произвольной цепочки символов, в том числе из букв кириллицы. Но эта цепочка должна быть заключена между обратными косыми. Это, так называемый, расширенный идентификатор. Например:
С, A_and_B, \наш сигнал\, \а+в\, \process\
являются корректными идентификаторами.
Перечисляемый литерал.К перечисляемым литералам относятся символьный литерал и идентификатор. Из этих литералов формируется множество перечисляемого типа.
Строчный литерал.Строчным литералом является цепочка символов, заключенная в двойные кавычки, например, "абвг". Литерал битовой строки может иметь различный вид в зависимости от базиса системы счисления. Например, литералы "01111010", в"01111010", х"7А" представляют собой одно и то же значение, причем в и х означают двоичный и шестнадцатиричный базисы, соответственно.
В числовых литералах и битовых строках допускается вставлять символы подчеркивания для удобства чтения, которые удаляются при компиляции. Например, x'^BBA^CDCD", "1101_011Г\ 1_024.
Тип
Тип - это множество значений с общим признаком. VHDL - строго типизированный язык. Каждый объект объявляется своим типом и может присваивать значение только данного типа. Соблюдение строгого соответствия типов в операторах присваивания, выражениях, вызовах подпрограмм требует дополнительных усилий программиста. Но благодаря этой особенности, программы VHDL имеют высокую надежность и обеспечивают экономию времени при отладке.
Перечисляемый типопределяется как список (перечисление) всех возможных значений данного типа. Объявления этого типа выглядит как:
type\имя типа\ is (\перечисляемый литерал\
{Д перечисляемый литерал\});
Элементы списка литералов нумеруются при компиляции слева -направо, начиная с нуля. Например, объявление
type\цвет\ is (\красный\,\желтый\Дзеленый\);
означает, что состояния идентификатора \цвет\ будут кодироваться так, что \красный\ соответствует 0, \зеленый\ - 2. Целый тип.Объявление этого типа выглядит как:
type\имя типа\ is range\диапазон целых\;
где \диапазон целых\::=\выражение\ to \выражение\
|\выражение\ downto\выражение\ .
Выражение целого типа в диапазоне должно быть вычислимо в
период компиляции. Максимальный диапазон целых задается как:
-2147483647 to 2147483647.
Тип с плавающей запятойопределяется аналогично целому типу, но с диапазоном с плавающей запятой. Максимальный диапазон зависит от компилятора.
Регулярный типпредставляет собой множество элементов одинакового типа. Различают неограниченные и ограниченные регулярные типы. Неограниченный тип объявляется как:
type\имя регулярного типа\ is
array(\имя типа диапазона\гапде<>) of \имя типа элементах;
где \имя типа диапазонах — имя типа integer или какого-либо подтипа от integer.
Ограниченный регулярный тип объявляется как:
type\имя регулярного типа\ is
array (Хдиапазон целых\ of \имя типа элементах);
Неограниченный регулярный типприменяют тогда, когда заранее неизвестен диапазон типа, например, в процедуре. Но на период компиляции (точнее - на этапе связывания) диапазон объекта этого типа должен быть определен, например, при вызове процедуры с конкретным операндом.
VHDL допускает многомерные массивы. В их определениях диапазоны индексов перечисляются через запятую, например:
type MATR is array(integer range<>, integer range<>) of integer
Комбинированный типопределяет множество значений, как и регулярный тип, но эти значения могут быть разнотипными. Объявление комбинированного типа выглядит как:
type\имя комбинированного типа\ is record\имя элементах:\тип элементах; {\имя элементах:\тип элементах;} endгесо^[\имя комбинированного типа\];
Физический типпредставляется целым числом, единица которого имеет вес единицы измерения некоторой физической величины. Наиболее распространенным физическим типом в VHDL является время time, которое измеряется в фемтосекундах (fs), пикосекундах (ps), наносекундах (ns) и т.д. Объекты физического типа, как правило, не синтезируются, но они могут участвовать как операнды в вычислениях констант других типов. Задание физического типа отличает VHDL от других языков.
Другие типы объектов
Особенными типами являются тип ссылки (access)и тип файла (file).Тип ссылки позволяет манипулировать с массивами переменных, объем которых заранее неизвестен и которые создаются и ликвидируются динамически во время вычислений, как и в других языках. Тип файла обеспечивает доступ к файлам, записанным в дисковой памяти. Переменные такого типа применяют для ввода-вывода исходных данных и результатов вычислений.
Подтип
Подтипом называется тип с дополнительными ограничениями. Объявление подтипа имеет следующий упрощенный синтаксис:
\подтип\::=subtype\имя подтипах is \базовый тип\ [\ограничение\];
Здесь \ограничение\ - диапазон или подмножество, в зависимости от базового типа. Подтип используют для отождествления группы объектов. Ограничение подтипа позволяет выявить ошибки на этапе моделирования. Объекты разных подтипов, у которых один родона-чальный тип, могут участвовать в вычислениях без конфликтов типов.
Предопределенные типы данных
Основные типы данных VHDL определены в пакете standard, который подключается к проекту по умолчанию. Вот так в нем определены некоторые стандартные типы объектов:
typeboolean is(false, true);
type bit is CO', '!');
typeinteger is range-2147483647 to 2147483647;
subtypenatural isinteger range0 to2147483647;
typebit„vector is array(natural range<>) ofbit;
Также определены типы character как набор букв, цифр и знаков, включая буквы альтернативного алфавита, подтип positive, включающий положительные значения типа integer, тип string как одномерный регулярный тип из элементов типа character.
Сигнал
Сигналом является объект, который переносит значение от одного процесса к другому и вместе с ним - синхронизирующее воздействие. Сигнал может быть запомнен в своей истории и воспроизведен в симуляторе в виде графика или таблицы. Объявление сигнала выглядит как:
signal:\идентификатор\{,\идентификатор\}[:= \начальное значение\];
где - \начальное значение\ - выражение, представляющее константу, значение которой принимает сигнал перед первым запуском процесса.
Константа
Константой является объект, не изменяющий свое значение при вычислениях. После объявления константы присваивание ей значения запрещено (кроме случая отложенной константы). Пример объявления константы:
constantthousand: integer:=1000;
Переменная
Переменная - это объект, хранящий значение в пределах операторов процесса, функции или процедуры. В отличие от сигнала, присваивание переменной выполняется немедленно. Синтаксис объявления переменной:
\объявление переменной\::=
[shared] variable\идентификатор\{Дидентификатор\}:\тип\ [:=\начальное значением;
Пример объявления переменной:
variable byte_int: integer range-128 to 127:=0;
При объявлении глобальных переменных используют ключевое слово shared. Глобальную переменную можно объявлять в любом месте объявлений проекта.
Порт
В структуре программы VHDL выделяются объекты проекта, называемые entity. Их не следует путать с объектами языка. Порт представляет собой интерфейсный сигнал объекта проекта. Как и в декларации сигнала, в декларации порта указывается его идентификатор, тип, начальное значение. Дополнительно указывается режим работы: in - прием, out - передача, inout - прием и передача, buffer - передача и использование как сигнал-операнд внутри объекта проекта и link. Упрощенный синтаксис объявления портов объекта проекта следующий:
\объявление портов объекта\::=port (\объявление порта\
{; \объявление порта\}); \объявление порта\::=\идентификатор\: inI out|inout|buffer|1ink
\тип\ [:=\начальное значение\] .
Режим link является анахронизмом. Он был введен для аналогового моделирования, но теперь в аналоговом VHDL он не используется.
Настроечная константа generi с
Настроечная константа generic кодирует определенное свойство объекта проекта. Она используется, например, для задания разрядности линий связи, кодирования структуры моделируемого устройства. При вставке компонента через интерфейс связывания настроечных констант, настройка объекта верхнего уровня передается объектам нижнего уровня. Упрощенный синтаксис объявления настроечных констант следующий:
\объявление настроечных констант\::=
депепс(\о6ъявление настроечной константы\
{; \объявление настроечной константы\}); \объявление настроечной константы\::=
\идентификатор\:\тип\[:=\начальное значение\]
Переменная цикла
Переменная цикла - это специальный объект в том смысле, что он не требует объявления. Подробнее о ней сказано при описании оператора цикла loop.
Начальное значение объекта
Начальное значение объекта в его объявлении - это то значение, которое принимает объект перед первым циклом моделирования. Если начальное значение не присвоено, то симулятор присваивает наименьшее значение данного типа, если тип - числовой или самое левое значение, если тип - перечисляемый.
Это значение может быть выражением. Но значение выражения должно быть вычисленным до момента трансляции данного объявления. Например, первое объявление:
signal bb:bit:=aa; signal aa:bit : = Ч';
неверно, так как при его рассмотрении компилятор еще не имеет сведений об идентификаторе аа.
В аппаратной модели начальное значение объекта эквивалентно состоянию триггеров и шин сразу после включения питания до прихода сигналов сброса, т.е. оно не определено. Поэтому компиляторы-синтезаторы, как правило, не допускают (иногда - игнорируют) начальные значения всех объектов, кроме констант или объектов, которые не изменяют свое значение при вычислениях.
Выражения
В VHDL выражения выполняют арифметические или логические вычисления над одним или несколькими операндами. Выражения используются в операторах присваивания сигналу, переменной, при присваивании начального значения, как операнд в других операторах, как входной параметр вызова процедуры или функции.
Операции в выражениях
Операции VHDL перечислены в таблице 3.1 в порядке их приоритета.
Тип операции | Символ или ключевое слово |
Логические | and, or, nand, nor, xor, хпог |
Сравнения | =, /=f <, <=, >, >= |
Сдвига | sll, srl, sla, sra, rol, ror |
Сложения | +, -, & (конкатенация) |
Унарные (знак) | + » - |
Умножения | *, /, mod, rem |
Различные | **, abs, not |
Логические операции имеют самый низкий приоритет. Операнды логических операций должны быть одного типа bit или boolean, или одномерного регулярного типа (векторы) из элементов типа bit или boolean. Для однозначной компиляции логических выражений необходимо использовать скобки, например:
(a or b) andс and(d or с).
Операции сравнения выполняются над операндами одинакового типа и возвращают тип boolean. Операции равенства "=" и неравенства "/=" выполняются над всеми типами. Остальные операции сравнения выполняются над перечисляемыми типами, целыми типами и одномерными регулярными типами (векторами) из элементов такого типа.
При сравнении перечисляемых типов элемент, стоящий в ряду правее (старший), считается большим. При сравнении векторов сравниваются пары элементов векторов, начиная с самых левых. Если пара элементов неодинакова, то вектор с более старшим элементом считается бо лыиим. Если пара элементов одинакова то рассматривается следующая пара элементов. Например, в сравнении векторов битов "0111" >=м01011" результат будет true.
Операции сдвига выполняют сдвиг вектора битов на число разрядов типа integer. Например, результатом выражения "100110" sra 3 будет вектор "111100", т.е. происходит арифметический сдвиг вправо на 3 разряда.
Операции сложения - вычитания "+", "-" предопределены для целых чисел и чисел с плавающей запятой. Операция конкатенации "&" применяется со всеми одномерными регулярными типами или с их элементами. С помощью этой операции векторы - операнды объединяются в более длинные векторы. Например, выражение "101" & 'Г & "10" даст результат "101110".
Унарные операторы применяются к одиночным операндам. Оператор минус инвертирует значение операнда. Операторы умножения "*", деления "/" применяются с целыми операндами и операндами с плавающей запятой. Операторы mod(модуль), rem (остаток) применяются с целыми числами. Операции абсолютного значения abs и возведения в степень "**" определены для целых чисел и чисел с плавающей запятой, причем показатель степени должен быть целым.
Для многих операций языка существуют функции с таким же обозначением. Эти функции выполняют аналогичные действия, что и операции, но над другими типами операндов. Например, функция "+" из пакета numeric„bit библиотеки IEEE выполняет сложение векторов битов, которые кодируют целые числа. Такие функции перегружают операции в зависимости от типа операндов.
При программировании для синтеза следует учесть, что правый операнд для операций "/". mod,rem может быть равным только степени двойки, а левый операнд операции "**" должен быть равен 2, так что эти операции будут означать сдвиг двоичного кода.
Операнды в выражениях
Простейшими операндами являются литерал и идентификатор, такой как имя сигнала или переменной. Само выражение может быть операндом, если его окружить круглыми скобками. Операндами могут быть также агрегат, атрибут, вызов функции, имя с индексом, квалифицированное имя, значение комбинированного типа и его поля, вырезка регулярного типа, функция преобразования типа. Далее подробно рассматриваются эти виды операндов.
Простое выражениечаще всего представляет собой имя объекта со знаком +,- или без него. Для многих операторов операнды должны быть простыми выражениями. Особенно это касается стиля программ для синтеза.
Имя с индексомдает значение элемента регулярного типа, номер которого задается выражением зскобках. Например, vect(4) означает 4-й бит вектора vect, arr(i,j) означает элемент (i,j) двумерного массива агг.
Имя-вырезказадает цепочку элементов объекта регулярного типа. Его упрощенный синтаксис:
\имя-вырезка\::=\имя\(\выражение\ to | downto \выражение\)
\выражение\ - должно вычислять значение, не превосходящее диапазон индексов объекта регулярного типа с именем \имя\. Направление изменения индекса to или downto должно совпадать с направлением, заданным в объявлении типа. Например, если объявлен сигнал:
signalA: bit„vector(15 downto0);
то А(15 downto 8) - старший байт сигнала А.
Поле комбинированного типа.Чтобы оперировать с полем объекта комбинированного типа его вставляют в выражение согласно синтаксису:
\поле комбинированного типа\::=\имя комбинированного типа\.\имя поля\
где \имя поля\ - может представлять поле любого типа, а также его имя с индексом, имя-вырезку, агрегат. Например, если объявлены тип и сигнал:
type comp„vect is record
(Re: bit_vector(0 to 15); Im:bit_vector(0 to15)); end record; signalA: comp_vect;
то A.Re(0 to 7) - старший байт поля Re сигнала А типа comp_vect.
Вызов функции.При вызове функции выполняется функция с заданными значениями параметров. Упрощенный синтаксис вызова функции:
\вызов функции\::=\имя функции\ ([\имя параметра =>\] \выражение\ {,[\имя параметрах => ] \выражение\});
где \имя функции\ - имя функции, определенной ранее, \имя параметрах - необязательный формальный параметр этой функции. Выражение-параметр функции должно давать результат типа, соответствующий имени параметра. Параметры можно задавать с поименованным или позиционированным связыванием.
При позиционированном связывании выражения-параметры подставляются в порядке, определенном порядком следования имен параметров в определении функции. При поименованном связывании каждое имя параметра связывается с соответствующим параметром с помощью символов "=>", причем порядок следования параметров может быть произвольным.
Например, в пакете iEEE.Math_.Real определена функция синуса:
functionSin (x: inreal) returnreal;
Ее вызов по аргументу вещественного типа выглядит как: SIN(x=>math_2_pI * angle) или sin(math_2„pi * angle),
где math__2_pi - константа, равная 2, определенная в этом пакете.
Преобразование типа.Так как в VHDL присваивание значения объекту требует строгого соответствия типов, то в случае, если типы объектов не совпадают, необходимо выполнить преобразование типа. Его синтаксис соответствует синтаксису вызова функций с одним аргументом.
Различают два вида преобразования типа: переход типа и вызов функции преобразования типа. Переход типа применяется для преобразования тесно связанных типов или подтипов. Такими парами типов являются, например, real и integer, integer и natural, регулярные типы с одинаковым числом элементов того же самого типа и с одинаковыми диапазонами индексов. Например, при переходе из значения с плавающей запятой к целому значению:
C:=integer(123.5);
результат с округляется до ближайшего целого, т.е. до 124.
Если типы не тесно связанные, то необходимо выполнить вызов функции преобразования типа. Например, типы boolean и bit - не тесно связанные т.к. принадлежат к перечисляемым типам с различными множествами элементов. Поэтому, например, преобразование переменной х типа boolean в переменную Y типа bit может выполняться функцией преобразования типов, которая включает оператор:
if X then Y: = 'l'; elseY: = '0'; end if;
Часто программисты пользуются своими функциями преобразования типов. Большинство стандартных и коммерческих библиотек содержат наборы функций преобразования типов.
Атрибут.У объектов языка имеется некоторое множество свойств и особенных значений. Атрибут объекта - это специальная функция, которая возвращает его особенное значение. Например, атрибут objectl'left возвращает значение самого левого элемента объекта objectl перечисляемого типа. Подробнее об атрибутах будет рассмотрено в разделе, посвященном атрибутам.
Агрегат.Агрегатом называется операция, которая объединяет одно или несколько значений в значение составного типа, т.е. регулярного или комбинированного типа. Его упрощенный синтаксис:
\агрегат\::=(\связывание элементов\ {Довязывание элементов\}) \связывание элементов\::=[\альтернативы\ =>] \выражение\ \альтернативы\::=Лальтернатива\ {Д альтернатива\}
\альтернатива\: :=\простое выражение\|\диапазон\|\имя элемента\| others
Связывание элементов означает подстановку одного выражения в одно или несколько заданных полей или элементов значений составного типа. Связывание элементов может происходить в порядке нумерации элементов составного типа. Тогда оно называется позиционированным связыванием. Например, в объявлении:
variablev_5: bit_vector (0 to 4) : = С09, '0', ,01, '1', Ч') ;
битам 0, 1 и 2 присвоено начальное значение 0, а битам 2,3 -значение 1. Если каждый элемент связывается со своим значением по имени, то такое связывание называется поименованным. Например, для той же переменной v_5:
(3|4 => '1\ others => '0') или (0 to 2 => '0'; 3 to 4 => 'Г).
Здесь ключевое слово othersозначает остальные элементы значения и оно должно стоять последним в списке связываний. Возможны и комбинированные агрегаты, в которых первым используется позиционное связывание, а затем - поименованное связывание, например:
СО9,'О9, 3 to 4 => '1\ others -> 'О').
Но такое связывание допускают далеко не все трансляторы VHDL.
Такая альтернатива, как простое выражение, применяется только для регулярных типов и должна определять номер элемента из диапазона этого типа, например, агрегат (i => '!', others=> '0') задает вектор в котором на £-м месте стоит 1, а остальные биты — нулевые.
Альтернатива \имя элементах применяется только для комбинированных типов, например:
type complex is record(Re: integer; im: integer ); end record; variablex iscomplex:=(Re => 1000, im => 0);
Квалифицированное выражение.Результат выражения может принадлежать нескольким типам одновременно. Если этот результат должен принадлежать к конкретному типу, то его необходимо обозначить как результат, квалифицированный с заданным типом. Синтаксис такого выражения:
\квалифицированное выражение\::=\имя типа\'(\выражение\)
Например, если объявлено
type vect is bit„vector(0 to 9); var x: vect;
то выражение (3=>'l'.others => '0') может принадлежать к типу векторов любой длины и разных типов. Поэтому для присваивания переменной этого выражения необходимо выполнить его квалифицированным:
x^vect'O^'l' .others -> '0');
Статические выражения
Как уже указывалось, структура виртуальной параллельной вычислительной системы и ее параметры формируются при компиляций программы VHDL и остаются неизменными в процессе ее исполнения. Точнее, это происходит на последнем этапе - этапе связывания объектов (elaboration). В программах часто встречаются выражения, от результатов которых зависят структура и параметры системы. Это например, настроечные переменные (generic), определяющие порядок включения блоков, их разрядность. Некоторые операторы, например, case, вставки компонента, требуют, чтобы в них входили статические выражения. Результаты этих выражений должны иметь конкретные значения перед исполнением программы и не должны зависеть от входных сигналов и переменных. Такие выражение получили название статических. Другими словами, непосредственно перед моделированием статическое выражение должно быть вычислено до константы или приведено к сигналу или переменной конкретного типа. Выражения от литералов, констант, статических выражений и функций от них являются статическими выражениями.
Например, если объявлены сигналы
signal n: integer;
signal A: bit_vector(16 downto n+1);
то на момент начала моделирования операнд п неизвестен и симуля-тор будет пытаться подставить п = -2147483647, что вызовет аварийную остановку симулятора при размещении сигнала А в памяти, т.е. здесь выражение п+1 - не статическое.
Если симулятор дает широкие возможности исполнения программы, обеспечиваемые большими ресурсами памяти компьютера и последовательным многократным исполнением операторов, то при аппаратной реализации программы эти возможности значительно
уже. Поэтому если программа на VHDL предназначена для синтеза, то требования применения статических выражений встречаются значительно чаще.
В предыдущем примере симулятор может работать, если сигнал п - типа natural, который по умолчанию принимает начальное нулевое значение. Но для синтеза такая программа не годится, так как, во-первых, присваивание начального значения игнорируется или запрещается, во-вторых, в аппаратуре должны быть четко заданы разрядность регистров и шин, объем памяти и т.п.
Реализация выражения в аппаратной модели VHDL
Если выражение не упрощается при компиляции до константы или другого объекта, то оно реализуется в аппаратной модели в виде логических комбинационных схем. Операции в выражениях отображаются в схемы, выполняющие эти операции над операндами соответствующих типов.
Логические операции реализуются в соответствующих элементах: and— в элементе "И", not- элементе "НЕ" и т.д. При операциях над битовыми или булебскими данными реализуются одиночные логические элементы. При выполнении операции над операндами регулярного типа каждому элементу операнда ставится в соответствие один логический элемент.
Операции равенства и неравенства реализуются с помощью соответствующего числа элементов "И" с объединением их выходов в элементе "ИЛИ". Операции "больше" или "больше или равно" выполняются с помощью многоразрядной схемы сумматора-вычитателя, выход переполнения которой соответствует булевскому результату этой операции.
Операции, сложения, вычитания, изменения знака выполняются с помощью схемы сумматора, а операция умножения - с помощью комбинационного умножителя. При этом если операнды типа positive или natural, то умножение выполняется на умножителе без учета знака, а если типа integer - на умножителе со знаком.
Операция абсолютного значения absвыполняется на схеме получения положительного числа из отрицательного и мультиплексора, который в зависимости от знака числа пропускает результат на выход схемы.
Операция деления, модуля, остатка и возведения в степень, которые соответствуют сдвигу объекта, представленного двоичным числом, реализуются в схеме сдвигателя. При этом если операнд типа integer, то сдвиг вправо выполняется с учетом знака.
Операция "&" конкатенации пары операндов регулярного типа соответствует объединению двух шин, пересылающих эти операнды, в одну, состоящую из исходных шин.
При выполнении операций сложения и вычитания разрядность результата должна быть равна максимальной разрядности операндов. Операнды
операции умножения должны иметь суммарную разрядность, равную разрядности произведения.
Если операнды объявлены как тип integer без диапазона, то им соответствуют 32-разрядные типы и соответствующие 32-разрядные схемы реализации операций. Для минимизации оборудования рекомендуется принять объявление переменной с диапазоном: например, если переменные объявлены как:
variable a, b: integer range (-128 to 127);
то выражение a+b выполняется на 8-разрядном сумматоре.
Сложное выражение от нескольких операндов при отсутствии скобок и с равноприоритетными операциями выполняется последовательно слева направо. Ему соответствует схема из цепочки модулей, выполняющих эти операции. Вставка скобок в это выражение задает приоритет выполнения операций, который отображается в аппаратную схему. Благодаря этому результирующая схема имеет вид дерева из модулей, задержка логических схем которого может быть намного меньше, чем в исходной схеме. На рис. 24 показаны аппаратные схемы, соответствующие выражениям a+b+c+d и (a+b)+(c+d).
Таким образом, вставка скобок в выражение является одним из способов управления ходом синтеза, выполняемого компилятором-синтезатором.
Последовательные операторы
Последовательные операторы в VHDL вставляются в операторы процессов и исполняются последовательно в виртуальных процессорных элементах программистской модели. Все операторы в VHDL оканчиваются точкой с запятой. Несколько операторов можно размещать в одной строке и один оператор может занимать несколько строк.
Оператор присваивания
Он выполняет присваивание переменной или сигналу результата выражения. Этот оператор выглядит следующим образом:
\результат\:= \выражение\; - для присваивания переменной \результат\ <= \выражение\; - для присваивания сигнала.
Здесь результат \результат\ может быть именем, например, var, именем с индексом, как var(l), вырезкой, как var(0 to 1), полем, как гее.var или агрегатом, как (ReTim).
Присваивание переменной отличается от присваивания сигналу. Присваивание переменной выполняется немедленно.
Выполнение оператора присваивания сигналу означает вычисление его выражения, и лишь назначение сигналу. Само же присваивание сигналу фактически выполняется в момент остановки процесса по ожиданию события. Поэтому если в одном процессе стоит несколько присваиваний одному сигналу, то истинное присваивание происходит в момент остановки процесса. Если перед остановкой процесса выполнялось чтение этого сигнала (участие его в качестве операнда в выражении), то будет прочитано значение, присвоенное в прошлом запуске процесса.
При выполнении присваивания для части элементов сигнала составного типа или перечисляемого типа, например, имени с индексом, вырезке считается, что выполняется присваивание всем элементам сигнала, причем те элементы, которые не указаны в операции присваивания, принимают старое значение. Например, по фрагменту программы
signal d:bit_vector(0 to 7);
d <= (others => '0'); d(l to 3) <= "Oil"; d(4 to 5) <= "IIй; wait ...
сигналу d будет присвоено значение "00111100".
Всем операторам присваивания сигналу в одном процессе в модели виртуального процессорного элемента соответствует один источник сигнала. Если одному и тому же сигналу выполняется присваивание в различных процессах, то несколько источников сигналов соединяются своими выходами и в общем случае, результирующий сигнал может быть неопределенным. Поэтому над таким сигналом должна быть задана функция разрешения, которая разрешает кон-
фликт присваивания одному сигналу значений из нескольких источников сигнала.
Если пользоваться пакетом ieee.STD_logic_1164, to сигнал, объявленный как stcLlogic, можно присваивать в разных процессах, так как в этом пакете есть функция разрешения для такого типа сигналов.
Присваивание сигналу при моделировании
При моделировании дискретных систем важное место занимает моделирование распространения сигнала с учетом задержки в проводниках или в вентилях. Для этого используют следующий расширенный синтаксис присваивания сигналу:
\присваивание сигналу\::=\результат\ <= [\способ задержки\] \график\; \спосо6 задержки\::= transport |[reject \выражение времени\] inertia! \график\::= \выражение\ [after \выражение времени\]
{, \выражение\ [after \выражение времени\] }
Здесь график (waveform) представляет собой запись, состоящую из одной или нескольких пар: величина сигнала - задержка сигнала. В первой паре задержка может не указываться, подразумевается, что она нулевая.
Способ задержки transportозначает, что при присваивании сигналы, представленные в графике, будут задержаны подобно тому, как сигнал задерживается в линии задержки или в проводниках. Величина задержки отсчитывается относительно момента остановки процесса и задается выражением \выражение времени\, которое имеет тип time.
Способ задержки inertia!реализует поведение задержки в источнике сигнала, который не реагирует на слишком короткие входные импульсы. Фразой rejectзадается минимальная ширина импульса, которая выдается источником. Если этой фразы нет, то минимальная ширина импульса задается в фразе after.По умолчанию в операторе применяется способ задержки inertia"!.В следующем ряде примеров показано действие оператора.
Y<= х after 10 ns;
- значение сигнала х на момент запуска процесса присвоится сигналу Y с задержкой 10 не, при этом импульсы шириной менее 10 не будут подавлены.
Y<= '0\ '1' after 10 ns, '0' after 20 ns, '1' after 30 ns;
- сигналу Y сначала присвоится 0, через 10 не - 1, через 20 не - 0, и
через 30 не - 1. Иногда таким способом задаются тестовые последо
вательности сигналов.
Y<= а, А+в after delay_sum;
- сигналу Y сначала присвоится А, а через задержку, определяемую
статическим выражением delay_sum - сумма сигналов А и в.
Y<= transport X after 1000 ns;
- модель линии задержки сигнала х с задержкой 1 мкс.
Y<= reject t_rej inertial A and в after t_d;
- моделируется вентиль "И" с задержкой t_d , который не пропус
кает импульсы короче t_rej.
Оператор ожидания события wai t
Этот оператор уже упоминался при описании модели для программирования на VHDL и принципов работы симулятора. На этом операторе процесс останавливается, в момент остановки выполняются присваивания сигналам, и процесс продолжает исполнение при появлении события, которое выбирается этим оператором. Синтаксис оператора wai t:
\оператор waitY- :=wait [on \имя сигнала\ {Димя сигнала\}]
[until \6улевское выражение\] [for \выражение времени\];
где ключевое слово on начинает список чувствительности, until -условие ожидания, a for - означает задержку ожидания. По оператору
wait on clk, rst;
продолжение выполнения процесса начнется по событию изменения сигналов clk или RST. По оператору
wait until CLK='l';
продолжение начнется в момент изменения состояния clk из '0' в '1', т.е. по фронту этого сигнала. Оператор
wait for clk_period;
остановит процесс на время, заданное переменной clk_period типа ti me.
Возможно комбинирование списка чувствительности и условия ожидания в одном операторе. Оператор wait без списка чувствитель-
ности, условия ожидания и задержки останавливает процесс до конца моделирования.
Оператор i f
Этот условный оператор в зависимости от заданных условий выполняет цепочки последовательных операторов, причем от условия зависит, которая из цепочек операторов выполняется. Упрощенный синтаксис оператора:
\оператор if\::=if \условие 1\ then
{\последовательный оператор 1\}
[ { elsif \условие 2\ then
{\последовательный оператор 2\}]
[else
{"^последовательный оператор 3\}]
end if;
Каждое из условий должно быть выражением, вычисляющим результат булевского типа. При выполнении этого оператора условия проверяются последовательно друг за другом, пока результат условия не будет true. Тогда выполняется соответствующая этому условию цепочка операторов и выполнение данного оператора if прекращается.
Оператор case
Этот оператор разрешает выполнение одной из цепочек последовательных операторов в зависимости от значения выражения селектора. Его синтаксис:
\оператор case\::=case \простое выражение\ is
when \альтернативы\ => {"^последовательный оператор\} {when \альтернативы\ => {"^последовательный оператор\}} end case; \альтернативы\:= \альтернатива\{ | \альтернатива\}
В выражении селектора \простое выражение\ должен вычисляться целый результат или значение перечисляемого или регулярного типа. Каждая из альтернатив \альтернатива\ должна быть такого же типа, что и \выражение\ и представлена статическим выражением или диапазоном, например, 0 to 4. Никакие два значения, получаемые из выражений альтернатив, не должны быть равны друг другу, т.е. множества альтернатив не перекрываются. Последней альтернативой может быть ключевое слово others, которое указывает на не перечисленные альтернативы. Если others не применяется, то в аль-
тернативах должны быть перечислены все возможные значения, принимаемые в селекторе \выражение\. Пример оператора case:
variable sel, a: integer 0 to 9;
case sel is
when 0 => a <= 0;
when 112 I 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;
Оператор цикла
Этот оператор несколько раз выполняет последовательность операторов. Его синтаксис:
\оператор цикла\::=[\метка\:][\схема итерации\]1оор ^последовательный оператор\}
{next[\MeTKa\][when \условие\];} {ехЩ\метка\] [when \условие\];} end loop [\метка\]; \схема итерации\::=while \условие\
| for \переменная цикла \ in \диапазон\
Метка \метка\ необязательна, она отмечает начало цикла и с помощью ее во вложенных циклах указывается, в каком цикле начать новую итерацию по оператору nextили из какого цикла выйти по оператору exit.
По первой схеме итераций цикл, ограниченный ключевыми словами loopи end loopбудет выполняться, пока условие \условие\ не примет значение false. Причем, это условие проверяется до выполнения цикла и если оно сразу равно false, то цикл не выполняется.
В примере:
variable vec: bit_vector(l to n); variable or_vec:bit; variable i:natural;
i:=l;
or_vec:='0'; while i<=n loop
or_vec:= or_vec or vec(i);
i: =i +1; end loop;
вычисляется переменная or_vec, равная функции ИЛИ от всех разрядов вектора vec длины п. Если п = 0, то цикл не вычисляется. Этот пример можно записать с помощью второй схемы итерации как:
variable vec: bit_vector(l 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 п. Если необходим обратный порядок изменения переменной цикла: п, п-1,... то этот диапазон может быть задан как: n downto 1. Переменную цикла не нужно объявлять, как другие переменные и ей нельзя выполнять присваивания.