阻塞賦值與非阻塞賦值

賦值語句的實質:不是進行賦值,而是產生一個電路,要賦的值爲電路的輸出,被賦方爲電路的輸入。

if(!rst_n) cnt <= 0; else cnt <= cnt + 1;

 

在描述組合邏輯的 always 塊中用阻塞賦值,則綜合成組合邏輯的電路結構。
在描述時序邏輯的 always 塊中用非阻塞賦值,則綜合成時序邏輯的電路結構。

 

RHS – 賦值等號右邊的表達式或變量可分別縮寫爲: RHS 表達式或 RHS 變量。
LHS – 賦值等號左邊的表達式或變量可分別縮寫爲: LHS 表達式或 LHS 變量。

 

非阻塞賦值(<=):並行執行;塊結束後完成對變量的賦值,賦的值爲上次賦值得到的結果。

這是因爲在賦值操作時刻開始時計算非阻塞賦值符的 RHS 表達式,賦值操作結束時刻才更新LHS。在計算非阻塞賦值的 RHS 表達式和更新 LHS 期間,其他的 Verilog 語句,包括其他的 Verilog 非阻塞賦值語句都能同時計算 RHS 表達式和更新 LHS。非阻塞賦值允許其他的Verilog 語句同時進行操作。

非阻塞賦值的操作可以看作爲兩個步驟的過程:
1)在賦值開始時刻,計算非阻塞賦值 RHS 表達式。
2)在賦值結束時刻,更新非阻塞賦值 LHS 表達式。 

非阻塞賦值操作只能用於對寄存器類型變量進行賦值,因此只能用在"initial"塊和"always"塊等過程塊中。非阻塞賦值不允許用於連續賦值。

[例]. 用非阻塞賦值的反饋振盪器
module fbosc2 (y1, y2, clk, rst);
output y1, y2;
input clk, rst;
reg y1, y2;
always @(posedge clk or posedge rst)
if (rst) y1 <= 0; // 預置值
else y1 <= y2;
always @(posedge clk or posedge rst)
if (rst) y2 <= 1; // 預置值
else y2 <= y1;

endmodule
同樣,按照 IEEE Verilog 的標準,上例中兩個 always 塊是並行執行的,與前後次序無
關。復位信號回到 0 後,無論哪一個 always 塊的有效沿先到,兩個 always 塊中的非阻塞賦值都在賦值開始時刻計算 RHS 表達式,而在結束時刻才更新 LHS 表達式。所以復位信號從1 回到 0 後,無論哪個 always 塊的有效時鐘沿早到幾個皮秒, y1 爲 1 而 y2 爲 0 是確定的,因爲實質上 y1 被賦的 y2 值是由 rst 正跳變沿確定的,而 y2 被賦的 y1 值也是由 rst 正跳變沿確定的(若以後 rst 繼續保持爲 0,時鐘信號不斷重複,則每次被賦值的 y1 和 y2 都是由上一個週期的時鐘有效沿確定的)。從用戶的角度看這兩個非阻塞賦值好象是並行執行的。

 

阻塞賦值(=):順序執行;賦值立即生效;當所有語句執行完後,塊才結束。

阻塞賦值的執行可以認爲是隻有一個步驟的操作:計算 RHS 並更新 LHS,此時不能允許有來自任何其他 Verilog 語句的干擾。

所謂阻塞的概念是指在同一個 always 塊中,其後面的賦值語句從概念上(即使不設定延遲)是在前一句賦值語句結束後再開始賦值的。

如果在一個過程塊中阻塞賦值的 RHS 變量正好是另一個過程塊中阻塞賦值的 LHS 變量,這兩個過程塊又用同一個時鐘沿觸發,這時阻塞賦值操作會出現問題,即如果阻塞賦值的次序安排不好,就會出現競爭。若這兩個阻塞賦值操作用同一個時鐘沿觸發,則執行的次序是
無法確定的。下面的例子可以說明這個問題:

[例]. 用阻塞賦值的反饋振盪器
module fbosc1 (y1, y2, clk, rst);
output y1, y2;
input clk, rst;
reg y1, y2;
always @(posedge clk or posedge rst)
if (rst) y1 = 0;
else y1 = y2;
always @(posedge clk or posedge rst)
if (rst) y2 = 1;
else y2 = y1;
endmodule

按照 IEEE Verilog 的標準,上例中兩個 always 塊是並行執行的,與前後次序無關。若
復位信號已從 1 到回 0,且上面的 always 塊的有效時鐘沿比下面的 always 塊的時鐘沿早幾個皮秒(由時鐘偏差造成)到達,則 y1 和 y2 都會取 1,而若下面的那個 always 塊的有效時鐘沿早幾個皮秒到達,則 y1 和 y2 都會取 0。這清楚地說明這個 Verilog 模塊是不穩定的,會產生冒險和競爭的情況。

 

阻塞非阻塞語句的編程要點

1) 時序電路建模時,用非阻塞賦值。
2) 鎖存器電路建模時,用非阻塞賦值。
3) 用 always 塊建立組合邏輯模型時,用阻塞賦值。
4) 在同一個 always 塊中建立時序和組合邏輯電路時,用非阻塞賦值。
5) 在同一個 always 塊中不要既用非阻塞賦值又用阻塞賦值。
6) 不要在一個以上的 always 塊中爲同一個變量賦值。
7) 用$strobe 系統任務來顯示用非阻塞賦值的變量值。
8) 在賦值時不要使用 #0 延遲。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章