Verilog - testbench 的撰寫

我們利用 Verilog 完成電路設計後

必須要測試這個電路的所有功能和輸出是否和預期符合

因此我們可以撰寫 testbench 來去測試該電路模組的功能

本篇會假設事前已經完成了一個電路設計 

(以下簡稱 DUT,Design Under Test,顧名思義就是待測試的電路設計)

所以主要會著重在 testbench 的撰寫來去測試這個 DUT


假設這是我的 DUT

(lab02.v)

module lab02(clk, A, B, C);

input clk, A;

output B, C;

reg B, C;

always@(posedge clk) begin

B <= A;

C <= B;

end

endmodule


然後在同個資料夾底下新建檔案 tb.v

步驟大概分為以下

  1. 先打上預期的 延遲時間單位 / 波型時間單位
  2. 似新建 Verilog 模組的撰寫,但注意 ( ) 內無需加入 parameter
  3. 將原本的 input 訊號線宣告為 reg,output 訊號線宣告為 wire
  4. 加入 DUT Module,並各自連接上在此模組對應宣告的 reg 和 wire 線
  5. 設定你想要的波型
1. 先打上預期的 延遲時間單位 / 波型時間單位

    這邊可以自己設計想要的
    舉個例子來說
    
    `timescale 1ns / 100ps
    
    (1 ns) 波型時間單位是什麼意思應該很好懂
    就是你在跑模擬波型圖時,間隔一個時間單位會是多久
    (100 ps) 延遲時間單位則是設定波型時
    會利用例如 #1 讓某個訊號線在延遲一個時間單位後做對應動作
    而這個 #1 所代表的時間單位即是你的延遲時間單位

2. 似新建 Verilog 模組的撰寫,但注意 ( ) 內無需加入 parameter

    `timescale 1ns / 100ps
    module tb();
    endmodule

3. 將原本的 input 訊號線宣告為 reg,output 訊號線宣告為 wire
從 DUT 的宣告,可以知道 input 有 clk 和 A,output 則是 B 和 C

    `timescale 1ns / 100ps
    module tb();
    reg clk, A; //input
    wire B,C; //output
    endmodule

4. 加入 DUT Module,並各自連接上在此模組對應宣告的 reg 和 wire 線

    `timescale 1ns / 100ps
    module tb();
    reg clk, A; //input
    wire B,C; //output
    lab02 module1(.clk(clk), .A(A), .B(B), .C(C));
    endmodule

5. 設定你想要的波型

主要會用到的有 initial always


initial 就是初始化時用的

用法為 initial begin 初始化動作 end

例如

    `timescale 1ns / 100ps
    module tb();
    reg clk, A; //input
    wire B,C; //output
    lab02 module1(.clk(clk), .A(A), .B(B), .C(C));
    initial begin
    clk <= 1'b0;
    A <= 1'b0;
    end
    endmodule

即表示 clk 和 A 在初始時會被設定為 0


always 則是在每延遲指定時間單位時,執行指定之事件

用法為 always #延遲時間單位 執行事件;

    `timescale 1ns / 100ps
    module tb();
    reg clk, A; //input
    wire B,C; //output
    lab02 module1(.clk(clk), .A(A), .B(B), .C(C));
    initial begin
    clk <= 1'b0;
    A <= 1'b0;
    end
    always #2 A = ~ A;
    always #1 clk = ~clk;
    endmodule

即表示每經過 2 個延遲時間單位 (根據上面的設定即是 2 * 100ps = 200 ps)

A 會反轉

而每經過 1 個延遲時間單位 (即為 100 ps)

clk 會反轉


到這邊大致就完成了!

但這邊在額外介紹 $monitor()

()裡面就類似 C 的撰寫方式

即可在指定時間監控你想要觀察的數值

例如下方

    `timescale 1ns / 100ps
    module tb();
    reg clk, A; //input
    wire B,C; //output
    lab02 module1(.clk(clk), .A(A), .B(B), .C(C));
    initial begin
    clk <= 1'b0;
    A <= 1'b0;
    end
    always #2 A = ~ A;
    always #1 clk = ~clk;
    initial begin
    $monitor("simtime = %g,  A =%b, B =%b, C =%b", $time, A, B, C);
    end
    endmodule

當然前面也可以加上 #2 (#2 monitor(...))

就會變成在經過 2 個延遲時間單位後

輸出這段字串


ref: 

How to write a testbench in Verilog?


留言

這個網誌中的熱門文章

Formal Verification(正規驗證)介紹和如何使用 SVA(System Verilog Assertion) 做驗證

Quartus Qsys + Nios II 入門使用

Quartus Qsys + Nios II + SDRAM 進階使用