[文檔].艾米電子 – 阻塞賦值與非阻塞賦值,Verilog

來源:互聯網
上載者:User
文章目錄
  • 阻塞賦值VS非阻塞賦值
說明

翻譯自:FPGA Prototyping By Verilog Examples: Xilinx Spartan-3 Version的第7章第一節

 

內容阻塞賦值VS非阻塞賦值

有兩種指派陳述式被用在always塊內:阻塞賦值與非阻塞賦值。關於阻塞與非阻塞複製有3條簡單的準則:

  • 將電路分為兩部分:寄存器電路和組合電路
  • 在寄存器電路中使用非阻塞賦值
  • 在組合電路中使用阻塞賦值

 

1 概覽

阻塞賦值 基本文法如下:

[var] = [expression];

當該條語句被執行時,右手邊的運算式將被賦給左手邊的變數,期間不允許其他語句的幹擾。因此,就阻塞了其他語句,直到該條語句執行完畢為止。阻塞賦值的行為與C語言中的變數賦值類似。

 

非阻塞賦值 基本文法如下:

[var] <= [expression];

非阻塞賦值的行為非常令人難以琢磨。當always塊被啟用(在time step的開始),右手邊的運算式被賦初值。當運行到always塊的結尾(即time step的結尾),運算所得的值被賦給左手邊的變數。

以x變數執行非阻塞賦值為例。因為Verilog模型的實際流程比較複雜,我們將非阻塞賦值的行為翻譯成一下幾個步驟:

  • 在alway塊的開始,x值傳遞給x_entry;
  • 右手邊的變數x的值被x_entry取代;
  • 左手邊變數x的值被x_exit取代;
  • 在always塊的結束,x_exit的值傳遞給x。

 

在下面的程式碼片段內,上述四個步驟被呈現在代碼的注釋中。

always@*begin               // x_entry = x  y <= x & ...      // y       = x_entry & ...  x <= ...          // x_exit  = ...end                 // x       = x_exit

 

範例 為了瞭解阻塞賦值和非阻塞賦值的區別,我們用三輸入的的電路來做討論。

代碼1 使用阻塞賦值的電路

module and_blocking(  input      a,  input      b,  input      c,  output reg y);  always@*begin  y = a;  y = y & b;  y = y & c;endendmodule

阻塞賦值的欣慰類似於C語言中的順序賦值。y最終得到的值為a & b & c。注意,此代碼僅用於示範,使用順序語意學來描述電路是比較差勁的行為。

 

下面給出的代碼,其中的阻塞賦值被替換為非阻塞賦值。代碼注釋詳細說明了y的賦值動作。

代碼2 使用非阻塞賦值的電路

module and_nonblocking(  input      a,  input      b,  input      c,  output reg y);  always@*begin               // y_entry = y  y <= a;           // y_exit  = a  y <= y & b;       // y_exit  = y_entry & b  y <= y & c;       // y_exit  = y_entry & cend                 // y       = y_exitendmodule

注意always塊內的前2條語句將不會產生任何效果。上述always塊等價與:

always@*          y <= y & c;  

 

2 組合電路

上一個小節的範例屬於極端的情況。除了預設值,大部分的組合電路並不會多次賦值同一變數。阻塞賦值和非阻塞賦值都可以用於描述同一電路。然而,它們有一些微妙的區別。下面的範例用於解釋這些不同。讓我們以一位同或(異或非)電路為例。我們將詳細列出敏感列表中的變數。

代碼3 使用阻塞賦值的一位同或電路

module eq1_blocking(  input      i0,  input      i1,  output reg eq); reg p0, p1;always@(i1, i2)     // 只有i0和i1在敏感列表begin               // 語句的順序非常重要  p0 = ~i0 & i1;  p1 = i0 & i1;  eq = p0 | p1;endendmodule

注意到敏感列表僅包括i0和i1,。當其中之一變化時,always塊被啟用,p0、p1和ep被順序運算,ep在第一個time step的結尾被更新。語句的順序非常重要。假設性我們移動最後面的語句到最前面。

always@(i1, i2)     begin                 eq = p0 | p1;  p0 = ~i0 & i1;  p1 = i0 & i1;end

在第一條語句中,由於p0和p1還沒有被指定新的值,因此先前被啟用的值將會被用到。而先前的值將意味著鎖存器的存在,故此代碼是不正確的。

 

下面將使用非阻塞賦值替換阻塞賦值。

代碼4 使用非阻塞賦值的一位同或電路

module eq1_nonblocking(  input      i0,  input      i1,  output reg eq); reg p0, p1;always@(i1, i2, p0, p1)       // p0、p1也在敏感列表中                               // 語句的順序不重要      begin                         // p0_entry = p0; p1_entry = p1               p0 <= ~i0 & i1;             // p0_exit = ~i0 & ~i1  p1 <= i0 & i1;              // p1_exit = i0 & i1  eq <= p0 | p1;              // eq_exit = p0_entry | p1_entryend                           // eq = eq_exit; p0 = p0_exit; p1 = p1_exit                          endmodule

注意p0和p1也包括在敏感列表中。當i0或i1變化時,always塊被啟用;在第一個time step的結尾,p0和p1被賦以新值。既然ep取決於p0和p1(p0_entry和p1_entry)的舊值,那麼其值在第一個time step的結尾保持不變。噹噹前的time step執行完畢,always塊重新被啟用,因為p0和p1發生了變化(這便於為何p0和p1也要置于敏感列表之中的原因)。注意語句的順序不影響結果。

 

3 儲存單元

使用非阻塞賦值來引用儲存空間。例如,D觸發器:

always@(posede clk)  q <= d;

當然也可以用阻塞賦值來引用D觸發器,如下:

always@(posede clk)  q = d;

