テストベンチの書き方_VHDL編(1)

テストベンチの書き方_VHDL編(1)

 VHDLのテストベンチを書いてみましょう。VHDLの構文(1)のソースコードをシミュレータで確認してみます。

 テストベンチはテストしたいファイルの「親」になって、「子」である被検査ファイルをテストする。という関係になります。テストベンチファイルが「親」で、テストされるファイルが「子」という事です。

 「子」であるテストされるファイルがFPGAの回路になります。テストベンチは回路に全く関係ありません。「子」の回路がエンジニアの思想通りに動くのか? というのを確認するためのテストベンチです。

  テストベンチには概ね次のように3通りの方法があります。テストベンチが「親」で、テストしたいファイルが「子」である事に変わりはありません。

 これから説明するのはCASE-1のパターンです。1つのVHDLファイルをシミュレートします。一番確実で単純な方法です。

 CASE-2はあまりお勧めできないパターンです。テストしたいファイルが2個あって、テストベンチは1個なので、本当の意味でテストベンチとは言えないのです。

 1個目のファイルと2個目のファイルの間に「配線」が生じます。信号を接続するという事です。その接続を実際のFPGAの回路ではなく、テストベンチで接続してしまう事になります。

 テストベンチはFPGAの回路に関係無いので、もし1個目と2個目の間の配線をテストベンチで接続してしまうと、FPGAの回路に反映されません。もしくは、反映する別のVHDLファイルを作る事になってしまいます。

 最初のうちはCASE-2のダメな事がわかりにくいと思います。なので、2つのVHDLファイルを1つのテストベンチでシミュレートするのはダメだ。と覚えていただいて構いません。

  CASE-3は「親」と「子」の関係になっている回路をテストベンチで確認する方法です。2つ以上のファイルをテストベンチで確認したい場合には、CASE-2の方法ではなくCASE-3の方法で行うようにしてください。

 CASE-2と違うのは「親」と「子」の関係になっている事です。この関係を含めてテストするというのは非常に重要です。

 HDLでテストベンチを作る際にわかりにくいのは、テストベンチだ。という根本的な事です。これは作ったエンジニアしかわからない。と言っても良いぐらいにテストベンチのファイルと回路になるHDLファイルに違いが無い場合があります。

 したがって、私はテストベンチはファイル名にTBを付けるようにしています。

 datasel.vhd のテストベンチは TB_datasel.vhd という具合です。

--  TITLE:					"TB_datasel.vhd"
--  MODULE NAME:			TB_datasel
--  PROJECT CODE:			
--  AUTHOR:					(****@*****.**.**)
--  CREATION DATE:			2020.1.1
--  SOURCE:            		
--  LICENSE:           		Copyright (c) 2020 Nakahara-Giken. All rights reserved. 
--  DESCRIPTION:            datasel.vhdのテストベンチ
--  NOTES TO USER:			
--  SOURCE CONTROL:			
--  REVISION HISTORY:  	    v0.1	2020.1.2	First edition
--
--
--
--
--
--
--
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;

entity TB_datasel is
end TB_datasel;

architecture sim of TB_datasel is

component datasel is
port (
	clock:				in	std_logic;						-- system clock
	nreset:				in	std_logic;						-- asynchronous reset 				____reset___|~~~normal~~~
	enable:				in	std_logic;						-- enable							________|~enable~|_______
	SwitchIn_A:			in	std_logic;						-- 入力ピンからの信号A 				
	SwitchIn_B:			in	std_logic;						-- 入力ピンからの信号B				
	input_sel:			in	std_logic;						-- 入力ピンからのセレクト信号		___input_A__|~~input_B~~~
	output_ans:			out	std_logic						-- A/B選択結果信号,レジスタ付き
);
end component;


constant SYSCLK_PERIOD : time := 20 ns; 					-- 50MHZ


