VHDLステートマシンのテストベンチを細かく解説

VHDLステートマシンのテストベンチを細かく解説

VHDLのステートマシンを細かく説明」で製作したステートマシンのテストベンチを解説します。本稿はVerilogと内容的に同じですので、Verilogでの解説が必要な方はこちらを参照してください。

 「VHDLのステートマシンを細かく説明」で作成したステートマシンが動作しているのかを確認するにはテストベンチでステートマシンの動作を見ます。テストベンチの全コードを次に示します。

--  TITLE:					"TB_MCP3002drv.vhd"
--  MODULE NAME:			TB_MCP3002drv
--  PROJECT CODE:			
--  AUTHOR:					 (****@nakaharagiken.com)
--  CREATION DATE:			2020.7.25
--  SOURCE:            		
--  LICENSE:           		Copyright (c) 2020 nakaharagiken All rights reserved. 
--  DESCRIPTION:            MCP3002drv.vhdのテストベンチ
--  NOTES TO USER:			
--  SOURCE CONTROL:			
--  REVISION HISTORY:  	    v0.1	2020.7.25	First edition

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.std_logic_arith.all;

entity TB_MCP3002drv is
end TB_MCP3002drv;

architecture sim of TB_MCP3002drv is

component MCP3002drv is
port (
	clock:				in	std_logic;						-- system clock
	nreset:				in	std_logic;						-- asynchronous reset 				____reset___|~~~normal~~~
	enable:				in	std_logic;						-- イネーブル						_________|~|_____________
	SPI_ncs:			out	std_logic;						-- SPIチップセレクト信号:プルアップ	~~~|_________________|~~~
	SPI_clk:			out	std_logic;						-- SPIクロック信号
	SPI_MOSI:			out	std_logic;						-- SPI MOSI
	SPI_MISO:			in	std_logic;						-- SPI MISO :プルダウン
	ch0_dat:			out	std_logic_vector(9 downto 0);	-- ADCデータチャンネル0
	ch1_dat:			out	std_logic_vector(9 downto 0);	-- ADCデータチャンネル1
	dataset:			out	std_logic;						-- ADCデータチャンネル0と1のデータ確定	_____|~|_________________
	busy:				out std_logic						-- 本ブロック動作中					_________|~~~busy~~~~~~~~
);
end component;


constant SYSCLK_PERIOD : time := 100 ns; 				-- 10MHz

signal	i_clock:	std_logic;						-- system clock
signal	i_nreset:	std_logic;						-- asynchronous reset 				____reset___|~~~normal~~~
signal	i_enable:	std_logic;						-- イネーブル
signal	o_SPI_ncs:	std_logic;						-- SPIチップセレクト信号:プルアップ	~~~|_________________|~~~
signal	o_SPI_clk:	std_logic;						-- SPIクロック信号
signal	o_SPI_MOSI:	std_logic;						-- SPI MOSI
signal	i_SPI_MISO:	std_logic;						-- SPI MISO :プルダウン
signal	o_ch0_dat:	std_logic_vector(9 downto 0);	-- ADCデータチャンネル0
signal	o_ch1_dat:	std_logic_vector(9 downto 0);	-- ADCデータチャンネル1
signal	o_dataset:	std_logic;						-- ADCデータチャンネル0と1のデータ確定	_____|~|_________________
signal	o_busy:		std_logic;						-- 本ブロック動作中					_________|~~~busy~~~~~~~~

begin


inst_MCP3002drv : MCP3002drv
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	イネーブル						_________|~|_____________
	SPI_ncs		=>	o_SPI_ncs,			-- out	std_logic	SPIチップセレクト信号:プルアップ	~~~|_________________|~~~
	SPI_clk		=>	o_SPI_clk,			-- out	std_logic	SPIクロック信号
	SPI_MOSI	=>	o_SPI_MOSI,			-- out	std_logic	SPI MOSI
	SPI_MISO	=>	i_SPI_MISO,			-- in	std_logic	SPI MISO :プルダウン
	ch0_dat		=>	o_ch0_dat,			-- out	std_logic_vector(9 downto 0)	ADCデータチャンネル0
	ch1_dat		=>	o_ch1_dat,			-- out	std_logic_vector(9 downto 0)	ADCデータチャンネル1
	dataset		=>	o_dataset,			-- out	std_logic;	ADCデータチャンネル0と1のデータ確定	_____|~|_________________
	busy		=>	o_busy				-- out 	std_logic	本ブロック動作中					_________|~~~busy~~~~~~~~
);

