深入分析 verilog 阻塞和非阻塞賦值
越是看似簡單、經常接觸的。我們越是不知其所以然。這就是我寫本文的原因。
阻塞和非阻塞賦值一般使用在程序中,包括always和initial程序、assign賦值等操作中。
在Verilog HDL中,描述程序的基本語句是always和initial。always過程反覆執行其中的塊語句,而initial過程語句只執行一次。此外,一個assign賦值語句,一個例項元件的呼叫也都是一個獨立的程序。
程序只有兩種狀態,即執行狀態和等待狀態,一旦滿足特定的條件,如敏感變數傳送變化,程序即進入執行狀態,執行完畢或遇到停止語句後,即停止執行,自動返回到起始語句,進入等待狀態。
在進行數字系統設計的時候,應該注意以下幾點:
將硬體電路的行為以合理的方式對映為一些程序,對每個程序,以最合理的方式描述並實現。
將組合邏輯實現的電路和用時序邏輯實現的電路儘量分配到不同的程序中。
程序中輸出的訊號在各種可能的情況下都應該被賦值,且賦值號右端不再出現該訊號。
多個程序之間通過訊號線進行通訊,在設計中,為了達到多個程序協調執行,可以設定一些握手訊號,在程序中檢測這些握手訊號的狀態,以決定是否進行必要的操作。在有的設計中,這種握手訊號的協調是必不可少的。
一個程序中一般只描述對應於一個時鐘訊號的同步時序邏輯。
程序必須由敏感訊號的變化來啟動,因此必須精心選擇程序敏感表示式中的敏感變數。
——
阻塞賦值與非阻塞賦值
always @(event-expression)
begin <LHS1=RHS1>
<LHS2=RHS2>
......
end
同樣可將採用非阻塞賦值方式的always程序塊寫成下面的形式:
always @(event-expression)
begin <LHS1<=RHS1>
<LHS2<=RHS2>
......
end
阻塞賦值“=”與非阻塞賦值“<=”的本質區別在於:非阻塞賦值語句右端表示式計算完後並不立即賦值給左端,而是同時啟動下一條語句繼續執行,我們 可以將其理解為所有的右端表示式RHS1、RHS2等在程序開始時同時計算,計算完後 ,等程序結束時同時分別賦給左端變數LHS1、LHS2等。
而阻塞賦值語句在每個右端表示式計算完後立即賦給左端變數,即賦值語句LHS1=RHS1執行完後LHS1是立即更新的,同時只有LHS1=RHS1執行 完後才可執行語句LHS1=RHS2,依次類推。前一條語句的執行結果直接影響到後面語句的執行結果。
非阻塞賦值不能用於“assign”持續賦值中。阻塞賦值則既能用於“assign”持續賦值,也能用於“initial”和“always”等過程塊 中,阻塞賦值則技能用於“assign”持續賦值,也嗯那個用於“initial”和“always”等過程賦值中。
對於時許邏輯描述和建模,應儘量使用非阻塞賦值方式。
——
用阻塞賦值方式描述了一個移位暫存器:
EX1:
module weise1(Q0,Q1,Q2,Q3,din,clk);
output Q0,Q1,Q2,Q3;
input clk,din;
reg Q0,Q1,Q2,Q3;
always @(posedge clk)
begin
Q3=Q2;
Q2=Q1;
Q1=Q0;
Q0=din;
end
endmodule
其RTL綜合結果:
——
——
將上面例子中的阻塞賦值語句保持不變,僅僅將其兩條語句的排列順序改一下的話,則綜合器綜合的結果就會大不同。
EX2:
module weise1(Q0,Q1,Q2,Q3,din,clk);
output Q0,Q1,Q2,Q3;
input clk,din;
reg Q0,Q1,Q2,Q3;
always @(posedge clk)
begin
Q3=Q2;
Q1=Q0;
Q2=Q1;
Q0=din;
end
endmodule
其RTL綜合結果:
——
將四條阻塞賦值語句的順序完全顛倒的話,則綜合器實際上等效成一個觸發器。
EX3:
module weise1(Q0,Q1,Q2,Q3,din,clk);
output Q0,Q1,Q2,Q3;
input clk,din;
reg Q0,Q1,Q2,Q3;
always @(posedge clk)
begin
Q0=din;
Q1=Q0;
Q2=Q1;
Q3=Q2;
end
endmodule
其RTL綜合結果:
——
而用非阻塞賦值方式描述的移位暫存器,無論將其“always”過程塊中四條賦值語句的順序怎麼變動,均不會影響其綜合幾個,其結果與第一個例子的結果相 同。對於時許邏輯描述和建模,應儘量使用非阻塞賦值方式。此外,若在同一個“always”過程塊中描述時許和組合邏輯混合電路時,也最好使用非阻塞賦值 方式。
——
非阻塞賦值不能用於“assign”持續賦值中,一般只出現在“initial”和“always”等過程塊中,對reg型變數進行賦值。像assign out<=a+b;這樣的語句是錯誤的。
當用“always”塊來描述組合邏輯時,既可以用阻塞賦值,也可以採用非阻塞賦值。但在同一個過程塊中,最好不要同時用阻塞賦值和非阻塞賦值,雖然同時使用這兩種賦值方式在綜合時並不一定會出錯。
在向函式(function)的返回值賦值時,應使用阻塞賦值“=”。
不能在一個以上的“always”過程塊中對同一個變數賦值,這樣會引起衝突,在綜合時會報錯。
在一個模組中,嚴禁對同一個變數既進行阻塞賦值,又進行非阻塞賦值,這樣在綜合時會報錯。
對時序邏輯描述和建模,應儘量使用非阻塞賦值方式,此外,若在同一個“always”過程塊中描述時序和組合邏輯混合電路時,也最好使用非阻塞賦值方式。
——