透過 Verilog 完成一個具有特定功能的電路後,並不代表你的工作已經完成了,TestBench(tb) 在電路設計中也是一個非常重要的環節,往往驗證電路所花的時間還會比較開發來的多。
而 TestBench 則是另一個 .v 檔,TestBench 的工作就是產生待測模塊的輸入信號,用這些訊號模擬真實的情況,接著透過波型來觀察輸出結果是否如自己預期,如果不如預期,也可以再透過把待測電路中的各個訊號叫出來觀察,以此 debug 也會比自己一直盯著程式碼來除錯來的有效率唷!
我們可以先來看[Day15]中的範例程式
module testFSM(
clkSys,
rst_n,
en,
out
);
/*--------localparam--------*/
localparam one = 2'd0;
localparam two = 2'd1;
localparam three = 2'd2;
localparam four = 2'd3;
/*--------ports declarations--------*/
input clkSys;
input rst_n;
input en;
output [2:0]out;
reg [2:0]out;
/*--------variables--------*/
reg [1:0]fstate;
.
.
.
.
endmodule
可以看到這個模塊有三個輸入,分別是 clkSys, rst_n, en,那麼我們在 testbench 那邊就會需要有對應這三個訊號的 register(通常我名字會取一樣),而輸出則是一個 3 bit的 out,那麼對應 testbench,就會有一個 3 bit 的 wire 對應它。
再來稍微解釋一下為甚麼 testbench 那邊一定要模塊的輸入用 reg,而輸出用 wire,因為 reg 屬於過程性賦值(Procedural Assignment),意思是值是可以一直隨心所欲變動的,而 wire 則屬於連續性賦值(Continuous Assignment),通常用於連接訊號用。
所以就會有對應的這區塊程式:
`timescale 10ns/1ns
module tb_testFSM();
reg clkSys;
reg rst_n;
reg en;
wire [2:0]out;
testFSM UUT(
.clkSys(clkSys),
.rst_n(rst_n),
.en(en),
.out(out)
);
先來談談最上面那行 timescale 10ns/1ns
timescale 是 Verilog 中的一種時間預編譯指令,它用來定義模組模擬的時間單位以及時間精度。
格式長這樣:
`timescale 時間單位 / 時間精度
需要注意到的是:
以上兩者的數字只能是 1 or 10 or 100,而且時間單位必須大於時間精度。
以下來舉個例子:
`timescale 1ns/10ps
reg clk_50M;
initial begin
clk_50M = 0;
end
always #10 clk_50M = ~clk_50M;
現在時間單位設為 1ns 那麼 #1 就會 delay 1ns,#10 則是 delay 10 個 ns,所以 delay 10 個 ns 則 clk_50M 會反向一次,所以反向兩次可以得到 1 周期的 clk,所以一個 clk 總共 delay (1ns)x(delay 10 個)x(反向 2 次) = 20 ns,得到此頻率為 50 MHZ。
現在回到 testBench 那個程式,宣告完 reg 以及 wire 後,剩下的就是以 by name 的方式來引用模組了。
註: TestBench 中引用的測試模塊通常命名為 UUT(Unit Under Test)
再接著:
initial begin
clkSys = 0;
rst_n = 0;
en = 0;
repeat(2)@(posedge clkSys)rst_n = 0;//push rst_n
rst_n = 1;//release rst_n
en = 1;
#20 en = 0;
#40;
en = 1;
#20 en = 0;
#40;
en = 1;
#20 en = 0;
#40;
en = 1;
#20 en = 0;
#100 $stop;
end
always #10 clkSys = ~clkSys;
endmodule
initial begin 是用於 TestBench 中初始化變數值的語法,而且 initial block 中的程式只會執行一遍,並不會像 always 一直重複執行,在 initial block 內初始化訊號後,就要開始對輸入訊號的變數賦值了,而 $stop 語法則可以停止波形的模擬(否則會一直跑下去,會一直佔用電腦的資源)。
Assignment/setting
Simulation/Compile test bench --->點選右側 Test Bench.. 按鈕
New...
上面兩行打上 module 名稱,下方選擇 tb 的 .v 檔並 add
接著連串的 ok ok...
tools/options
EDA Tool Options,並選擇路徑
Tools/Run Simulation Tool/RTL Simulation
這樣好好看的波形就會出來囉!!
順帶解釋一下 RTL 與 Gate-level Simulation 的差異:
RTL模擬是所謂的功能上的模擬,也就是不考慮硬體電路中實際的 delay,所有情況皆為理想,所以適合拿來純測功能,而 Gate-level 模擬則是時序上的模擬,此時會考慮到所有的不理想因素,因此會有 delay 的情況發生,所以跑模擬的順序都會是先跑 RTL 再跑 Gate-level。