在Verilog語言中經常要用到延時語句,延時語句添加的位置不同,輸出的結果就會不同。今天就來分析比較一下延時語句在不同位置時,對指派語句的影響。
一、阻塞式左延時指派
檔案代碼:
`timescale 1ns/1ns
module delay(
a,
b,
sum
);
input [3:0] a;
input [3:0] b;
output reg [4:0] sum;
//阻塞式左延時指派語句
always @(*) begin
#12 sum = a + b;
end
endmodule
測試代碼
`timescale 1ns/1ns
module delay_tb;
reg [3:0] a;
reg [3:0] b;
wire [4:0] sum;
delay delay(
.a(a),
.b(b),
.sum(sum)
);
initial begin
a = 0; b = 0;
#5;
a = 1; b = 1;
#5;
a = 2; b = 2;
#5;
a = 3; b = 3;
#5;
a = 4; b = 4;
#5;
a = 5; b = 5;
#5;
a = 6; b = 6;
#5;
a = 7; b = 7;
#5;
a = 8; b = 8;
#5;
a = 9; b = 9;
#5;
a = 10; b = 10;
#5;
#30;
$stop;
end
endmodule
a、b的值5ns改變一次,通過阻塞式語句讀取a、b的和,延時語句加在左側。
仿真波形如下:
通過波形可以看到初始化之後,a、b的值每5ns變化一次,在第12ns時,sum輸出a+b的和為4,說明在延時時間到了之後,才取a和b的值計算,然後更新給sum。執行完阻塞指派語句後,程式退出always塊,等待下一次資料變化。在第15ns時,a、b的值又發生了變化,延時等待12ns後,在第27ns取出a和b的值并計算,然後更新給sum。也就是說延時語句在阻塞指派左側時,在延時時候到了之後,系統更新右值同時指派給左值。sum總是為a和b最新值的和。
二、阻塞式右延時指派
代碼修改如下:
`timescale 1ns/1ns
module delay(
a,
b,
sum
);
input [3:0] a;
input [3:0] b;
output reg [4:0] sum;
//阻塞式右延時指派語句
always @(*) begin
sum = #12 a + b;
end
endmodule
測試代碼保持不變,仿真波形如下:
通過仿真波形可以看出,在第12ns的時候,sum輸出值為0,說明初始化之後,程式進入always塊中計算a+b值,延時等待12ns之後,再将值更新給sum。雖然此時a和b的值都變為了2。但是計算的依然是12ns之前的值。計算完成之後推出always塊,當第15ns時,a、b的值發生了變化,又進入always塊中計算此時a+b的值,等待12ns之後,也就是在第27ns時将結果6指派給sum。由此可以看出,當延時語句在阻塞指派右邊時,更新的是延時之前的值。在延時等待過程中資料發生變化時将會被忽略。
三、非阻塞式左延時指派
修改代碼如下:
`timescale 1ns/1ns
module delay(
a,
b,
sum
);
input [3:0] a;
input [3:0] b;
output reg [4:0] sum;
//非阻塞式左延時指派語句
always @(*) begin
#12 sum <= a + b;
end
endmodule
測試代碼不變,仿真波形如下:
通過波形可以看到,系統初始化之後a、b的值5ns變化一次,在第12ns時sum結果為4。說明計算的是a、b的最新值。在第15ns時,a、b的值發生了更新,延時12ns後,也就是第27ns,讀取a、b目前最新值,計算累加和指派給sum輸出。由此可看到延時加在非阻塞指派左側時,在延時時間到了之後,讀取a、b最新值并計算累加和。
四、非阻塞式右延時指派
修改代碼如下:
`timescale 1ns/1ns
module delay(
a,
b,
sum
);
input [3:0] a;
input [3:0] b;
output reg [4:0] sum;
//非阻塞式右延時指派語句
always @(*) begin
sum <= #12 a + b;
end
endmodule
測試代碼不變,仿真波形如下:
通過波形可以看出,初始化之後a、b的值每5ns更新一次,在第12ns時sum值為0,說明計算的是0ns時a、b的值。在第17ns時,sum值為2,說明計算的是第5ns時,a、b的值。後面的值以此類推,說明sum的值統一延遲的12ns。但是每次a、b的變化都被捕捉到了。說明延時加在非阻塞指派的右側時,輸出結果會統一延遲。但是不會漏掉任何一次資料變化。
五、連續指派
修改代碼如下:
`timescale 1ns/1ns
module delay(
a,
b,
sum
);
input [3:0] a;
input [3:0] b;
output [4:0] sum;
assign #12 sum = a + b;
endmodule
測試不變,仿真波形如下:
由波形圖可以看出,當a、b停止變化後12ns,sum才會輸出最後一次a+b的值。
通過上面幾種延時方法比較,可以看出,延時在不同語句中不同位置,輸出結果也不相同。