procedure for testbench
procedureを使うと、シミュレーションが楽に書ける。
architecture test of test_module is
procedure pe(signal CLK : in std_logic) is
begin
wait until CLK'event and CLK='1';
end pe;
procedure pe( num : in integer;
signal CLK : in std_logic) is
begin
for I in 1 to num loop
wait until CLK'event and CLK='1';
end loop;
end pe;
begin
end test;注意するのは"signal"の記述で、これが
ある→procedureの中でその信号の変化を読める(この場合だと、CLKの変化を読んでいる。一方、numは「変化」を読んでいる訳ではない。
ない→procedureの中でその信号の変化は読まない。
ということ。
もうちょっと巨大なprocedureとしては、こんなのがある。
architecture test of test_module is
procedure write_reg(
signal CLK : in std_logic;
Rd_dt_in : in std_logic_vector(31 downto 0);
Rd_dt_out : out std_logic_vector(31 downto 0);
signal Sof1_out : out std_logic) is
constant dly_rd_dt : time := 1ns;
constant dly_Sof1 : time := 2ns;
begin
wait until CLK'event and CLK='1';
Rd_dt_out<=Rd_dt_in after dly_rd_dt;
wait until CLK'event and CLK='1';
Sof1_out<='0' after dly_Sof1;
wait until CLK'event and CLK='1';
Sof1_out<='1' agter dly_Sof1;
end ;
begin
...
...
end test;とかで書き込める。
state machineの作り方
ポイントは三つ。
1、state のタイプ宣言は以下の通り。
type STATE is ( STA0 , STA1 , STA2 ); signal CURRENT_STATE,NEXT_STATE : STATE;
現在のステートと次のステートを作っておく。
「次」とは、次のクロックのことを指す。
2、clkでステートを入れ替える。
3、(NEXT_STATEを作る+current stateに応じた出力を出す)processのセンシティビティリストは、
・CURRENT_STATE
・CURRENT_STATEに加えて、次のSTATEを決定するのに必要なsignal
を入れる。
あと、忘れがちなcase記法を復習しておく。
case STATE is
when <STATE1> =>
....
when <STATE2> =>
....
....
when others =>
....
end case;ここの when は、以下のように書くことも許されている。
when <STATE1>|<STATE2>|...|<STATEn> =>.... when <STATE1> to <STATEn> =>....
クロックを入れたい場合(たとえばstate Aに入ってから10クロック目にstate Bに移行したい)は、以下のようにする。
architecture....
....
signal count : Integer range 0 to 15;
....
begin
....
--counter process
process(clk,reset)begin
if(reset='1')then
count<=0;
elsif(clk'event and clk='1')then
if(CURRENT_STATE=stateA)then
count<=count+1;
else
count<=0;--important!!
end if;
end if;
end process;
process(CURRENT_STATE,sig1,sig2,count)begin
case CURRENT_STATE is
when stateA =>
....
if(count=10)then
NEXT_STATE<=stateB;
else
NEXT_STATE<=stateA;
end if;
when stateB=>
....
end case;
end process;まとめて一例を。
entity MULSTATE is
port( clk,reset : std_logic;
sig : std_logic;
out1,out2 : std_logic);
end MULSTATE;
architecture RTL of MULSTATE is
--state definition
type STATE is (STA0,STA1,STA2);
signal CURRENT_STATE,NEXT_STATE : STATE;
begin
--Flip Flop for remember the state.
process ( clk , reset ) begin
if(reset='1')then
CURRENT_STATE<=STA0; --load the initial state
elsif ( clk'event and clk ='1')then
CURRENT_STATE<=NEXT_STATE;-- load the next state
end if;
end process;
--state exchange process
process(CURRENT_STATE,sig)begin
case CURRENT_STATE is
when STA0 =>
out1<='0';
out2<='0';--output some signals to the external module
--set next state
if(sig='0')then
NEXT_STATE<=STA2;
else
NEXT_STATE<=STA1;
end if;
when STA1=>
out1<='1';
out2<='0';--output some signals to the external module
--set next state
if(sig='0')then
NEXT_STATE<=STA0;
else
NEXT_STATE<=STA2;
end if;
when STA2=>
out1<='1';
out2<='1';--output some signals to the external module
--set next state
if(sig='0')then
NEXT_STATE<=STA1;
else
NEXT_STATE<=STA0;
end if;
end case;
end process;
end RTL;
bit列の一斉初期化
Y<=( 3=>0, 2=>0, 1=>0, 0=>0);
の省略として、次のように書ける。
Y<=(3 downto 0 => 0);
もしくは、othersを使って、
Y<=(others=>0);
と書く。
これらはもちろん、テストベンチの中でしか使えない。。。というか、使わないことにしておくこと。
唯一VHDL中で使えるのは、constant宣言の時のみで、
... signal ... ... constant <constant name> : STD_LOGIC_VECTOR( <length> downto 0 ) :=(others=>'0'); ... begin ...
などとして使える。
TestBenchの一例
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
ENTITY testbench IS
END testbench;
ARCHITECTURE behavior OF testbench IS
COMPONENT syncFIFO
PORT(
clk : IN std_logic;
reset : IN std_logic;
din : IN std_logic_vector(3 downto 0);
dout : OUT std_logic_vector(3 downto 0);
rd : IN std_logic;
wr : IN std_logic;
full : OUT std_logic;
empty : OUT std_logic
);
END COMPONENT;
signal clk : std_logic := '0';
signal reset : std_logic := '0';
signal din : std_logic_vector(3 downto 0) := (others => '0');
signal rd : std_logic := '0';
signal wr : std_logic := '0';
signal dout : std_logic_vector(3 downto 0);
signal full : std_logic;
signal empty : std_logic;
constant clk_period : time := 10ns;
BEGIN
uut: syncFIFO PORT MAP (
clk => clk,
reset => reset,
din => din,
dout => dout,
rd => rd,
wr => wr,
full => full,
empty => empty
);
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
process
begin
wait for clk_period;
wait until (clk'event and clk='1');wait for 1ns;
reset<='1';
wait until (clk'event and clk='1');wait for 1ns;
reset<='0';
wr<='1';
rd<='0';
din<="0000";
for i in 0 to 10 loop
wait until (clk'event and clk='1');wait for 1ns;
din<=din+'1';
end loop;
wr<='0';
rd<='1';
for i in 0 to 10 loop
wait until (clk'event and clk='1');wait for 1ns;
end loop;
wr<='1';
rd<='0';
din<="0000";
for i in 0 to 10 loop
wait until (clk'event and clk='1');wait for 1ns;
din<=din+'1';
end loop;
wr<='0';
rd<='1';
for i in 0 to 10 loop
wait until (clk'event and clk='1');wait for 1ns;
end loop;
wr<='1';
rd<='1';
din<="0000";
for i in 0 to 20 loop
wait until (clk'event and clk='1');wait for 1ns;
din<=din+'1';
end loop;
wait;
end process;
END;
FPGAメモ
・「カウンタを作るとき、最大値を超えたら勝手に元に戻るだろう」という発想は危険。きちんと初期値に戻るよう記述してあげないと(何故か)シミュレーションが途中で止まる。
・Integerの範囲指定は、
signal
として行う。2**
・複数のプロセス文をまたがって、一つの変数への代入を行わないようにする。つまり、基本的に一つの変数は一つのプロセス中で処理しきること(唯一例外があって、3-state bufferを推定させる記述を使えばこの限りではない。そのためには、必要ないときに'Z'を代入してハイインピーダンスを作ってやる)
・[xilinxのwebiseの場合]stimulate behavioral modelをダブルクリックするときに、選択されているファイルがテストベンチであることを確認しないとまずい。uutを選んであると、入力がすべて無くなる。