1. 程式人生 > >【 Verilog HDL 】進一步瞭解 Verilog HDL 的賦值運算子

【 Verilog HDL 】進一步瞭解 Verilog HDL 的賦值運算子

以前已經寫過博文專門介紹阻塞賦值和非阻塞賦值運算子了,見博文:【Verilog HDL】賦值語句之阻塞賦值方式與非阻塞賦值方式,可今天看《FPGA之道》這本書時,回首過去,覺得說得還不夠,這裡再一次總結下 Verilog 中的賦值運算子。其中包括阻塞賦值和非阻塞賦值,感覺理解更進一步了。

包括對阻塞以及非阻塞這些字眼的理解,還有其他字眼的理解,這本書可謂真是通俗易懂,可惜買不到珍藏了。

連續賦值符號

連續賦值(continues assignments),它常配合assign關鍵字使用,僅能用於線網型別的變數賦值,例如:

input b;
wire a;
assign a = b;

當然也可以這樣寫:

input b;
wire a = b;

相比之下,我們可以稱帶有assign關鍵字的賦值方式為顯式地連續賦值,而簡化後的賦值方式為隱式地連續賦值。隱式地連續賦值,如:

input b;
a = b;

但我們不推薦這麼寫,前兩種方式隨便用。

為什麼叫連續賦值呢?

這是因為該賦值語句所描述的硬體功能,賦值電路不需要等待任何事件的觸發,也不會受任何事件的影響而中斷,會連續不斷地執行(當然了,在模擬的時候顯然不能這樣,否則將進入模擬死迴圈,故這裡不是描述的模擬中的用法)。顯然,這種模式只能描述組合電路,故只能用於線網型別變數的賦值。

阻塞賦值符號

阻塞賦值主要用於組合邏輯,它只能操作暫存器類的變數,賦值符號為“=”。一般來說,當我們期望變數被綜合成為FPGA中的硬體連線時,我們常常會對變數用阻塞賦值,而對應的賦值語句一般要寫在表示組合邏輯的always程式段中。

在always程式段中,語句的執行一般都是順序的,阻塞賦值符號的作用就是保證上一條語句已經執行並且賦值操作完成後才開始下一條語句的執行,也因此得名為阻塞賦值。例如:

[email protected](c)
begin
    b = c;
    a = b;
end

如何理解上面的這一個邏輯塊功能呢?

如果當前狀態 c為邏輯1,b為邏輯1,a也為邏輯1。若此時 c 變為邏輯0,那麼在本次 c 改變後,b的邏輯為0,a也為邏輯0。從硬體實現上說,上述程式碼就是三段首尾相連的硬體連線,其實就是一根線,試想一下,如果連線的輸入端值改變了,那麼整個連線的值肯定也都跟著變了,所以c處的值傳給b,同時經過b也傳給了a;

從阻塞賦值符號的作用來說,由於在第1條語句的賦值完成以後才開始執行第2條語句,所以第2條語句中的b是b的新值。

非阻塞賦值

非阻塞賦值主要用於時序邏輯,它也只能操作暫存器類的變數,賦值符號為“<=”。一般來說,當我們期待變數被綜合為FPGA中的暫存器時,我們常常會對變數用非阻塞賦值符號,當然了,對應的賦值語句也應該寫在表示時序邏輯的always塊內。在always程式段中,語句的執行一般都是順序的,非阻塞賦值符號的作用就是可以在上一條語句已執行但是賦值操作還沒有完成前就開始下一條語句的執行。例如:

[email protected]( posedge clk )
begin
    b <= c;
    a <= b;
end

如果在上一次時鐘上升沿觸發後,b為邏輯1,a為邏輯1。若此時c保持為邏輯0,那麼在本次時鐘上升沿觸發後,b為邏輯0,a為上一次b的值,即為邏輯1。從硬體實現上來說,上述程式碼就是一個移位暫存器,每一次時鐘觸發後,c處的值傳給b,b處的值傳給a,值的傳遞只能跨越1個暫存器。

從非阻塞賦值符號的作用上說,由於第一條語句的賦值還沒有完成時,就開始執行第2條賦值語句,所以第2條語句中的b仍然使用的是b的舊址。

對映賦值符號

所謂的對映賦值就是模組的例項化中,埠之間的一種對應關係。例如:

wire line0, line1, result;
cellAnd m0( .a(line0), .b(line1), .c(result) );

無論埠的方向是 input 還是 output,都一律使用“.”來對映賦值,至於賦值的方向,編譯器會根據上下文自己推斷。

位置賦值

位置賦值和對映賦值一樣,都是例項化中埠的一種對應關係,不過此時是位置嚴格對應,而不適用“.”了而已。例如:

cellAnd m0( line0, line1, result );

不推薦這種賦值方式,因為對映賦值是於位置無關的,這裡呢?還必須位置嚴格對應,容易出錯。