考虑以下示例:
module test;
reg a;
initial begin
a = 1'b0;
a <= 1'b1;
$display(a);
$monitor(a);
end
endmodule
上面的示例显示为0。我的原因是因为非阻塞分配将在“分层事件队列”的步骤3中分配,而阻塞分配和$ display在步骤1中完成。如果我将示例修改为:
module test;
reg a;
initial begin
a = 1'b0;
a <= 1'b1;
$monitor(a);
$display(a);
end
endmodule
然后打印0和1,因为我假设$ monitor在事件队列(?)的第4步执行。但是,如果我进一步修改示例:
{{1}}
再次输出是:0和1-我没想到。我希望可以打印1和1,因为$ monitor将在事件队列的第4步进行评估,此时“ a”已经为1。之后,我们有了$ display,应该打印1。
参考文献中我可以找到有关“当前模拟时间”和“分层事件队列”的信息,但是我不确定它是如何工作的。
感谢您的解释! 谢谢
答案 0 :(得分:1)
verilog模拟周期比您当前的说明所描述的更为复杂。您问题的简短答案是$monitor
不等待当前周期结束,而是显示其消息,然后继续执行该过程(因此随后触发$display
),而只是安排消息在任何因变量(在此情况下仅为a
)发生变化的任何模拟周期结束时显示;这是在仿真过程中监视信号变化的一种非常特殊(甚至是过时)的方式。但是$display
立即执行,从而打印出当时的a
。因此,另一种思考方式是非阻塞分配(<=
),$monitor
只是设置了以后要发生的事情,执行继续到下一条语句,而不是内联发生。
您应该考虑学习systemverilogs仿真模型,并在阻塞分配(=
,非阻塞分配(<=
)和{{1 }}分别运行。
答案 1 :(得分:1)
Verilog仿真是事件驱动的。事件是Verilog变量(或命名事件)的值的更改。仿真是分步进行的。
从输入事件放入事件队列开始。评估导致值的每个新变化都会创建新事件,这些事件将添加到队列中。当队列为空时(不再有活动事件),模拟结束。每个这样的步骤都会增加仿真时间。
该步骤本身分为多个区域,这些区域使用标准中定义的算法执行。
对于verilog 2K,大约有3个主要区域:
阻止分配区域。 Verilog执行事件队列安排的所有程序块,并对新的块分配事件做出反应。它只是安排nbas事件在以后执行。完成所有阻止事件后,它会到达下一个区域。
非阻塞分配区。在这里,它执行对日程表nba事件作出反应的所有块。它将把ba和nba事件都放入队列。完成所有nba后,如果发生ba事件并重新执行,则可能会返回到区域“ 1”。
监视/选通区域-这是$ monitor(和$ strob)工作时的区域。在ba和nba区域都完成后(没有更多事件),它将执行。
在您的情况下,a = 1
在阻止分配区域中执行。该值将一直保持到该区域结束。 $display
也将在此区域中执行。因此,它将看到'a == 0'的值。
a <= 1
将被安排在非阻塞区域执行。
完成无阻塞操作后,$monitor
将在监视区域中选择事件。因此,它将向您显示1
的值。
您的语句在initial
块中执行。结果,没有事件传播。仅通过always
和assign
语句选择事件。如果将$display
放在always块中,将会看到更多有趣的结果。 always @* $display(a);
您应该阅读verilog中的标准模拟语义以获取更多信息。