Определение.
subprogram_specification ::= procedure designator [ ( formal_parameter_list ) ] | [ pure | impure ] function designator [(formal_parameter_list) ] return type_mark
Подпрограммы имеют две формы – функции и процедуры.
В декларации функции определяется указатель на функцию, её формальные параметры (если они есть), возвращаемый тип, и явлиется ли функции impure.
Функция является impure только в случае, если декларация функции содержит зарезервированное слово impure; иначе подразумевается pure функция.
Указатель на проедуру - это всегда идентификатор. Указатель на функцию - либо идентификатор, либо символ оператора.
Если в качестве указателя используется оператор, то такая функция переопределяет оператор (and, or, nand, nor, xor, xnor, =, /=, <, <=, >, >=, sll, srl, sla, sra, rol, ror, +, –, &, +, –, *, /, mod, rem, **, abs, not).
Подпрограммы могут быть декларированы в тексте пакета, интерфейсе объекта проекта, архитектурном теле, процессе, процедуре или функции.
Подпрограммы могут вызывать другие подпрограммы.
Общий вид оператора декларации функции
[pure | impure] function имя функции (параметр {, параметр} ) return тип возвращаемого функцией значения is раздел деклараций begin тело функции end [имя функции];
Общий вид оператора вызова функции
имя функции ( фактический параметр {, фактический параметр} );
Функция имеет только входные параметры. Следующий иллюстративный пример показывает (декларирует) функцию BOOL_TO_SL, преобразующую тип BOOLEAN в тип STD_ULOGIC.
Пример.
function BOOL_TO_SL(X : boolean) return std_ulogic is begin if X then return '1'; else return '0'; end if; end BOOL_TO_SL;
Следующий пример показывает функцию преобразования типа bit в тип boolean. Напомним, что данные типы не эквивалентны.
function bit_bool (inp_bit : in bit) return boolean is begin if (inp_bit = '1') then return true; else return false; end if; end bit_bool;
Функция может содержать последовательные операторы, исключая операторы ожидания и назначения сигналов. В теле функции могут декларироваться локальные переменные.
Общий вид оператора декларации процедуры
procedure имя процедуры ( параметр {, параметр} ) is раздел деклараций begin тело процедуры end [имя процедуры];
Процедура может иметь входные (in), выходные (out) и вход/выходные (inout) параметры.
Это могут быть сигналы, переменные или константы. По умолчанию входные параметры – константы, выходные и вход/выходные параметры – переменные.
Общий вид оператора вызова процедуры
имя процедуры ( фактический параметр {, фактический параметр} );
Таким образом, вызов процедуры состоит из имени процедуры и списка фактических параметров. Процедуры могут вызываться последовательно или параллельно. При параллельном вызове происходит выполнение процедуры, когда какой-нибудь входной вход/выходной параметр изменился. VHDL-код с текстом подпрограммы, т.е. функции или процедуры может находится в разделе деклараций архитектурного тела, либо в пакете. Если подпрограмма определена в пакете, то текст подпрограммы должен быть в теле пакета. Если подпрограмма находится в пакете, то в этом случае перед текстом entity, где процедура используется (процедуры могут использоваться в архитектурных телах), требуется указание имени библиотеки и имени пакета, в котором содержится текст подпрограммы.
Следующий пример процедуры PARITY показывает отличия процедуры от функции: функция имеет только входные параметры, режим (mode) которых не специфицируется, в процедуре могут содержаться операторы назначения сигналов.
procedure PARITY ( signal X : in std_ulogic_vector; signal Y : out std_ulogic) is variable TMP : std_ulogic := '0'; begin for J in X'range loop TMP := TMP xor X(J); end loop; Y <= TMP; -- в процедуре могут быть операторы назначения сигналов end PARITY;
Следующий пример показывает процедуру DISPLAY_MUX и ее вызов в архитектурном теле SUBPROG.
procedure DISPLAY_MUX ( ALARM_TIME, CURRENT_TIME : in digit; SHOW_A : in std_ulogic; signal DISPLAY_TIME : out digit) is begin if (SHOW_A = '1') then DISPLAY_TIME <= ALARM_TIME; else DISPLAY_TIME <= CURRENT_TIME; end if; end DISPLAY_MUX; architecture SUBPROG of DISP_MUX is ... begin -- вызов процедуры DISPLAY_MUX (ALARM_TIME, CURRENT_TIME, SHOW_A, DISPLAY_TIME); end SUBPROG;
Пакет (package) в VHDL – это VHDL-текст, который может включать множество деклараций:
В теле пакета (package body) находятся тела функций, тела процедур и другие VHDL-описания. Однако в пакете не декларируются, а в тело пакета не записываются entity, архитектурные тела (architecture), конфигурации (configuration). Функции и процедуры иногда называют подпрограммами. Пример функции языка VHDL: функция NOW возвращает текущее время системы моделирования. Приведем только пример декларации процедуры, более подробно подпрограммы будут рассмотрены далее. Пакет multiplexer показывает, что процедура MX декларируется в пакете и тело процедуры определяется в теле пакета.
package multiplexer is procedure MX( signal SEL : in bit; signal x0 : in bit; signal x1 : in bit; signal F : out bit); end multiplexer; package body multiplexer is procedure MX( signal SEL : in bit; signal x0 : in bit; signal x1 : in bit; signal F : out bit) is begin case SEL is when '0' => F <= x0; when others => F <= x1; end case; end MX; end multiplexer;
Конфигурация – эффективный инструмент управления составом иерархически организованного проекта, она позволяет задать поддерево дерева иерархии проекта. Изучим применение конфигурации сначала на простом примере, когда при конкретизации компонента можно использовать различные архитектурные тела. Например, в схеме compare в архитектурном теле eq1 выходной сигнал EQ, равен 1 тогда и только тогда, когда значения входных сигналов совпадают. Это сравнение входных сигналов на равенство.
library ieee; -- прочитать библиотеку use ieee.std_logic_1164.all; -- сделать библиотеку видимой entity compare is port( A, B: in integer range 0 to 3; EQ: out std_ulogic); end compare; architecture eq1 of compare is begin EQ <= '1' when (A = B) else '0'; end eq1; architecture lt1 of compare is begin EQ <= '1' when (A < B) else '0'; end lt1; architecture gt1 of compare is begin EQ <= '1' when (A > B) else '0'; end gt1;
Легко видеть, что архитектурные тела lt1, gt1 определяют совсем другое поведение схемы compare. По синтаксису языка это допускается, по семантике (смыслу) это не корректно – все архитектурные тела, привязанные к одному и тому же entity, должны быть функционально эквивалентны и при конкретизации компонента по умолчанию предполагается, что будет использовано одно и то же архитектурное тело.
Например, пусть имеется следующий VHDL-код, описывающий схему comp_3.
library ieee; use ieee.std_logic_1164.all; library work; entity comp_3 is port ( signal a,b: in integer range 0 to 3; signal EQ,LT,GT: out std_ulogic); end comp_3; architecture str of comp_3 is component compare port ( a,b: in integer range 0 to 3; EQ: out std_ulogic); end component; begin COMP1: compare port map (A,B,EQ); COMP2: compare port map (A,B,LT); COMP3: compare port map (A,B,GT); end str;
В VHDL-коде метки COMP1, COMP2, COMP3 – это имена подсхем. Предполагается, что при моделировании (синтезе) для каждой из подсхем с именами COMP1, COMP2, COMP3 будет использоваться одно и то же архитектурное тело. Однако какое же из трех архитектурных тел eq1, lt1, gt1 будет использоваться? Если все три архитектурных тела содержатся в одном файле, то ответ достаточно прост: будет использоваться последнее “прочитанное” в проект архитектурное тело. В данном случае при конкретизации компонета compare будет использовано последнее архитектурное тело gt1. Чтобы использовать для подсхемы COMP1 архитектурное тело eq1, для COMP2 – архитектурное тело lt1, для COMP3 – архитектурное тело gt1, можно написать простую конфигурацию default_configuration.
Поясним данный VHDL-код. Ссылка на рабочую библиотеку work говорит о том, что все архитектурные тела должны быть в рабочей библиотеке.
В следующих двух строчках все “связывается” – указывается имя конфигурации (default_configuration), для какой схемы (comp_3) она составлена и для какого архитектурного тела (str).
Далее записывается, что для подсхмы COMP1 требуется использовать архитектурное тело eq1, и т.д.
Таким образом, из многих вариантов реализации одной и той же подсхемы можно выбрать нужный вариант.
! Конфигурация позволяет в случае одинакового интерфейса использовать различные архитектурные тела.