本文詳細闡述了在一個testbench中,應該如何使用阻塞賦值與非阻塞賦值。首先說結論,建議在testbench中,對時鐘信號(包括分頻時鐘)使用阻塞賦值,對其他同步信號使用非阻塞賦值。
下面是一個簡單的D觸發(fā)器模塊,本文將針對它的testbench進行討論。
moduleDff(inputclk, rst_n, data_in,outputregdata_out); always@(posedgeclk,negedgerst_n)begin if(!rst_n) data_out <=?1'b0; ? ? ? ?else? ? ? ? ? ? ?data_out <= data_in; ? ?endendmodule
在Verilog仿真時,仿真波形與真實波形是有一定差距的,這體現(xiàn)在同步信號的改變與時鐘沿一直是對齊的,而真實情況下,數(shù)據(jù)信號在時鐘沿后需要延遲一段時間才會發(fā)生改變。
體現(xiàn)在上面的模塊中就是數(shù)據(jù)信號data_in的改變是與時鐘信號clk同步的,data_out的改變也是與時鐘信號clk同步的。
圖1展示了一個簡單的仿真波形,其中信號data_in和信號data_out的改變都與時鐘沿同步,需要注意的是在時鐘沿處,信號data_out得到的是信號data_in在時鐘沿處的原值,而不是改變后的值。
圖1 仿真波形
也就是說,一個更加真實的波形可能如圖2所示。
圖2 真實波形
下面給出圖1所示波形的testbench。
moduleDff_t; regrst_n =1; regclk =0; regdata_in =0; wiredata_out; Dff dff(.clk(clk),.rst_n(rst_n),.data_in(data_in),.data_out(data_out)); //時鐘產生 alwaysbegin #10clk = ~clk; end //異步復位信號 initialbegin #3rst_n =0; #3rst_n =1; end //同步數(shù)據(jù)輸入 initialbegin #10data_in <=?1; ? ? ? ? #20?data_in <=?0; ? ? ? ? #20?data_in <=?1; ? ? ? ? #20?data_in <=?0; ? ?end? ? ?endmodule
其中時鐘信號和異步復位信號使用了阻塞賦值,而數(shù)據(jù)信號使用了非阻塞賦值。如果不是這樣,就無法保證產生如圖1所示的仿真波形,下面將分別討論。
1、如時鐘信號使用非阻塞賦值,數(shù)據(jù)信號也使用非阻塞賦值
moduleDff_t; regrst_n =1; regclk =0; regdata_in =0; wiredata_out; Dff dff(.clk(clk),.rst_n(rst_n),.data_in(data_in),.data_out(data_out)); //時鐘產生 alwaysbegin #10clk <= ~clk; ? ?end? ? ??//異步復位信號? ? ?initial?begin? ? ? ? ?#3?rst_n =?0; ? ? ? ? #3?rst_n =?1; ? ?end? ? ??//同步數(shù)據(jù)輸入? ? ?initial?begin? ? ? ? ?#10?data_in <=?1; ? ? ? ? #20?data_in <=?0; ? ? ? ? #20?data_in <=?1; ? ? ? ? #20?data_in <=?0; ? ?end? ? ?endmodule
圖3 錯誤的波形(一種可能)
此時進行仿真,可能會出現(xiàn)圖3所示的錯誤波形,信號data_out得到的是信號data_in在時鐘沿處改變后的值。
拿第一個時鐘上升沿即10ns時舉例,此時時鐘信號clk被非阻塞賦值,同時data_in被非阻塞賦值。首先說明非阻塞賦值的過程,非阻塞賦值是分兩步進行的,第一步是將賦值號<=右表達式求值,在當前仿真時間的所有賦值和非阻塞賦值右表達式求值(活躍事件)完成后,再進行第二步,即非阻塞賦值的賦值(非阻塞賦值的賦值順序由求值順序決定),即非阻塞賦值分為兩步:求值與賦值,后文僅使用“賦值”一詞代表非阻塞賦值中的賦值這個步驟,注意其與阻塞賦值的區(qū)別。
由于initial結構和always結構是并行的,因此無法確定哪一個非阻塞賦值的右表達式求值是先進行的,但可以確定的是,信號clk的賦值和信號data_in的賦值以某種先后順序被調度到之后(非阻塞賦值更新區(qū))執(zhí)行。當進行第二步時,clk的賦值和data_in的賦值都從非阻塞賦值更新區(qū)激活到活躍事件區(qū)執(zhí)行,此時有多種執(zhí)行方式:
1、如果clk的賦值先執(zhí)行(即之前clk非阻塞賦值右表達式先求值),則其又觸發(fā)了@(posedge clk),接著是執(zhí)行data_out非阻塞賦值右表達式求值,還是執(zhí)行data_in的賦值,是不確定的,它們都是活躍事件。如果先執(zhí)行data_out非阻塞賦值右表達式求值,則data_out得到的是data_in的舊值即0;如果先執(zhí)行data_in的賦值,則data_out得到的是data_in的新值即1(圖3可能就是這種情況)。
2、如果data_in的賦值先執(zhí)行(即之前data_in非阻塞賦值右表達式先求值),則最后data_out得到的一定是data_in的新值即1(圖3可能就是這種情況)。
2、如時鐘信號使用阻塞賦值,數(shù)據(jù)信號也使用阻塞賦值
moduleDff_t; regrst_n =1; regclk =0; regdata_in =0; wiredata_out; Dff dff(.clk(clk),.rst_n(rst_n),.data_in(data_in),.data_out(data_out)); //時鐘產生 alwaysbegin #10clk = ~clk; end //異步復位信號 initialbegin #3rst_n =0; #3rst_n =1; end //同步數(shù)據(jù)輸入 initialbegin #10data_in =1; #20data_in =0; #20data_in =1; #20data_in =0; end endmodule
圖4 錯誤的波形(一種可能)
此時進行仿真,可能會出現(xiàn)圖4所示的錯誤波形,信號data_out得到的是信號data_in在時鐘沿處改變后的值。
拿第一個時鐘上升沿即10ns時舉例,此時時鐘信號clk被阻塞賦值,同時data_in被阻塞賦值。由于initial結構和always結構是并行的,因此無法確定哪一個阻塞賦值是先進行的,此時有多種執(zhí)行方式。
1、如果clk的阻塞賦值先進行,則其又觸發(fā)了@(posedge clk),接著是執(zhí)行data_out非阻塞賦值右表達式求值,還是執(zhí)行data_in的阻塞賦值,是不確定的,它們都是活躍事件。如果先執(zhí)data_out非阻塞賦值右表達式求值,則data_out首先得到的是data_in的舊值即0;如果先執(zhí)行data_in的阻塞賦值,則則data_out得到的是data_in的新值即1(圖4可能就是這種情況)。
2、如果data_in的阻塞賦值先進行則最后data_out得到的一定是data_in的新值即1(圖4可能就是這種情況)。
3、如時鐘信號使用非阻塞賦值,數(shù)據(jù)信號使用阻塞賦值
moduleDff_t; regrst_n =1; regclk =0; regdata_in =0; wiredata_out; Dff dff(.clk(clk),.rst_n(rst_n),.data_in(data_in),.data_out(data_out)); //時鐘產生 alwaysbegin #10clk <= ~clk; ? ?end? ? ??//異步復位信號? ? ?initial?begin? ? ? ? ?#3?rst_n =?0; ? ? ? ? #3?rst_n =?1; ? ?end? ? ??//同步數(shù)據(jù)輸入? ? ?initial?begin? ? ? ? ?#10?data_in =?1; ? ? ? ? #20?data_in =?0; ? ? ? ? #20?data_in =?1; ? ? ? ? #20?data_in =?0; ? ?end? ? ?endmodule
圖5 錯誤的波形
此時進行仿真,一定會出現(xiàn)圖5所示的錯誤波形,信號data_out得到的是信號data_in在時鐘沿處改變后的值。
拿第一個時鐘上升沿即10ns時舉例,此時時鐘信號clk被非阻塞賦值,同時data_in被阻塞賦值。由于initial結構和always結構是并行的,因此無法確定是非阻塞賦值的右表達式求值先進行還是阻塞賦值先進行,但是阻塞賦值一定是在非阻塞賦值的賦值前進行的(根據(jù)非阻塞賦值的定義),所以不管有多少種執(zhí)行方式,此時只有一種結果。
1、data_out得到的一定是data_in的新值即1(圖5就是這種情況)。
4、時鐘信號使用阻塞賦值,數(shù)據(jù)信號使用非阻塞賦值
moduleDff_t; regrst_n =1; regclk =0; regdata_in =0; wiredata_out; Dff dff(.clk(clk),.rst_n(rst_n),.data_in(data_in),.data_out(data_out)); //時鐘產生 alwaysbegin #10clk = ~clk; end //異步復位信號 initialbegin #3rst_n =0; #3rst_n =1; end //同步數(shù)據(jù)輸入 initialbegin #10data_in <=?1; ? ? ? ? #20?data_in <=?0; ? ? ? ? #20?data_in <=?1; ? ? ? ? #20?data_in <=?0; ? ?end? ? ?endmodule
最后分析正確的testbench,拿第一個時鐘上升沿即10ns時舉例,此時時鐘信號clk被阻塞賦值,同時data_in被非阻塞賦值。由于initial結構和always結構是并行的,因此無法確定是非阻塞賦值的右表達式求值先進行還是阻塞賦值先進行。
1、如果clk的阻塞賦值先進行,則其又觸發(fā)了@(posedge clk),接著是執(zhí)行data_out非阻塞賦值右表達式求值,還是執(zhí)行data_in非阻塞賦值右表達式求值,是不確定的,它們都是活躍事件。但是可以肯定的是,data_out得到的一定是data_in的舊值,因為非阻塞賦值的賦值一定在所有非阻塞賦值的求值后進行(根據(jù)非阻塞賦值的定義)。
2、如果data_in非阻塞賦值右表達式求值先進行,則在之后clk阻塞賦值進行后,其又觸發(fā)了@(posedge clk),接著執(zhí)行data_out非阻塞賦值右表達式求值,但求值時是使用data_in的舊值,因為非阻塞賦值的賦值一定在所有非阻塞賦值的求值后進行(根據(jù)非阻塞賦值的定義)。
來源:https://blog.csdn.net/weixin_45791458/article/details/137046594
-
仿真
+關注
關注
51文章
4212瀏覽量
135055 -
Verilog
+關注
關注
28文章
1364瀏覽量
111460 -
阻塞賦值
+關注
關注
0文章
10瀏覽量
9214 -
非阻塞賦值
+關注
關注
0文章
11瀏覽量
10055
原文標題:在testbench中使用阻塞賦值和非阻塞賦值的區(qū)別
文章出處:【微信號:gh_9d70b445f494,微信公眾號:FPGA設計論壇】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
Verilog語言中阻塞和非阻塞賦值的不同
Verilog中阻塞賦值和非阻塞賦值的正確使用
【技巧分享】FPGA至簡設計-阻塞賦值與非阻塞賦值
verilog中阻塞賦值和非阻塞賦值到底有什么區(qū)別

VerilogHDL語言:清阻塞賦值和非阻塞賦值
簡述阻塞賦值和非阻塞賦值的可綜合性

評論