引言:在編寫完HDL代碼后,往往需要通過仿真軟件Modelsim或者Vivadao自帶的仿真功能對HDL代碼功能進行驗證,此時我們需要編寫Testbench文件對HDL功能進行測試驗證。本文我們介紹寫Testbench編寫的一些要點。
1.Testbench文件結構模板
編寫Testbench的目的是為了測試設計電路的功能、性能與設計的預期是否相符。驗證軟件功能通過包括以下步驟:
????? ? 產生合適的模擬激勵(波形):該激勵通常要覆蓋被測HDL模塊(黑盒或者稱作DUT模塊)所有可能得輸入狀態;
????? ? 將產生的激勵加入到被測試模塊中并觀察其響應:即將DUT模塊例化到Testbench文件中,運行仿真軟測測試;
????? ? 將輸出響應與期望值相比較:該步驟是驗證DUT功能較耗時的部分,需要仔細分析代碼功能是否達到預期設計,所有代碼段功能是否正常。
Testbench結構一般模板如下:
?
module Test_bench_name();//通常無輸入無輸出 //01:信號或變量聲明定義 //--邏輯設計中輸入對應 reg 型 //--邏輯設計中輸出對應 wire 型 //02:使用 initial 或 always 語句產生激勵 //03:例化待測試DUT模塊 //04:監控和比較輸出響應 endmodule2.時鐘激勵輸入示例
?
常見的時鐘有:50%占空比連續時鐘、固定周期數時鐘、非50%占空比時鐘,示例如下。
?
/*---------------------------------------------------------------- 時鐘激勵產生方法一:50%占空比時鐘 ----------------------------------------------------------------*/ parameter ClockPeriod=10; //參數化時鐘周期 initial begin clk_i=0; forever#(ClockPeriod/2) clk_i = ~clk_i; end /*---------------------------------------------------------------- 時鐘激勵產生方法二:50%占空比時鐘 ----------------------------------------------------------------*/ initial begin clk_i=0; end always #(ClockPeriod/2) clk_i=~clk_i; /*---------------------------------------------------------------- 時鐘激勵產生方法三:產生固定數量的時鐘脈沖 ----------------------------------------------------------------*/ parameter ClockPeriod=10; //參數化時鐘周期 initial begin clk_i=0; repeat(6) #(ClockPeriod/2) clk_i=~clk_i; end /*---------------------------------------------------------------- 時鐘激勵產生方法四:產生非占空比為 50%的時鐘 ----------------------------------------------------------------*/ parameter ClockPeriod=10; //參數化時鐘周期 initial begin clk_i=0; forever begin #((ClockPeriod/2)-2) clk_i=0; #((ClockPeriod/2)+2) clk_i=1; end end3.復位激勵輸入示例
?
復位輸入主要包括異步復位、同步復位,代碼示例如下。
?
/*---------------------------------------------------------------- 復位信號產生方法一:異步復位 ----------------------------------------------------------------*/ initial begin rst_n_i=1; #100; rst_n_i=0; #100; rst_n_i=1; end /*---------------------------------------------------------------- 復位信號產生方法二:同步復位 ----------------------------------------------------------------*/ initial begin rst_n_i=1; clk_i = 0; @(negedge clk_i) rst_n_i=0; #100; //固定時間復位 repeat(10) @(negedge clk_i); //固定周期數復位 @(negedge clk_i) rst_n_i=1; end always #5 clk_i=~clk_i; /*---------------------------------------------------------------- 復位信號產生方法三:復位任務封裝 ----------------------------------------------------------------*/ task reset; input [31:0] reset_time; //復位時間可調,輸入復位時間 RST_ING=0; //復位方式可調,低電平或高電平 begin rst_n=RST_ING; //復位中 #reset_time; //復位時間 rst_n_i=~RST_ING; //撤銷復位,復位結束 end endtask4.雙向口inout示例
/*---------------------------------------------------------------- 雙向信號inout 在 testbench 中定義為 wire 型變量 ----------------------------------------------------------------*/ reg sck; wire sda; //inout信號sda定義為wire型 reg sda_r; //inout 輸出定義為reg型 reg sda_en; assign sda_r = (sda_en) ? mosi : 1'bz; assign sda =sda_r;5.特殊信號設計
/*---------------------------------------------------------------- 特殊激勵信號產生描述一:輸入信號任務封裝 ----------------------------------------------------------------*/ task i_data; input [7:0] dut_data; begin@(posedge data_en); send_data=0; @(posedge data_en); send_data=dut_data[0]; @(posedge data_en); send_data=dut_data[1]; @(posedge data_en); send_data=dut_data[2]; @(posedge data_en); send_data=dut_data[3]; @(posedge data_en); send_data=dut_data[4]; @(posedge data_en); send_data=dut_data[5]; @(posedge data_en); send_data=dut_data[6]; @(posedge data_en); send_data=dut_data[7]; @(posedge data_en); send_data=1; #100; end endtask //調用方法:i_data(8'hXX); /*---------------------------------------------------------------- 特殊激勵信號產生描述二:多輸入信號任務封裝 ----------------------------------------------------------------*/ task more_input; input [7:0] a; input [7:0] b; input [31:0] times; output [8:0] c; begin repeat(times) //等待 times 個時鐘上升沿 @(posedge clk_i) c=a+b; //時鐘上升沿 a,b 相加 end endtask //調用方法:more_input(x,y,t,z);?//按聲明順序 /*---------------------------------------------------------------- 特殊激勵信號產生描述三:輸入信號產生,一次 SRAM 寫信號產生 ----------------------------------------------------------------*/ initial begin cs_n=1; //片選無效 wr_n=1; //寫使能無效 rd_n=1; //讀使能無效 addr=8'hxx; //地址無效 data=8'hzz; //數據無效 #100; cs_n=0; //片選有效 wr_n=0; //寫使能有效 addr=8'hF1; //寫入地址 data=8'h2C; //寫入數據 #100; cs_n=1; wr_n=1; #10; addr=8'hxx; data=8'hzz; end /*---------------------------------------------------------------- 特殊激勵信號產生描述四:@與 wait ----------------------------------------------------------------*/ //@使用沿觸發 //wait 語句都是使用電平觸發 initial begin start=1'b1; wait(en=1'b1); #10; start=1'b0; end
?
6.仿真控制語句及系統任務描述
?
/*---------------------------------------------------------------- 仿真控制語句及系統任務描述 ----------------------------------------------------------------*/ $stop // 停止運行仿真,modelsim 中可繼續仿真 $stop(n) //帶參數系統任務,根據參數 0,1或2不同,輸出仿真信息 $finish //結束運行仿真,不可繼續仿真 $finish(n) //帶參數系統任務,根據參數 0,1或2不同,輸出仿真信息 //0:不輸出任何信息 //1:輸出當前仿真時刻和位置 //2:輸出當前仿真時刻、位置和仿真過程中用到的 memory 以及 CPU 時間的統計 $random //產生隨機數 $random % n //產生范圍-n 到 n 之間的隨機數 {$random} % n //產生范圍 0 到 n 之間的隨機數 /*----------------------------------------------------------------7. 仿真終端顯示描述
/*---------------------------------------------------------------- 仿真終端顯示描述 ----------------------------------------------------------------*/ $monitor //仿真打印輸出, 打印出仿真過程中的變量,使其終端顯示 /*$monitor($time,,,"clk=%d reset=%d out=%d",clk,reset,out);*/ $display //終端打印字符串,顯示仿真結果等 /* $display(” Simulation start ! "); $display(” At time %t,input is %b%b%b,output is %b",$time,a,b,en,z); */ $time //返回 64 位整型時間 $stime //返回 32 位整型時間 $realtime //實行實型模擬時間8. 文本輸入方式
/*---------------------------------------------------------------- 文本輸入方式:$readmemb/$readmemh ----------------------------------------------------------------*/ //verilog 提供了讀入文本的系統函數 $readmemb/$readmemh("<數據文件名>",<存儲器名>); $readmemb/$readmemh("<數據文件名>",<存儲器名>,<起始地址>); $readmemb/$readmemh("<數據文件名>",<存儲器名>,<起始地址>,<結束地址>); $readmemb:/*讀取二進制數據,讀取文件內容只能包含:空白位置,注釋行,二進制數 數據中不能包含位寬說明和格式說明,每個數字必須是二進制數字。*/ $readmemh:/*讀取十六進制數據,讀取文件內容只能包含:空白位置,注釋行,十六進制數 數據中不能包含位寬說明和格式說明,每個數字必須是十六進制數字。*/
?
審核編輯:黃飛
評論
查看更多