process(st,one,two,three) begin

Case st is

when1 => cntrl<= one;

when2 to3 => cntrl<= two; when others=> cntrl<= three,-end case; end process;

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

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

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

Параллельный вызов процедуры

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


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

Отложенные параллельные операторы

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

Оператор вставки компонента

Оператор вставки компонента играет важную роль для реализа­ции иерархического проектирования. Его синтаксис:

\оператор вставки компонентах::= \метка экземпляра элементах :

Хвставляемый элемент\ [generic тар(\связывание настроечной константы\ {, \связывание настроечной константы\});] [port map (Дсвязывание порта\ {Дсвязывание порта\})]; Хвставляемый элемент\ ::= [component] \имя компонентах

I entity \имя объектах[идентификатор архитектуры] (configuration \имя конфигурации\

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

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

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


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

Если на момент связывания, объект, выступающий компонентом не скомпилирован или в указанных в фразе use библиотеках не на­шлось объекта с подходящим названием и интерфейсом, то такой компонент не будет вставлен. Об этом транслятор даст предупрежде­ние. При моделировании такого устройства, на выходы неподклю­ченного компонента симулятор подает сигналы 'и' - не инициали­зировано. А при синтезе - компилятор представит его "черным ящи­ком" (black box), который он попытается заменить схемой из EDIF-файла с соответствующим названием, если такой имеется в рабочем каталоге.

Неподключенные порты с режимом out или inout допускается не указывать в списке связывания портов. Но более понятным и пра­вильным считается связывание таких портов с условным сигналом, обозначенным ключевым словом open.

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

u_rg: RG16 port map (clk=>clk,

E => \разр_зп_рг\,

DI => D,

D0(15)=> open,

D0(14)=> \знак_й\,

D0(13 downto 0)=>\мантисса_й\ );

Более полный синтаксис допускает связывать порт и сигнал в ви­де статического выражения с использованием вызовов функций, на­пример:

Dl => conv_integer(D(n-l downto 0)); To_Bit(DO(14)) => \знак_0\,

т.е. здесь для совмещения типов порта DI в режиме in и сигнала D, разряда DO(14) порта в режиме out и сигнала \знак_й\ используются функции преобразования типа.


Следует отметить, что компиляторы-синтезаторы, как правило, не допускают связывание порта с функцией преобразования типа. Если выход компонента не подключен, как, например, DO(15)=>openf или если выхода нет в списке связываний, то компилятор-синтезатор может минимизировать в компоненте цепи и логику, от­носящиеся к этому выходу, в примере - удалить триггер, подклю­ченный к D0(15).

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

Все компиляторы-синтезаторы поддерживают настроечные кон­станты целого типа.

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

entity RGn is

generi c(n: i nteger);

port(CLK:bit; DI, DO: bit_vector(n-l downto 0)); end entity;

architecture behav of RGn is begin process(CLK) begi n

if clk='1' and CLK'event then

DO<=Dl ; end process; end architecture behav;

Тогда следующий оператор в теле архитектуры более высокого уровня иерархии выполняет вставку компонента этого регистра и настраивает его разрядность равной п = 8:

U_RG8: entity RGn(behav) generic map(8),

port map (CLK,DI=>DATA_IN,DO=>DATA_OUT);

Оператор generate

Если необходимо неоднократно повторить один или несколько параллельных операторов, то используют оператор generate. Его синтаксис:


\оператор generate\::= \метка\: for\идентификатор\ in\диапазон\ generate

[{\объявление в 6локе\} begin]

{ \параллельный оператор\} end generate[\метка\];

Метка оператора generate необходима для обозначения сгенери­рованной структуры, \идентификатор\ - это параметр оператора gen­erate, а фраза \диапазон\ - диапазон его изменения. Они имеют та­кие же синтаксис и семантику, как и в операторе loop. В операторе могут быть вставлены такие же объявления, как в декларативной части тела архитектуры.

В отличие от оператора loop, который повторяет в цикле один или несколько последовательных операторов, оператор generate де­лает несколько копий параллельных операторов, когда параметр оператора пробегает все значения из заданного диапазона.

В следующем примере с помощью оператора generate запрограм­мирована схема сдвигового регистра длиной п на триггерах FD из библиотеки компонентов ПЛИС Xilinx, описанного в пакете UNlslM.umsim_viTAL с входом DI и выходом do, тактируемого син-хросерией clk.

signalt: std_logic_vector(l ton+1);

t(i)<=DI;

FIFO: fori in1 ton generate

u_ tt: fd(c=>clk, D=>t(i), Q=>t(i+1)); end generate;D0<=t(n+1);

Для того, чтобы управлять структурой проектируемого устройст­ва используется условный оператор generate. Его синтаксис:

Хусловный оператор generate\::=\MeTKa\:if \6улевское выражение\ generate

[ {\объявление в 6локе\} begin]

{\параллельный оператор\} end generate[\метка\];

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


RESn: if \подключить_Р1Л_1_иР\=1 generate

RESl:for i inDATA^BUS1range generate

U_ RES: PULLUP(DATA_BUS(i));

end generate; end generate;

если целое значение \подключить_Р1Л_1_иР\ равно 1, то к шине DATA_BUS подключаются компоненты нагрузочных резисторов PULLUP из библиотеки unisim.

Оператор block

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

\оператор block\::=[\метка\]: block[\выражение сдерживаниях] [is] [депепс(\объявление настроечной константы\

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

{, \связывание настроечной константы\});] [port (\объявление порта\ {;\объявление порта\});] [port map(\связывание порта\

{Дсвязывание порта\})]; {\объявление в 6локе\} begin

{\параллельный оператор\ } end block[\метка\];

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

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

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


блоки с другим исполнением. Эквивалентным блоком можно заме­нить любую пару объект-архитектура, используемую как компонент.

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

Для этого, во-первых, процесс с оператором присваивания сигна­лу или соответствующий параллельный оператор помещают в блок с выражением сдерживания. Во-вторых, оператор присваивания сиг­налу оформляют как оператор со сдерживанием, для чего перед вы­ражением оператора ставится ключевое слово guarded. Например, блоки В1 и В2:

signalА,В,С: outinteger bus:=0; disconnectc:integer after 2 ns;

Bl: block(sel = 1) is begin

с <= guarded A;

end block Bl;

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, как правило, запрещаются. Также не поддерживаются связывания портов и настроечных констант в блоках.

Стили программирования

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

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

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

Естественно, архитектуры, описанные различными стилями, мо­гут иметь произвольное количество операторов generate и block. Часто встречаются архитектуры, описанные смешанным стилем.

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

Хорошим стилем программирования считается, когда в иерархи­ческом проекте объекты верхних уровней описываются структурным стилем.