iT邦幫忙

2021 iThome 鐵人賽

DAY 16
1
Software Development

verilog or very lag系列 第 16

【Day16】TestBench 的撰寫技巧

透過 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

先來談談最上面那行 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 語法則可以停止波形的模擬(否則會一直跑下去,會一直佔用電腦的資源)。


如何在 Quartus 完成對 TestBench 的設定以及跑模擬

Assignment/setting

Simulation/Compile test bench --->點選右側 Test Bench.. 按鈕

New...

上面兩行打上 module 名稱,下方選擇 tb 的 .v 檔並 add

接著連串的 ok ok...


設定 modelsim 路徑

tools/options

EDA Tool Options,並選擇路徑

模擬

Tools/Run Simulation Tool/RTL Simulation

這樣好好看的波形就會出來囉!!

順帶解釋一下 RTL 與 Gate-level Simulation 的差異:
RTL模擬是所謂的功能上的模擬,也就是不考慮硬體電路中實際的 delay,所有情況皆為理想,所以適合拿來純測功能,而 Gate-level 模擬則是時序上的模擬,此時會考慮到所有的不理想因素,因此會有 delay 的情況發生,所以跑模擬的順序都會是先跑 RTL 再跑 Gate-level。


上一篇
【Day15】狀態機的撰寫
下一篇
【Day17】Uart_TX 狀態機的實現
系列文
verilog or very lag30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言