1.阻塞赋值(Blocking)
阻塞赋值,顾名思义即在一个 always 块中,后面的语句会受到前语句的影响,具体来说就是在同一个always 中,一条阻塞赋值语句如果没有执行结束,那么该语句后面的语句就不能被执行,即被“阻塞”。也就是说 always 块内的语句是一种顺序关系,这里和 C 语言很类似。
符号“=”用于阻塞的赋值(如:b = a;)阻塞赋值“=”在 begin 和 end 之间的语句是顺序执行,属于串行语句。
在时序逻辑下使用阻塞赋值为例来说明
图1 阻塞赋值代码
图2 波形
代码中使用的是阻塞赋值语句,从波形图中可以看到,在复位的时候(rst_n=0), a=1, b=2,c=3;而结束复位之后(波形图中的 0 时刻),当 clk 的上升沿到来时(波形图中的 2 时刻),a=0, b=0, c=0。这是因为阻塞赋值是在当前语句执行完成之后,才会执行后面的赋值语句,因此首先执行的是 a=0,赋值完成后将 a 的值赋值给 b,由于此时 a 的值已经为 0,所以 b=a=0,最后执行的是将 b 的值赋值给 c,而 b 的值已经赋值为 0,所以 c 的值同样等于 0。
2.非阻塞赋值(Non-Blocking)
符号“<=”用于非阻塞赋值(如:b <= a;),非阻塞赋值是由时钟节拍决定,在时钟上升到来时,执行赋值语句右边,然后将 begin-end 之间的所有赋值语句同时赋值到赋值语句的左边,注意:是 begin—end 之间的所有语句,一起执行,且一个时钟只执行一次,属于并行执行语句。这个是和 C 语言最大的一个差异点。
图3 非阻塞赋值代码
图4 波形
代码中使用的是非阻塞赋值语句,从波形图中可以看到,在复位的时候rst_n=0, a=1,b=2, c=3;而结束复位之后(波形图中的 0 时刻),当 clk 的上升沿到来时(波形图中的 2 时刻), a=0, b=1, c=2。这是因为非阻塞赋值在计算 RHS 和更新 LHS 期间,允许其它的非阻塞赋值语句同时计算 RHS 和更新 LHS。在波形图中的 2 时刻, RHS 的表达是 0、 a、 b,分别等于 0、 1、 2,这三条语句是同时更新 LHS,所以 a、b、 c 的值分别等于 0、 1、 2。
说明:
RHS:赋值等号右边的表达式或变量
LHS:赋值等号左边的表达式或变量
3.什么时候使用阻塞赋值,什么时候使用非阻塞赋值
①
在描述组合逻辑电路的时候,使用阻塞赋值,比如 assign 赋值语句和不带时钟的 always 赋值语句,这种电路结构只与输入电平的变化有关系。
Demo1: assign赋值语句
assign data = (data_en == 1'b1) ? 8'd255 : 8'd0;
Demo2:不带时钟的always语句
always @(*) begin
if (en) begin
a = a0;
b = b0;
end
else begin
a = a1;
b = b1;
end
end
②
在描述时序逻辑的时候,使用非阻塞赋值,综合成时序逻辑的电路结构,比如带时钟的 always 语句;这种电路结构往往与触发沿有关系,只有在触发沿时才可能发生赋值的变化。
Demo3:
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
a <= 1'b0;
b <= 1'b0;
end
else begin
a <= c;
b <= d;
end
end
本文说明:参考正点原子FPGA开发指南,仅用作学习记录,如有侵权请告知!!!
版权声明:本文为qq_38716211原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。