Verilog 中的确定性;事件控制

Determinism in Verilog; Event Controls

考虑以下示例:

module test;
  reg a;
  initial begin
    a = 1'b1;
  end
  initial begin
    wait(a) $display("wait(a): %b", a);
    $display("wait(a)");
  end
  initial begin
    @a $display("@a: %b", a);
    $display("@a");
  end
endmodule

当我运行它时,我总是得到这个输出:

wait(a): 1
wait(a)

这让我很困惑。我对代码的理解是这样的:

  1. a 的默认值为 x
  2. 所有初始块在时间 0 处并行开始。
  3. 第一个初始块执行块分配,同时 wait@a 事件控件读取 a.
  4. 由于三者之间的先后顺序没有确定性,阻塞赋值a=1'b1可以在wait(a)@a之前或之后执行。
  5. 如果在 wait(a)@a 之前执行阻塞分配,则不应显示任何输出,因为 wait(a)@a 不会检测到 [=12] 中的任何更改=].
  6. 但是,如果在 wait(a)@a 中读取 a 之后执行阻塞赋值 a=1'b1,两者都将读取为 x, 那么两者的输出应该在阻塞分配完成后显示。

但是,正如我上面指出的,我看到的输出始终是 wait(a) 的输出。有人可以给我解释一下吗:

  1. 这是怎么回事,我的理解有问题吗?

更一般地说,在上面的例子之外:

  1. 当模拟器遇到 wait(a)@a 时到底发生了什么?
  2. wait(a)@a 检测电平和边缘变化(在示例中,电平和边缘变化是相同的)。当我们在这种情况下说 "change" 时,是否意味着在最后一次读取事件控件中涉及的变量(在本例中为 a)之后发生了变化?

谢谢

你在第 5 点之前都是正确的。

如果 a=1'b1wait(a) 之前执行,则它没有任何效果——它不会挂起进程。如果顺序相反,wait(a) 暂停进程并在赋值 a=1'b1 后恢复。在您的示例中,无论顺序如何,您始终会看到第二个 initial 块的输出。

但是第三个 initial 块的顺序非常重要。 @a 必须在对 a 进行任何更改之前执行,否则它会暂停直到看到另一个更改。尽管您不应该依赖它,但大多数工具都按源代码顺序执行初始块。但是不同模块中 initial 块之间的优化和排序永远不能保证排序。