常见的对于非阻塞复制的误解
- 1,非阻塞赋值和$display
- 1.1,RTL案例
- 1.2,功能实现
- 1.3,解释误解
- 2,#0延时赋值
- 2.1,RTL案例
- 2.2,功能实现
- 2.3,解释误解
- 3,对同一变量进行多次非阻塞赋值
- 3.1,RTL案例
- 3.2,功能实现
- 3.3,解释误解
- 4,小结
1,非阻塞赋值和$display
1.1,RTL案例
module display_cmds;
reg a;
initial $monitor("\$ monitor: a = %b", a);
initial begin
$strobe ("\$ strobe : a = %b", a);
a = 0;
a <= 1;
$display ("\$ display: a = %b", a);
#1 $finish;
end
endmodule
1.2,功能实现
1.3,解释误解
误解1: 使用$display命令不能用来显示非阻塞语句的赋值;
事实是:非阻塞语句的赋值在所有的$display命令执行后才更新数值。
对上述语句的解释:
以上3条语句是非阻塞赋值和 d i s p l a y 模块的仿真结果,这说明 display模块的仿真结果,这说明 display模块的仿真结果,这说明display命令的执行是安排在活动事件队列中,但排在非阻塞赋值数据更新事件之前。
注意事项:
$display,在仿真期间会自动执行,但在综合到实际硬件时可能会被忽略,因此请仅将其用于仿真和调试目的。
2,#0延时赋值
2.1,RTL案例
// #0延时赋值
module nb_schedule;
reg a, b;
initial begin
a = 0;
b = 1;
a <= b;
b <= a;
$monitor("%0dns: \ $ monitor: a = %b, b = %b", $stime, a, b);
$display("%0dns: \ $ display: a = %b, b = %b", $stime, a, b);
$strobe ("%0dns: \ $ strobe: a = %b, b = %b\n", $stime, a, b);
#0 $display("%0dns: #0: a = %b, b = %b", $stime, a, b);
#1 $monitor("%0dns: \ $ monitor: a = %b, b = %b", $stime, a, b);
$display("%0dns: \ $ display: a = %b, b = %b", $stime, a, b);
$strobe ("%0dns: \ $ strobe : a = %b, b = %b\n", $stime, a, b);
$display("%0dns: #0: a = %b, b = %b", $stime, a, b);
#200 $finish;
end
endmodule
2.2,功能实现
以上8条语句是#0
延时赋值模块的仿真结果,这说明#0
延时命令在非阻塞赋值事件发生前,在停止运行事件队列中执行。
#0
延时赋值建议遵循以下的原则7:
原则7 用$strobe系统任务来显示,应该用非阻塞赋值的变量值。
2.3,解释误解
误解2: #0延时把赋值强制到仿真时间步的末尾;
事实是:#0延时将赋值事件强制加入停止运行事件队列中。
3,对同一变量进行多次非阻塞赋值
3.1,RTL案例
// 对同一变量进行多次非阻塞赋值
module multi_touch;
reg a;
initial begin
a <= 0;
a <= 1;
end
endmodule
3.2,功能实现
执行该模块时,有两个非阻塞赋值更新事件加入到非阻塞赋值更新队列。以前的规划要求将非阻塞赋值更新事件按照它们在源文件的顺序加入队列,这便要求按照事件在源文件中的顺序,将事件从队列中取出并执行。因此,在仿真第一步结束时刻,变量a被设置为0,然后是1。
结论:
最后一个非阻塞赋值决定了变量的值。
3.3,解释误解
误解3: 在Verilog语法标准中未定义,可在同一个always块中对某一变量进行多次非阻塞赋值。
事实是:Verilog标准定义了在同一个always块中,可对某同一变量进行多次非阻塞赋值,但在多次赋值中,只有最后一次赋值对该变量起作用。
4,小结
在夏宇闻的《Verilog数字系统设计教程》的第14章-深入理解阻塞和非阻塞赋值的不同中,其所有的原则归纳如下所示:
(1)原则1:时序电路建模时,用非阻塞赋值;
(2)原则2:锁存器电路建模时,用非阻塞赋值;
(3)原则3:用always块写组合逻辑时,采用阻塞赋值;
(4)原则4:在同一个always块中同时建立时序和组合逻辑电路时,用非阻塞赋值;
(5)原则5:在同一个always块中不要同时使用非阻塞赋值和阻塞赋值;
(6)原则6:不要在多个always块中为同一个变量赋值;
(7)原则7:用$strobe系统任务来显示用非阻塞赋值的变量值;
(8)原则8:在赋值时,不要使用 #0
延迟。
结论:
遵循以上原则,有助于正确的编写可综合硬件,并且可以清楚90%~100%在仿真时可能产生的竞争冒险现象。