0

对于 SystemVerilog 的 2012 规则 4.7 是如何实现的,我仍然有些困惑。该规则规定,在这样的情况下:

module test;
  logic a;
  integer cnt;

  initial begin
    cnt = 0;
    #100;
    a <= 0;
    a <= 1;
    a <= 0;
    a <= 1;
    a <= 0;
  end

  always @(posedge a)
    begin
      cnt <= cnt + 1;
    end
endmodule

所有分配都将安排在非阻塞分配队列上,然后必须按顺序执行。最后一个值获胜。到这里,一切都清楚了。

但对于所有模拟器来说,接下来发生的事情并不相同。iverilog 和 Modelsim(至少 Vivado 2016/3 版)在“a”上创建一个事件,这会导致 cnt 增加。这似乎也符合卡明斯先生在 SNUG 2000 上说明的行为

然而,VCS 会过滤掉中间值并仅应用最后一个值,顺便说一下,这也是真正的触发器工作的方式。

在这种情况下,这不是纯粹的假设性讨论,仿真结果不同,iverilog/modelsim 行为可能会导致很难捕捉到的错误,因为触发器会切换,但波形中看不到值变化。

另一点是:如果iverilog/modelsim 是正确的,那么为什么他们要创建一个事件而不是两个?

编辑:附加说明。

上面的例子确实意义不大。一个更现实的情况是

always @(posedge clk)
  begin
    clk2 <= 1'b1;
    if (somecondition)
      clk2 <= 1'b0;
  end

always @(posedge clk2, negedge rst_n)
  begin
    if (!rst_n)
      q <= 1'b0;
    else
      q <= ~q;
end

这是完全合法的,并且在真正的硬件中永远不会出现故障。第一个总是在逻辑上实际上等同于

always @(posedge clk)
  begin
    if (somecondition)
      clk2 <= 1'b0;
    else
      clk2 <= 1'b1;
  end

但是,如果您使用 ModelSim 模拟第一个版本,您会看到您的 q 愉快地切换,clk2 常量为 0。这将是调试的噩梦。

4

1 回答 1

1

你的最后一个问题很容易解释。并不是说模拟器只创建一个事件,他们不会——只是第一个事件安排@(posedge) 来恢复always进程,而其他事件发生在 NBA 区域,然后总是块在下一个活动事件中恢复执行地区。

我无法证明其他模拟器的行为是合理的。在真实硬件中不允许对同一个触发器进行多次分配,所以你的类比没有那么简单。有可能有一个不定时的描述并在没有时间过去的情况下获得多个(@posedge)。所以过滤会阻止这种编码风格。

于 2016-11-11T17:24:59.250 回答