Verilogでモジュールを記述した後は本当に論理が合っているか検証が必要であるため,適当な信号を与え出力信号を見るテストベンチが必要である.
今回はテストベンチの記述に必要なことをまとめる.
テストベンチ記述例
先にテストベンチの例を示す.
サンプルコードとしてadderのテストベンチ:adder_tbを書いておく.
詳しくはページ後半で説明する.
`timescale 100ps/1ps
module adder_tb ();
parameter clk_period_p = 10;
parameter bit_p = 32;
wire [bit_p-1:0] z;
reg [bit_p-1:0] a_r;
reg [bit_p-1:0] b_r;
reg clk_r, reset_r;
adder adder (
.a_i(a_r),
.b_i(b_r),
.z_o(z),
.clk_i(clk_r),
.reset_i(reset_r)
);
initial begin
a_r = 0;
b_r = 0;
reset_r = 0;
clk_r = 0;
/* --- make signal --- */
#(clk_period_p) a_r = 10; b_r = 5;
#(clk_period_p) a_r = 1; b_r = 3;
#(clk_period_p) a_r = 1; b_r = 5; reset_r = 0;
#(clk_period_p) $finish;
end
always begin
#(clk_period_p/2.0) clk_r = ~clk_r;
end
initial begin
$shm_open("adder_tb.shm");
$shm_probe("AS");
end
endmodule
テストベンチの説明
テストベンチ内ではパラメータなどの宣言に加え
- 時間スケール
- モジュールの宣言
- 入力信号を与えるためのワイヤ・レジスタの宣言
- テスト信号の記述,生成
- シミュレーション結果の出力
について記述する.それぞれについて順に説明していく.
時間スケール
次のコードで時間スケールを設定する.
`timescale {1スケールあたりの時間}/{丸め精度}
サンプルコードでは clk_period = 10
としているのでクロックは1 GHzとなる.
`timescale 100ps/1ps
モジュールの宣言
次の部分ではモジュールを宣言している.
これはモジュールを検証するためのモジュールを宣言するということになる.
テストベンチは入出力ピンは必要ないので括弧内は空白で良い.
module adder_tb ();
検証対象のモジュールとワイヤ・レジスタの宣言
次の部分では,検証に必要なワイヤ・レジスタを宣言し,検証したいモジュールを呼び出して接続を記述する.
module adder #( parameter bit_p = 32 ) ( wire [bit_p-1:0] z; reg [bit_p-1:0] a_r; reg [bit_p-1:0] b_r; reg clk_r, reset_r; adder U0 ( .a_i(a_r), .b_i(b_r), .z_o(z), .clk_i(clk_r), .reset_i(reset_r) ); );
検証したいモジュールには
- モジュールの入力 ← 入力信号を駆動するためのレジスタを接続
- モジュールの出力 ← 出力を見るためのワイヤを接続
のようにする.
よって,adderの入力にはレジスタ(a_r, b_r, clk_r, reset_r
)を接続し,出力にはワイヤzを接続する.
モジュールの呼び出し方は次のようにする.
moduleNameにmodule名,instNameは基本何でもよい.
括弧内は接続を表し,.{モジュールの入出力ピン}({接続ノード}) のように記述する.
moduleName instName(.moduleInOut(Inout), ... );
上で作成した例ではテストベンチ内の接続図は次のようになる.

テスト信号の記述
次はテスト信号の記述である.
上の接続より,レジスタ(a_r, b_r, clk_r, reset_r)の値を変えることで入力信号を変えることができる.
次の部分ではクロック信号の生成を行っている.always begin ... end
内は何度も繰り返される.
#(実数)は待機を表し,下のコードでは#(5)となるので(5×timescale)分だけ待つことを表す.
その後,clk_rの論理が反転される.
よって,このコードでクロック波形が作れる.
always begin #(clk_period_p/2.0) clk_r = ~clk_r; end
次のコードでは各入力信号を表している.initial begin ... end
内は1度のみ実行される.
最初に各レジスタの値を初期化し,その後は#(実数)で待機時間,代入によって値を決めて信号を生成する.
また,$finish
でシミュレーションを終了する.$finish
がないとシミュレーションが終了しないので注意.
なしでシミュレーションを開始してしまった場合は,「Ctrl+C」で強制終了する.
initial begin a_r = 0; b_r = 0; reset_r = 0; clk_r = 0; /* --- make signal --- */ #(clk_period_p) a_r = 10; b_r = 5; #(clk_period_p) a_r = 1; b_r = 3; #(clk_period_p) a_r = 1; b_r = 5; reset_r = 0; #(clk_period_p) $finish; end
シミュレーション結果の出力
次の部分でシミュレーション結果を出力する.
initial begin
$shm_open("adder_tb.shm");
$shm_probe("AS");
end
まとめ
モジュールの作成の仕方に続いて,モジュールの論理を確かめるためのテストベンチの書き方について説明した.
テストベンチ内ではパラメータなどの宣言に加え
- 時間スケール
- モジュールの宣言
- 入力信号を与えるためのワイヤ・レジスタの宣言
- テスト信号の記述,生成
- シミュレーション結果の出力
について記述する.
また,検証したいモジュールには
- モジュールの入力 ← 入力信号を駆動するためのレジスタを接続
- モジュールの出力 ← 出力を見るためのワイヤを接続
のようにしテストベンチを配線する.