過程性賦值是在 ?initial
?或 ?always
?語(yǔ)句塊里的賦值,賦值對(duì)象是寄存器、整數(shù)、實(shí)數(shù)等類型。
這些變量在被賦值后,其值將保持不變,直到重新被賦予新值。
連續(xù)性賦值總是處于激活狀態(tài),任何操作數(shù)的改變都會(huì)影響表達(dá)式的結(jié)果;過程賦值只有在語(yǔ)句執(zhí)行的時(shí)候,才會(huì)起作用。這是連續(xù)性賦值與過程性賦值的區(qū)別。
Verilog 過程賦值包括 2 種語(yǔ)句:阻塞賦值與非阻塞賦值。
阻塞賦值屬于順序執(zhí)行,即下一條語(yǔ)句執(zhí)行前,當(dāng)前語(yǔ)句一定會(huì)執(zhí)行完畢。
阻塞賦值語(yǔ)句使用等號(hào) ?=
? 作為賦值符。
前面的仿真中,?initial
? 里面的賦值語(yǔ)句都是用的阻塞賦值。
非阻塞賦值屬于并行執(zhí)行語(yǔ)句,即下一條語(yǔ)句的執(zhí)行和當(dāng)前語(yǔ)句的執(zhí)行是同時(shí)進(jìn)行的,它不會(huì)阻塞位于同一個(gè)語(yǔ)句塊中后面語(yǔ)句的執(zhí)行。
非阻塞賦值語(yǔ)句使用小于等于號(hào) ?<=
? 作為賦值符。
利用下面代碼,對(duì)阻塞、非阻塞賦值進(jìn)行仿真,來(lái)說明 2 種過程賦值的區(qū)別。
`timescale 1ns/1ns
module test ;
reg [3:0] ai, bi ;
reg [3:0] ai2, bi2 ;
reg [3:0] value_blk ;
reg [3:0] value_non ;
reg [3:0] value_non2 ;
initial begin
ai = 4'd1 ; //(1)
bi = 4'd2 ; //(2)
ai2 = 4'd7 ; //(3)
bi2 = 4'd8 ; //(4)
#20 ; //(5)
//non-block-assigment with block-assignment
ai = 4'd3 ; //(6)
bi = 4'd4 ; //(7)
value_blk = ai + bi ; //(8)
value_non <= ai + bi ; //(9)
//non-block-assigment itself
ai2 <= 4'd5 ; //(10)
bi2 <= 4'd6 ; //(11)
value_non2 <= ai2 + bi2 ; //(12)
end
//stop the simulation
always begin
#10 ;
if ($time >= 1000) $finish ;
end
endmodule
仿真結(jié)果如下:
語(yǔ)句(1)-(8)都是阻塞賦值,按照順序執(zhí)行。
20ns 之前,信號(hào) ai,bi 值改變。由于過程賦值的特點(diǎn),value_blk = ai + bi 并沒有執(zhí)行到,所以 20ns 之前,?value_blk
?值為 X(不確定狀態(tài))。
20ns 之后,信號(hào) ai,bi 值再次改變。執(zhí)行到 value_blk = ai + bi,信號(hào) ?value_blk
?利用信號(hào) ai,bi 的新值得到計(jì)算結(jié)果 7。
語(yǔ)句(9)-(12)都是非阻塞賦值,并行執(zhí)行。
首先,(9)-(12)雖然都是并發(fā)執(zhí)行,但是執(zhí)行順序也是在(8)之后,所以信號(hào) ?value_non
?= ai + bi 計(jì)算是也會(huì)使用信號(hào) ai,bi 的新值,結(jié)果為 7。
其次,(10)-(12)是并發(fā)執(zhí)行,所以 ?value_non2
?= ai2 + bi2 計(jì)算時(shí),并不關(guān)心信號(hào) ai2,bi2 的最新非阻塞賦值結(jié)果。即 ?value_non2
?計(jì)算時(shí)使用的是信號(hào) ai2,bi2 的舊值,結(jié)果為 4'hF。
上述仿真代碼只是為了讓讀者更好的理解阻塞賦值與非阻塞賦值的區(qū)別。實(shí)際 Verilog 代碼設(shè)計(jì)時(shí),切記不要在一個(gè)過程結(jié)構(gòu)中混合使用阻塞賦值與非阻塞賦值。兩種賦值方式混用時(shí),時(shí)序不容易控制,很容易得到意外的結(jié)果。
更多時(shí)候,在設(shè)計(jì)電路時(shí),?always
?時(shí)序邏輯塊中多用非阻塞賦值,?always
?組合邏輯塊中多用阻塞賦值;在仿真電路時(shí),?initial
?塊中一般多用阻塞賦值。
如下所示,為實(shí)現(xiàn)在時(shí)鐘上升沿交換 2 個(gè)寄存器值的功能,在 2 個(gè) ?always
?塊中使用阻塞賦值。
因?yàn)?nbsp;2 個(gè) ?always
?塊中的語(yǔ)句是同時(shí)進(jìn)行的,但是 a=b 與 b=a 是無(wú)法判定執(zhí)行順序的,這就造成了競(jìng)爭(zhēng)的局面。
但不管哪個(gè)先執(zhí)行(和編譯器等有關(guān)系),不考慮 ?timing
?問題時(shí),他們執(zhí)行順序總有先后,最后 a 與 b 的值總是相等的。沒有達(dá)到交換 2 個(gè)寄存器值的效果。
always @(posedge clk) begin
a = b ;
end
always @(posedge clk) begin
b = a;
end
但是,如果在 ?always
?塊中使用非阻塞賦值,則可以避免上述競(jìng)爭(zhēng)冒險(xiǎn)的情況。
如下所示,2 個(gè) ?always
?塊中語(yǔ)句并行執(zhí)行,賦值操作右端操作數(shù)使用的是上一個(gè)時(shí)鐘周期的舊值,此時(shí) a<=b 與 b<=a 就可以相互不干擾的執(zhí)行,達(dá)到交換寄存器值的目的。
always @(posedge clk) begin
a <= b ;
end
always @(posedge clk) begin
b <= a;
end
當(dāng)然,利用下面代碼也可以實(shí)現(xiàn)交換寄存器值的功能,但是顯然不如在 ?always
?塊中直接用非阻塞賦值簡(jiǎn)單直觀。
always @(posedge clk) begin
temp = a ;
a = b ;
b = temp ;
end
點(diǎn)擊這里下載源碼
更多建議: