1. 程式人生 > >阻塞(=)賦值和非阻塞(

阻塞(=)賦值和非阻塞(

  對於我這樣的初學者而言,首先要掌握可綜合風格的Verilog模組程式設計的8個原則,並且牢記,才能在綜合佈局佈線的模擬中避免出現競爭冒險現象。

  (1)  時序電路建模時,用非阻塞賦值。

  (2)  鎖存器電路建模時,用非阻塞賦值。

  (3)  用always塊建立組合邏輯模型時,用阻塞賦值。

  (4)  在同一個always塊中建立時序和組合邏輯電路時,用非阻塞賦值。

  (5)  在同一個always塊中不要既用非阻塞賦值又用阻塞賦值。

  (6)  不要在一個以上的always塊中為同一個變數賦值。

  (7)  用$strobe系統任務來顯示用非阻塞賦值的變數值。

  (8)  在賦值時不要使用 #0延時。

  這樣做的目的是為了使綜合前模擬綜合後模擬一致。在很多時候,用"="或者是"<="實際上對應的是不同的硬體電路,這點一定要十分清楚。

關鍵是組合邏輯中是實時變化的,而時序邏輯中一個cycle才變化一次
比如:
always @(a or b)
begin
    c = a + b;
end
always @(posedge clk)
begin
    if(rst)
      c <= 0;
   else
     c <= a + b;
end
在組合邏輯的always block中,a和b的變化都會引起c值的變化;
而時序邏輯中c至少會維持一個clock cycle,也就是說如果a和b的變化導致c變化的時間是在下一個clock的上升沿,而不會讓c立刻改變
--------------------------------------------------------------------------------------------------------------------
好,說正題
阻塞賦值“=”與非阻塞賦值“<=”的本質區別在於:
非阻塞賦值語句右端表示式計算完後並不立即賦值給左端,而是同時啟動下一條語句繼續執行,可以將其理解為所有的右端表示式RHS1、RHS2等在程序開始時同時計算,計算完後 ,等程序結束時同時分別賦給左端變數LHS1、LHS2等;
而阻塞賦值語句在每個右端表示式計算完後立即賦給左端變數,即賦值語句LHS1=RHS1執行完後LHS1是立即更新的,同時只有LHS1=RHS1執行完後才可執行語句LHS1=RHS2,依次類推。前一條語句的執行結果直接影響到後面語句的執行結果。

  阻塞賦值(=):

  我們先做下面定義:RHS—賦值等號右邊的表示式,LHS—賦值等號左邊的表示式。在序列語句塊中,阻塞賦值語句按照它們在塊中的排列順序依次執行,即前一條語句沒有完成賦值之前,後面的語句不可能被執行,換言之,後面的語句被阻塞了。阻塞賦值的執行可以認為只有一個步驟的操作,即計算RHS並更新LHS,此時不允許有來自任何其他Verilog語句的干擾。所謂阻塞的概念是指在同一個always塊中,其後面的賦值語句從概念上是在前一條賦值語句結束後開始賦值的。有句話我一直沒讀懂:從理論上講,它與後面的賦值語句只有概念上的先後,而無實質上的延時。

  例如:

  begin

    B = A;

    C = B + 1;

  end

  首先第一條語句執行,將A的值賦給B,接著執行第二條語句,將B+1(即A加1),並賦給C。也就是說C = A + 1。

  非阻塞賦值(<=):

  非阻塞語句的執行過程是:首先計算語句塊內部所有右邊表示式(RHS)的值,然後完成對左邊暫存器變數的賦值操作,例如,下面兩條非阻塞賦值語句的執行過程是:先計算右邊表示式的值並暫存在一個暫存器中,A的值被儲存在一個暫存器中,而B+1的值被儲存在另一個暫存器中,在begin和end之間所有語句的右邊表示式都被計算並存儲完後,對左邊的暫存器變數的賦值才會進行。這樣C得到的是B的原始值而不是A加一。

  begin

    B <= A;

    C <= B +1;

  end

  如果我們想讓兩個最基本的D觸發器串聯,我們用阻塞和非阻塞賦值看看結果有什麼不同

  阻塞和非阻塞的不同造成了電路上巨大的不同,因此他們的差別應該牢記。

  我們在從模擬(Simulation)的角度去看一下,在輸出結果上有造成什麼樣的不同,我們有同樣的的testbench。

程式碼 1 `timescale 1 ps/1 ps
2 module blocking_vlg_tst();
3 4 reg clk;
5 reg iD;
6 // wires 7 wire oQA;
8 wire oQB;
9 10 // assign statements (if any) 11 blocking i1 (
12 // port map - connection between master ports and signals/registers 13 .clk(clk),
14 .iD(iD),
15 .oQA(oQA),
16 .oQB(oQB)
17 );
18 initial19 begin20 clk =1'b0;21 iD =1'b0;22 end23 24 always #10 clk = (~clk);
25 26 always27 begin28 #8 iD = (~iD);
29 end30 endmodule31

  模擬波形如下:

  可以看到,在阻塞賦值的情況下當時鐘上升沿來的時候讀取輸入iD的值,並且輸出oQA和oQB的值應該是一樣的,從波形中我們可以看出輸出oQA和oQB的波形是完全一樣的。

  在非阻塞賦值的情況下,它是先計算 iD 和 oQA的值,開始 iD的值為1, oQA的值是不定的,所以oQA被賦為1, 而oQB還是被賦為不定值,兩者的波形不一致。

  阻塞和非阻塞的學習隨著以後的深入還得深刻理解,在用時要遵循規則,避免麻煩。

原文地址:http://www.eefocus.com/weidk/blog/2012-04/214655_54407.html