本文将站在电路角度上对阻塞与非阻塞赋值进行深入解读,希望大家能够知其然并知其所以然。本文将从综合区别/仿真时序/常见问题三部分进行介绍。
在我的理解中,阻塞和非阻塞是为了区分连线“wire”和D触发器的赋值。同样是赋值,在时序逻辑和组合逻辑中,其综合出来的电路结构是不同的。
always @(*)begin
b = a;
end
对block进行综合,得到的就是简单的a与b的连线,而b可以是DFF/锁存器或连接线,其赋值将是每时每刻的。
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
b <= 1'b0;
else
b <= a;
end
综合出来将会是下图这样一个DFF采样电路,上一级的值被一个边沿触发的D触发器采样并保持,只在边沿的瞬间赋值。
基于上述综合区别的理解,理解时序区别将变得简单。为什么阻塞赋值需要等block中前置的逻辑结束后才能执行,而非阻塞赋值可以同时执行?
always @(*)begin
b[3:0] = a[3:0];
c[3:0] = b[3:0];
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
b[3:0] <= 4'h0;
c[3:0] <= 4'h0; //wechat bug!
end
else begin
b[3:0] <= a[3:0];
c[3:0] <= b[3:0];
end
end
在清楚区分阻塞和非阻塞逻辑后,入门阶段常会犯的一个错误——使用阻塞累加器,代码如下。
always @(*)begin
a[3:0] = a[3:0] + 4'b1;
end