雖然在單個D-FF情況下面,上面的代碼工作正常,但是當多個寄存器互相動作的時候,這裡就出現許多微妙的問題。

考慮兩個寄存器在每個刻度交換資料。使用阻塞賦值,代碼為:

always@(posede clk)  a = b;  always@(posede clk)  b = a;

在clk的上升沿,兩個always塊都被啟用,並行操作。這兩個操作應該在同一time step結束。根據Verilog的標準,兩個always塊的執行可以以任何順序列入。若第一個always塊先執行,則由於阻塞賦值的緣故a立即得到b的值。當第二個always塊執行的時候,b得到a的重新整理值,及b的原始值,因此b保持不變。類似的,若第二個always塊先執行,a得到的也是其初始值。這就是Verilog中的競爭冒險(race condition)。從Verilog的角度看,兩種結果都是有效。

下面我們修改代碼中的阻塞賦值為非阻塞賦值。

always@(posede clk)begin        // b_entry = b  a <= b;    // a_exit  = b_entryend          // a       = a_exit  always@(posede clk)begin        // a_entry = a  b <= a;    // b_exit  = a_entryend          // b       = b_exit

通過注釋我們看到,因為輸入(entry)值都被用於賦值,所以無論執行的順序,a和b都得到正確的值。

因此為了避免競爭冒險,我們使用非阻塞賦值來引用D-FF和觸發器。

 

4 混用阻塞和非阻塞賦值的時序電路

在同一個always塊內,有可能混用阻塞賦值和非阻塞賦值。下面我們使用簡單的常式來解釋不同組合的行為,以加強對賦值的理解。

圖4.1 通過混合賦值來引用電路

 

考慮圖4.1(b)所示的原理圖。當時鐘上升沿來臨之時,a、b與運算所得的值被存入D-FF。基於前面的講解,我們可以將儲存和組合電路分配到兩段代碼中。如代碼4.1所示。

代碼4.1 兩段實現

module ab_dff_2seg(  input clk,  input a,  input b,  output reg q);reg q_next;// D-FFalways@(posedge clk)  q <= q_next;// 組合電路always@*  q_next = a & b;endmodule

 

我們可以變換一下,將兩段組合在一起,使用單個always塊來描述電路。下面通過六次嘗試,來描述阻塞和非阻塞賦值的不同組合的區別。如代碼4.2所示。

代碼4.2 混合賦值常式

module ab_dff_mix(  input clk,  input a,  input b,  output reg q0,  output reg q1,  output reg q2,  output reg q3,  output reg q4,  output reg q5);reg ab0, ab1, ab2, ab3, ab4, ab5;// 嘗試0always@(posedge clk)begin  ab0 = a & b;  q0 <= ab0;end// 嘗試1always@(posedge clk)begin                   // ab1_entry = ab1; q1_entry = q1  ab1 <= a & b;         // ab1_exit = a & b  q1  <= ab1;           // q1_exit = ab1_entryend                     // ab1 = ab1_exit; q1 = q1_exit// 嘗試2always@(posedge clk)begin  ab2 = a & b;  q2  = ab2;end// 嘗試3(調換嘗試1的順序)always@(posedge clk)begin  q0 <= ab0;  ab0 = a & b;end// 嘗試4(調換嘗試2的順序)always@(posedge clk)begin                   // ab4_entry = ab4; q4_entry = q4  q4  <= ab4;           // q4_exit = ab4_entry  ab4 <= a & b;         // ab4_exit = a&bend                     // ab4 = ab4_exit; q4 = q4_exite// 嘗試5(調換嘗試3的順序)always@(posedge clk)begin  q5  = ab5;  ab5 = a & b;endendmodule

在嘗試0中,起初賦值給ab0和q0將引用兩個寄存器,一個用於儲存寄存器ab0,另一個用於儲存寄存器q0。因為ab0在塊賦值時被立即更新,所以q0得到了a&b的值。對應的原理圖4.1(a)所示。由於ab0在always塊外沒有被使用,因此寄存器ab0的輸出就不是必需存在的,即相應的寄存器可以被移除。這樣,結果電路就4.1(b)所示,也就是所需的電路。

在嘗試1中,對ab1使用了非阻塞賦值,對應的闡述寫到了注釋裡面。注意q1得到的是ab1_entry而非ab1_exit。而ab1_entry是先前儲存的ab值,即對應一個寄存器的輸出。相應的原理圖4.1(c)所示。一個不確定的輸入緩衝被引用,同時a&b的值延遲一個刻度後才被儲存到q1中。

在嘗試2中,ab2和q2都是用了阻塞賦值。該代碼所引用的電路,與嘗試1等同,4.1(a)和(b)所示。由於使用阻塞賦值來引用D-FF,有可能產生競爭冒險,因此不推薦使用這種類型的代碼。

出於示範的目的,讓我們來測試一下調換嘗試0、1和2的賦值順序會發生什麼。其結果代碼如嘗試4、5和6所示。在嘗試3中,ab3未更新便被使用,因此q3得到的是先前啟用區塊所產生的值。所引用的電路如4.1(c)所示。而嘗試4,交換語句的順序不影響綜合的效果,因此等同於嘗試1。嘗試5中,由於ab5未更新值便被使用,因此q5得到的寄存器a&b的值,等同於嘗試3。

簡而言之,只有嘗試0描述的電路正確且可靠。在嘗試0中,我們可以將ab0移除,合并代碼如下:

// 嘗試0always@(posedge clk)begin  q0 <= a & b;end

 

推薦閱讀

1 SNUG.Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!

 

參考

1 Pong P. Chu.FPGA Prototyping By Verilog Examples: Xilinx Spartan-3 Version.Wiley

 

另見

[與艾米一起學FPGA/SOPC].[邏輯實驗文檔連載計劃]

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.