# Testbench 介紹 [TOC] ## 更新進程 <font color=green>3/21 新增 clk 介紹。</font> ## 前言 在測試電路的時候,會需要用到`Testbench`來驗證所寫出來的電路是否正確。而`Testbench`也是由`Verilog`語言寫成,基本上可以把它視為另一個 module,把需要測試的 module 接進去,並藉由餵進去不同 input 資料,來觀察 output 是否正確。 | ![](https://i.imgur.com/IU2TGsi.png) | | -------- | ## 先備知識 在寫`Testbench`的時候,由於只是模擬資料輸入,可以使用較高階語言的方式來描述所想使用的功能(像是`for`、`repeat`等等),此外時間也可以由自己控制(像是幾個 cycle 後做什麼事)。 <font color=#bf2222>**宣告變數:**</font> 通常會將`input port`接到`reg`型別的變數當中以利<font color=#bf2222>提供不同測試資料</font>。 ```verilog= reg [2:0]a; ``` 通常會將`output port`接到`wire`型別的變數當中,以利<font color=#bf2222>接收電路測試的結果</font>。 ```verilog= wire [2:0]f; ``` <font color=#bf2222>**呼叫 module:**</font> 把寫好的 module 接進來。這部分跟呼叫 AND、OR 等 logic gate 有些類似,包括`module 的名稱`、`命名`、`input port 及 output port`。 ```verilog= Mux_3bits m_0(.a (a), .b (b), .sel (sel), .f (f)); ``` <font color=#bf2222>**設置 delay:**</font> 時間是模擬的基礎,換句話說,沒有時間看不出資料出入的關係。使用方式是`#`後面加上 delay 的時間刻度。 ```verilog= parameter delay = 5; #delay ``` 另外,`timescale`是用來告訴模擬軟體時間刻度,以下方為例 ,1ns 為時間單位,以 10ps 為單位察看一次電路的行為。 ```verilog= `timescale 1ns/10ps //<--定義時間刻度 ``` 通常在寫sequential circuit 會先定義一個 cycle 的時間長短,並使用`always`來控制 clock 信號的變化(Combinational circuit 則不一定要使用規律的 clock 信號)。 ```verilog= always #(CYC/2) clk = ~clk; //<--每半個cycle反向 ``` <font color=#bf2222>**測試程序:**</font> 這一步要設計測試的順序,通常使用`initial block`來安排。而`initial`即是指程式一開始會先從此處開始執行,並依序向下進行。 ```verilog= initial begin a = 3'b000; //<--給予a初值 ... end ``` <font color=#bf2222>**迴圈:**</font> 一些重複性的測試在`Testbench`中可藉由迴圈達成,常用的語法像是`for`或者`repeat`。 以`repeat`舉例,() 當中填入要執行的次數,並在 begin 跟 end 之間加入需要執行的項目。 ```verilog= repeat(2**3)begin //<--執行8次 #delay //<--隔一個delay a = a + 1'b1; //<--a就會+1 end ``` 而`for`其實用法類似,也蠻直覺的,要注意的是這裡不像`C語言`可以寫`i++`,要寫成`i=i+1`。 ```verilog= for(i=0;i<8;i=i+1)begin //<--執行8次 #delay //<--隔一個delay a = a + 1'b1; //<--a就會+1 end ``` <font color=#bf2222>**其他語法:**</font> - `$display`類似於`C語言`當中的`printf`,用於顯示一些資訊。 - `$finish`用於結束檢驗時。 ## 範例 就以一個 3-bit 的多工器(MUX)為例: ```verilog= module Mux_3bits (a, b, sel, f); input [2:0]a, b; input sel; output [2:0]f; Mux_1bit m0(a[0],b[0],sel,f[0]); Mux_1bit m1(a[1],b[1],sel,f[1]); Mux_1bit m2(a[2],b[2],sel,f[2]); endmodule module Mux_1bit(a, b, sel, f); input a, b; input sel; output f; wire w0; wire w1, w2; not not_0(w0, sel); and and_0(w1, sel, a); and and_1(w2, w0, b); or or_0(f, w1, w2); endmodule ``` 接下來要測試此電路,接上寫好的`Testbench`: ```verilog= `timescale 1ns/1ps module Mux_3bit_tb(); parameter delay=5; reg [2:0]a; reg [2:0]b; reg sel; wire [2:0]f; Mux_3bits m_0(.a (a), .b (b), .sel (sel), .f (f)); initial begin a = 3'b000; b = 3'b000; sel = 1'b0; repeat (2 ** 7) begin #delay $display("a=%b , b=%b , sel=%b , f=%b", a, b, sel, f); if((sel == 1'b1 && a != f)||(sel == 1'b0 && b != f)) begin $display("Wrong!"); $finish; end {a, b, sel} = {a, b, sel} + 1'b1; end $display("Complete."); end $finish; endmodule ``` ## 補充 用到 Design Version 合成的電路會有 .sdf(Standard Delay Format)檔的產生,裡面描述了關於 gate delay 的資訊,因此在檢查合成後的電路時會需要加入這個檔案。而 .fsdb 檔則是描述波形圖,在使用 nWave 工具的時候會需要使用到。 因此在助教提供的`Testbench`當中可能會看到像是下方範例的結構: ```verilog= initial begin `ifdef SDF $sdf_annotate(`SDFFILE, xxx); $fsdbDumpfile("xxx_syn.fsdb"); `else $fsdbDumpfile("xxx.fsdb"); `endif $fsdbDumpvars; end ``` # [HOMEPAGE](https://hackmd.io/s/HJdaLPTQV)