Архитектура ПЛИС фирмы Xilinx
Фирма Xilinx принадлежит к числу родоначальников ПЛИС и самых крупных их производителей. Ниже рассматривается краткое описание архитектурных особенностей ПЛИС серии Virtex выпускаемой этой фирмой. Эти особенности наследуются в новых сериях ПЛИС, а также в серии Spartan, микросхемы которой призваны заменить заказные СБИС в мало- и среднесерийном производстве изделий электроники. Кроме того, принципы функционирования структурных элементов ПЛИС этой серии узнаваемы в архитектурах ПЛИС других фирм-производителей, таких как, Altera, Actel, Atmel.
Атрибут foreign.
Специальный атрибут foreign присоединяется к архитектуре, процедуре или функции. Он указывает симулятору, что соответствующий объект должен моделироваться особенным способом. Это может быть специальная программа на ассемблере или другом языке, или аппаратный ускоритель.
Атрибуты для регулярного типа.
Для регулярного типа A предопределены следующие атрибуты:
A'left[(N)] – левое значение диапазона индексов по N-й размерности.
A'right[(N)] - правое значение диапазона индексов по N-й размерности.
A'high[(N)] - наибольшее значение диапазона индексов по N-й размерности.
A'low[(N)] - наименьшее значение диапазона индексов по N-й размерности.
A'range[(N)] – диапазон индексов по N-й размерности.
A'reverse_range[(N)] – обратный диапазон индексов по N-й размерности.
A'length[(N)] – протяженность диапазона индексов по N-й размерности.
A'ascending[(N)] - функция, равная true, если диапазон индексов по N-й размерности - возврастающий.
Примеры применения атрибутов:
type s2 is array(2 downto 1, 0 to 3) of integer;
s2'left(1) = 2, s2'right(2) = 3, s2'high(1) = 2, s2'low(2) = 0,
s2'range(2) = 0 to 3, s2'reverse_range(1) = 1 to 2, s2'length(2) = 4.
Атрибуты для скалярного типа.
Для скалярного типа Т предопределены следующие атрибуты:
T'left – самое левое значение множества элементов скалярного типа Т.
T'right – самое правое значение множества элементов скалярного типа Т.
T'high – наибольшее значение в множестве элементов скалярного типа Т.
T'low –наименьшее значение в множества элементов скалярного типа Т.
T'image(X) – функция строкового представление выражения Х типа Т.
T'value(Х) – функция значения типа Т от строкового представления Х.
T'pos(Х) – функция номера позиции элемента Х типа Т.
T'val(Х) –функция значения элемента типа Т стоящего в позиции Х.
Примеры атрибутов:
type st is (one,two,three);
st'right = three, st'pos(three) = 2, st'val(1) = two.
positive'low = 1, positive'high =2147483647.
integer'value("1_000") =1000, integer'image(330) ="330".
Атрибуты пользователя.
Эти атрибуты предназначены для присваивания объектам языка дополнительных свойств, не предусмотренных встроенными типами и атрибутами. При проектировании дискретных устройств такими свойствами могут быть способ кодирования состояний автомата, указания компилятору – синтезатору по управлению оптимизацией, размещению блоков, их исполнению, назначение портов номерам выводов, начальное состояние схем памяти и т.п. Т.е. эти свойства не связаны напрямую с алгоритмом, реализуемым в программе. Задание атрибута состоит из его объявления и спецификации.
Объявление атрибута имеет синтаксис, похожий на объявление переменной:
\объявление атрибута\::=atribute \идентификатор\ : \ тип\
где \тип\ - любой ранее определенный тип, например, string, positive, time.
Спецификация атрибута имеет синтаксис:
\спецификация атрибута\::=attribute \идентификатор\ of
\имя объекта\[{,\имя объекта\}] | others | all : \класс объекта\ is \выражение\
\имя объекта\::= ((\идентификатор\ |\символьный литерал\ | \символ оператора\)
[\сигнатура\])
\класс объекта\::= entity | architecture | configuration | package | procedure | function | type | subtype | constant | signal | variable | file | component | label | literal | units | group
Здесь \идентификатор\ - имя атрибута, объявленнного ранее, \имя объекта\ - имя объекта, которому присоединен атрибут. \сигнатура\ - это список типов параметров, если объектом является процедура, функция или перечисляемый литерал, предназначенный для идентификации перезагружаемых процедур, функций и литералов.
Спецификация атрибута обычно вставляется сразу же после объявления этого атрибута.
Атрибуты пользователя обычно не влияют на поведение модели и такие атрибуты игнорируются симулятором. Но они имеют большое значение для компилятора – синтезатора и для средств реализации схемы в кристалле. Поэтому, как правило, фирмы – поставщики компиляторов и производители микросхем предлагают для использования свои наборы атрибутов пользователя. В следующем примере атрибут указывает способ кодирования состояний автомата:
type \состояние\ is ( \сброс\,\начало\,\работа\,\конец\);
attribute enum_encoding : string;
attribute enum_encoding of \состояние\ : type is "000 001 010 100" ;
Атрибуты сигналов
Атрибуты сигналов S:
S'stable[(T)] – сигнал, равный true, если за промежуток времени Т не было событий у сигнала S.
S'transaction – сигнал типа bit, меняет значение на противоположное в циклах моделирования, в которых было присваивание нового значение сигналу S.
S'event – сигнал, равный true, если произошло событие в сигнале S в данном цикле моделирования.
S'active – сигнал, равный true, если произошло присваивание нового значение сигналу S в данном цикле моделирования.
S'last_value – сигнал такого же типа, что и S, содержащий значение S до последнего события в нем.
Примером применения атрибутов сигналов является следующий процесс, моделирующий синхронные триггеры.
process(CLK) begin
if CLK='1' and CLK'event then-- D- триггер
q1<=a;
end if;
if not CLK'stable then -- D- триггер
q2<=a;
end if;
if CLK'last_value /= CLK then-- D- триггер
q3<=a;
end if;
if CLK'active-- D- триггер
q4<=a;
end if;
q5<=CLK'transaction; -- T- триггер
end process;
Блоки ввода-вывода сигналов
ПЛИС находят широкое применение благодаря тому, что их можно включать в большинство проектов вычислительных устройств и ими можно заменять большое количество старых микросхем. Предпосылкой этому служит большое число блоков ввода-вывода сигналов IOB, настраиваемых под различные стандарты электрического соединения входов микросхем. На рис. показана структура одного IOB.
Сигнальный вывод ПЛИС получил название PAD. С помощью настройки к нему можно подключать внутренний нагрузочный резистор PULLUP или резистор PULLDOWN, соединенные с шиной питания или шиной земли, соответственно. Эти резисторы обеспечивают режим выхода с открытым коллектором (стоком) для систем с различными уровнями логики. Входной сигнал с PAD поступает на компаратор IBUF, порог срабатывания которого программируется под уровни ТТЛ, КМОП, шины PCI и многие другие, а также может регулироваться установкой подаваемого снаружи напряжения. Для обеспечения временного сдвига сигнала относительно фронта синхросерии, обеспечивающего надежный прием сигнала во внутренние триггеры, в цепь входного сигнала может включаться специальная схема задержки.
Выходной сигнал в IOB формируется в тристабильном буфере OBUFT, причем его уровень максимального тока программируется ступенями и может достигать 20 мА. Для обеспечения быстродействующего ввода-вывода передаваемые и принимаемые биты данных, а также сигнал управления тристабильным буфером могут запоминаться в триггерах.
В новых сериях ПЛИС предусмотрена настройка входного и выходного импеданса PADа, а также бифазное функционирование пар PADов для достижения помехоустойчивой высокоскоростной передачи данных.
При диагностике и отладке, в одном из режимов конфигурирования ПЛИС может быть переключена в режим пограничного сканирования (Boundary Scan). В этом режиме все IOB соединяются в цепочку одного длинного регистра сдвига. Путем стандартного внешнего управления этим регистром сдвига через интерфейс JTAG можно считывать состояния выводов, подавать тестовые сигналы, конфигурировать ПЛИС.
В период конфигурирования ПЛИС для того, чтобы подключаемые к ней устройства не функционировали неопределенным образом, выходы IOB отключаются и на них обычно выставляется уровень H слабой единицы (Weak Keeper).
Что такое FPGA?
Программируемые логические интегральные схемы (ПЛИС) появились полтора десятилетия назад как альтернатива программируемым логическим матрицам (ПЛМ). От последних ПЛИС отличаются как по архитектуре, так и по технологии изготовления.
ПЛМ представляет собой матрицу многовходовых (несколько десятков входов) логических элементов с триггерами, в которых перемычками программируются конституенты единиц дизъюнктивных нормальных форм функций этих элементов. Вначале перемычки выполнялись в виде пережигаемых тонких проводничков. Теперь перемычки выполняются в виде МОП-транзистора с плавающим затвором, т.е. как в электрически перепрограммируемом ПЗУ, т.е. ПЛМ изготовляются по технологии флэш-памяти. Большие ПЛМ (CPLD) отличаются только тем, что несколько ПЛМ собраны на одном кристалле и объединены программируемым полем связей.
ПЛИС представляет собой матрицу маловходовых (от двух до пяти входов) логических элементов, триггеров, отрезков линий связи, соединяемых перемычками из полевых транзисторов. Судя по английскому названию - Field Programmable Gate Array (FPGA) - ПЛИС программируются изменением уровня электрического поля (field) в затворах этих транзисторов. В отличие, например, от LPGA - Laser Programmable Gate Array. Затворы всех "программирующих" полевых транзисторов подключены к выходам триггеров одного длинного сдвигового регистра, который заполняется при программировании ПЛИС. Некоторые из участков этого регистра могут также выполнять роль ячеек ПЗУ.
Прошивка обычно хранится в ПЗУ, стоящем рядом с ПЛИС и после включения питания или по сигналу сброса она автоматически переписывается в программирующий сдвиговый регистр ПЛИС. Этот процесс называется конфигурированием ПЛИС. Так как основу ПЛИС составляют триггеры, хранящие прошивку, то ПЛИС изготавливаются по технологии микросхем статического ОЗУ.
По сравнению с CPLD, ПЛИС выигрывают,
во-первых, в неограниченном количестве перепрограммирований, во-вторых, в логической емкости, в том числе в удельной емкости вентилей на цент, в-третьих, в малом энергопотреблении.Как правило, ПЛИС имеют на два - три порядка большую емкость в числе эквивалентных логических вентилей, чем CPLD и также как статическое ОЗУ, почти не потребляют энергии при отсутствии переключений.
Кроме того, у ПЛИС на порядок выше надежность (ниже интенсивность отказов), чем у CPLD.
К недостаткам относят необходимость внешнего ПЗУ прошивки, генератора синхросерии. Но 8-выводовое ПЗУ занимает на плате значительно меньше места, чем сама ПЛИС с многими сотнями выводов. То же касается генератора синхросерии.
Много сомнений у пользователей возникает с защитой проекта от копирования. Действительно, прошивка ПЛИС хранится во внешнем ПЗУ, содержимое которого просто копируется. НО изменить или расшифровать прошивку, например, для скрытия авторства или восстановления схемы, практически невозможно, так как семантика битов в файле прошивки - секрет фирмы, а неосторожное изменение ее может вывести ПЛИС из строя. Если требуется защита, то загрузку программы выполняют с помощью внешней CPLD, автомат в которой обеспечивает защиту проекта. В ПЛИС новых поколений предусматривается шифрование прошивки, например, с помощью встроенного шифрователя DES с обеспечением сохранения ключа с помощью батарейки.
Ещё один тахометр
Редкий радиолюбитель, владелец автомобиля, не полезет в него с паяльником. Вот и размножаются сотнями любительские схемы разных блоков зажигания, октан-корректоров, тахометров, зарядных устройств, охранной сигнализации. Некоторые идут дальше – и появляются бортовые компьютеры, телевизионные зеркала заднего обзора и даже устройства распознавания знаков дорожного движения.
В данной статье не будет предлагаться автомобильная навигационная система. Просто - ещё один тахометр. Тахометр - это измеритель числа оборотов двигателя за единицу времени. Входные данные Fx поступают с датчика числа оборотов, которым чаще всего является прерыватель системы зажигания или емкостной датчик импульсов напряжения в свечных проводах. Результат измерения получают путем интегрирования импульсов одинаковой длительности в аналоговой схеме или простым подсчетом импульсов за единицу времени в частотомере.
Но частота Fx слишком низкая для измерения с точностью до 3-5 десятичных цифр в реальном масштабе времени. Измерение частоты на выходе генератора переменного тока бортовой сети не решает проблему кардинально. Кроме того, ещё необходима коррекция результата измерения путем умножения на масштабный коэффициент, т.е.Y=M*Fx. Выход в том, что необходимо измерять период Тх сигнала, а измеряемую величину находить как результат деления Y=M/Tx.
Для вычисления Y=M/Tx существует очень простой и удобный алгоритм. Если из большеразрядного целого М вычитать малоразрядное Тх до тех пор, пока М не приблизится к нулю, то число вычитаний будет равно искомому Y. При этом счетчик числа этих вычитаний можно выполнить по любому основанию, например, по основанию 2, 10, в кодах 7-сегментных индикаторов, в унитарном коде, т.е. коде бегущей единицы, в коде отображения столбика единиц и т.п.
Недостатком алгоритма является его высокая алгоритмическая сложность, т.е. то, что для получения 3-5 – разрядного десятичного результата необходимо выполнить до 1 –100 тыс. вычитаний и столько же сложений с единицей на одно измерение или 0.1 – 100 млн. операций в секунду, в зависимости от быстродействия измерений. Это довольно сложно для микроконтроллера, зато совсем нетрудно для ПЛИС и даже CPLD.
Здесь приводится простая модель тахометра. Модель представлена в Приложении. Тахометр работает периодически с последовательным повторением четырех фаз. В фазе Waiting ожидается фронт входного сигнала, в фазе Measure измеряется период сигнала Period как число тактов синхросерии между двумя соседними фронтами входного сигнала. При этом период меньше measureMIN не фиксируется, так как в нем могут быть импульсы дребезга контактов. В фазе Calculate вычисляется частота F= Masstab/Period . Эта частота F вычисляется в виде кода столбика единиц, который пригоден для непосредственного вывода на линейный светодиодный индикатор. В фазе Display ничего не происходит, кроме вывода результатов измерения.
Частота синхросерии равна 6,8 кГц. Она может быть подстроена выбором констант Masstab, measure_T, а также повышена при использовании дополнительного делителя частоты.
Такой тахометр помещается в любой корпус ПЛИС или CPLD . Он без особенной оптимизации занимает 125 LUT и 71 триггер. Так что весь прибор занимает один корпус CPLD XC9572 и генератор синхроимпульсов, не считая индикатора. Кстати, выходного тока ПЛИС или CPLD достаточно для прямого подключения светодиодов.
Если датчиком является прерыватель или емкостный датчик на проводе свечи зажигания, то на выходе такого датчика присутствуют высоковольтные импульсы. Хотя входы микросхемы защищены от высоковольтного низкотокового воздействия, следует вход микросхемы защитить от перенапряжения, например, резисторным делителем напряжения с диодным стабилизатором.
Приложение --^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- FILE: TAСHOMETER.VHD -- PROJECT: VHDL_HOBBY -- AUTHOR: Anatoli Sergyienko -- Created: 15/01/02 -- Email: aser@comsys.ntu-kpi.kiev.ua -- -- FUNCTION: - measuring and displaying the rotating frequency --of the car engine. -- ALGORITHM: 1. Period of the signal DATAI is measured in clocks -- 2. frequency is calculated as F= Masstab/Period -- 3. frequency is outputted through DATAO to the -- barcode display -- CONSTRAINTS: the barcode display length is limited by Fmax, -- maximum period of the signal is measure_T; -- display period is equal to Disp_T - Fmax. --^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ library IEEE; use IEEE.std_logic_1164.all; entity Taсhometer is generic( Fmax: integer:=32); -- Максимальная частота, -- 1 деление=200 об/мин port(CLK: in STD_LOGIC; RST: in STD_LOGIC; DATAI: in STD_LOGIC; DATAO: out STD_LOGIC_VECTOR (Fmax-1 downto 0)); end Taсhometer; architecture Hobby of Taсhometer is constant measure_T: integer := 1024;--Максимальный период сигнала, --тактов, соответствует ~400об/мин constant measureMIN:integer := 68; --Минимальный период сигнала, --тактов=1024/15, соответствует ~6000об/мин constant Disp_T: integer := 4093;--Период отображения, тактов constant Masstab:integer := 1000;--Масштабный коэффициент signal DATAId: STD_LOGIC; signal Calculate,Measure,Display, Waiting :boolean;--FSM states signal CT2:integer range 0 to Disp_T+3; signal Period: integer range 0 to measure_T; signal M: integer range 0 to measure_T-1; signal F: STD_LOGIC_VECTOR(Fmax-1 downto 0); --F = Masstab/Period begin --DATAI __/^^\___/^^\___/^^\___ --DATAId __/^^\___/^^\___/^^\___ --Measure__|^^^^^|_____________________ --Calculate_________|^^^^^^|_____________ --Display __________________|^^^^^^^^^^^|____ --Waiting ^^|_______________________________|^^^^ CNTRL:process(CLK,RST) begin if RST='1' then Calculateelsif CLK='1' and CLK'event then DATAIdif ( DATAI='1' and DATAId='0' and Waiting ) then Measureelsif ( DATAI='1' and DATAId='0'and Period>MeasureMIN ) then Measureelsif(CT2 = Disp_T) then Displayelsif (CT2 = Fmax)then Calculateend if; --clock counter if ( calculate or display) then CT2elsif Waiting then CT2end if; end if; end process; CT_PERIOD: process(CLK,RST) --Счетчик периода вх.импульсов begin if RST='1' then Periodelsif CLK='1' and CLK'event then if Measure then Periodelsif Waiting then Periodend if; end if; end process; AU_FREQ:process(CLK,RST)--вычисление частоты и ее отображение begin if RST='1' then f<=(others=> '0'); Melsif CLK='1' and CLK'event then if measure then Mothers=> '0'); elsif calculate then if ( M-Period >0 ) then Mdownto 0) & '1'; --сдвиговый регистр- столбик end if; end if; end if; end process; DATAOend Hobby;Ход проектирования с использованием VHDL.
На рисунке показана схема разработки проекта ВУ, предназначенного для исполнения в программируемой логической интегральной схеме (ПЛИС).
Вначале ВУ описывается в виде своей поведенческой модели, на которой отрабатывается задуманный алгоритм функционирования ВУ. Затем эта модель вручную перерабатывается в синтезируемую модель ВУ, описанную на уровне регистровых передач. Такая модель, будучи странслированной компилятором-синтезатором, дает проектную документацию в виде файла описания схемы ВУ на уровне вентилей (EDIF - файл). При этом автоматически выполняется логическая оптимизация ВУ. Одновременно этот файл автоматически преобразуется в VHDL- модель ВУ на уровне вентилей.
Проект ВУ в виде Electronic Distribution International Format (EDIF) - файла принимается как исходный всеми САПР изготовления ПЛИС и СБИС. Эти САПР выполняют замену вентилей на библиотечные компоненты, их размещение на площади кристалла, трассировку межсоединений, проектирование масок, проверку соответствия проектным нормам и т.п. В результате записываются файлы проектной документации изготовления кристалла и его логической модели, учитывающей задержки как в вентилях, так и в межсоединениях. Эта модель также представляется на VHDL.
Стоимость ошибок при проектировании СБИС очень высока, особенно на ранних этапах. Поэтому все этапы проектирования - алгоритмический, структурный, логический, технологический - сопровождаются моделированием ВУ с помощью, так называемого испытательного стенда (testbench). Этот стенд представляет собой VHDL-модель, составными частями которой являются модель тестируемого ВУ и модели генератора тестовых сигналов и логического анализатора, проверяющих правильность функционирования ВУ. Причем на всех этапах может использоваться один и тот же испытательный стенд и те же тестовые файлы.
Изучение VHDL...
Подготавливается к публикации.
E-mail: aser@comsys.ntu-kpi.kiev.ua
Изучение VHDL Методика HALLO, WORLD
Эта методика пришла к нам из времен компьютеров – динозавров. Представьте начинающего программиста у консоли компьютера в виде телетайпа. Вводится программа, запускается на компиляцию – через нecколько минут реакция консоли – ошибки в таких-то строках. Опять вводится программа – аналогичная реакция. И так далее, пока хватит терпения программиста. Бывало, что на этой почве у программиста развивался комплекс неполноценности перед тупым компьютером.
Поэтому в большинстве учебников по языкам программирования предлагалось свою первую программу написать как самую элементарную, но требующую минимум усилий для отладки. Обычно приводился один и тот же пример: программа выдачи на консоль сообщения: " HАLLO, WORLD". А дальше предлагалось последовательно совершенствовать и усложнять эту программу добавляя операторы и заменяя одни операторы на другие.
В наше время при изложении языка VHDL в большинстве учебников также не отходят от этой методики. Правда, программ выдачи на консоль этого сообщения не приводится. Тем не менее, сперва предлагается, как начать программировать логические схемы на VHDL, а затем постепенно уточняются сведения о синтаксисе, семантике и нюансы языка, которые отличают его от других алгоритмических языков.
Рассмотрим, как выглядит эта методика в чистом виде. Чтобы выдать сообщение на консоль необходимо скомпилировать и запустить на моделирование программу:
entity hаllo is --заголовок объекта проектаend hаllo; architecture empty of hаllo is --заголовок архитектуры empty объека hаllo
begin -- начало исполнительной части архитектуры
assert 1/=1 report "Hаllo,world" ;--оператор сообщения
end hаllo; --конец архитектуры и программы
Здесь текст, начинающийся двумя тире и оканчивающийся в конце строки, означает комментарий. Оператор сообщения-ловушки assert предназначен для проверки условия моделирования и если оно ложно – значение false – выводится сообщение об ошибке. В данном случае (1/=1)= false.
Изучение VHDL. Стиль программирования для синтеза
Одним из важнейших назначений VHDL является описание проектов дискретных устройств для автоматизированного проектирования микросхем. В основе технологии разработки микросхем (заказных СБИС или ПЛИС) лежит автоматическая трансляция VHDL-описания дискретного устройства в схему на логическом уровне, которая выполняется с помощью компилятора-синтезатора. Здесь под синтезом понимается получение аппаратной модели, которая исполняет исходную VHDL-программу и преобразование её в логическую схему. Причем подбор структуры модели, её логическая оптимизация по критериям минимума аппаратуры и максимума быстродействия с учетом элементного базиса целевой микросхемы выполняются автоматически.
Программирование на VHDL означает организацию вычислительного процесса на программистской модели параллельной вычислительной системы, состоящей из виртуальных процессорных элементов (ВПЭ). Например, каждый из таких параллельных операторов, как процесс, параллельное присваивание сигналу, выполняется на таком ВПЭ. А последовательные операторы процесса образуют программу этого ВПЭ .
Работа компилятора-синтезатора основана на взаимно-однозначном инъективном отображении программистской модели, отвечающей исходной VHDL-программе, в аппаратную модель. Это означает, что каждому из виртуальному ВПЭ с его программой ставится в соответствие некоторый специализированный процессорный элемент (СПЭ), а граф линий связи между ВПЭ и граф соединений между СПЭ - изоморфны.
Различают два типа СПЭ: СПЭ с памятью и без неё. СПЭ без памяти представляют собой комбинационную схему, состояние выходов которой (источников сигнала) представляет собой некоторую логическую функцию от состояния её входов (приемников сигнала).
СПЭ с памятью имеют в своей структуре комбинационную схему и регистры для хранения результатов и промежуточных операндов. Состояние выходов СПЭ является логической функцией не только от состояния входов, но и от состояния регистров. Регистры могут запоминать операнды как по уровню синхросигнала (защелка), так и по его фронту (триггер).
В отличие от ВПЭ задержка от входов СПЭ до его выходов представляет собой величину, определяемую по характеристикам элементного базиса, а не дельта-задержку или задержку, заданную оператором wait.
При отображении вместо оператора каждого типа подставляется соответствующая ему логическая схема. Так, операции and ставится в соответствие логическое "И", а операции "*" - комбинационный умножитель.
Если, по ceмантике оператора процесса предполагается, что не вce его переменные и сигналы выполняют присваивания при некотором запуске процесса, то это означает, что такие переменные и сигналы должны хранить свое предыдущее состояние при этом запуске. Поэтому эти процессы отображаются в СПЭ с памятью.
На аппаратную модель реализации VHDL налагается ряд ограничений, свя-зан-ных с особенностями элементной базы СБИС или ПЛИС. Эти ограниче-ния имеют прообраз в программистской модели. В основном, они образуют множество объектов и операторов языка, которые не могут быть отображены в аппаратуру, так как не имеют в ней соответствующего эквивалента.
На ceгодняшний день не могут быть отображены в аппаратуру сигналы и переменные типа с плавающей запятой, динамического типа, файлового типа, операция деления, операторы wait с параметром задержки, операторы вывода на консоль assert и report. Также глобальные переменные не находят своего отображения.
Некоторые значения перечисляемого типа, такие как "U" - не инициализированное, "Х" - неизвестное, "-" - безразличное, также не могут быть отображены в аппаратуру, а другие, как например, "Н" - слабая единица или "L" - слабый ноль, отображаются, соответственно в 1 и 0.
Не могут быть синтезированы такие языковые конструкции, для которых невозможно определить конкретную комбинационную схему на период компи-ля-ции. Например, оператор цикла отображается в многоуровневую комбинаци-он-ную схему, в которой число уровней равно количеству итераций. И если ко-ли-чест-во итераций неизвестно на период компиляции, т.е. это количество не выражено статическим выражением (например, если пара-метр итераций вычисляется в процесce), то такую схему построить невозможно.
Говорят, что VHDL-программа, в которой отсутствуют несинтезируемые объек-ты, операторы и конструкции, написана стилем для синтеза. При составлении программы стилем для синтеза желательно принять во внимание следующее.
»Существует несколько широко распространенных компиляторов-синтезаторов от различных фирм-поставщиков. Эти компиляторы различаются, в частности, списком несинтезируемых элементов языка VHDL. Причем с появлением новых версий компиляторов этот список обычно сокращается.
»Компиляторы-синтезаторы также существенно различаются по возможностям оптимизации отображения, набором атрибутов, управляющих синтезом, библиотеками процедур и функций, возможностями распознавания идиом языка, которые эффективно отображаются в СПЭ, адаптированные к целевой элементной базе. Поэтому для умелого написания программ для синтеза желательно накопить опыт работы с тем или иным компилятором.
Программисты, которые уже ощутили смысл и тонкости синтезируемого стиля, программируют свою собственную программистскую модель. Такая модель является тем самым вычислительным устройством, которое проектируется. При этом естественным образом представляется, как за каждым параллельным оператором стоит аппаратный узел, который исполняет этот оператор.
Например,
Сprocess(clk) begin if rising_edge(clk) then if ena='1'; then Сend if; end if; end process; -- отображается в регистр с разрешением записи, а process(clk) begin if rising_edge(clk) then if ena='1' then Сend if ; end if; end process; -- отображается в тот же сумматор с тем же регистром на выходе.Изучение VHDLАрхитектура объекта.
Архитектура объекта представляет собой отдельную часть, в которой описано, каким образом реализован объект. Ее синтаксис:
\тело архитектуры\::= architecture \идентификатор\ of \имя объекта\ is
{\объявление в блоке\}
begin
{ \параллельный оператор\}
end [architecture][\идентификатор\];
Идентификатором обозначается имя конкретного тела архитектуры, а имя объекта указывает, который из объектов описан в этом теле. Одному объекту проекта может соответствовать несколько архитектур, в каждой из которых описан один из вариантов реализации объекта.
Объявление в теле архитектуры такое же, как в блоке и им может быть: объявление и тело процедуры или функции, объявление типа и подтипа, объявление файла, псевдонима, константы, глобальной переменной, объявление и спецификация атрибута, объявление группы, описание use, а также объявление компонентов. Объявленные в теле архтектуры типы, сигналы, подпрограммы видимы только в пределах этой архитектуры.
Исполнительную часть архитектуры составляют параллельные операторы, такие как процесс, блок, параллельное присваивание сигналу и др. Эти операторы исполняются параллельно.
Так как все операторы в исполнительной части тела архитектуры – параллельные, их взаимный порядок – безразличен. Хорошим стилем считается, когда параллельные операторы ставятся в последовательности, соответствующей цепочкам вершин граф-схемы алгоритма, реализуемого в архитектуре.
Примером тела архитектуры служит архитектура для объявления объекта 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;
architecture BEHAV of RS_FF is --описание архитектуры объекта
begin
process(S,R)
variable qi: bit;
begin
if S='1' then
qi:='1' ;
elsif R='1' then
qi:='0';
end if;
Q<=qi after delay;
nQ<=not qi after delay;
end process;
end architecture BEHAV;
Данную программу, включающую объявление объекта и тело архитектуры можно транслировать и моделировать. Если из объявления объекта удалить исполнительную часть и описание generic, то программа будет написана синтезируемым стилем и ее можно также компилировать в логическую схему.
Изучение VHDLАтрибуты.
Язык VHDL предоставляет программисту широчайшие возможности для выражения того, чего он задумал. Один и тот же проект можно описать по-разному, но получить одинаковые результаты. Если характер этих различий выстраивается в некоторую систему, то говорят, что программа написана каким-то стилем.
Ниже рассматриваются основные выработанные стили программирования на VHDL.
Входным блоком любого транслятора является синтаксический анализатор (parser). Его главная функция - определить, написан ли данный текст таким-то языком, или нет (мол, есть ли ошибки и где), и если да - то предоставить грамматический разбор. Ему безразлично то, что этот текст означает и его форма написания, т.е. его семантика и стилистика. Собственно компиляция означает подстановку цепочек библиотечных компонентов вместо значимых операторов и выражений в соответствии с их семантикой. Стилистика программы VHDL различается только компиляторами-синтезаторами. И то только в том плане, что они отказываются компилировать программы, не соответствующие синтезируемому стилю. В частности, здесь устоялся характерный стиль описания регистров и блоков памяти.
Операторы процесса задают поведение сигналов в зависимости от событий, происходящих во времени. Поэтому если архитектура включает только операторы процесса, то говорят, что такая архитектура описана поведенческим стилем.
Операторы параллельного присваивания, вызова процедуры, условного и селективного параллельного присваивания указывают потоки данных между линиями связи, обозначенными идентификаторами сигналов, а также обработку этих потоков. Поэтому если в теле архитектуры встречаются только такие операторы, то говорят, что эта архитектура написана стилем потоков данных.
Наконец, в архитектуре, описанной только операторами вставки компонента, непосредственно закодирована структура проектируемого устройства. Сами операторы отвечают структурным блокам, а сигналы, связанные с портами – линиям связи между этими блоками. Поэтому говорят, что такая архитектура описана структурным стилем.
Естественно, архитектуры, описанные различными стилями, могут иметь произвольное количество операторов generate и block. Часто встречаются архитектуры, описанные смешанным стилем.
В программах, предназначенных для синтеза, регистры и другие схемы с памятью можно описать только с помощью оператора процесса или вставкой компонента с памятью. Так как в архитектуре, описанной стилем потоков данных, нет операторов процессов, то такая архитектура описывает комбинационную схему. Исключением является случай, поддерживаемый некоторыми компиляторами, когда регистр задается оператором block со сдерживаемыми операторами параллельного присваивания, выражение сдерживания которого является условием разрешения записи.
Хорошим стилем программирования считается, когда в иерархическом проекте объекты верхних уровней описываются только структурным стилем.
Стиль программирования разработчиков может отличаться в соответствии с их вкусами. Например, многие, особенно начинающие, предпочитают стиль потоков данных с применением операторов процесса только для описания регистров. Такой стиль дает прямую аналогию между программой и логической схемой. Для многих разработчиков этот стиль перекочевал из технологии программирования ПЛМ.
Автор больше склоняется к такому стилю написания программ, когда используется малое количество больших операторов процесса. При этом проект устройства представляется в воображении как параллельная система из специализированных процессорных элементов, соответствующих операторам процесса. Кроме того, так как число процессов мало, поведенческое моделирование проекта выполняется более ускоренно.
Но слишком большой и неструктурированный процесс может стать запутанным, а синтезированная по нему схема - неоптимальной (руководство по синтезатору иногда предупреждает об этом). В этом единственный недостаток такого стиля. В этом плане полезен совет из программирования на Си: - программный модуль должен быть не большим и не маленьким, а таким, чтобы помещался в поле зрения. Поэтому оптимальный по величине оператор процесса должен занимать не более 1 страницы текста.
Атрибутом называют особенное, долговременное свойство предмета. В языке VHDL сигналы, переменные и другие объекты, кроме своего значения, также имеют множество атрибутов. У каждого типа объектов есть несколько предопределенных атрибутов. Пользователь также может ввести ряд специальных атрибутов. Атрибуты бывают различного типа: атрибут – тип, значение, сигнал, функция, диапазон.
Атрибут объекта записывается как
\имя объекта\' \имя атрибута\ .
Ниже рассматриваются некоторые предопределенные атрибуты.
Изучение VHDLМетки в программе.
В языке VHDL любой оператор может иметь метку. Метка представляет собой идентификатор, уникальный в пределах данной программной единицы, который отделен от оператора двоеточием. Так, в синтаксисе оператора цикла указывается, что он может иметь метку, которая используется для организации вложенных циклов и работы операторов запуска следующей итерации и выхода из цикла. Такие операторы, как generate, вставки компонента, обязаны иметь метки.
Обычно программисты пренебрегают расстановкой меток. VHDL и так требует много текстового описания (в ~1,5 раза больше, чем Verilog), а тут еще и метки… Но метки - это всё-таки неплохо. Как можно более широкое применение меток обуславливается следующими причинами.
1) В операторах процесса, блока и др. встречаются объявления констант, процедур и функций, которые видимы в пределах данного оператора. Чтоб они были видимы в другом месте, можно использовать описание use, в котором как адрес объявления, указывается метка.
2) Операторы, такие как процесс, блок, могут занимать большое количество строк текста. Тогда метка, поставленная в конце оператора, совпадающая с меткой вначале, служит закрывающей скобкой, по которой программист быстро найдет границу оператора.
3) Такие операторы, как вставка компонента и блок, обязательно имеют метку. По этой метке с помощью объявления конфигурации можно подставить нужную реализацию компонента или блока, отличную от заданной в объекте проекта.
4) При моделировании симулятор работает со скомпилированной программой, в которой всем параллельным операторам поставлены метки. Если у оператора не было метки, то симулятор ставит метку по своему усмотрению, например, номер строки, где стоит оператор. По этой метке программист ищет в модели переменные и сигналы, изменяемые в операторе. Поиск переменных удобнее делать по метке, название которой по смыслу указывает на место в программе.
5) При трансляции программы в логическую схему компилятор-синтезатор каждому параллельному оператору ставит в соответствие логическую схему или библиотечный компонент с именем, соответствующим метке оператора. Если метка отсутствует, то компилятор ставит произвольное имя, например, букву с порядковым номером. Такое имя затрудняет дальнейшие отладку и тестирование проекта на уровне логической схемы и схемы после размещения и трассировки. А по уникальной и смыслосодержащей метке можно легко найти тот самый вентиль или триггер в EDIF -файле, или VHDL-модели после разводки, в которые отразился соответствующий оператор из исходной программы. По-другому это сделать значительно труднее, так как размеры указанных файлов могут достигать нескольких сотен тысяч строк.
6) Имя метки может отражать специфику и алгоритм функционирования данного оператора. Например, процесс, моделирущий регистр с аккумулятором, может обозначаться меткой RG_ACC. В этом случае другому программисту легче разобраться в программе. Поэтому вставка смыслосодержащих меток операторов это обязательное требование для проектов, предназначенных для повторного использования.
Но при сочинении смыслосодержащей метки, как и смыслосодержащих имен переменных, сигналов, объектов проекта, нельзя переусердствовать с длиной имен. Существует практика написания длинных имен в программировании на Си, которая неприменима в программировании на VHDL.
Дело в том, что если проект иерархический, то при его синтезе компилятор приводит его до одного уровня. При этом имена вентилей и линий связи строятся как объединение имен соответствующих сигналов, меток экземпляров объектов на всех уровнях проекта. В результате, в EDIF -файле, или VHDL-модели после разводки могут появиться имена длиной в сотни символов, которые не помещаются на экране целиком, не говоря уже о длине самих файлов.
Изучение VHDLОбъявление конфигурации.
После того, как проект описан в виде объекта и его архитектуры, которая включает в себя различные компоненты, эти компоненты можно заменить на другие с таким же интерфейсом, применив объявление конфигурации. Его упрощенный синтаксис:
\объявление конфигурации\::=
configuration \идентификатор\ of \имя объекта\ is
for \имя архитектуры\
{for \указатели вставки компонента\: \имя компонента\
\указатель связывания\;
end for;}
end for;
end [configuration] [\идентификатор\];
\ указатели вставки компонента \::=\метка вставки компонента\
{,\метка вставки компонента\} | others | all
\указатель связывания\::= use entity
\имя объекта\ [(\идентификатор архитектуры\)]
При разработке вычислительного устройства его обычно тестируют на различных этапах проектирования с помощью одного и того же испытательного стенда (test bench), который также описан с помощью пары объект – архитектура, например, ALU_TB(TB_ARCH). В этом случае вставленный в испытательный стенд компонент тестируемого объекта, например, ALU с меткой UUT (unit under test), имеет различное исполнение, т.е. архитектуру, например, RTL. Для того, чтобы не изменять описание архитектуры испытательного стенда, изменяют только его конфигурацию, например:
configuration TESTBENCH_FOR_ALU of ALU_TB is
for TB_ARCH
for UUT: ALU
use entity work.ALU(RTL);
end for;
end for;
end TESTBENCH_FOR_ALU;
Расширенный синтаксис объявления конфигурации предполагает такие возможности, как подключение других конфигураций, вставку компонента непосредственно в конфигурации (в указателе связывания), связывание настроечных констант компонента с новыми значениями, отключение компонента от схемы (отложенное включение, когда в указателе связывания – ключевые слова use open).
Если в конфигурации используются компоненты, описанные в другой библиотеке, то их делают видимыми с помощью описаний library и use , которые ставят перед конфигурацией.
Изучение VHDLОбъявление объекта.
Объявление объекта указывает, как объект проекта выглядит снаружи и каким образом его можно включить в другом объекте в качестве компонента, т.е. он описывает внешний интерфейс объекта. Синтаксис объявления объекта:
\объявление объекта\::= entity \идентификатор\ is
[generic(\объявление настроечной константы\
{; \объявление настроечной константы\});]
[port (\объявление порта\ {;\объявление порта\});]
{\объявление в объекте\}
[begin
{\оператор assert\ | \пассивный вызов процедуры\ | \пассивный процесс\ }]
end [entity][\идентификатор\];
Здесь \идентификатор\ - имя объекта. Синтаксис объявления настроечной константы и объявления порта рассмотрены в разделе описания объектов и типов языка.
Изучение VHDLОператор block.
В языке VHDL блок представляет собой выделенное множество параллельных операторов. Этот оператор, как и оператор процесса является основным операторам языка VHDL. Все операторы вставки компонента в проекте можно заменить на эквивалентные операторы блока. Большой иерархический объект проекта можно представить одним объектом, в котором компоненты заменены эквивалентными блоками. Синтаксис этого оператора:
\оператор block\::=[\метка\]: block [\выражение сдерживания\] [is]
[generic(\объявление настроечной константы\
{; \объявление настроечной константы\});]
[generic map(\связывание настроечной константы\
{, \связывание настроечной константы\});]
[port (\объявление порта\ {;\объявление порта\});]
[port map (\связывание порта\
{,\связывание порта\})];
{\объявление в блоке\}
begin
{\параллельный оператор\ }
end block [\метка\];
В описании блока фраза generic объявляет типы внутренних настроечных констант блока, фраза generic map, описывает список связывания настроечных констант, поступающих извне с внутренними настроечными константами, объявления порта описывают входные и выходные сигналы блока, а список связываний портов задает соответствие внешних сигналов и сигналов портов. В блоке могут быть объявлены те же объекты языка, которые объявляются в теле архитектуры.
Отдельное необязательное булевское выражение сдерживания неявно задает специальный необъявляемый сигнал guard, который разрешает или запрещает (сдерживает) выполнение операторов присваивания сигналу с условием guard. Этот же сигнал может участвовать как операнд в выражениях в пределах блока.
Как и в других языках программирования, блоки в VHDL выполняют две основные функции: создание локальной памяти для сигналов и введение обособленной области их действия (области видимости). Также блоки могут иметь иерархическое построение, т.е. могут применяться в блоках на более высоком уровне. С помощью оператора конфигурации можно вместо одних блоков подставлять блоки с другим исполнением. Эквивалентным блоком можно заменить любую пару объект-архитектура, используемую как компонент.
В разделах, посвященных операторам процесса и присваивания сигналу указывалось, что нельзя одному сигналу присваивать значение в разных процессах, если над типом сигнала не определена функция разрешения. Для реализации корректного присваивания сигналу любого типа в разных процессах, язык VHDL предоставляет операторы присваивания сигналу со сдерживанием.
Для этого, во-первых, процесс с оператором присваивания сигналу или соответствующий параллельный оператор помещают в блок с выражением сдерживания. Во-вторых, оператор присваивания сигналу оформляют как оператор со сдерживанием, для чего перед выражением оператора ставится ключевое слово guarded. Например, блоки В1 и В2:
signal A,B,C: out integer bus :=0;
disconnect С:integer after 2 ns;
…
4B1: block (sel = 1) is begin
С <= guarded А;
end block B1;
B2: block (sel = 2) is begin
С <= guarded D;
end block B2;
выдают в общую шину, представленную сигналом С, целое значение А при условии равенства 1 управляющего сигнала sel (т.е. когда сигнал guard<=(sel = 1) равен true) и значение сигнала D при другом условии в выражении сдерживания. Если guard = false, то источник сигнала отключается от шины, т.е. выполняется его сдерживание. Отключение источника может происходить с задержкой, устанавливаемой в объявлении disconnect, которое следует за объявлением сигнала. В приведенном примере отключение происходит с задержкой 2 нс.
В случае, когда не выбран ни один источник, сигнал принимает свое предыдущее значение, если источник сигнала типа register или предварительно заданное значение, если источник сигнала типа bus. Ключевыми словами register и bus сигналы обозначаются при их объявлении. Благодаря механизму сдерживания, один сигнал может иметь несколько источников – выходов блоков. При этом правильное поведение этого сигнала состоит в выборке не более одного источника сигнала одновременно, т.е. сигнал guard защищает (guards) общую шину от неправильного функционирования. Таким образом, еще одной основной функцией блоков в VHDL является организация нескольких источников для одного сигнала.
Обычно трансляция операторов блоков поддерживается компиляторами-синтезаторами. Но использование механизма подключения к общей шине, обеспечиваемого блоками, а также программирование поведения модели, связанное с ключевыми словами register, bus, disconnect, как правило, запрещаются. Также не поддерживаются связывания портов и настроечных констант в блоках. Следует отметить, что при внедрении проекта устройства иногда его необходимо перевести на язык Verilog, в котором отсутствует оператор, эквивалентный оператору block. Поэтому использование оператора block при синтезе не рекомендуется.
Изучение VHDLОператор цикла.
Этот оператор несколько раз выполняет последовательность операторов. Его синтаксис:
\оператор цикла\::=[\метка\:][\схема итерации\]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, т.е. реализована функция приоритетного шифратора. Сравните, насколько проще оказалось программирование этой схемы по сравнению с программированием стилем потоков данных (заметка "Hallo, World"), при том, что синтезатор синтезирует этот фрагмент программы достаточно эффективно.
Оператор loop часто применяется без схемы итерации, т.е. когда цикл может выполняться неопределенно большое число раз. Следующий пример с таким циклом илюстрирует модель счетчика синхроимпульсов CLK.
signal clk: bit;
signal numb:natural;
…
numb<=0;
loop
wait until clk='1';
numb<=numb+1;
end loop;
Изучение VHDLОператор generate.
Если необходимо неоднократно повторить один или несколько параллельных операторов, то используют оператор generate. Его синтаксис:
\оператор generate\::= \метка\: for \идентификатор\ in \диапазон\ generate
[{\объявление в блоке\}
begin]
{ \параллельный оператор\}
end generate [\метка\];
Метка оператора generate необходима для обозначения сгенерированной структуры, \идентификатор\ - это параметр оператора generate, а фраза \диапазон\ - диапазон его изменения. Они имеют такие же синтаксис и семантику, как и в операторе loop. В операторе могут быть вставлены такие же объявления, как в декларативной части тела архитектуры.
В отличие от оператора loop, который повторяет в цикле один или несколько последовательных операторов, оператор generate делает несколько копий параллельных операторов, когда параметр оператора пробегает все значения из заданного диапазона.
В следующем примере с помощью оператора generate запрограммирована схема сдвигового регистра длиной n на триггерах FD из библиотеки компонентов ПЛИС Xilinx, описанного в пакете UNISIM.unisim_VITAL с входом DI и выходом DO, тактируемого синхросерией CLK.
signal t: std_logic_vector(1 to n+1);
…
t(1)<=DI;
FIFO: for i in 1 to n generate
U_ TT: FD(C=>CLK, D=>t(i), Q=>t(i+1));
end generate;
DO<=t(n+1);
Для того чтобы управлять структурой проектируемого устройства используется условный оператор generate. Его синтаксис:
\условный оператор generate\::= \метка\: if \булевское выражение\ generate
[ {\объявление в блоке\}
begin]
{ \параллельный оператор\}
end generate [\метка\];
В зависимости от условия, заданного булевским выражением, оператор вставляет или нет в структуру устройства узлы, представленные параллельными операторами. Так как это булевское выражение влияет на структуру устройства, оно должно быть статическим. В примере:
RESn: if \подключить_PULLUP\=1 generate
RES1:for i in DATA_BUS'range generate
U_ RES: PULLUP(DATA_BUS(i));
end generate;
end generate;
если целое значение \подключить_PULLUP\ равно 1, то к шине DATA_BUS подключаются компоненты нагрузочных резисторов PULLUP из библиотеки UNISIM.
Направлением научной деятельности автора является синтез структур вычислительных устройств. Поэтому язык VHDL нравится именно тем, что с помощью таких средств, как оператор generate можно программировать структуру устройства в зависимости от параметров ее настройки. Например, можно создать проект универсального цифрового фильтра, число ступеней которого изменяется в зависимости от заданного качества фильтрации.
К сожалению, в языке Verilog нет операторов, аналогичных generate. И только поэтому не рекомендуется в проектах для синтеза использовать этот оператор, так как такой проект трудно перевести на Verilog, если возникнет такая необходимость. В этом случае прийдется написать столько Verilog - программ, сколько вариантов настройки структуры. Или на каком-то алгоритмическом языке, например, Java, Perl, VHDL написать программу, генерирующую Verilog - файл, соответствующий заданной настройке.
Изучение VHDLОператор ожидания события wait.
Этот оператор уже упоминаляся при описании вычислительной модели для программирования на VHDL, принципов работы симулятора. На этом операторе выполнение процесса останавливается, в момент остановки выполняются присваивания сигналам и процесс продолжает исполнение при появлении события, которое выбирается этим оператором. Синтаксис оператора 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 без списка чувствительности, условия ожидания и задержки ожидания остановит процесс до конца моделирования. Процесс, в котором последним оператором стоит единственный оператор wait on \СЧ\; эквивалентен процессу со списком чувствительности \СЧ\, в котором стоят те же операторы, кроме wait on . Эта эквивалентная форма процесса несколько уменьшает текст программы, улучшает его чтение и напоминает фразу allways из языкаVerilog. Программа с каким - либо оператором процесса, в котором отсутствует и список чувствительности, и оператор wait , зависает, так как такой процесс начинает вычисляться циклически без остановки и без передачи управления другим процессам.
Иногда при моделировании необходимо, чтобы процесс вначале один раз выполнил, например, процедуру ST1, а затем исполнялся периодически как обычно, допустим, выполнял процедуру ST2. Такой процесс можно запрограммировать следующим образом:
process begin
ST1;
loop
ST2;
wait on some_signal_list;
end loop;
end process;
Например, таким способом просто запрограммировать генератор синхроимпульсов:
process begin
CLK<='0';
loop
CLK<=not CLK ;
exit when end_of_simulation;
wait for 10 ns;
end loop;
wait;
end process;
Этот процесс генерирует синхросерию с периодом 10+10 наносекунд в цикле loop, выходит из него при условии end_of_simulation=true и останавливается.
Обычно симулятор VHDL работает заданный промежуток времени или без остановки. А что делать, если моделирование выполняется неопределенное время? Например, запустили тяжелое моделирование на выходные. А в понедельник пришли и нашли зависший компьютер, переполненный ненужными результатами. Тогда можно использовать такое решение.
Часто в проекте синхрогенератор - это единственный источник событий, запускающих моделирование. Каждый симулятор построен таким образом, что в случае, когда нет событий, то он останавливается с сообщением: "Simulation has finished. There are no more vectors to simulate". Следовательно, вышеописанный генератор синхросерии - удобное средство для остановки симуляции по какому - то запрограммированному условию, которое вырабатывается тогда, когда симуляция с получением ожидаемых результатов завершена.
Изучение VHDLОператор процесса.
Оператор процесса – это параллельный оператор, представляющий основу языка VHDL. Его упрощенный синтаксис:
\оператор процесса\ ::=[postponed] process [(\имя сигнала\ {,\имя сигнала\})] [is]
{\объявление в процессе\}
begin
{\последовательный оператор\}
end process;
Объявленными в процессе могут быть: объявление и тело подпрограммы, объявление типа и подтипа, объявление константы, переменной, файла, псевдонима, объявление и спецификация атрибута, объявление группы, описание use. То, что объявлено в процессе, имеет область действия (видимость), ограниченную данным процессом.
Все процессы в программе выполняются параллельно. Процессы обмениваются сигналами, которые выполняют синхронизацию процессов и переносят значения между ними. Если над сигналами определена функция разрешения, то выходы источников сигнала могут объединяться. Сигналы нельзя объявлять в процессах. Процесс невозможно поместить в процесс, так как там есть место только для последовательных операторов.
В круглых скобках заголовка процесса указывается множество сигналов, по которым процесс запускается – список чувствительности. Это форма оператора процесса, альтернативная процессу с оператором wait on, стоящим последним в цепочке последовательных операторов тела процесса. Любой процесс со списком чувствительности может быть преобразован в эквивалентный процесс с оператором wait on, стоящим последним в списке последовательных операторов. В операторе процесса со списком чувствительности ставить операторы wait не допускается.
Об отложенных процессах, отмеченных ключевым словом postponed, уже говорилось, когда шла речь об архитектуре симулятора VHDL. Здесь следует добавить, что, так как отложенный процесс запускается последним в цепочке процессов с дельта-задержкой, то он сам должен исполняться с ненулевой задержкой, т.е. в нем должен быть оператор wait for.
Процесс представляет собой маленькую программу, которая выполняется на виртуальном процессорном элементе. Рассмотрим процесс, вычисляющий функцию синуса y от аргумента x по аппроксимирующей формуле:
sin(x) = c1x+c2x3+c3x5+c4x7.
Процесс выглядит следующим образом:
process
type tabl is array(0 to 3) of real;
constant c:tabl:=(0.99999, -0.16666, 0.00831, -0.00019);
variable xtmp, p: real:=0.0;
begin
xtmp:=x;
p:=c(0)*xtmp;
for i in 1 to 3 loop
p:=p+c(i)*xtmp*x*x;
end loop;
y<=p;
wait on x;
end process;
При моделировании логических схем в список чувствительности процесса необходимо вносить все входные сигналы, иначе моделирование схемы будет отличаться от ожидаемого. Например, процесс
process(A) begin
c<= A or B;
end process;
при моделировании дает графики как на рис. Из графиков видно, что изменение результирующего сигнала С происходит только в моменты изменения сигнала A, т.е. процесс моделирует некоторую триггерную схему, а не схему ИЛИ.
Если в процессе запрограммирован алгоритм функционирования триггерной схемы, например, регистра, то допускается в списке чувствительности оставлять только сигналы управления записью и разрешения чтения, например, сигналы сброса и синхросерии.
При синтезе списки чувствительности игнорируются компилятором.
E-mail: aser@comsys.ntu-kpi.kiev.ua
Назад | Содержание | На главную | Далее |
Изучение VHDLОператор вставки компонента.
Оператор вставки компонента - это любимый оператор начинающих программистов. Он играет основную роль для реализации иерархического проектирования. Его синтаксис:
\оператор вставки компонента\::= \метка экземпляра элемента\ :
\вставляемый элемент\
[generic map(\связывание настроечной константы\
{, \связывание настроечной константы\});]
[port map (\связывание порта\
{,\связывание порта\})];
\вставляемый элемент\ ::= [component] \имя компонента\
| entity \имя объекта\[идентификатор архитектуры]
| configuration \имя конфигурации\
Действие этого оператора заключается в подстановке вместо себя одного экземпляра компонента (вставляемый элемент - компонент) или объекта (вставляемый элемент - объект проекта), или компонента, указанного в конфигурации. Если вставляется компонент, то он должен быть объявлен в данной архитектуре.
Сколько раз встречается имя вставляемого компонента – столько копий объекта вставляется в странслированную программу. При этом каждая копия имеет уникальное имя, указанное в метке компонента. Таким образом, при многократной вставке компонента в странслированном проекте дублируются несколько раз все параллельные операторы указанного компонента, а, следовательно, дублируются сответствующие им виртуальные процессорные элементы программистской модели.
Фраза \связывание порта\ указывает порядок подключения сигналов данного тела архитектуры к портам – сигналам компонента. Связывание может быть как позиционным, так и ассоциативным (поименованным), а также комбинированным. При позиционном связывании параметры-выражения подставляются в порядке, определенном порядком следования имен параметров в объявлении компонента. При поименованном связывании каждое имя порта связывается с соответствующим сигналом с помощью символов "=>", причем порядок следования портов может быть произвольным. Второй способ связывания предпочтителен, так как поименованное связывание более понятно при чтении и меньше вероятность допустить ошибку при записи.
Неподключенные порты с режимом out или inout допускается не указывать в списке связывания портов. Но более понятным и правильным считается связывание таких портов с условным сигналом, обозначенным ключевым словом open.
В поименованном связывании допускается связывать вырезку порта с сигналом. Например, вставка компонента регистра, выходы которого подключены к различным сигналам, имеет вид:
U_RG: RG16 port map (CLK => CLK,
E => \разр_зп_рг\,
DI => D,
DO(15)=> open,
DO(14)=> \знак_D\,
DO(13 downto 0)=>\мантисса_D\ );
Более полный синтаксис допускает связывать порт и сигнал в виде статического выражения с использованием вызовов функций, например:
DI => Conv_Integer(D(n-1 downto 0));
To_Bit(DO(14)) => \знак_D\,
т.е. здесь для совмещения типов порта DI в режиме in и сигнала D, разряда DO(14) порта в режиме out и сигнала \знак_D\ используются функции преобразования типа.
Следует отметить, что компиляторы – синтезаторы, как правило, не допускают связывание порта с функцией преобразования типа. Если выход компонента не подключен, как, например, DO(15)=>open или если выхода нет в списке связываний, то компилятор-синтезатор может минимизировать в компоненте цепи и логику, относящиеся к этому выходу, в примере – удалить триггер, подключенный к DO(15).
Синтаксис связывания настроечной константы аналогичен синтаксису связывания порта. При таком связывании настроечная константа, обозначающая, например, разрядность шин, объем памяти, задержку элемента, передается из объекта проекта более высокого уровня в объект более низкого уровня, который становится компонентом. Другими словами, при связывании настроечных констант выполняется настройка в некотором смысле обобщенного объекта до компонента с конкретными параметрами.
Все компиляторы – синтезаторы поддерживают настроечные константы целого типа.
Пусть на нижнем уровне иерархии описана модель синхронного регистра разрядности n, который принимает данное DI по фронту синхросигнала CLK:
entity RGn is
generic(n: integer);
port(CLK:bit; DI, DO: bit_vector(n-1 downto 0));
end entity;
architecture behav of RGn is begin
process(CLK)
begin
if CLK='1' and CLK'event then
DO<=DI ;
end process;
end architecture behav;
Тогда следующий оператор в теле архитектуры более высокого уровня иерархии выполняет вставку компонента этого регистра и настраивает его разрядность равной n = 8:
U_RG8: entity RGn(proc) generic map(8),
port map (CLK, DI=>DATA_IN, DO=>DATA_OUT);
Изучение VHDLОператоры assert и report.
Эти операторы были введены в язык VHDL для выявления ошибок моделирования и сообщения о них на консоль. В методике "Hallo, World" этот оператор активно применяется. У оператора ловушки assert следующий синтаксис:
\оператор assert \::= assert \булевское выражение\
[report \строка сообщения\][severity \выражение\];
Здесь \булевское выражение\ – проверка какого–либо условия правильности моделирования, которое равно false, если найдена ошибка и true, если моделирование верно;
\строка сообщения\ - выражение типа string, представляющее строку сообщения о причине ошибки. Например, оператор
assert a(i)='0'
report "бит " & integer'image(i) &" не равен 0";
вызовет выдачу на экран дисплея сообщения:
# : ERROR : бит 1 не равен 0
# : Time: 2000 ns, Iteration: 0, TOP instance.
если a(1) ? 0 на 2-й микросекунде моделирования. Здесь атрибут integer'image возвращает строку, в которой представлено значение целого i в читаемом виде. Выражение \выражение\ имеет предопределенный тип severity_level, состоящий из элементов note, warning, error и failure. Значение выражения соответствует уровню критичности найденной ошибки и при самом высоком уровне failure моделирование останавливается. Например, если требуется остановить моделирование, можно записать оператор:
assert 1/=1
report "конец моделирования " severity failure;
Если не нужно ловить ошибку, а только вывести сообщение о ходе моделирования, то применяют оператор сообщения с синтаксисом:
report \строка сообщения\ [severity \выражение\];
Предыдущий пример можно переписать как:
report "конец моделирования " severity failure;
Изучение VHDLПакеты.
В пакет объединяются декларации различных объектов и типов языка, связанных общим признаком. Затем декларации из пакета можно повторно использовать в различных частях проектов, ссылаясь на этот пакет. Многие пакеты стандартизированы и их использование упрощает разработку новых проектов, а также служит для стандартизации включения и тестирования этих проектов. Несколько пакетов, подчиненных одной сущности, собирают в библиотеку library. Библиотека, в которой собраны программы и пакеты пользователя, по умолчанию имеет название WORK.
Начинающий программист обычно обходится без составления новых пакетов. Но с какого-то момента развития творческих умений возникает желание оформлять проекты более компактно и более понятно, чтоб был явно виден свой авторский стиль. Тогда и возникает желание составлять свои собственные пакеты. Также без разработки пакетов не обходится создание крупных проектов, в которых участвуют несколько прграммистов и которые имеют широкое и длительное развитие.
В данной заметке показано, как разрабатываются пакеты. Пакет состоит из объявления пакета и необязательно, из тела пакета.
Изучение VHDLПараллельные операторы.
VHDL – это язык параллельного программирования. Параллелизм в программе задается явным образом в параллельных операторах. Параллельным операторам соответствуют виртуальные процессорные элементы в программистской модели вычислителя VHDL. Параллельные операторы образуют исполнительную часть тела архитектуры. Оператор процесса - это основной параллельный оператор. Оператор вставки компонента - также важный оператор, наиболее встречаемый в проектах. В этом разделе рассмотрены эти и другие параллельные операторы.
Все параллельные операторы, кроме оператора блока и вставки компонента, могут быть заменены на эквивалентные операторы процесса, в которых список чувствительности содержит все входные сигналы выражений исходного оператора и у которых оператор wait стоит последним в цепочке последовательных операторов.
Оператор параллельного присваивания.
Этот оператор имеет такой же синтаксис, как и оператор присваивания сигналу в процессе. Такой оператор эквивалентен оператору процесса, в котором этот оператор повторен в его исполнительной части, а последним оператором стоит оператор wait со списком чувствительности. Например, следующие два оператора эквивалентны:
ADDER:A<=B+C;
ADDER_P:process begin
A<=B+C;
wait on B,C;
end process;
Оператор условного параллельного присваивания.
Оператор условного параллельного присваивания имеет синтаксис:
\условное параллельное присваивание\::= \имя\<= [\способ задержки\]
{\график\ when \булевское выражение\ else }
\график\[when \булевское выражение\];
где определение способа задержки и графика представлено выше при описании оператора присваивания сигналу.
Любой оператор условного параллельного присваивания имеет эквивалентное представление в виде процесса, как например, оператор:
cntrl<= one when st=1 else
two when st=2 or st=3 else
three;
эквивалентен оператору
process(st,one,two,three)
begin
if st=1 then
cntrl<= one;
elsif st=2 or st=3 then
cntrl<= two;
else
cntrl<=three;
end if;
end process;
Оператор селективного параллельного присваивания.
Оператор селективного параллельного присваивания имеет синтаксис:
\селективное параллельное присваивание\::= with \выражение\ select
{\имя\<= [\способ задержки\]{\график\ when \альтернативы\,}
\график\[when others ];
где \альтернативы\ имеют то же значение, что и в операторе case. Этот оператор эквивалентен соответствующему процессу, как например, оператор:
with st select
cntrl<= one when 1,
two when 2 to 3,
three when others;
выполняет такие же действия, что и процесс:
process(st,one,two,three)
begin
case st is
when 1 => cntrl<= one;
when 2 to 3 => cntrl<= two;
when others => cntrl<= three;
end case;
end process;
Требования к выражению селектора и альтернативам оператора такие же, как у оператора case. Так, каждая из альтернатив должна быть такого же типа, что и \выражение\ и представлена статическим выражением или диапазоном. Никакие два значения, получаемые из выражений альтернатив, не должны быть равны друг другу.
Параллельный оператор assert.
Этот оператор имеет такой же синтаксис, как и соответствующий ему последовательный оператор. Он выполняется точно также, как и процесс, в исполнительной части которого стоит последовательный оператор assert с таким же содержанием.
Параллельный вызов процедуры.
Параллельный вызов процедуры имеет такой же синтаксис, как у последовательного вызова процедуры. Он исполняется точно так же, как процесс, который имеет в своей исполнительной части такой же вызов процедуры с такими же параметрами и оператор wait ожидания прихода сигналов - входных параметров. Поэтому каждый параллельный вызов процедуры соответствует некоторому виртуальному процессорному элементу, исполняющему алгоритм этой процедуры.
Если программа предназначена для синтеза, то процедура, вызываемая параллельно, не должна иметь операторов wait. Такая процедура отображается в комбинационную схему или комбинацию шин, т.е. некоторый специализированный процессорный элемент.
Отложенные параллельные операторы.
Так как всем вышеперечисленным параллельным операторам ставится в соответствие оператор процесса, то поскольку процесс бывает отложенным, то и эти параллельные операторы могут быть отложенными. Такие операторы, как и отложенный процесс, обозначаются ключевым словом postponed, которое ставится перед оператором.
Изучение VHDLПоследовальные логические операторы.
Последовательные логические операторы применяются только в процессах и схожи с логическими операторами других языков, например, Паскаля.
Изучение VHDLПоследовательные операторы
Последовательные операторы в VHDL вставляются в операторы процессов и исполняются последовательно в виртуальных процессорных элементах программистской модели, как операторы обычных алгоритмических языков. Далее рассматриваются все последовательные операторы, кроме операторов присваивания, assert и report.
Изучение VHDLПроцедуры и функции.
Процедуры и функции относятся к числу подпрограмм. Здесь рассмотрены правила и особенности составления и объявления процедур и функций, а также их вызова.
Изучение VHDLПсевдонимы.
Под псевдонимом в языках программирования понимают другое имя объекта. Псевдонимы в VHDL помогают представить программу в виде, более удобном для чтения и моделирования. Объявление псевдонима имеет синтаксис:
\объявление псевдонима\::= alias \идентификатор\ | символьный литерал\
| \символ оператора\ [:\подтип\] is \имя\ [\сигнатура\];
Наиболее часто псевдоним дают константам, переменным и сигналам. Например, псевдоним
alias \код операции\: bit_vector(7 downto 0) is \команда\(31 downto 24);
помогает обращаться с полем кода операции команды как с отдельным сигналом, не объявляя этот сигнал. При этом бит \код операции\(7) равен биту \команда\(31).
Также псевдоним можно присваивать типу. Например, если дать псевдоним
alias vect is std_logic_vector;
то можно сократить текст программы, присваивая тип vect вместо std_logic_vector, правда, за счет ухудшения ее чтения другими программистами.
Можно давать псевдоним функциям и процедурам. Например:
alias TO_V is CONV_STD_LOGIC_VECTOR [integer, integer return std_logic_vector];
где сигнатура в квадратных скобках указывает для какой из перезагружаемых функций, различаемых по набору параметров, сделать псевдоним.
Часто псевдоним дают длинным селективным именам, которые обозначают объекты, принадлежащие различным библиотекам, как например:
alias PI is IEEE.math_real.MATH_PI ;
это псевдоним константы числа пи.
Псевдонимы поддерживаются компиляторами – синтезаторами, но далеко не всеми и не в полном объеме. Не поддерживаются, например, псевдонимы процедур и функций.
Изучение VHDLСтруктура программы на VHDL.
Дискретная система может быть представлена в VHDL как объект проекта. Объект – это основная составная часть проекта. Объект может быть использован в другом проекте, который, в свою очередь, описан как объект или может являться объектом более высокого уровня в данном проекте. Не путать объект проекта с объектами языка.
Объект проекта описывается набором составных частей проекта, таких как: объявление объекта называемое entity, тело архитектуры объекта (или просто архитектура), именуемое architecture, объявление пакета (package), тело пакета (package body) и объявление конфигурации (configuration). Каждая из составных частей объекта может быть скомпилирована отдельно. Составные части проекта сохраняются в одном или нескольких текстовых файлах с расширением .VHD. В одном файле может сохраняться несколько объектов проекта.
Объект проекта обычно описывается соглано синтаксису:
\объект проекта\::= [\описание library\]
[\описание use\]
\объявление объекта\
\тело архитектуры\
[\объявление конфигурации\]
[\описание library\]::= library \идентификатор\ {, \идентификатор\};
где идентификаторы – названия библиотек, которые используются в объекте проекта. Они указывают транслятору местоположение этих библиотек. Описание use указывает, какие пакеты и какие элементы этих пакетов могут быть использованы в объекте. Далее - более подробно об этом описании.
Как работает симулятор
При работе на VHDL программист программирует параллельные операторы, которые выполняются на некоторой виртуальной параллельной вычислительной системе. Нижний уровень программистской модели образует архитектура виртуального процессорного элемента (ВПЭ), который исполняет один параллельный оператор, а верхний уровень - множество ВПЭ, объединенных запрограммированной системой межпроцессорных связей, по которым пересылаются сигналы.
Модель вычислителя с точки зрения программиста не может быть реализована в виде реальной многопроцессорной вычислительной системы из-за чрезмерно высоких аппаратных затрат. С другой стороны, язык VHDL разрабатывался с целью реализации в симуляторах дискретных систем. Собственно, IEEE Standard VHDL Language Reference Manual представляет собой описание синтаксиса конструкций языка и как они должны исполняться в симуляторе. Такой симулятор, как правило, реализован на однопроцессорной ЭВМ. Рассмотрим архитектуру вычислителя VHDL с точки зрения разработчика симулятора.
На рис. условно показана архитектура симулятора VHDL.
В данной модели каждый ВПЭ реализован как отдельный вычислительный процесс (ВП). Все вычислительные процессы разделяют во времени один и тот же аппаратный ресурс - центральный процессорный элемент (ЦПЭ) микропроцессора ПЭВМ.
Все ВП разделены на три подмножества - очередь спящих процессов, очередь готовых процессов и исполняемый процесс. Большинство ВП относится к числу спящих, т.е. к ВП, для исполнения которых нет готовых входных данных. Например, такой ВП ожидает какой-либо входной сигнал, из списка чувствительности его оператора wait. При поступлении сигнала этот ВП переносится в очередь готовых к исполнению ВП. Один из готовых ВП, выбранный произвольно, пересылается в кэш-ОЗУ микропроцессора для исполнения. Исполняемый ВП выполняет свои операторы в соответствии с семантикой функционирования ВПЭ на ресурсах ЦПЭ микропроцессора и алгоритмами соответствующих библиотек процедур. При достижении оператора wait ВП останавливается. Выработанные им сигналы запоминаются и пересылаются другим ВП, которые являются приемниками этих сигналов. Затем данный ВП пересылается в очередь спящих процессов.
Один особенный исполняемый ВП служит диспетчером для остальных процессов. Он называется ядром симулятора и формирует очереди спящих ВП и готовых к исполнению ВП, а также выбирает ВП для исполнения. Он также рассылает сигналы от исполняемого ВП к другим ВП. Кроме того, он ведет счетчик времени моделирования ТС, выполняет связь с консолью, обслуживает обращение к дисковой памяти и памяти глобальных переменных.
Для моделирования программист создает проект – каталог с файлами VHDL, имеющий название проекта. После компиляции в проекте создается библиотека проекта, которая имеет название проекта и содержит все скомпилированные объекты проекта. После запуска программы на моделирование сперва выполняется связывание объектов проекта и назначение начальных значений переменным и сигналам (elaboration).
Затем запускается собственно моделирование. При этом выбранные программистом сигналы записываются в отдельной области памяти в своем развитии и могут быть отображены на дисплее в виде таблиц или графиков.Для того, чтобы сохранить семантику исполнения множества параллельных процессов, такую же, как у системы из ВПЭ, в каждом цикле моделирования, кроме начального, симулятор выполняет следующие шаги:
Каждый остановленный ВП, для которого произошло событие в предыдущем цикле моделирования, которое ожидает соответствующий оператор wait, запускается на исполнение; в ВП, остановленных для ожидания задержки проверяется окончание этой задержки и если задержка истекла, эти ВП также запускаются. Каждый запущенный ВП исполняется до своей остановки на операторе wait, при этом вычисляются новые значения сигналов в операторах присваивания сигналам. Вычисляется новое значение текущего времени ТВ как ближайший момент времени, в который будет запущен какой-либо ВП, остановленный на операторе wait ожидания окончания задержки или момент времени следующей активации источников сигнала. Счетчик времени принимает новое значение ТС = ТВ . Каждому сигналу, для которого было вычислено новое значение, присваивается это значение; эти изменения сигналов проверяются, являются ли они событиями для каких-либо ВП.Если в следующем цикле моделирования не запускается ВП по окончанию заданной задержки или активация источников сигнала происходит без задержки, то в данном цикле счетчик времени ТС сохраняет свое прежнее значение, измеряемое в фемта- или пикосекундах. В этом случае считается, что время моделирования увеличилось на дельта-задержку.
Моделирование имеет такую особенность, что серия, включающая от нуля до нескольких циклов с дельта-задержкой сменяется одним циклом с конкретной задержкой. Обычно таких циклов в серии 0-10. Если моделируется комбинационная схема из n уровней, каждый из которых задан процессом без задержки, то будет n циклов в серии. Если программа неправильная и зацикливается, тогда циклов в серии будет значительно больше. Так, симулятор Active HDL останавливается, если циклов в цепочке более 1000.
Допустим, что в модели находятся два процесса, обменивающихся одной глобальной переменной. Тогда порядок обмена этой переменной не контролируется программистом, так как он не знает какой из этих процессов сработает первым в серии циклов с дельта-задержкой. Для того, чтобы эти процессы были запущены не в произвольном, а именно в последнем цикле с дельта-задержкой из серии циклов, причем после всех процессов, то такие процессы обозначаются как отложенные, т.е. в программе перед словом process ставится ключевое слово postponed.
При составлении VHDL-программ желательно иметь в виду следующее.
Даже небольшой процесс занимает в памяти несколько килобайт. А максимальное количество процессов в скомпилированной программе определяется объемом динамической памяти компьютера. Смена одного ВП другим ВП представляет собой смену контекста в работе ЦПЭ, которая может длиться несколько тысяч тактов. Следовательно, чем меньше процессов и вообще - параллельных операторов - тем быстрее моделирование. Наибольшую долю времени занимает исполнение ВП ядра симулятора, которая возрастает нелинейно с увеличением числа ВП и числа сигналов в списках чувствительности их операторов wait. Поэтому опять же, чем меньше процессов в откомпилированной программе и сигналов в списках чувствительности - тем быстрее выполняется эта программа в симуляторе. Не следует программировать процесс без оператора wait (или без списка чувствительности), т.к. после того, как этот процесс станет активным, он монопольно захватит ресурсы ЦПЭ.Насколько важно следовать этим рекомендациям? Это дело вкуса. В одной из первых моих VHDL- моделей я вставил модель ПЗУ в виде:
А(0) …А(4095)
И долго удивлялся, почему инициализация модели длилась несколько минут, а модель такого простенького ПЗУ занимала в памяти больше 6 Мбайт. Понимание пришло, когда узнал, что каждой такой строчке соответствует отдельный ВП. При замене массива-сигнала на массив- переменную моделирование существенно ускорилось, а модель ПЗУ стала занимать 0,6 Мбайт. А когда ПЗУ было закодировано константой, то место в ОЗУ для его модели уменьшилось до 0,13 Мбайт и соответственно, ускорилось моделирование.
Кое-что о VHDL- симуляторах.
Сейчас любая солидная САПР электроники включает в себя VHDL-симулятор. Но группа видных международных авторитетов в программировании на VHDL сходятся на том, что для обучения лучше всего подходит VHDL-симулятор Active HDL фирмы Aldec. Кроме того, что по важности не самое последнее, этот симулятор допускает коментарии, сообщения и идентификаторы на русском языке. Его бесплатную версию для обучения можно получить на сайте www.aldec.com , а литературу о нем на русском языке – на сайте www.aldec.com.ua .
Для моделирования в симуляторе Active HDL сперва нужно создать проект – каталог с файлами VHDL, имеющий название проекта. Это облегчает встроенный помощник. После компиляции в проекте создается библиотека проекта, которая имеет название проекта и содержит все скомпилированные объекты проекта. После запуска программы на моделирование сперва выполняется связывание объектов проекта и назначение начальных значений переменным и сигналам (elaboration). Затем запускается собственно симуляция. И для данной программы на консоль будет выдано сообщение:
# : ERROR : Hаllo,world
# : Time: 0 ps, Iteration: 0, TOP instance.
# KERNEL: stopped at time: 100 ns
# KERNEL: Simulation has finished. There are no more test vectors to simulate.
Программа на VHDL состоит из одного или нecкольких файлов. В одном файле размещаются одна или нecколько пар: объект проекта – архитектура объекта. Объект проекта – это интерфейсная часть, в которой указана информация о том, как включать данный объект внутри другого объекта, находящегося на более высоком уровне иерархии. А в архитектуре объекта описан алгоритм его функционирования. У одного объекта может быть нecколько архитектур, соответствующих разным алгоритмам функционирования, проектам на различных этапах проектирования. Такая структура программ VHDL позволяет строить библиотеки объектов, процедур, типов и т.п., выполнять программирование проекта в произвольном порядке: снизу-вверх или сверху-вниз, а также параллельно нecколькими программистами, использовать объекты из других проектов, тестировать проекты по одинаковой методике.
Расмотрим программирование проекта приоритетного шифратора. На вход шифратора поступают сигналы А1, …,А7 , а на выход выдаются сигналы Y2,Y1,Y0, которые кодируют номер входного сигнала, причем у А7 – наивысший приоритет. Т.е. при поступлении лог.1 на А7 и любой комбинации на остальные входы код Y2,Y1,Y0=111, при поступлении лог.0 на А7 , лог.1 на А6 и любой комбинации на остальные входы - код Y2,Y1,Y0=110 и т.д. Объект проекта выглядит как:
library std ; -- описание: используемая стандартная библиотека STD
use std.standard.all; -- описание: используются все типы из пакета STANDARD библиотеки STD
entity PRIORITY is -- название объекта - PRIORITY
port( --объявление портов
A1 : in BIT; -- входной порт А1 типа BIT
A2 : in BIT;
A3 : in BIT;
A4 : in BIT;
A5 : in BIT;
A6 : in BIT;
A7 : in BIT;
Y1 : out BIT; -- выходной порт Y1 типа BIT
Y2 : out BIT;
Y0 : out BIT );
end PRIORITY; -- конец объявления объекта
Так как библиотека STD – стандартная, она встроена во все симуляторы и может быть указана неявно. Для других библиотек, которые используются при описании объекта, нужно использовать их описание library и use. Здесь они приведены для примера.
Ключевое слово port открывает описание входов-выходов (портов) объекта. Слово in указывает на вход, а out – на выход. BIT – это тип порта, который, согласно определению этого типа в пакете standard, принимает значения 0 и 1.
Название объекта вначале и в конце – обязательно. Это дополнительная рутина, зато удобно для различения объектов, если их описание занимает много места, - как открывающаяся и закрывающаяся скобка особенного типа.
Описание архитектуры:
architecture HALLO of PRIORITY is -- начало архитектуры HALLO объекта PRIORITY
--декларативная часть архитектуры
signal t1,t2,t3,t4,t5,t6,t7:BIT; --объявление используемых сигналов
begin --начало описательной (поведенческой) части архитектуры
-- Y2Y1Y0
--A7 --1 1 1
t1<= not A7 and A6; -- 1 1 0
t2<= not A6 and A5 and not t1; -- 1 0 1
t3<= not A5 and A4 and not t1 and not t2; -- 1 0 0
t4<= not A4 and A3 and not t1 and not t2 and not t3; -- 0 1 1
t5<= not A3 and A2 and not t1 and not t2 and not t3 and not t4; -- 0 1 0
t6<= not A2 and A1 and not t1 and not t2 and not t3 and not t4 and not t5; -- 0 0 1
Y0<= A7 or t2 or t4 or t6;
Y1<= A7 or t1 or t4 or t5;
Y2<= A7 or t1 or t2 or t3;
end HALLO; --конец архитектуры
Раздел архитектуры состоит из декларативной и описательной частей. В декларативной части объявляются используемые внутри объекта сигналы, константы, специальные (свои собственные) типы, атрибуты, процедуры и функции, описания этих атрибутов, процедур и функций. Описательная часть состоит из списка параллельных операторов. Все параллельные операторы выполняются одновременно. Их порядок в списке не имеет другого значения, кроме значения, определяемого вкусом программиста.
В параллельных операторах процесса стоят последовательные операторы, выполняемые по очереди, как в программах на обычных языках. Схемы с памятью, например, триггер, регистр, ОЗУ моделируются с помощью оператора процесса или оператора вставки компонента с функцией памяти, описанного парой объект-архитектура в другом месте.
В данной программе все операторы – операторы параллельного присваивания, обозначенные символами "<=", которые сигналам присваивают значение выражения справа. Здесь в выражениях используются функции and, or и not. Hад операндами типа BIT определены еще функции nand, nor, xor, xnor. А функции сравнения "=" и "/=" - возвращают результат типа boolean со значениями true, false. Для задания четкого порядка выполнения функций в выражениях следует использовать скобки.
Эта архитектура написана стилем потоков данных, т.е. в ней использованы только параллельные операторы, кроме операторов процесса и вставки компонента. Здесь операторы как бы указывают потоки данных между линиями связи, обозначенными идентификаторами сигналов, а также обработку этих потоков.
Для проверки правильности проекта обычно используют испытательный стенд (testbench). Это тоже пара: объект – архитектура, в которой испытуемый блок использован как компонент. В Active HDL есть функция генерации испытательного стенда, которая генерирует его заготовку. Такая заготовка состоит из оператора включения испытуемого блока и набора сигналов, которые подключены к блоку. Остается только добавить операторов для генерации входных сигналов и возможно, для проверки выходных сигналов блока. Испытательный стенд для блока PRIORITY(HALLO):
entity priority_tb is --пустой объект, т.к. входов-выходов нeт
end priority_tb;
architecture TB_ARCHITECTURE of priority_tb is
component priority(hallo) -- компонент, который будет испытываться
port( -- выглядит почти так же, как объявление объекта проекта
A1 : in BIT;
A2 : in BIT;
A3 : in BIT;
A4 : in BIT;
A5 : in BIT;
A6 : in BIT;
A7 : in BIT;
Y1 : out BIT;
Y2 : out BIT;
Y0 : out BIT );
end component; -- сигналы внутри испытательного стенда
signal A1 : BIT:='0'; --сигнал объявлен с начальным состоянием = 0;
signal A2 : BIT:='0'; -- начальное состояние можно было бы не объявлять -
signal A3 : BIT:='0'; -- у битового типа и так симулятор назначает начальное состояние=0. signal A4 : BIT:='0'; -- В реальных проектах сигналы типа STD_LOGIC
signal A5 : BIT:='0'; -- и им симулятор по умолчанию назначает начальное состояние
signal A6 : BIT:='0'; -- = U - " не инициализированное "
signal A7 : BIT:='0'; -- поэтому для таких сигналов желательно объявить
signal Y1 : BIT:='0'; -- начальное состояние по своему усмотрению
signal Y2 : BIT:='0';
signal Y0 : BIT:='0';
begin -- описательная часть архитектуры
UUT : priority -- параллельный оператор вставки компонента
port map ( -- поименованное связывание портов и сигналов
A1 => A1, --порт А1 подключен к сигналу А1
A2 => A2,
A3 => A3,
A4 => A4,
A5 => A5,
A6 => A6,
A7 => A7,
Y1 => Y1,
Y2 => Y2,
Y0 => Y0
);
-- это операторы присваивания сигналу - генерируют тестовые сигналы
A1<= not A1 after 2 ns; -- оператор инвертирует сигнал,
--затем ждет 2нс и опять инвертирует и т. д. до бесконечности
A2<= not A2 after 4 ns;
A3<= not A3 after 6 ns;
A4<= not A4 after 8 ns;
A5<= not A5 after 10 ns;
A6<= not A6 after 12 ns;
A7<= not A7 after 14 ns;
end TB_ARCHITECTURE;
Эта программа запускается на моделирование и в окне графиков (waveform window) можно увидеть следующие графики:
Эти графики показывают, что модель приоритетного шифратора работает правильно. Если архитектура объекта PRIORITY претерпит изменения или модернизацию, то на этом испытательном стенде можно ее проверить опять, ничего в нем не меняя.
Итак, в данной статье рассмотрены основы программирования на VHDL и получена работоспособная, синтезируемая модель приоритетного шифратора. Эту модель можно совершенствовать, изменять число и функциональность портов ввода-вывода и т.п. Так что, согласно методике Hallo, World, можно сказать, что VHDL – это очень просто.
Конфигурирование ПЛИС
Для конфигурирования ПЛИС в ней предусмотрены входы задания режима M2, M1, M0, вывод синхросерии программирования CCLK, вход последовательности конфигурации PROGRAM, выход флага окончания конфигурирования DONE и выводы порта JTAG. В зависимости от установленного режима можно загружать прошивку ПЛИС через однобитовый вход PROGRAM, порт JTAG или 8-разрядную шину D c использованием для управления выводов WRITE и BUSY.
Конфигурирование через однобитовый вход длится до нескольких десятков секунд. Это стандартный способ конфигурирования и для него не требуется дополнительного оборудования, кроме ПЗУ прошивки с однобитовым выходом.
Для реализации конфигурирования через шину D необходимо дополнительное внешнее устройство (автомат или микроконтроллер), управляющее записью и выдающее последовательность адресов чтения на входы байтового ПЗУ. Зато оно происходит значительно быстрее - практически с максимальным темпом чтения из ПЗУ.
Разработка систем на кристалле (СНК) - это устойчивая современная тенденция. И программирование ПЛИС для СНК - один из этапов главных такой разработки. Выпуск ПЛИС новых поколений, например, Xilinx VirtexPro, направлен на поддержку развития СНК. Разработка СНК без применения языка VHDL или Verilog практически невозможна.
Назад | Содержание | На главную | Далее |
Кратко о VHDL
Традиционно одним из этапов пректирования средств вычислительной техники является разработка электрических схем. Эта ответственная работа связана с большими трудозатратами, контролем правильности и соответствия задуманному проекту, необходимостью четкого и емкого описания созданных схем, трудностями с их сопровождением и модернизацией. САПР вычислительной техники, как правило, имеют средства ввода и редактирования схем. Однако два десятилетия назад при разработке СБИС отказались от схемного проектирования.
Язык Very high speed integrated circuits Hardware Description Language (VHDL) был разработан в 1983 г. по заказу Министерства обороны США с целью формального описания логических схем для всех этапов разработки электронных систем, начиная модулями микросхем и кончая крупными вычислительными системами. Он является стандартным языком с 1987 г. Стандартом 1993 г. закреплены многие его усовершенствования [1]. Наряду с языком Verilog он является базовым языком при разработке аппаратуры современных вычислительных систем.
Литералы
Где-то треть жителей планеты говорит на английском языке. Из них около половины не знают английского языка. Например, чтоб разговаривать на пиджин-инглиш, достаточно иметь словарный запас 200-300 слов. Естественно, на таком диалекте произведений не пишут. Приблизительно то же самое можно сказать и о пишущих на VHDL. Но для конструирования произведений с помощью VHDL нужно хотя бы знать синтаксис языка. Данная страничка и несколько других этому посвящаются.
В языке литералом задается такой лексический элемент, который при компиляции кодируется некоторым числовым кодом, который остается постоянным в программе при ее исполнении. Константы, операнды в выражениях, идентификаторы представляются литералами. То, что синтаксис литерала отображает признак типа соответствующего ему объекта, является одной из особенностей VHDL.
Числовой литерал представляет собой целое или вещественное число.
Десятичный литерал - это числовой литерал в системе счисления по основанию (базису) 10, например, 120.
Вещественный литерал отличает обязательное наличие точки, отделяющей целую часть от дробной, например, 120.0, 1.20е2.
Базисный литерал - это число в системе счисления с заданным базисом от 0 до 16. Его условный синтаксис:
\базисный литерал\::=\базис\#\число в базисе\#[\экспонента\]
Напоминание: при описаниие синтаксиса текст в квадратных скобках означает необязательный элемент. Например, 10#112# = 16#70# = 2#1110000# = 2#111#e4. Можно также применять базис и 3, и 4, и 5…
. Какой ещё язык предоставляет такую возможность?!
Символьный литерал используется как значение для операторов или как элемент перечисляемого типа, например, бит. Он записывается как символ в одиночных кавычках, например, '1', 'F' , '@'.
Идентификатор. Идентификатор используется как имя константы, переменной, функции, сигнала, порта, подпрограммы, объекта проекта, а также как метка. Он содержит латинские буквы, с которых он начинается, цифры и некоторые символы, например, однократный символ подчеркивания. Идентификаторы с одинаковым названием но с различными заглавными и строчными буквами считаются одним идентификатором, т.е. они "нечувствительны" к высоте букв. Ключевое слово языка не может быть идентификатором.
Идентификатор может состоять из произвольной цепочки символов, но эта цепочка должна быть заключена между обратными косыми. Это так называемый, расширенный идентификатор. Например:
C, A_and_B, \наш сигнал\, \а+в\, \process\
являются корректными идентификаторами.
Перечисляемый литерал. К перечисляемым литералам относятся символьный литерал и идентификатор. Из этих литералов формируется множество перечисляемого типа.
Строчный литерал. Строчным литералом является цепочка символов, заключенная в двойные кавычки, например, "АБВГ". Литерал битовой строки может иметь различный вид в зависимости от базиса системы счисления. Например, литералы "01111010", В"01111010", Х"7А" представляют собой одно и то же значение, причем В и Х означают двоичный и шестнадцатиричный базисы, соответственно.
В числовых литералах и битовых строках допускается вставлять символы подчеркивания для удобства чтения, которые удаляются при компиляции.
Например, Х"АВ_CD", "1101_0111", 1_024, 0FF_ABBA .
Логическая таблица
Роль основного логического элемента в ПЛИС играет логическая таблица (ЛТ) или look-up table (LUT), представляющая собой однобитное ОЗУ на 16 ячеек. В ЛТ по адресу G3,G2,G1,G0 записана единица, если код адреса представляет собой конституенту единицы заданной четырехвходовой логической функции. Например, если по адресу 1,1,1,1 записана единица, а по остальным адресам - ноль, то ЛТ реализует четырехвходовую функцию И. На рис. показан пример кодирования функции Исключающее ИЛИ на четыре входа.
Триггеры ЛТ входят в состав программирующего сдвигового регистра и их начальное состояние заполняется в период конфигурирования ПЛИС.
Мультиплексоры в ПЛИС
Большую долю оборудования в ВС занимают мультиплексоры. С помощью ЛТ можно реализовать двухвходовой мультиплексор. Для эффективной реализации 4-х и более - входовых мультиплексоров в КЛБ имеются схемы мультиплексоров F5 и F6, которые играют роль верхних уровней древовидного мультиплексора. Также они используются для построения функции 5-входовой (F5) и 6-входовой (F6) логики.
Начальное значение порта или настроечной константы.
Начальное значение объекта в его объявлении - это то значение которое принимает объект перед первым циклом моделирования. Если начальное значение не присвоено, то симулятор присваивает наименьшее значение данного типа, если тип - числовой или самое левое значение, если тип - перечисляемый. Например, если тип STD_LOGIC, то начальное значение будет U - неинициализировано. Если при моделировании не предусматривается подача сигналов на порт такого типа, то этот порт лучше инициализировать, например, значением '0'.
Начальное значение может быть выражением. Но значение выражения должно быть вычисленным до момента трансляции данного объявления. Например, первое объявление порта:
port( bb:bit:=aa;
aa:bit :='1');
неверно, так как при его рассмотрении компилятор еще не имеет сведений об идентификаторе аа.
В аппаратной модели начальное значение порта эквивалентно состоянию шины сразу после включения питания до прихода сигналов сброса, т.е. оно не определено. Поэтому компиляторы – синтезаторы не допускают или игнорируют начальные значения всех объектов, кроме констант или объектов, которые не изменяют свое значение при вычислениях. Настроечные константы generic кодируют определенные свойства объекта проекта, например, разрядность линий связи, параметры задержки, кодирование структуры моделируемого устройства и их начальные значения принимаются во внимание.
Объявления в объекте.
Объявленными в объекте могут быть: объявление и тело процедуры или функции, объявление типа и подтипа, объявление глобальной переменной, файла, псевдонима, константы, объявление и спецификация атрибута, объявление группы, описание use.
Исполнительная часть.
В исполнительной части, которая открывается словом 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 выдает сообщение об ошибке.