はじめに
VHDLではprocedureとfunctionによってsubprogramを定義できます。
それぞれの使い分けを把握していなかったのでまとめました。
functionのほうが制約が厳しいのでどちらでもいい場合はfunctionを使うほうがよさそうです。
function
functionは以下の特徴を持ちます。
- ディレイやイベント制御は使えない(wait文は使えない)
- 常に1つの値を返す
- inputの引数をもてる(もたなくてもよい)
- outputやinoutの引数はもてない
- non-blockingは使用できない
以上の特徴からfunctionは主に組合せ回路の実装に使用できます。
例えば以下のようにandリダクション演算をfunctionで定義できます。
function and_reduce (arg : std_logic_vector ) return std_logic is
variable var : std_logic;
begin
var = '1';
for i in arg'range loop
var := var and arg(i);
end loop;
return var;
end function;
procedure
procedureは以下の特徴を持ちます
- ディレイやイベント制御ができる(wait文が使える)
- 複数の値を返すことができる
- inputの引数をもてる(もたなくてもよい)
- outputやinoutの引数をもてる
- ノンブロッキング代入も使用できる
以上のようにfunctionでできなかったことができるようになっています。
procedureでは複数の出力とwait文を使うことができるため
以下のようにSPI通信のマスタの動作を定義できます。
ただし、wait文を使った場合は回路として論理合成することはできません
wait文を使わない場合はこちらの記事のように論理合成することもできます。
constant data_bits : natural := 8;
procedure send_spi (
signal data : in std_logic_vector(data_bits - 1 downto 0);
signal sdo : out std_logic;
signal sclk : out std_logic;
signal ss : out std_logic
) is
constant sclk_period : time := 1 us; -- 1MHz
begin
ss <= '0';
for i in 0 to data'length - 1 loop
sclk <= '0';
wait for sclk_period / 2;
sclk <= '1';
sdo <= data(i);
wait for sclk_period / 2;
end loop;
sclk <= '0';
ss <= '1';
end procedure;
上記のprocedureを使えばスレーブのテストコードは以下のように簡単になります。
この処理をさらにprocedureとして定義することもできます。
master_data := X"AC";
send_spi (data => master_data, sdo => sdi, sclk => sclk, ss => ss);
wait for clk_period;
check_equal(receive_data, master_data, "data error"); -- VUnit
並列procedure?順次procedure?
FPGAの部屋では入力信号にsignal宣言を書かないことで順次procedureとして扱うことができるとされている。
内容を読む限りはsignal宣言の有無ではなく
wait文の有無で並列procedureか順次procedureが決まるように思えますが
参考にされている図書を持っていないので詳細については不明です。
参考
[pdf] Functions, Procedures, and Testbenches - Xilinx
vhdlwhiz.com - HOW TO USE A PROCEDURE IN VHDL
vhdlwhiz.com - HOW TO USE A FUNCTION IN VHDL
Qiita - VHDL で ビット幅を可変にできる Priority Encoder を書く
FPGAの部屋 - procedureを使うときの注意点