一、源代码
module block_nonblock(clk,rst_n,a,b,c,out);
input clk;input rst_n;input a;input b;input c;output out;
reg [1:0]out;reg [1:0]d;
always@(posedge clk or negedge rst_n)
if(!rst_n)
out <= 2'b0;
else begin
d <= a + b;
out <= c + d; //此处都是非阻塞赋值 <=
end
endmodule
二、测试文件
`timescale 1ns / 1ps
module block_nonblock_tb();
reg clk;reg rst_n;reg a;reg b;reg c;
wire [1:0]out;
block_nonblock block_nonblock_inst0( .clk(clk),.rst_n(rst_n),.a(a),.b(b),.c(c),.out(out));
initial clk = 0;
always #10 clk = ~clk;
initial begin
rst_n = 0;a = 0;b = 0;c = 0;#201;
rst_n = 1;#200; a = 0;b = 0;c = 1;#200;
a = 0;b = 1;c = 0;#200; a = 0;b = 1;c = 1;#200;
a = 1;b = 0;c = 0;#200; a = 1;b = 0;c = 1;#200;
a = 1;b = 1;c = 0;#200; a = 1;b = 1;c = 1;#200;
$stop;
end
endmodule
三、波形
1、疑问:
在2处的上升沿,a=1,b=1, d <= a + b(1+1=10) 所以 d 的值是 10,
c=0,out <= d + c ,按理说,10 + 0 = 10 ,也就是 out 应该是 10,但是却是01?
其实这是非阻塞赋值引起的现象。
2、理解误区:
d <= a + b;
out <= c + d;
按照这个代码,可能我们会理解成,先执行第一条语句,
再执行第二条语句(即我们理解成先算出 d 的结果,再将 d 的结果带入第二条语句,算出 out 的结果)
这种理解,是阻塞赋值的思想(阻塞赋值即,只有先执行完前面的语句,才能执行后面的语句。)
但是,上面两条语句是非阻塞赋值,非阻塞赋值的两条语句会同时执行!
3、答案:
d <= a + b;
out <= c + d;
在2上升沿处,两条语句要同时执行。
但是在2上升沿处,第一条语句还没有执行完,d值还没有产生,第二条语句没有对应的 d 值,out的值怎么计算?
要计算 2 处上升沿的 out 值,这条语句(out <= c + d;)中 d 的值只能用 1处上升沿的 d 值!
所以 第二条语句(out <= c + d;)的理解应该是
所以 2处上升沿的out 值 = 2处上升沿的c值 + 1处上升沿的 d 值!
四、源代码生成的电路图
( d 和 out 变量都生成了寄存器。在上面的源代码中,即便改变两条非阻塞赋值语句的顺序,生成的电路图也一样。非阻塞赋值的多条语句,只表示电路的连接方式,所以vivado生成的电路都一样。)