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

IEEE Verilog阻塞賦值和非阻塞賦值的區(qū)別

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

評論