一、何为“阻塞”?
所谓“阻塞”,可以理解为阻止顺序语句块中其他语句的执行。例如,在一个块语句中,如果含有多条阻塞式赋值语句,当执行到其中某条语句时,若该语句未执行完,那么其后面的语句将处于等待中,不会被执行,好像都被阻塞了一样。
二、阻塞赋值与非阻塞赋值
赋值操作可以细分为两个部分:(1)RHS运算操作(计算等式右手方向的数值);(2)将RHS运算结果赋值给LHS。
那么阻塞赋值与非阻塞赋值两者最本质的区别在于操作(1)与操作(2)是并行执行的还是串行执行的。
1. 阻塞式赋值“=”
阻塞赋值即执行RHS的运算,同时将RHS的运算结果赋值给LHS。
①赋值语句立即执行,执行完毕后才执行下一条语句(即为阻塞的含义,依次顺序执行);
②计算完“=”右边的值之后,立刻更新“=”左边的值,即左侧值在赋值语句执行完后立即改变。
assign连续(阻塞)赋值代码如下(示例):
wire [DW-1:0] RHS;
assign LHS = RHS;
在always块中进行阻塞赋值代码如下(示例):
reg [DW-1:0] RHS;
always @(*) begin
LHS = RHS;
end
2.非阻塞式赋值“<=”
非阻塞赋值先执行将RHS的运算,再将RHS的运算结果赋值给LHS。在计算非阻塞赋值的RHS表达式和更新LHS期间,其他的Verilog语句,包括其他的Verilog非阻塞赋值语句都能同时计算RHS表达式和更新LHS,非阻塞赋值允许其他的Verilog语句同时进行操作。
①语句执行到此时,先计算“<=”右侧值,但不立即赋值给左侧;
②always块结束后才完成此次赋值操作;
所有过程语句中的非阻塞赋值语句,必须在块语句执行结束时才会整体完成赋值更新。非阻塞赋值只能用于对reg进行赋值,因此只能用在initial和always块等过程块中。
在always块中进行非阻塞赋值代码如下(示例):
reg [DW-1:0] RHS;
always @(边沿信号) begin
LHS <= RHS;
end
阻塞赋值中 “RHS运算操作” 与 “将RHS运算结果赋值给LHS” 是并行执行的,即RHS中运算结果一旦发生变化就立马赋值给LHS,LHS立马随之变化。而在非阻塞赋值中,“RHS运算操作” 与 “将RHS运算结果赋值给LHS” 是串行执行的,即先执行“RHS运算操作” ,得到RHS运算结果,再“将RHS运算结果赋值给LHS” 。
三、什么时候用阻塞赋值或非阻塞赋值?
组合逻辑用阻塞赋值,时序逻辑用非阻塞赋值。
- assign赋值语句中只能使用“=”,且等号左边的目标对象只能是wire型
- initial和always语句中,两种赋值符号都可以使用,但等号左边的目标对象只能是reg型变量。
- always块中用阻塞赋值“=”,综合生成组合逻辑的电路结构,这种电路结构只与输入电平的变化有关。
- always块中用非阻塞赋值“<=”,综合成时序逻辑的电路结构,这种电路结构往往与触发沿有关,只在触发沿时才可能发生赋值的变化。
注意:在一个always块中,不要既用阻塞赋值又用非阻塞赋值。不允许在多个always块中对同一个变量进行赋值。
程序(1)为阻塞赋值,结果显示使用了1个寄存器; 程序(2)为非阻塞赋值,结果显示使用了2个寄存器。
另外,begin end中赋值语句的顺序对阻塞赋值有影响,而对非阻塞赋值没有影响,因为非阻塞赋值允许其他的Verilog语句同时进行操作,而对于阻塞赋值必须执行完该赋值后才执行下一条语句,示例如下。
- 阻塞赋值
- 非阻塞赋值