2.10.1 Общие сведения
Крупные проекты получают существенные выгоды от повторного использования кода и параметризации. Субпрограммы являются эффективным средством организации обоих приемов разработки – они позволяют как организовать программный код для его использования в нескольких модулях, так и сделать этот код достаточно абстрактным для его использования с различными параметрами. Язык VHDL предлагает различные виды субпрограмм – процедуры и функции.
Рекомендуется использование процедур и функций для выполнения стандартных, повторяющихся действий, или реализация с их помощью сложных операций, требующих повышенного внимания разработчика. Помещение ответственных операций в субпрограммы, а в дальнейшем – в package, позволяет разграничить области работы с различными по сложности модулями. Отлаженная и протестированная субпрограмма может в дальнейшем использоваться как блок с известными характеристиками, вокруг которого может выстраиваться проект. Оформление исходных текстов субпрограмм в отдельных файлах снижает опасность их некорректного изменения при разработке.
2.10.2 Процедуры
Процедуры в VHDL имеют следующий вид:
procedurePROC1 is-- объявление процедуры
variableVAR1; -- объявление
-- локальных переменных
begin
<операторы>
end procedure PROC1;
Описанная таким образом процедура может быть вызвана просто по имени. Процедура может быть объявлена и с использованием параметров:
procedurePROC2 (IN1: in<type>;
OUT1: out <type>;
BI_DIR1: inout<type>) is
Параметры с модификатором in могут только читаться. Параметры out могут только изменяться (перезаписываться), и возвращаются вызывающему модулю. Параметры inout могут и читаться процедурой, и изменяться, и также возвращаются вызывающему модулю.
Параметры в VHDL могут принадлежать к следующим классам:
- signal;
- variable;
- constant;
- file.
По умолчанию, параметры типа in (входные) предполагаются имеющими класс constant, а out и inout – variable. При необходимости изменить эти классы следует явно указать их в объявлении процедуры, т.е.
procedure PROC2 (signal IN1: in std_logic;
signal OUT1: out std_logic;
BI_DIR1: inout<type>) is
Смысл передачи сигнала в процедуру заключается в том, что в случае передачи константы передается «мгновенное значение», а передача сигнала позволяет процедуре воспользоваться «историей сигнала». Например, если тактовый сигнал будет передан как константа, процедура сможет узнать его текущее значение, но выражение clk’event внутри процедуры использоваться не может, так как понятие event («событие») требует передачи в процедуру не просто мгновенного значения, а всей истории изменения этого сигнала.
Для процедуры с параметрами возможен вызов с позиционным или именованным назначением фактических параметров.
PROC2(a, b, c);
PROC2(IN1 => a, OUT1 => b, BI_DIR1 => c);
Как и для подключения сигналов к портам модулей, именованное назначение фактических параметров снижает риск появления ошибки из-за неаккуратности разработчика.
Если процедура объявляется внутри модуля VHDLpackage, ее заголовок должен быть объявлен отдельно, а тело описано в разделе packagebody.
packagemy_pack is
procedure PROC1(in std_logic a; out std_logic b);
end package my_pack;
package body my_pack is
procedure PROC1(in std_logic a;
outstd_logic b) is
begin
…
end procedure;
end package body my_pack;
2.10.3 Функции
Функции в VHDL имеют вид:
function FUNC1 (parameters) return <type> is
variable …
begin
<операторы>
end function FUNC1;
Функция отличается от процедуры тем, что возвращает единственный объект, тип которого указан после ключевого слова return:
function PAR_GEN (BV : in bit_vector)
return bit is
variable PAR : bit := ‘0’;
begin -- function
for i in BV’range loop
PAR := PAR xor BV(i) ;
end loop ;
return PAR ;
endfunction PAR_GEN ;
begin -- architecture
DATA_FRAME <= D_WORD & PAR_GEN (D_WORD);
В примере показана функция, которая формирует бит четности для некоторого многоразрядного сигнала с именем BV (от BitVector). Ее использование показано в разделе architecture. Результатом синтеза для представленной строки будет комбинаторная схема, состоящая из цепочки элементов xor.
4Показанный пример не создает схему, которая работает циклически, в течение нескольких тактов вычисляя бит четности. Цикличной является только операция синтеза схемы, соединяющая вентили xor.
Функции могут быть перегружены (overloading). Под перегрузкой понимается возможность использования одной и той же функции с различными сочетаниями типов параметров. Например, среди стандартных функций пакета std_logic_unsigned имеются варианты оператора +, работающие с двумя значениями std_logic_vector, двумя значениями integer, парой значений std_logic_vector и integer и т.д. (VHDL не имеет предопределенных операторов такого вида). Это позволяет пользоваться в VHDL выражениями вида a<= a + 1;, где a может иметь тип std_logic_vector, но перегрузка оператора + позволяет свободно использовать его с целочисленным значением 1. Это освобождает разработчика от необходимости постоянно производить преобразования типов, что существенно загромождает исходный текст.