Verilog中的“当前模拟时间”和事件队列到底是什么?

时间:2019-06-09 20:24:02

标签: verilog system-verilog system-verilog-assertions iverilog

考虑以下示例:

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。

参考文献中我可以找到有关“当前模拟时间”和“分层事件队列”的信息,但是我不确定它是如何工作的。

感谢您的解释! 谢谢

2 个答案:

答案 0 :(得分:1)

verilog模拟周期比您当前的说明所描述的更为复杂。您问题的简短答案是$monitor不等待当前周期结束,而是显示其消息,然后继续执行该过程(因此随后触发$display),而只是安排消息在任何因变量(在此情况下仅为a)发生变化的任何模拟周期结束时显示;这是在仿真过程中监视信号变化的一种非常特殊(甚至是过时)的方式。但是$display立即执行,从而打印出当时的a。因此,另一种思考方式是非阻塞分配(<=),$monitor只是设置了以后要发生的事情,执行继续到下一条语句,而不是内联发生。

您应该考虑学习systemverilogs仿真模型,并在阻塞分配(=,非阻塞分配(<=)和{{1 }}分别运行。

答案 1 :(得分:1)

Verilog仿真是事件驱动的。事件是Verilog变量(或命名事件)的值的更改。仿真是分步进行的。

从输入事件放入事件队列开始。评估导致值的每个新变化都会创建新事件,这些事件将添加到队列中。当队列为空时(不再有活动事件),模拟结束。每个这样的步骤都会增加仿真时间。

该步骤本身分为多个区域,这些区域使用标准中定义的算法执行。

对于verilog 2K,大约有3个主要区域:

  1. 阻止分配区域。 Verilog执行事件队列安排的所有程序块,并对新的块分配事件做出反应。它只是安排nbas事件在以后执行。完成所有阻止事件后,它会到达下一个区域。

  2. 非阻塞分配区。在这里,它执行对日程表nba事件作出反应的所有块。它将把ba和nba事件都放入队列。完成所有nba后,如果发生ba事件并重新执行,则可能会返回到区域“ 1”。

  3. 监视/选通区域-这是$ monitor(和$ strob)工作时的区域。在ba和nba区域都完成后(没有更多事件),它将执行。

在您的情况下,a = 1在阻止分配区域中执行。该值将一直保持到该区域结束。 $display也将在此区域中执行。因此,它将看到'a == 0'的值。

在$ dislpay完成后,

a <= 1将被安排在非阻塞区域执行。 完成无阻塞操作后,$monitor将在监视区域中选择事件。因此,它将向您显示1的值。

您的语句在initial块中执行。结果,没有事件传播。仅通过alwaysassign语句选择事件。如果将$display放在always块中,将会看到更多有趣的结果。 always @* $display(a);

您应该阅读verilog中的标准模拟语义以获取更多信息。