系统 verilog 2012 中的错误关于 always_comb 中的非阻塞参考指南?和延迟断言 属性 标记?

Error in system verilog 2012 Reference guide regarding non-blocking in always_comb ? and delayed assertion property marker?

2 个问题

  1. 在 system verilog 2012 参考指南中,有一个关于在 always_comb 中编写时序逻辑的参考,这是否可能,因为 always_comb 块没有时钟参考 - 如此处所示-> [always_comb 中的顺序逻辑]

  1. 在 Synopsys Verdi 中使用系统 Verilog 断言时,绿色箭头(表示满足断言 属性)是否有可能在 属性 之后的半个或一次时钟周期后触发满意

谢谢 :D

关于问题 1。非阻塞赋值并不一定意味着顺序行为。 Blocking/non-blocking 作业是模拟结构。让我们看一个小例子来更好地理解它:

module some_gate(
  input logic a,
  input logic b,
  output logic c,
  output logic d
);

  // c is 'a or b'
  // d is 'a and c'
endmodule

我们有两个输入信号和两个输出信号。我们要为复合门建模。

在经典的 Verilog 风格中,我们将编写如下内容:

always @(a or b) begin
  c = a || b;
  d = a && c;
end

这意味着,每当 ab 发生变化时,计算 cd 的值。因为我们对 c 使用了阻塞赋值,所以我们在这里计算的值得到 "propagated" 到 d 的计算。这实质上意味着我们将 d 描述的逻辑链接到 c.

的逻辑之后

我们可以使用一个小测试台来测试它:

module test; 
  logic a, b, c, d;

  some_gate dut(.*);

  always @(a or b or c or d)
    $display("[%0d] a = %b, b = %b, c = %b, d = %b", $time(), a, b, c, d);

  initial begin
    #1 a = 1;
    #1 b = 1;
    #1 a = 0;

    #1 $finish();
  end  
endmodule

如果我们模拟这个,我们会得到:

[1] a = 1, b = x, c = x, d = x
[1] a = 1, b = x, c = 1, d = 1
[2] a = 1, b = 1, c = 1, d = 1
[3] a = 0, b = 1, c = 1, d = 1
[3] a = 0, b = 1, c = 1, d = 0

这是因为每次变量变化都会触发一次显示过程。 ax 更改为 1,但 c 尚未更新。然后 cd 在同一时间步得到更新。稍后,我们更改 b,但这不会触发 cd 的任何更改。然后,我们在同一时间片中再次更改 a,稍后更新 d

必须指定敏感度列表有点多余,因为如果我们知道我们需要组合逻辑,我们应该在赋值右侧的某些内容发生变化时重新触发该过程。这就是 always_comb 的用途。

我们可以使用 always_comb 重写代码,只需删除敏感列表即可:

always_comb begin
  c = a || b;
  d = a && c;
end

运行 此代码将导致相同的打印:

[1] a = 1, b = x, c = x, d = x
[1] a = 1, b = x, c = 1, d = 1
[2] a = 1, b = 1, c = 1, d = 1
[3] a = 0, b = 1, c = 1, d = 1
[3] a = 0, b = 1, c = 1, d = 0

有趣的部分来了。我们可以使用 always_comb 和非阻塞赋值对完全相同的电路进行建模:

always_comb begin
  c <= a || b;
  d <= a && c;
end

运行 不过,这段代码会产生略有不同的打印结果:

[1] a = 1, b = x, c = x, d = x
[1] a = 1, b = x, c = 1, d = x
[1] a = 1, b = x, c = 1, d = 1
[2] a = 1, b = 1, c = 1, d = 1
[3] a = 0, b = 1, c = 1, d = 1
[3] a = 0, b = 1, c = 1, d = 0

请注意,在第一个时间步骤中,我们有 3 个指纹,而不是一个。让我们仔细看看这里发生了什么。首先,我们更改 a,但 cd 尚未更新。其次,c 得到更新,但 d 保持不变。这是因为 c 上的非阻塞赋值导致 d "seeing" c 的 "old" 值。第三,在 c 正式更新后,该工具安排在 d 更新,我们看到了第一个时间步的最后打印。其余同上例

请记住上一段中提到的 always_comb 每当赋值右侧的内容发生变化时都会重新触发。这里的技巧是这个 always_comb 实际上表现得像:

always @(a or b or c) begin
  c <= a || b;
  d <= a && c;
end

这是非标准的 Verilog,但仍会模拟相同的逻辑。请注意,c 已明确添加到敏感度列表中。如果我们忽略这一点,那么我们将描述一个闩锁。不鼓励这种风格,因为它很容易出错(即忘记将中间逻辑节点添加到敏感列表)。

这里的关键要点是阻塞或非阻塞赋值既不描述顺序逻辑也不描述组合逻辑。是整个上下文(即确定它们何时被执行的敏感度列表)控制着从代码中推断出什么逻辑电路。

完整的代码示例可在 EDAPlayground 上找到。

关于问题 2。这是特定于工具的,不是针对此问题的论坛。你应该在供应商的网站上问这个问题。