过程赋值:用于对reg型变量赋值,改变寄存器的值或为以后排定改变。
语法
|
{阻塞性(blocking)赋值} RegisterLValue = [ TimingControl] Expression; {非阻塞性(non-blocking)赋值} RegisterLValue <= [ TimingControl] Expression; |
阻塞:在本语句中“右式计算”和“左式更新”完全完成之后,才开始执行下一条语句;
非阻塞:当前语句的执行不会阻塞下一语句的执行。
过程赋值右边的表达式在赋值执行的时候算出。如果没有内部赋值延时,左边的寄存器由于阻塞性赋值将立即更新,而非阻塞性赋值则下一个仿真周期才更新左边的寄存器。如果有内部赋值延时,左边的寄存器只在发生内部赋值延时后更新。
例如对于阻塞性赋值:
- 当执行赋值语句时,算出右边的表达式的值,但左边的值不更新,直到产生定时控制事件或延时(称为“内部赋值延时”)。
- 直到左边被更新后(即经过内部赋值延时后)阻塞性赋值才完成。begin-end块中的下一个语句直到此时才开始执行。
结合编程语句区分如下:
• 非阻塞(non-blocking) 赋值语句(b<= a):
- 块内的赋值语句同时赋值;
- b的值被赋成新值a的操作, 是与块内其他赋值语句同时完成的;
- 建议在可综合风格的模块中使用非阻塞赋值。
• 阻塞(blocking) 赋值语句(b = a):
- 完成该赋值语句后才能做下一句的操作;
- b的值立刻被赋成新值a;
- 硬件没有对应的电路,因而综合结果未知。
阻塞赋值和非阻塞赋值如果使用不当会存在冒险和竞争现象,必须按照下面两条准则:
1)在描述组合逻辑的always块中使用阻塞赋值,则综合组合逻辑的电路结构;
2)在描述时序逻辑的always块中使用非阻塞赋值,则综合时序逻辑的电路结构。
在时钟沿触发的always块中,如果用非阻塞赋值语句对reg型变量赋值;或者当reg型变量经过多次循环其值仍保持不变,则会在综合中生成触发器。若不想生成触发器,而希望用reg型变量生成组合逻辑,则应使用电平触发。在组合逻辑中,阻塞赋值只与电平有关,往往和触发沿没有关系,可以将其看成并行执行的;在时序逻辑中,非阻塞赋值是并行执行的;因此,优秀的HDL设计,其内部语句也是并行执行的。
非阻塞赋值与阻塞赋值示例:
1. 非阻塞赋值方式
1 module nonblocking(input clk, 2 input a, 3 output reg c); 4 reg b; 5 6 always @(posedge clk) begin 7 b <= a; 8 c <= b; 9 end 10 11 endmodule