------------------------------------
-- 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_SPI_MISO <= '0';									-- SPI MISO :プルダウン

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

	i_enable <= '1';
	i_SPI_MISO <= '0';

	wait until (o_SPI_ncs = '0');							-- chip select
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 1
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 2 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 2 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 3 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 3 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 4 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 4 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);							-- up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B9 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B9 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B8 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B8 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B7 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B7 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B6 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B6 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B5 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B5 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B4 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B4 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B3 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B3 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B2 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B2 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B1 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B1 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B0 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B0 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B0 up	null
	wait for (SYSCLK_PERIOD * 1);

	wait until (o_SPI_ncs = '1');
	wait for (SYSCLK_PERIOD * 1);

	wait until(o_SPI_ncs = '0');

	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 1
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 2 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 2 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 3 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 3 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 4 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 4 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);							-- up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B9 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B9 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B8 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B8 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B7 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B7 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B6 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B6 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B5 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B5 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B4 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B4 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B3 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B3 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B2 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B2 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B1 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B1 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B0 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B0 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B0 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until(o_SPI_ncs = '1');
	wait for (SYSCLK_PERIOD * 1);

	wait until (o_SPI_ncs = '0');
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 1
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 2 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 2 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 3 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 3 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 4 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 4 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);							-- up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B9 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B9 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B8 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B8 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B7 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B7 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B6 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B6 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B5 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B5 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B4 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B4 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B3 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B3 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B2 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B2 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B1 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B1 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B0 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B0 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B0 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until (o_SPI_ncs = '1');
	wait for (SYSCLK_PERIOD * 1);

	wait until (o_SPI_ncs = '0');
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 1
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 2 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 2 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 3 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 3 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);						-- 4 down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);						-- 4 up
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- down
	wait for (SYSCLK_PERIOD * 1);
	wait until rising_edge(o_SPI_clk);							-- up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B9 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B9 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B8 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B8 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B7 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B7 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B6 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B6 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B5 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B5 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B4 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B4 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B3 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B3 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B2 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B2 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B1 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '0';
	wait until rising_edge(o_SPI_clk);							-- B1 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B0 down
	wait for (SYSCLK_PERIOD * 1);
	i_SPI_MISO <= '1';
	wait until rising_edge(o_SPI_clk);							-- B0 up	null
	wait for (SYSCLK_PERIOD * 1);
	wait until falling_edge(o_SPI_clk);							-- B0 up	null
	wait for (SYSCLK_PERIOD * 1);

	wait until (o_SPI_ncs = '1');
	wait for (SYSCLK_PERIOD * 1);

	wait until (o_SPI_ncs = '0');									-- chip select

end process;

end sim;

 40行目constant SYSCLK_PERIOD : time := 100 ns; は本テストベンチのクロック周波数の定数定義です。10MHzで動作させます。

  42~52行目でテストベンチのレジスタを宣言していますが、VHDLの場合入力信号と出力信号の区別はありません。テストベンチによっては勝手に色分けしてくれるものもありますが、レジスタ名の頭にi_、o_を付けて入力と出力がわかるようにしています。

 75~80行目でクロック信号を生成しています。クロックデューティーは50%になっています。

 99行目でwait until (o_SPI_ncs = ‘0’);により、o_SPI_ncsがLowになるまで待ちます。動作の信号は下のデータシートを参照してください。o_SPI_ncsはnCS(一番上の信号:CSの負論理)信号です。

MicroChip MCP3002から抜粋

 101行目の同じようにwait until rising_edge(o_SPI_clk);でo_SPI_clk信号(CLK信号)がHiになるまで待っています。これがシリアルクロックの1ビット目です。

 その後、121行目のi_SPI_MISO <= ‘1’;でMSBビットをi_SPI_MISOに入れています。

 172行目のwait until (o_SPI_ncs = ‘1’);でo_SPI_ncsがHiになるのを待っています。

 このようにテストベンチは多少野暮ったくても簡素に書く方が動作確認に徹することができると思います。

 VHDLの場合、〇〇〇が×××まで待つ。というテストベンチを書くときに、wait until rising_edge(o_SPI_clk);のようにwait untilを使うのが便利です。この場合、o_SPI_clkの立ち上がりエッジを待っています。

 本ソースコートはステートマシンの説明用に作成したもので、実機での動作確認を行っていません。実機で使用しないようにお願いします。