1. 程式人生 > >阻塞非阻塞

阻塞非阻塞

阻塞和非阻塞

阻塞: =
可用在assign語句和always語句中,
表示只要源訊號發生變化,目標訊號就立刻完成賦值操作,
在always塊中,結果與語句順序有關,
在always塊中是順序關係
非阻塞:         <=
只能用在always語句中,
表示該語句結束時完成賦值操作,
結果與語句順序無關,
並行關係

可以這樣理解:阻塞賦值,程序會阻塞在某條語句,而非阻塞賦值,程序不會阻塞在某條語句。
例如: r_data_out_0 = data_in;
r_data_out_1 = r_data_out_0;
程序阻塞在語句1,完成語句1後再進行語句2的賦值,調換語句1和語句2會改變結果,可以看成是順序關係。
語句1和語句2順序交換後綜合結果與非阻塞結果相同。

r_data_out_0 <= data_in;
r_data_out_1 <= r_data_out_0;
程序不會阻塞在語句1,在進行語句1的同時也在進行語句2,調換語句1和語句2不會改變結果,可以看成是並行關係。
語句2中的r_data_out_0其實是語句1賦值前的r_data_out_0的值。

也可以這樣理解:阻塞和非阻塞關注的是程式在等待呼叫結果(訊息,返回值)時的狀態.
   阻塞呼叫是指呼叫結果返回之前,當前執行緒會被掛起。呼叫執行緒只有在得到結果之後才會返回。
   非阻塞呼叫指在不能立刻得到結果之前,該呼叫不會阻塞當前執行緒。

在always塊中需要討論的各種情況:
1、 賦值左側變數各不相同,且左側變數不在右側出現。
r_data_out_0 <= data_in_0; r_data_out_0 = data_in_0;
r_data_out_1 <= data_in_1; r_data_out_1 = data_in_1;
這種情況,阻塞、非阻塞模擬結果、綜合結果均相同。

2、賦值左側變數相同,但左側變數不出現在右側。
r_data_out <= data_in_0; r_data_out = data_in_0;
r_data_out <= data_in_1; r_data_out = data_in_1;
這種情況,非阻塞第一條語句綜合時會被優化掉,模擬時第一條語句也被覆蓋掉。
阻塞的第二條語句會覆蓋第一條語句,綜合時第一條語句被優化掉。當然,模擬時第一條語句也被覆蓋掉。
總之,阻塞和非阻塞模擬結果、綜合結果均相同。不管是模擬還是綜合,第一條語句都不會起作用,完全可以刪掉。
需要注意的是,若兩條語句出現在不同always塊中,綜合時會出錯。所以這種情況完全不應該出現,出現了也沒意義。

3、賦值左側變數不相同,但左側變量出現在右側。
r_data_out_0 <= data_in;     r_data_out_0 = data_in; r_data_out_1 = r_data_out_0;
r_data_out_1 <= r_data_out_0;    r_data_out_1 = r_data_out_0; r_data_out_0 = data_in;
這種情況,在時序電路中:
非阻塞在語句1未賦完值前就執行語句2,因而語句2賦到的值是上一clk週期的r_data_out_0值。
阻塞在語句1賦完值後就執行語句2。
非阻塞和阻塞1模擬結果、綜合結果均不相同。非阻塞是兩級D觸發器,阻塞1是兩個一級D觸發器。
注意阻塞情況下,順序不同結果也不同,非阻塞和阻塞2模擬結果、綜合結果均一樣。
在組合電路中:
阻塞、非阻塞模擬結果、綜合結果均一樣。因為就算是非阻塞,語句2被賦予了r_data_out_0賦予data_in值之前的值,
但一旦r_data_out_0被賦予了data_in的值,r_data_out_1就會被賦予r_data_out_0賦予data_in值之後的值。
特別注意,阻塞2綜合結果同阻塞1、非阻塞一樣,但模擬結果不一樣。

4、賦值左側變數相同,且出現在右側。
r_data_out <= r_data_out + 2'b10; r_data_out = r_data_out + 1'b1;
r_data_out <= r_data_out + 1'b1; r_data_out = r_data_out + 1'b1;
這種情況,非阻塞第一條語句會被優化掉,只執行第二條語句。
 阻塞執行完第一條語句執行第二條語句。
總結:
1、一般在時序電路中使用非阻塞賦值,在組合電路中採用阻塞賦值。
2、對於非阻塞賦值,不要多條語句賦值給同一變數。