Verilog中阻塞與非阻塞語句


這幾天一直在糾結阻塞與非阻塞的問題,到現在基本弄清楚了。在糾結這個問題的時候,還順便弄清楚了前仿真與后仿真,Verilog的分層事件隊列,使用系統任務的一些原則等。這些問題以后再說,現在只談一下我對阻塞與非阻塞的理解。

概念這東西,還是引用教材中的比較好。

    關於阻塞:計算RHS並更新LHS,此時不能允許有來自任何其他Verilog語句的干擾。 所謂阻塞的概念是指在同一個always塊中,其后面的賦值語句從概念上(即使不設定延遲)是在前一句賦值語句結束后再開始賦值的。

這段代碼實現的功能就是,在clk上升沿到來的時候,把a的值賦給b,再把b的值賦給c,並顯示ab的值。當條件符合時,執行上述操作。在把a的值賦給b的這個過程中,其他的語句都“被阻塞”,被迫停下來,結束之后,進入下一句,直到執行完begin---end中語句。所以相當於把a的值通過b傳遞給c

這里所有的測試文件用的都是這一個testbench 

仿真結果:

綜合之后只有一級寄存器。相當於把a的值直接傳遞給c。而b只是中間變量而已,並沒有實際意義。

如果把上述代碼中的兩個賦值語句相互交換,如下所示,結果就不同了

在第一個clk上升沿到來時,由於b的值未知,賦給c之后,c也為未知值;緊接着,把a的值給b,由於a的值已經給出,所以,結束之后,ab的值相同,cx

綜合之后,生成兩級移位寄存器。

 

 

    關於非阻塞:

1) 在賦值時刻開始時,計算非阻塞賦值RHS表達式。

2) 在賦值時刻結束時,更新非阻塞賦值LHS表達式。

    這段代碼在posedge clk到來時,計算所有的RHSRight Hand Side)的值,此時,a的值為3b的值為x,這是同時進行的,沒有先后順序;然后更新LHSleft Hand Side)的值,結束之后,b的值變為3c的值為前一時刻b的值,即x。如波形圖所示:

綜合之后生成兩級移位寄存器:

如果把上述代碼中的兩個賦值語句相互交換,如下所示,結果和上面是一樣的。所以在一個begin---end中的非阻塞語句並不會因為放置的位置不同,出現不同的結果。

關於非阻塞的例子,分析的貌似蠻有道理,但是從腳本上卻看出了問題,第一個clk上升沿到來之后,a的值為3,而bc的值卻為x,就是說,並沒有執行操作,但是從波形圖看,確實在posedge clk的時候,把a的值傳遞給了b。到底怎么回事呢?直到看了一篇博文(http://blog.sina.com.cn/s/blog_58649eb30100biox.html),想起了Verilog的層次化事件隊列的概念。再一翻書,明白了。原來是系統任務用的不對,$display命令的執行是安排在活動時間隊列中,但排在非阻塞賦值數據更新事件之前。這就解釋了為什么b的值是3,顯示的卻是x。換成$strobe之后,和預想的就相當一致了。

這下就對了。用$strobe系統任務來顯示,應該用非阻塞賦值的變量值。

 

再了解一下Verilog的層次化事件隊列有助於理解阻塞與非阻塞。阻塞賦值、計算非阻塞賦值語句右邊的表達式、連續賦值、執行$display命令都放在動態事件隊列中。而非阻塞賦值語LHS的更新卻不放在這里,排在其他隊列中的事件要被排入動態事件隊列中后,才能等待執行。所以,排在動態事件隊列中的事件優先級最高。

$strobe顯示命令是排列在監控事件隊列中,在仿真結束的時候,所有的值都賦完之后,$strobe才會顯示出要求顯示的變量的值。解釋了應該用$srobe來顯示非阻塞賦值的結果。

 

最后還剩下到現在都沒想明白的兩個問題:

單從代碼中可以看出,當posedge clk到來時,發生了兩次移位,至於哪次在前哪次在后並不能確定,順序是隨機的。唯一可以確定的就是:確實發生了兩次移位。從仿真結果來看,當條件滿足時,先執行的是b = a,接着是c = b,和阻塞賦值的第一種情況一樣。

但是卻綜合出來了一個兩級移位寄存器的RTL級視圖:

把兩條語句交換后如下:

仿真結果應該和上面是一樣的才對,但很明顯不一樣,結果顯示,第一次posedge clk結束時b的值為3c的值為x,合理的解釋是:clk上升沿到來,先執行的是c = b,然后才是b = a。而這種結果也應該是不確定的,但做了多次之后,每次結果都是這樣。

綜合后出現的RTL級視圖和上面是一樣的。

 

這兩個例子綜合后出現的兩級移位寄存器說明,在每個clk上升沿,確確實實有兩次移位,並且這兩次移位是順序進行的,所以出現了兩個寄存器,而移位的先后順序卻不同,所以仿真的結果也就不同。但是既然仿真結果不一樣,也不確定,怎么會出現相同的RTL級視圖呢?怎么會綜合出正確的結果呢?

好吧,只好用教材上的兩段句來解釋這個問題(雖然我還是看不太明白):

阻塞賦值分別被放在不同的always塊里。仿真時,這些塊的先后順序是隨機的,因此可能出現錯誤的結果。這是Verilog中的競爭冒險,按不同的順序執行這些塊將導致不同的結果。但是,這些代碼的綜合結果卻是正確的流水線寄存器。也就是說,前仿真和后仿真的結果可能會不一致。

always塊的順序稍作變動,也可以被綜合成正確的移位寄存器邏輯,但仿真結果可能不正確。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM