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

System verilog 系统verilog 2012参考指南中关于always_comb中非阻塞的错误?和延迟断言属性标记?,system-verilog,system-verilog-assertions,System Verilog,System Verilog Assertions,2个问题 在system verilog 2012参考指南中,有一个参考文件提到在始终梳中对顺序逻辑进行编码,这是可能的,因为始终梳块没有时钟参考文件-如这里所示->[在始终梳中的顺序逻辑] 在Synopsys Verdi中使用系统verilog断言时,是否可能在满足属性后,在半个或一个时钟周期后触发绿色箭头(表示已满足断言的属性) 谢谢:关于问题1,D。非阻塞分配不一定意味着顺序行为。阻塞/非阻塞分配是一种模拟构造。让我们看一个小例子来更好地理解它: module some_gate(

2个问题

  • 在system verilog 2012参考指南中,有一个参考文件提到在
    始终梳
    中对顺序逻辑进行编码,这是可能的,因为
    始终梳
    块没有时钟参考文件-如这里所示->[在
    始终梳
    中的顺序逻辑]
  • 在Synopsys Verdi中使用系统verilog断言时,是否可能在满足属性后,在半个或一个时钟周期后触发绿色箭头(表示已满足断言的属性)

  • 谢谢:关于问题1,D

    。非阻塞分配不一定意味着顺序行为。阻塞/非阻塞分配是一种模拟构造。让我们看一个小例子来更好地理解它:

    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
    
    这意味着,每当
    a
    b
    发生变化时,计算
    c
    d
    的值。因为我们对
    c
    使用了阻塞赋值,所以我们在这里计算的值会“传播”到
    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
    
    这是因为变量的每次更改都会触发一次显示过程<代码>a从
    x
    更改为
    1
    ,但
    c
    尚未更新。然后
    c
    d
    在同一时间步中得到更新。稍后,我们更改
    b
    ,但这不会触发
    c
    d
    上的任何更改。然后,我们再次更改
    a
    ,稍后在同一时间片中,
    d
    得到更新

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

    我们可以使用
    always\u 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
    
    现在是有趣的部分。我们可以使用
    始终\u comb
    和非阻塞分配对完全相同的电路进行建模:

    always_comb begin
      c <= a || b;
      d <= a && c;
    end
    
    请注意,在第一个时间步骤中,我们有3个打印,而不是一个。让我们仔细看看这里发生了什么。首先,我们更改了
    a
    ,但是
    c
    d
    尚未更新。其次,
    c
    得到更新,但
    d
    保持不变。这是因为
    c
    上的非阻塞赋值导致
    d
    看到
    c
    的“旧”值。第三,在
    c
    正式更新后,该工具计划在
    d
    上进行更新,我们第一次看到最后一次打印。其余情况与前面的情况相同

    请记住上一段中的内容,
    总是_comb
    在任务右侧的内容发生变化时重新触发。这里的诀窍是,这个
    总是\u comb
    实际上表现为:

    always @(a or b or c) begin
      c <= a || b;
      d <= a && c;
    end
    
    始终@(a、b或c)开始
    
    关于问题1,c。非阻塞分配不一定意味着顺序行为。阻塞/非阻塞分配是一种模拟构造。让我们看一个小例子来更好地理解它:

    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
    
    这意味着,每当
    a
    b
    发生变化时,计算
    c
    d
    的值。因为我们对
    c
    使用了阻塞赋值,所以我们在这里计算的值会“传播”到
    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
    
    这是因为变量的每次更改都会触发一次显示过程<代码>a
    x
    更改为
    1
    ,但
    c
    尚未更新。然后
    c
    d
    在同一时间步中得到更新。稍后,我们更改
    b
    ,但这不会触发
    c
    d
    上的任何更改。然后,我们再次更改
    a
    ,稍后在同一时间片中,
    d
    得到更新

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

    我们可以使用
    always\u 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
    
    现在是有趣的部分。我们可以使用
    始终\u comb
    和非阻塞分配对完全相同的电路进行建模:

    always_comb begin
      c <= a || b;
      d <= a && c;
    end
    
    请注意,在第一个时间步骤中,我们有3个打印,而不是一个。让我们仔细看看这里发生了什么。首先,我们更改了
    a
    ,但是
    c
    d
    尚未更新。其次,
    c
    得到更新,但
    d
    保持不变。这是因为
    c
    上的非阻塞赋值导致
    d
    看到
    c
    的“旧”值。第三,在
    c
    正式更新后,该工具计划在
    d
    上进行更新,我们第一次看到最后一次打印。其余内容与上一个ca中的内容相同