VHDLで関数を使う
今回のお題は、VHDLで関数を扱うもの。
環境
その1からずっとOdyssey MAX10 FPGA Eval KitおよびQuartus利用。
サンプル
LEDを用いてストップウォッチを実現
ボタン0(BTN0)押下でスタート、再押下でラップ、再押下でストップ(リセット)する。
STOP -> RUNNING -> LAP (RUNNING) -> STOP -> RUNNING -> ....
という状態遷移(繰り返し)となる。ボタン1(BTN1)が押下されていないときには、スタートからの経過時間(秒)をLED表示、ボタン1が押下されたときには、ラップ時間をLED表示するものとする。
関数の利用
スタートからの経過時間(秒)およびラップ時間(秒)をLEDで表現するところに関数を用いる。表現方法としては、前回その11の秒カウンタと同じ方式を用いる。なお、あえて関数化する必要はないレベルではあるが、単純な例の方が関数を説明する上でわかりやすいであろう。
functionとprocedure
関数化の方法として、VHDLには、functionとprocedureとがあるらしい。今回はprocedureを利用。今回、VHDLの関数について参考にしたサイトは次のとおり。
VHDLコード
ライブラリおよび信号定義
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all; -- necessary for conv_std_logic_vector
entity ProcTest is
port (
CLK, BTN0, BTN1 : in std_logic;
LED0, LED1, LED2, LED3, LED4, LED5, LED6, LED7 : out std_logic);
end;
ここは自明なので、説明省略。
関数部分
architecture RTL of ProcTest is
procedure p_Disp (
constant p_NUM : in integer;
signal p_OUT : out std_logic_vector(7 downto 0) ) is
begin
p_OUT <= not conv_std_logic_vector(p_NUM,8);
end p_Disp;
procedure利用。次の引数がある。
- p_NUM:入力 - LEDで表現したい数値
- p_OUT;出力 - ビット変換した結果(呼び出し側でLEDに代入)
conv_std_logic_vector()を使って、数値をビット値へ変換する。
変数定義
signal LED: std_logic_vector(7 downto 0) := "11111111"; -- Off
constant CYCLE : integer := 50000000;
signal CNT : integer range 0 to CYCLE-1;
signal SEC : integer := 0;
signal LAP : integer := 0;
signal FLAG: integer := 0; -- 0:Stop 1:Start->Running 2:Lap(&Running)
- LED:LED用のビット列(初期値OFF、負論理)
- CYCLE:1秒(50MHz)
- CNT:クロック用カウンタ
- SEC:秒カウンタ
- LAP:ラップ値
- FLAG:状態遷移フラグ(0:停止 → 1:実行中 → 2:ラップかつ実行中 → 0 → 1 → 2 → 0 ...)
メインルーチン
begin
LED0 <= LED(0); LED1 <= LED(1); LED2 <= LED(2); LED3 <= LED(3); -- ①
LED4 <= LED(4); LED5 <= LED(5); LED6 <= LED(6); LED7 <= LED(7); -- ②
process (BTN0) -- Removal of chattering should be considered -- ③
begin
if (BTN0'event and BTN0='0') then
if (FLAG = 0) then -- Stop
FLAG <= 1; -- to Running
elsif (FLAG = 1) then -- Running
FLAG <= 2;
LAP <= SEC; -- Record Lap -- ④
else -- FLAG = 2 -- Running
FLAG <= 0; -- to Stop
LAP <= 0; -- Init Lap
end if;
end if;
end process;
process (SEC, BTN1) -- ⑤
begin
-- if (BTN1'event and BTN1='0') then -- NG -- ⑥ 文法エラー
if (BTN1='0') then
p_Disp(LAP, LED); -- ⑦
else
p_Disp(SEC, LED); -- ⑧
end if;
end process;
process (CLK) -- ⑨
begin
if (FLAG = 1 or FLAG = 2) then -- Runinng -- ⑩
if (rising_edge(CLK)) then
if (CNT = CYCLE-1) then
CNT <= 0;
SEC <= SEC+1;
else
CNT <= CNT+1;
end if;
end if;
else -- FLAG = 0 (Stop) -- ⑪
CNT <= 0;
SEC <= 0;
end if;
end process;
end RTL;
- ①、②、③、⑤、⑨:同時に処理される
- ①、②:LED用ビット列をLED信号に代入
- ③:BTN0押下毎の状態遷移、実行中に押下されると、秒カウンタをLAPに代入(④)(チャタリングは未考慮)
- ⑤:LEDによる数値表示を関数「p_Disp」により毎秒実行、押下時はLAP表示(⑦)、非押下時は経過秒SEC表示(⑧)
- ⑥:この直後の行の代わりにこの行を用いると文法エラーとなる
- ⑨:実行中はクロックカウンタおよび秒カウンタインクリメント(⑩)、非実行中は両カウンタ初期化(⑪)