1. 程式人生 > >Verilog 初級入門概念講解(wire 和 reg 型別的區別, always 和 assign 的區別,“阻塞”賦值 和 “非阻塞賦值”的區別 )

Verilog 初級入門概念講解(wire 和 reg 型別的區別, always 和 assign 的區別,“阻塞”賦值 和 “非阻塞賦值”的區別 )

    很多剛學Verilog HDL (硬體描述語言)的朋友肯定會對阻塞賦值非阻塞賦值比較疑惑,那我們就一起來拋開這層迷霧吧。

    首先我們要理解兩種變數型別 Net Type(連線型) Register Type (暫存器型)。(有些參考書上有分為3種類型,這個無關緊要)

    Net Type(連線型),從名字上理解就是“導線”唄,導線的這頭和導線的另一頭始終是直接連通的,這頭是什麼值,那頭就是什麼值,所以輸出隨著輸入隨時變化的。連線型中 wire 最常見。

    Register Type(暫存器型),暫存器就不像普通導線了,它可以把值給存住,你只要給它賦一次值,它都會存住那個值,直到你給它賦一個新的值它才會改變。暫存器型中 reg

 最常見。

    最常用到的是 wire 和 reg 這兩種型別,其他的對我們初學者來說一般很少用到,可以暫時跳過,以後慢慢學下去自然會理解。

    注意:wire型變數如果沒有賦予初始值,預設初始值為高阻態“Z”。

               reg  型變數如果沒有賦予初始值,預設初始值為不定態“X”。

    在理解這兩種基本的資料型別之後,我們來看看verilog語言中的賦值語句。verilog語言中的賦值語句有兩種,一種是持續賦值語句(assign語句),另一種是過程賦值語句(always語句)

     持續賦值語句(assign語句)主要用於對wire型變數的賦值,因為wire(線型)的值不能存住,需要一直給值,所以需要用持續賦值。

          例如:assign c = a + b;    只要a和b有任意變化,都可以立即反映到c上,也就是說c的值是根據a,b的值隨時變化的。

     過程賦值語句(always語句)主要用於reg 型變數的賦值 ,因為always語句被執行是需要滿足觸發條件的,所以always過程塊裡面的內容不是每時每刻都被執行,因此需要將被賦值的物件定義成暫存器型別,以便這個值能被保持住。

    過程賦值又分為 阻塞賦值 “=”  和 非阻塞賦值 “<=” 兩種。這裡的非阻塞賦值符號 “<=” 與 “小於等於” 符號相同,他們在不同的語境下表示不同含義,要注意區分,例如在“if-else”等判斷語句中,一般都表示為“小於等於”。

    接下來對這兩種賦值作具體講解...

     ① 阻塞賦值 “=“ 。 阻塞賦值和我們平時理解的賦值差不多,不用太多解釋,就是按照語句的順序,一句句往下順序執行。一個賦值語句執行完,然後執行下一個賦值語句。

     ② 非阻塞賦值 “<=” 。非阻塞賦值就比較特別了,在同一個always過程塊中,非阻塞賦值語句都是同時併發執行的,並且在過程塊結束時才執行賦值操作。也就是說,在同一個always過程塊中,非阻塞賦值語句被執行沒有先後順序,在過程快結束時,大家一起被賦值。

     給大家舉一個具體的例子:

 module test (clk, a1, a2, b1, b2, c1, c2); // test為module名稱,括號內的是埠列表,包含所有輸入輸出的變數名稱

 input clk, a1, a2;           // 定義輸入變數,這裡沒有定義位寬,預設為1位寬度

 output b1, b2, c1, c2;    // 定義輸出變數,這裡沒有定義位寬,預設為1位寬度

 reg b1 = 0 , b2 = 0, c1 = 0 , c2 = 0;   // 注意!因為這些變數將會在always過程塊中被賦值,所以必須定義成 reg 型    

// 注意!這裡省略了對輸入訊號clk, a1, a2 的型別定義,它們預設為1位的wire 型(因為輸入訊號是隨時要變化,所以必須用wire型)              

always @ (posedge clk)   // always 用 clk 上升沿觸發

    begin

        b1 = a1;       // 這裡採用的是阻塞賦值

        c1 = b1;

    end

always @ (posedge clk)  // always 用 clk 上升沿觸發

    begin

        b2 <= a2;    // 這裡採用的是非阻塞賦值

        c2 <= b2;

    end   

endmodule     // endmodule 別忘了,與 module 成對使用

模擬輸入值設定圖如下:

 我們只需給輸入訊號賦值,輸出訊號根據輸入訊號的變化而變化。

下面請看用quartus 2 軟體模擬的波形圖

首先請看這兩張圖的區別,第一張是時序模擬波形圖(timing),黃色標記部分因為延時而產生,第二張圖為功能模擬波形圖(function),不考慮器件的延時。   在時刻,第一個時鐘上升沿到來(posedge clk), 兩個always過程塊同時被觸發(這就是PFGA器件強大的一點,可以併發執行)      a1,b1,c1採用的是阻塞賦值。阻塞賦值語句順序執行,先執行 b1 = a1; 由於 a1 此刻的值為 1,所以b1 變為 1,然後執行 c1 = b1;由於b1的值剛才已經變成 1 了,所以c1也變成了 1 。      a2,b2,c2採用的是非阻塞賦值。非阻塞賦值語句併發執行,也就是說 b2 <= a2; c2 <= b2; 這兩句同時執行。由於a2 此刻的值為1,所以 b2 變為1,與此同時,b2 的當前值也將賦值給 c2 , b2 的當前值是是多少呢? 這裡一定要分清楚了,b2 的當前值是 0,並不是 1 ,因為在 b2 還沒有變為 1 之前,b2 的值就要賦值給 c2 了,所以 c2 的值仍然是 0 。     直到在②時刻,第二個時鐘上升沿到來,兩個always再一次被同時觸發,這次在執行 c2 <= b2; 這條賦值語句時,b2 的當前值為 1 ,所以 c2 才被賦值為 1 。     大家可以根據上面的分析方法,自己分析一下在③、④時刻 b1,b2,c1,c2 應該分別為什麼值,與波形圖對照著理解一下。 其實verilog語言和 c語言大同小異,比較著來學習,會比較容易......     希望這篇文章對初學者會有幫助,其實我也是初學者,希望各位高手提出批評指點..... O(∩_∩)O~