Testbench 介紹

tags: verilog digital design 邏輯設計 邏設

前言

在寫完程式碼之後,勢必要測試它是否正確,而 testbench (簡稱 tb)就是用來幫助我們測試我們的程式是否有誤的方法。

testbench 基本上也是一個 verilog 檔案( .v ),所以裡面也是由一個 module 組成,不同的地方在於,一般 verilog 檔案會燒進電路板裡,而 testbench 只是讓我們在電腦模擬的檔案罷了。因此,可以用一些方便的工具執行,例如, for 迴圈、integer等。

寫法

這裡介紹一種最簡單的模板供大家使用,有興趣的,可以再自己深入研究。

step 1

首先,我們必須觀察我們寫好的 verilog 檔,判斷哪些是 input ,哪些是 output。

舉例來說:

module Binary_to_Grey (din, dout); input [4-1:0] din; output [4-1:0] dout; assign dout = {1'b0, din[4-1:1]} ^ din; endmodule

由此範例可得, input 為 din,而 output 為 dout。

step 2

剛剛說過,tb 也是一個 verilog 檔案,所以起手式都一樣。

`timescale 1ns / 1ps //時間參數,請打在 tb 的第一行 module Testbench(); // 由於 tb 是沒有 input , output 的,所以括號裡面不用放東西。 // 直接進入 參數設定 reg [3:0] din; wire[3:0] dout; reg CLK; . . . endmodule

step 3

接著要呼叫我們剛剛寫好的程式碼(呼叫裡面的 module)

`timescale 1ns / 1ps module Testbench(); // 由於 tb 是沒有 input , output 的,所以括號裡面不用放東西。 // 直接進入 參數設定 reg [3:0] din; wire[3:0] dout; reg CLK; Binary_to_Grey name(.din(din), .dout(dout) ); . . . endmodule
  • name 是幫這個呼叫取一個名字,因為在之後寫 code 時,每個 module 通常不會只呼叫一次,所以每一個呼叫都需要一個名字,且不能一樣。

step 4

設置常數。

`timescale 1ns / 1ps module Testbench(); reg [3:0] din; wire[3:0] dout; reg CLK; Binary_to_Grey name(.din(din), .dout(dout) ); always #5 CLK = ~CLK; initial CLK = 1'b1; . . . endmodule

always #5 指的是每經過 5 個 cycles ,就跑一次後面的式子。
initial 指的是程式一開始執行時,就先運行這一行式子。

step 5

開始運算

`timescale 1ns / 1ps module Testbench(); reg [3:0] din; wire[3:0] dout; reg CLK; Binary_to_Grey name(.din(din), .dout(dout) ); always #5 CLK = ~CLK; initial CLK = 1'b1; initial begin din = 4'b0000; //給 din 一個初值 repeat (2 ** 4) begin //重複 2 ^ 4 次以下這個動作 @(posedge CLK) test; //先照抄 @(nededge CLK) din = din + 1'b1; // din 變成下一個數字 end end $finish . . . endmodule

step 6

寫 test 部分

`timescale 1ns / 1ps module Testbench(); reg [3:0] din; wire[3:0] dout; reg CLK; Binary_to_Grey name(.din(din), .dout(dout) ); always #5 CLK = ~CLK; initial CLK = 1'b1; initial begin din = 4'b0000; //給 din 一個初值 repeat (2 ** 4) begin //重複 2 ^ 4 以下這個動作 @(posedge CLK) test; //先照抄 @(nededge CLK) din = din + 1'b1; // din 變成下一個數字 end end $finish task test; begin if ( (din ===4'd0 && dout === 4'b0000) || (din === 4'd1 && dout === 4'b0001) || (din === 4'd2 && dout === 4'b0011) || (din === 4'd3 && dout === 4'b0010) || (din === 4'd4 && dout === 4'b0110) || (din === 4'd5 && dout === 4'b0111) || (din === 4'd6 && dout === 4'b0101) || (din === 4'd7 && dout === 4'b0100) || (din === 4'd8 && dout === 4'b1100) || (din === 4'd9 && dout === 4'b1101) || (din === 4'd10&& dout === 4'b1111) || (din === 4'd11&& dout === 4'b1110) || (din === 4'd12&& dout === 4'b1010) || (din === 4'd13&& dout === 4'b1011) || (din === 4'd14&& dout === 4'b1001) || (din === 4'd15&& dout === 4'b1000) ) $display("din = %d, dout = %d, got it !!\n", din, dout); else $display("din = %d, dout = %d, OOOOOOoooooops!!!\n", din, dout); end endtask endmodule

task 是一個用來寫重複指令的方法,在這裡我們將所有正確的結果放在 if 裡面,這樣我們就能判斷我們的程式碼是否正確。

ps. $display 類似 c 語言的 printf

As4 Part

  • Simulate the clock signal.
always #(cyc/2) clk = ~clk;
  • Dump nWave file.
initial begin $fsdbDumpfile("as4_2.fsdb"); $fsdbDumpvars; end

:maple_leaf:Homepage:maple_leaf: