テストベンチでハンドシェイク

テストベンチでハンドシェイク

 テストベンチでいただく質問で一番多いのがハンドシェイクです。それは、次の図のように2つのモジュール間でのやり取りがあるような場合のモジュールを検査したい時に必要になります。

たとえば、上の図でモジュールBの設計を行っているとき、”データをおくっていい?”という問いに対して、モジュールAから”いいよ”という回答を得てから送信データを送る。という事があります。

このようにモジュール間で何かのスタートをする前にやり取りすることをハンドシェイクといいます。メモリの中が空になってから送ってほしいとか、モータやアームの位置が所定の位置になっているとか、いろいろなハンドシェイクがあります。

このような場合、本来であれば、モジュールAとモジュールBの両方を接続して、それらをまるごとシミュレートするのが良いのですが、設計の途中段階では、モジュールAも完成していない。という事もあります。

そのような時に、モジュールBだけを設計して、それをシミュレートしたい。という場面は頻繁に現れます。この場合、テストベンチはモジュールAと同じ動きをするテストベンチになりますので、以下のようなブロック図で示すことができます。

今回はVerilogで解説します。VHDLも同じ事ができます。

Verilogでウェイトの命令を使います。ウェイトは@(posedge rclock)のようにクロックの立ち上がりを待つ。という使い方は慣れているようですが、信号にも使えます。

たとえば、sendreqという信号を待ちたい時には、@(posedge sendreq)でsendreq信号の立ち上がりを待つことができます。sendreqの信号を待って、次のクロックでreadyをHiにしたい時には、

@(posedge sendreq) #SYSCLK_PERIOD;
ready <= 1'b1;

のように記述します。

では、モジュールBの例として、handshake.vというモジュールを作成します。そのテストベンチとして、handshakeTB.vを作成します。

//  TITLE:					"handshake.v"
//  PROJECT CODE:			blog
//	MODULE NAME:			blog prbs
//	Target Device:			fpga
//	EDA Tool:				
//  AUTHOR:					****** ************* (****@nakaharagikencom)
//  LICENSE:           		Copyright (c) 2021 nakaharagiken Co.,Ltd. All rights reserved. 
//  SOURCE code type:		(*)RTL / ()Test Bench
//  DESCRIPTION:            
//  NOTES TO USER:      	
//  CREATION DATE:			
//  REVISION HISTORY:  	    
//  SOURCE CONTROL:  	    
//							
//							sendreq				____|~~~~|_________
//
//							ready				______|~|__________
//
//
//

`timescale 1ns/10ps		// 単位1nsec,分解能10psec

module handshake(
	clock,
	nreset,						// (i)	非同期リセット			~~reset~~|__normal__
	sendreq,					// (o)	送信要求				______|~~~~~~~|_____
	ready,						// (i)	送信受付完了			____________|~|_____
	data						// (o)	データ
);

input	clock;
input	nreset;
output	sendreq;
input	ready;
output	data;


//シフト・レジスタ
reg 	[2:0] 	rshift;
reg				rsendreq;
reg		[3:0]	rcounter;

wire		wprbs3;
wire		wprbs9;
wire		wprbs15;


always @ (posedge clock, negedge nreset) begin
	if (!nreset) begin
		rsendreq <= 0;
	end else begin
		if (( rcounter == 4'b1000 ) &amp;&amp; (rsendreq == 1'b0)) begin
			rsendreq <= 1'b1;
		end else begin
			if ((rsendreq == 1'b1) &amp;&amp; (ready == 1'b1)) begin
				rsendreq <= 1'b0;
			end
		end
	end
end


always @ (posedge clock, negedge nreset) begin
	if (!nreset) begin
		rshift <= 3'b111;					// 初期値
		rcounter <= 4'b1000;				// 初期値
	end else begin
		if (rcounter < 4'b1000) begin
			rshift[2] <= rshift[1];
			rshift[1] <= rshift[0];
			rshift[0] <= rshift[2] ^ rshift[1];
			rcounter <= rcounter + 1;
		end else if ((rsendreq == 1'b1) &amp;&amp; (ready == 1'b1)) begin
			rcounter <= 0;
			rshift <= 3'b111;					// 初期値
		end else begin
			rcounter <= 4'b1000;
			rshift <= 3'b111;					// 初期値
		end
	end
end


assign data = rshift[2];

assign	sendreq = rsendreq;

endmodule

次にテストベンチです。

//  TITLE:					"handshakeTB.v"
//  PROJECT CODE:			blog
//	MODULE NAME:			blog prbs
//	Target Device:			fpga
//	EDA Tool:				
//  AUTHOR:					****** ************* (****@nakaharagikencom)
//  LICENSE:           		Copyright (c) 2021 nakaharagiken Co.,Ltd. All rights reserved. 
//  SOURCE code type:		()RTL / (*)Test Bench
//  DESCRIPTION:            
//  NOTES TO USER:      	
//  CREATION DATE:			
//  REVISION HISTORY:  	    
//  SOURCE CONTROL:  	    
//							
//
//
//


`timescale 1ns/100ps		// 時間単位,分解能

module handshakeTB;

parameter SYSCLK_PERIOD =  100; // 10MHz


reg			rclock;
reg			rnreset;
wire		wsendreq;
reg			rready;
wire		wdata;


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



//////////////////////////////////////////////////////////////////////
// Main
//////////////////////////////////////////////////////////////////////
initial
begin
	rclock <= 1'b0;
	rnreset <= 1'b0;
	rready <= 1'b0;
	repeat(100) @(posedge rclock);
	rnreset <= 1'b1;

	@(posedge wsendreq) #SYSCLK_PERIOD;
	rready <= 1'b1;
	#SYSCLK_PERIOD;
	rready <= 1'b0;

	@(posedge wsendreq) #SYSCLK_PERIOD;
	rready <= 1'b1;
	#SYSCLK_PERIOD;
	rready <= 1'b0;


end


handshake inst_handshake(
	.clock			(rclock),
	.nreset			(rnreset),				// (i)	非同期リセット			~~reset~~|__normal__
	.sendreq		(wsendreq),				// (o)	送信要求				______|~~~~~~~|_____
	.ready			(rready),				// (i)	送信受付完了			____________|~|_____
	.data			(wdata)					// (o)	データ
);



endmodule

 ハンドシェイクしているのは、handshakeTB.vの53行目からです。wsendreqの立ち上がりエッジを待って、次にクロック分の時間SYSCLK_PERIODを待ちます。そして、ハンドシェイクの答えである、rready信号をHiにして、1クロック後にLowにしています。

 最後にModelSimの波形を紹介します。

 wsendreq信号とrready信号の関係がハンドシェイクになっていることがわかります。このようにテストベンチは相手の信号とのやり取りをシミュレートしてハンドシェイクの確認をすることができます。