过程赋值用于更新 reg、integer、time、real、realtime和memory数据类型。过程赋值(procedural assignment)与连续赋值(continuous assignment)有很大区别:
- 连续赋值驱动net网络,每当输入操作数的值发生变化时,就会立刻对其输出进行评估和更新。
- 过程赋值则是在其所属过程流结构体的控制下更新变量值。
过程赋值的右侧可以是任何求值的表达式,左侧变量应是一个从右侧变量接收赋值的变量。过程赋值的左侧变量可以是以下形式之一:
-reg、integer、time、real、realtime数据类型:对这些数据类型之一的变量赋值。
-reg、integer、time数据类型的位选择:对单个bit位赋值,其他位保持不变。
- reg、integer、time数据类型的部分bit选择:对多个连续位选择,其他位不变。
- memory字数据:memory内存的一个字。
-上述任一形式的拼接或嵌套拼接。
当右侧值的位宽少于左侧值的位宽时,右侧值将被填充到左侧值的位宽大小。如果右边值是无符号的,则进行零填充。如果右侧值是有符号的,则进行符号扩展。
Verilog HDL 包含两种类型的过程赋值语句:
- 阻塞过程赋值语句(Blocking procedural assignment)
- 非阻塞过程赋值语句(Nonblocking procedural assignment)
阻塞和非阻塞过程赋值语句在顺序块中有不同的执行流程,我们接下来详细介绍~
阻塞过程赋值(Blocking procedural assignment)
在一个顺序块(sequential block)中,阻塞赋值语句应在执行其后的任何语句之前执行。在一个并行块(parallel block)中,阻塞赋值语句不应阻止其后任何语句的执行,顺序块和并行块的详细概念咱们稍后介绍,这里知道即可。阻塞过程赋值的语法见下表1:
表1:阻塞过程赋值语法
在该语法中,variable_lvalue 是对过程赋值语句有效的数据类型,= 是赋值操作符,delay_or_event_control 是可选的赋值内部时序控制。该控制可以是延迟控制(如 #6 ),也可以是事件控制(如 @(posedge clk) )。expression是应分配给左侧的右侧值。
另外,阻塞过程赋值使用的 = 赋值操作符也用于连续赋值。例如:下面的示例显示了阻塞过程赋值:
非阻塞过程赋值(Nonblocking procedural assignment)
非阻塞过程赋值允许在不阻塞过程流的情况下进行赋值调度,即在同一时间内可以进行多个变量赋值,而不考虑顺序或相互依赖关系。其语法如下表2所示:
表2:非阻塞过程赋值语法
在该语法中,variable_lvalue 是过程赋值语句有效的数据类型,<= 是非阻塞赋值操作符,delay_or_event_control 是可选的赋值内部时序控制。
我们要注意:非阻塞赋值运算符与小于或等于关系运算符是同一个运算符。编译器根据 <= 出现的上下文来决定其解释。<= 在表达式中使用时,应解释为关系运算符;在非阻塞过程赋值中使用时,应解释为赋值运算符。
在实际代码中,非阻塞过程赋值应分两步进行评估,这两个步骤如下例1所示:
module evaluates2 (out);
output out;
reg a, b, c;
initial begin
a = 0;
b = 1;
c = 0;
end
always c = #5 ~c;
always @( posedge c) begin
a <= b;
b <= a;
end
endmodule
第一步:在 posedge c时刻,仿真器会评估非阻塞赋值的右侧,并将在非阻塞赋值更新事件结束时安排新值的赋值。对应在例子1的5个时间单位开始时,a=0,b=1.
第二步:当仿真器激活非阻塞赋值更新事件时,仿真器会更新每个非阻塞赋值语句的左侧。对应在例子1的5个时间单位结束时,a=1,b=0.
例子2:
该例子2清楚的显示了阻塞和非阻塞赋值的最核心区别:阻塞!。
例子3:
//non_block1.v
module non_block1;
reg a, b;
initial begin
a = 0;
b = 1;
a <= b;
b <= a;
end
initial begin
$monitor ( $time ,"a = %b b = %b", a, b);
#100 $finish ;
end
endmodule
在例子3中,最终a=1,b=0.
例子4:
给定变量的不同非阻塞赋值的执行顺序应予以保留。换句话说,如果一组非阻塞赋值操作的执行有明确的顺序,那么由此产生的非阻塞赋值左侧变量的更新顺序应与执行顺序相同,正如例子4所示,这是非阻塞赋值的一种例外情况。
例子5:
如果仿真器同时执行两个过程块,并且这些过程块包含对同一变量的非阻塞赋值操作符,则该变量的最终值是不确定的。例子5中a的值是不确定的,与例子4形成鲜明对比。
例子6:
针对同一变量的两个非阻塞赋值在不同的过程块中,但其本身并不足以使变量的赋值顺序变得不确定。在例子6中,16个时间单位结束时a的值会确定为0。
例子7:
上面的的例子7显示了如何将 i[0]赋值给 r1,以及如何在每次延时后再循环进行赋值。
点赞加关注博主(ID:FPGA小飞)的博文,咱们一起系统学习verilog最终标准IEEE Std 1364-2005吧!