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