"Current Simulation Time" 和 Verilog 中的事件队列到底是什么?

What exactly is "Current Simulation Time" and Event Queue in Verilog?

考虑以下示例:

module test;
 reg a;
 initial begin
  a = 1'b0;
  a <= 1'b1;
  $display(a);
 end
endmodule

上面的例子显示0。我的原因是因为非阻塞赋值将在"Stratified Event Queue"的第3步赋值,而阻塞赋值和$display在第1步完成。如果我修改例如:

module test;
 reg a;
 initial begin
  a = 1'b0;
  a <= 1'b1;
  $display(a);
  $monitor(a);
 end
endmodule

然后打印 0 和 1,因为我假设 $monitor 在事件队列的第 4 步执行(?)。但是如果我进一步修改示例:

module test;
 reg a;
 initial begin
  a = 1'b0;
  a <= 1'b1;
  $monitor(a);
  $display(a);
 end
endmodule

再次输出:0 和 1——这是我没有预料到的。我希望打印 1 和 1,因为 $monitor 将在事件队列的第 4 步进行评估,到那时,"a" 已经是 1。之后我们有 $display,它应该打印 1.

参考资料 我可以找到关于 "current simulation time" 和 "stratified event queue" 的讨论,但我不确定它是如何工作的。

感谢您的解释! 谢谢

verilog 仿真周期比您当前的解释描述的更复杂。对您的问题的简短回答是 $monitor 不会等待当前周期结束,显示其消息然后继续执行该过程(从而触发 $display 之后),而是简单地安排消息在任何因变量(在本例中只是 a)发生变化的任何模拟周期结束时显示;这是一种非常特殊(而且相当过时)的方式来监控模拟过程中信号的变化。 $display 但是会立即执行,因此会打印当时 a 的内容。因此,另一种思考它的方式就像非阻塞赋值 (<=),$monitor 只是设置了一些稍后发生的事情,并且执行继续到下一条语句而不是内联发生。

您应该考虑了解 systemverilogs 仿真模型,注意活动区域、nba 区域和延迟区域,因为这些区域在 blocking-assignments(=)、非阻塞分配(<=)时和 $monitor 分别是 运行。

Verilog 仿真是事件驱动的。事件是 verilog 变量(或命名事件)值的变化。模拟是分步进行的。

一个步骤从放入事件队列的输入事件开始。由于评估而导致的每个新值更改都会创建新事件,这些事件会添加到队列中。当队列为空时模拟结束(没有更多活动事件)。每一个这样的步骤都会增加模拟时间。

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

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

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

  2. non-blocking分配区。在这里它执行所有对 nba 事件计划做出反应的块。它会将 ba 和 nba 事件都放在队列中。当所有 nba 完成后,如果有 ba 事件,它可能会回到区域“1”并重新开始。

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

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

a <= 1 将在 $dislpay 完成后安排在 non-blocking 区域执行。 $monitor 将在 non-blocking 完成后选择监控区域中的事件。因此,它将显示 1.

的值

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

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