signal	i_clock:		std_logic;						-- system clock
signal	i_nreset:		std_logic;						-- asynchronous reset 				____reset___|~~~normal~~~
signal	i_enable:		std_logic;						-- enable							________|~enable~|_______
signal	i_SwitchIn_A:	std_logic;						-- 入力ピンからの信号A 				
signal	i_SwitchIn_B:	std_logic;						-- 入力ピンからの信号B				
signal	i_input_sel:	std_logic;						-- 入力ピンからのセレクト信号		___input_A__|~~input_B~~~
signal	o_output_ans:	std_logic;						-- A/B選択結果信号,レジスタ付き



begin




inst_datasel : datasel
port map(
	clock			=>	i_clock,					-- in	std_logic;						-- system clock
	nreset			=>	i_nreset,					-- in	std_logic;						-- asynchronous reset 				____reset___|~~~normal~~~
	enable			=>	i_enable,					-- in	std_logic;						-- enable							________|~enable~|_______
	SwitchIn_A		=>	i_SwitchIn_A,				-- in	std_logic;						-- 入力ピンからの信号A 				
	SwitchIn_B		=>	i_SwitchIn_B,				-- in	std_logic;						-- 入力ピンからの信号B				
	input_sel		=>	i_input_sel,				-- in	std_logic;						-- 入力ピンからのセレクト信号		___input_A__|~~input_B~~~
	output_ans		=>	o_output_ans				-- out	std_logic						-- A/B選択結果信号,レジスタ付き
);


------------------------------------
-- Clock Driver
------------------------------------
process begin
	i_clock <= '1';
	wait for SYSCLK_PERIOD / 2;
	i_clock <= '0';
	wait for SYSCLK_PERIOD / 2;
end process;


------------------------------------
-- 信号作成
------------------------------------
process begin

	i_nreset <= '0';									--	初期値
	i_enable <= '0';
	i_SwitchIn_A <= '0';
	i_SwitchIn_B <= '0';
	i_input_sel <= '0';

	wait for (SYSCLK_PERIOD / 10);
	wait for (SYSCLK_PERIOD * 50);

	i_nreset <= '1';									--	初期値
	wait for (SYSCLK_PERIOD * 100);

	i_enable <= '1';
	wait for (SYSCLK_PERIOD * 100);

	i_input_sel <= '0';

	i_SwitchIn_A <= '1';
	i_SwitchIn_B <= '0';
	wait for (SYSCLK_PERIOD);
	i_SwitchIn_A <= '0';
	i_SwitchIn_B <= '0';
	wait for (SYSCLK_PERIOD);
	i_SwitchIn_A <= '1';
	i_SwitchIn_B <= '1';
	wait for (SYSCLK_PERIOD);
	i_SwitchIn_A <= '0';
	i_SwitchIn_B <= '1';
	wait for (SYSCLK_PERIOD*10);

	i_input_sel <= '1';
	i_SwitchIn_A <= '1';
	i_SwitchIn_B <= '0';
	wait for (SYSCLK_PERIOD);
	i_SwitchIn_A <= '0';
	i_SwitchIn_B <= '0';
	wait for (SYSCLK_PERIOD);
	i_SwitchIn_A <= '1';
	i_SwitchIn_B <= '1';
	wait for (SYSCLK_PERIOD);
	i_SwitchIn_A <= '0';
	i_SwitchIn_B <= '1';

	wait;

end process;

end sim;

 本当はテストベンチはすべてのブロックで一つ一つ作るべきです。つまり、1つのVHDLファイルを作ったなら、そのテストベンチを作る。という事です。それを繰り返して、どんどん上位のファイルを作ります。最後はトップファイルのテストベンチまで作る事ができれば完璧です。

 これはシミュレータプログラムにもよるのですが、ModelSimを使っていると、シミュレータの信号が入力なのか出力なのかがわかりにくいです。そこで私は46〜52行目のように入力信号の頭にiを付けるようにしています。

 テストベンチの親子関係についてはVHDLの階層構造と書き方は同じですので、階層構造_構文編(VHDL)を参照してください。