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

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

ステートマシンの構想」「Verilogのステートマシンを細かく説明」の続きとして、テストベンチの解説を行います。作成したステートマシンが動作しているのかを確認するにはテストベンチでステートマシンの動作を見ます。

 テストベンチのソースコードはそれほど難しくありません。全コードを次に示します。

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

module TB_MCP3002drv;

parameter SYSCLK_PERIOD = 100;		// 10MHz


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




//////////////////////////////////////////////////////////////////////
// Clock Driver
//////////////////////////////////////////////////////////////////////
always @(i_clock)
    #(SYSCLK_PERIOD / 2.0) i_clock <= !i_clock;


//////////////////////////////////////////////////////////////////////
// Main
//////////////////////////////////////////////////////////////////////
initial
begin

	i_clock <= 0;
	i_nreset <= 0;									//	初期値
	i_enable <= 0;
	i_SPI_MISO <= 0;								// SPI MISO :プルダウン


	repeat(50) @(posedge i_clock);
	i_nreset <= 1;
	repeat(100) @(posedge i_clock);

	i_enable <= 1'b1;
	i_SPI_MISO <= 1'b0;

	wait (o_SPI_ncs == 1'b0);						// B0 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 1
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 2 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 2 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 3 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 3 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 4 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 4 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);							// up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B9 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B9 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B8 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B8 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B7 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B7 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B6 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B6 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B5 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B5 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B4 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B4 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B3 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B3 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B2 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B2 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B1 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B1 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B0 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B0 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B0 up	null
	repeat(1) @(posedge i_clock);

	wait (o_SPI_ncs == 1'b1);						// B0 up	null
	repeat(1) @(posedge i_clock);

	wait (o_SPI_ncs == 1'b0);						// B0 up	null

	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 1
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 2 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 2 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 3 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 3 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 4 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 4 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);							// up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B9 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B9 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B8 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B8 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B7 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B7 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B6 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B6 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B5 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B5 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B4 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B4 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B3 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B3 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B2 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B2 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B1 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B1 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B0 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B0 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B0 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_ncs == 1'b1);						// B0 up	null
	repeat(1) @(posedge i_clock);


//////

	wait (o_SPI_ncs == 1'b0);						// B0 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 1
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 2 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 2 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 3 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 3 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 4 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 4 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);							// up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B9 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B9 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B8 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B8 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B7 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B7 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B6 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B6 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B5 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B5 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B4 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B4 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B3 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B3 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B2 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B2 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B1 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B1 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B0 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B0 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B0 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_ncs == 1'b1);						// B0 up	null
	repeat(1) @(posedge i_clock);


	wait (o_SPI_ncs == 1'b0);						// B0 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 1
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 2 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 2 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 3 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 3 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);						// 4 down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);						// 4 up
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// down
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b1);							// up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B9 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B9 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B8 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B8 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B7 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B7 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B6 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B6 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B5 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B5 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B4 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B4 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B3 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B3 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B2 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B2 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B1 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b0;
	wait (o_SPI_clk == 1'b1);							// B1 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B0 down
	repeat(1) @(posedge i_clock);
	i_SPI_MISO <= 1'b1;
	wait (o_SPI_clk == 1'b1);							// B0 up	null
	repeat(1) @(posedge i_clock);
	wait (o_SPI_clk == 1'b0);							// B0 up	null
	repeat(1) @(posedge i_clock);

	wait (o_SPI_ncs == 1'b1);						// B0 up	null
	repeat(1) @(posedge i_clock);

	wait (o_SPI_ncs == 1'b0);							/////// chip select



end


MCP3002drv inst_MCP3002drv (
	.clock		(i_clock),					//	in			system clock 10MHz
	.nreset		(i_nreset),					//	in			asynchronous reset 					____reset___|~~~normal~~~
	.enable		(i_enable),					//	in			シーケンスイネーブル				___disable__|~~enable~~~~
	.SPI_ncs	(o_SPI_ncs),				//	ouy			SPIチップセレクト信号:プルアップ	~~~|_________________|~~~
	.SPI_clk	(o_SPI_clk),				//	out			SPIクロック信号
	.SPI_MOSI	(o_SPI_MOSI),				//	out			SPI MOSI
	.SPI_MISO	(i_SPI_MISO),				//	in			SPI MISO :プルダウン
	.ch0_dat	(o_ch0_dat),				//	out	[9:0]	ADCデータチャンネル0
	.ch1_dat	(o_ch1_dat),				//	out	[9:0]	ADCデータチャンネル1
	.dataset	(o_dataset),				//	out			ADCデータチャンネル0と1のデータ確定	_____|~|_________________
	.busy		(o_busy)					//	out			本ブロック動作中					_________|~~~busy~~~~~~~~
);


endmodule

 24行目は本テストベンチで使用するクロック周波数の定数宣言です。10MHzで宣言しています。

  27~37行目でテストベンチのレジスタを宣言していますが、Verilogの場合入力信号はregで、出力信号はwireで宣言します。VHDLの場合区別はありません。ModelSimを使う場合ですと、入力信号と出力信号の区別がしにくいので、レジスタ名の頭にi_、o_を付けて入力と出力がわかるようにしています。

 45行目でクロック信号を生成しています。(SYSCLK_PERIOD / 2.0) i_clock <= !i_clock;としているのは、クロックデューティーが50%だからです。

 55~58行目で各入力信号の初期値を入れます。これ以降がテストベンチ動作になります。

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

 ×××を待ってから〇〇〇〇を動かす。というのはテストベンチでは頻繁に発生しますが、verilogの場合はこのようにwaitを使うのが簡単です。

MicroChip MCP3002から抜粋

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

 その後、90行目のi_SPI_MISO <= 1’b1;でMSBビットをi_SPI_MISOに入れています。138行目までが受信のシリアル信号です。

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

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

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