FPGA系統設計的仿真驗證之: 仿真測試文件(Testbench)的設計方法
7.5仿真測試文件(Testbench)的設計方法
7.5.1測試文件的用途
隨著(zhù)設計量和復雜度的不斷增加,數字設計驗證變得越來(lái)越難,所消耗的成本也越來(lái)越高。面對這種挑戰,驗證工程師必須依靠相應的驗證工具和方法才行。對于大型的設計,比如上百萬(wàn)門(mén)的設計驗證,工程師必須使用一整套規范的驗證工具;而對于較小的設計,使用具有HDLtestbench的仿真器是一個(gè)不錯的選擇。
Testbench已經(jīng)成為了HLL(High-Level-Language,高級語(yǔ)言)設計標準驗證方法。一般來(lái)說(shuō),它能夠完成下面一些任務(wù)。
·實(shí)例化DUT(DesignUnderTest,被測設計)。
·通過(guò)為模塊添加測試向量對DUT進(jìn)行仿真。
·通過(guò)終端或波形窗口提供仿真結果。
·比較實(shí)際輸出與期望輸出的差異。
一般來(lái)說(shuō),Testbench使用工業(yè)標準VHDL或者VerilogHDL語(yǔ)言來(lái)描述。簡(jiǎn)單的Testbench通過(guò)調用用戶(hù)設計的功能模塊,然后進(jìn)行仿真。較為復雜的Testbench還包括一些其他的功能,比如包含特定的激勵向量或者進(jìn)行實(shí)際輸出與期望輸出的比較等。
如圖7.32所示是一個(gè)標準的HDL驗證流程,圖中表達了上述的Testbench功能。
圖7.32HDLTestbench仿真流程
由于Testbench是使用VHDL或者VerilogHDL編寫(xiě)的,因此Testbench的驗證流程是跨平臺的。同時(shí)由于這兩種語(yǔ)言是標準的非私有語(yǔ)言,所以使用它們進(jìn)行驗證的流程可以在未來(lái)的設計中繼續使用。
下面講解Testbench的設計方法。
7.5.2測試文件設計方法
由于測試文件只是在仿真時(shí)使用,因此在綜合中對RTL語(yǔ)言的語(yǔ)法限制在測試文件中并不存在。相反地,測試文件可以編寫(xiě)得更加通俗,所有的行為結構語(yǔ)法都可以使用,使之更加容易理解。所有的測試文件都包含了如表7.1所示的結構。
表7.1 測試文件的共同結構
VHDL | VerilogHDL |
實(shí)體和結構聲明(Entity,Architecture) | 模塊聲明(Module) |
信號聲明(Signal) | 信號生命(Signal) |
頂層模塊實(shí)例化 | 頂層模塊實(shí)例化 |
激勵向量 | 激勵向量 |
正如所述,測試文件除了包含這些共有的結構意外,還完成一些額外的工作。例如顯示結果、嵌入的誤碼檢測等。下面通過(guò)一些例子來(lái)展現測試文件中常用的結構。
1.產(chǎn)生測試時(shí)鐘
仿真必須產(chǎn)生時(shí)鐘才能進(jìn)行,只有在推進(jìn)的仿真時(shí)鐘中才可以判定輸出的結果是否符合設計的要求。交互時(shí)鐘是硬件設計語(yǔ)言里面最容易實(shí)現的時(shí)鐘,下面通過(guò)Verilog語(yǔ)言的例子來(lái)說(shuō)明如何生成測試時(shí)鐘。
Parameter ClockPeriod = 10; // 聲明時(shí)鐘周期常量
//時(shí)鐘生成方法1:
initial begin
forever Clock = #(ClockPeriod / 2) ~ Clock;
end
//時(shí)鐘生成方法2:
initial begin
always #(ClockPeriod / 2) Clock = ~Clock;
end
在兩種實(shí)現方法中,都是用了initial塊語(yǔ)句。在方法1中,使用了forever語(yǔ)句,是最常用的產(chǎn)生時(shí)鐘的方法。在方法2中,使用過(guò)了always語(yǔ)句,同樣也實(shí)現了時(shí)鐘的生成。兩種方法都產(chǎn)生了周期為10的時(shí)鐘波形。
2.提供激勵源
為了得到Testbench的驗證結果,必須為DUT提供激勵向量。并行激勵模塊常常被用來(lái)為測試文件提供必要的激勵。有兩種不同的方法來(lái)實(shí)現并行的激勵:一種是絕對時(shí)間激勵,另一種是相對時(shí)間激勵。
在絕對時(shí)間激勵中,所有的仿真時(shí)間值都是相對仿真時(shí)間零點(diǎn)定義的。而在相對時(shí)間激勵中,一般會(huì )提供初始化值,然后等待事件來(lái)觸發(fā)激勵向量。兩種方法都可以根據設計者的需要在同一個(gè)測試文件中使用。
下面分別是兩種方法產(chǎn)生激勵的例子。
(1)絕對時(shí)間。
initialbegin
Reset=1;//仿真時(shí)間零點(diǎn)激勵
Load=0;//仿真時(shí)間零點(diǎn)激勵
Count_UpDn=0;//仿真時(shí)間零點(diǎn)激勵
#100Reset=0;//絕對時(shí)間100激勵
#20Load=1;//絕對時(shí)間120激勵,相對上一個(gè)時(shí)間點(diǎn)20
#20Count_UpDn=1;//絕對時(shí)間140激勵,相對上一個(gè)時(shí)間點(diǎn)20
end
(2)相對時(shí)間。
always@(posedgeclock)
TB_Count=TB_Count+1;//絕對時(shí)間的遞增
initialbegin
if(TB_Count=5)begin//觸發(fā)事件,產(chǎn)生下列激勵
Reset=1;
Load=0;
Count_UpDn=0;
end
elsebegin//觸發(fā)事件,產(chǎn)生下列激勵
Reset=0;
Load=1;
Count_UpDn=1;
end
end
initialbegin
if(Count==1100)begin//觸發(fā)事件,產(chǎn)生歸零激勵,并顯示結果
Count_UpDn=0;
$display(TerminalCountReached,nowcountingdown.);
end
end
值得注意的是,VerilogHDL語(yǔ)言的initial模塊之間是并行執行的,但是initial模塊內部是順序執行的。也就是說(shuō),測試文件的激勵順序在仿真時(shí)間零點(diǎn)同時(shí)啟動(dòng)并行模塊,然后根據各個(gè)模塊的內部激勵順序產(chǎn)生激勵向量。
3.結果輸出
測試文件通過(guò)關(guān)鍵詞$display和$monitor來(lái)實(shí)現結果的輸出。下面是使用VerilogHDL語(yǔ)言實(shí)現在終端上顯示結果的例子:
//在終端中打印信號的ASCII值
initialbegin
$timeformat(-9,1,ns,12);//設置輸出時(shí)鐘格式
$display(TimeClkRstLdSftRgDataSel);//顯示輸入的字符串
$monitor(%t%b%b%b%b%b%b,//設置輸出信號的格式
$realtime,clock,reset,load,shiftreg,data,sel);//指定輸出的信號
end
$display是將函數內部雙引號中的字符串輸出在終端中。而$monitor則不同,因此它的輸出是事件驅動(dòng)的。在例子中,$monitor信號列表中的$realtime信號變化會(huì )觸發(fā)終端顯示事件的發(fā)生,該信號被設計者對應到仿真時(shí)間中,每次$monitor的觸發(fā)將會(huì )把信號列表中的信號值顯示在終端中。
$monitor語(yǔ)句中的“%”用于定義信號列表中信號的輸出格式。例如,%t將信號按照時(shí)間格式輸出,%b將信號按照二進(jìn)制格式輸出。另外,VerilogHDL語(yǔ)言還提供了其他的輸出格式,比如%h為十六進(jìn)制輸出,%d為十進(jìn)制輸出,%o為八進(jìn)制輸出等。更為詳細的格式輸出定義可以參看Verilog參考手冊。
7.5.3測試常用語(yǔ)句
常用的Verilog測試用結構語(yǔ)句,比如$monitor、$display和$time在上面已經(jīng)介紹過(guò)了。下面再來(lái)介紹一些其他的常用語(yǔ)句。
1.force/release
force和release語(yǔ)句可以用來(lái)強制對執行過(guò)程中的寄存器或網(wǎng)絡(luò )型信號量賦值。這兩條語(yǔ)句共同完成一個(gè)強制賦值的過(guò)程。當一個(gè)被force的信號被release以后,這個(gè)信號將會(huì )保持當時(shí)的狀態(tài)直到下一個(gè)賦值語(yǔ)句產(chǎn)生為止。
下面舉個(gè)例子來(lái)說(shuō)明這兩條語(yǔ)句的使用。
moduletestbench;
...
initialbegin
reset=1;//在仿真時(shí)間零點(diǎn)將reset激勵為1
forceDataOut=101;//在仿真時(shí)間零點(diǎn)強制使DataOut為101,并保持
#25reset=0;//在仿真絕對時(shí)間25將reset激勵為0
#25releaseDataOut;//在仿真絕對時(shí)間50釋放
//DataOut值將保持直至下一個(gè)對它的賦值語(yǔ)句
...
end
endmodule
2.a(chǎn)ssign/deassign
assign/deassign語(yǔ)句與force/release語(yǔ)句相類(lèi)似,不過(guò)assign/deassign語(yǔ)句只能對設計中的寄存器型信號賦值。它們常常被用來(lái)設置輸入值。
下面是這兩個(gè)語(yǔ)句的例子。
moduletestbench;
...
initialbegin
reset=1;//絕對時(shí)間零點(diǎn)對reset賦值1
DataOut=101;
#25reset=0;//絕對時(shí)間25對reset賦值0
releaseDataOut;
...
end
initialbegin
#20assignreset=1;//此條語(yǔ)句覆蓋之前的賦值語(yǔ)句(即絕對時(shí)間零點(diǎn)的賦值)
#25reset=0;//絕對時(shí)間45對reset賦值0
#50releasereset;//絕對時(shí)間95釋放reset信號
endmodule
3.timescales
timescale語(yǔ)句用于定義測試文件的單位時(shí)間,同時(shí)也對仿真的精度有影響。它的語(yǔ)法定義如下:
‘timescalereference_time/precision
其中,reference_time是單位時(shí)間的度量,precision決定了仿真的推進(jìn)延遲精度,同時(shí)也設置了仿真的推進(jìn)步進(jìn)單位。下面是timescale語(yǔ)句的使用范例:
‘timescale1ns/1ps//度量參考為1ns,精度為1ps
moduletestbench;
...
initialbegin
#5reset=1;//5個(gè)仿真時(shí)間延遲,相當于5×1ns=5ns的仿真時(shí)間
#10reset=0;
...
end
initialbegin
//display語(yǔ)句將在每一個(gè)仿真推進(jìn)步進(jìn)中執行,也就是1ps執行一次
$display(“%d,Reset=%b”,$time,reset);
end
endmodule
應該注意的是,如果仿真中使用了時(shí)間延遲值,那么仿真的精度應大于最小的延遲值。例如仿真中使用了9ps的仿真時(shí)間延遲,那么仿真的推進(jìn)步進(jìn)精度必須為1ps來(lái)保證9ps的延遲。
4.ReadingMemoryInitializationFiles
VerilogHDL提供了$readmemb和$readmemh命令來(lái)讀取ASCII文件,用于初始化memory的內容。這兩個(gè)語(yǔ)句可以用于初始化FPGA中由IPCore生成的存儲器宏模塊,例如RAM、ROM等。
下面是利用這個(gè)語(yǔ)句對Xilinx的實(shí)例(design_instance)進(jìn)行初始化的例子。
$readmemb(“design.mif>”,design_instance);
其中,mif文件是Xilinx的CoreGenerator建立的對存儲器進(jìn)行初始化的文件。用戶(hù)也可以自己編寫(xiě)這個(gè)文件的內容。
評論