【问题标题】:Verilog sequence of non blocking assignmentsVerilog 非阻塞赋值序列
【发布时间】:2013-03-30 11:48:39
【问题描述】:

说出下面的代码部分(相同的块):

A <= 1
A <= 2

变量 A 总是被赋值为 2 吗?还是会存在竞争条件并分配 1 或 2?

我对非阻塞赋值的理解是,由硬件在将来分配变量 A,因此它可能是随机结果。然而,这是不直观的。模拟显示 2 总是被分配,但我想知道这是否绝对硬件合成的情况。

【问题讨论】:

    标签: verilog synthesis


    【解决方案1】:

    模拟中A为2,最后定义的值生效。如果它们不在同一个块中,则可能存在竞争条件,具体取决于模拟器调度程序,即最后在模拟中定义的调度程序。

    我已经看到这种技术被大量使用,并且在合成后从未见过任何意想不到的结果。

    来自 Verilog IEEE 1364-2005 第 11.4.1 节确定性

    begin-end 块中的语句应按照它们在该 begin-end 块中出现的顺序执行。特定开始-结束块中语句的执行可以暂停,以支持模型中的其他进程;但是,在任何情况下,begin-end 块中的语句都不能按照它们在源代码中出现的顺序以外的任何顺序执行。

    这也在 SystemVerilog-IEEE1800 2012 中作为第 4.6 节确定性

    这可能是一个 FSM,它稀疏地定义了它的输出:

    always @(posedge clk) begin
      out_one <= 1'b0;
      out_two <= 1'b0;
      out_thr <= 1'b0;
      case (state)
        2'd1 : out_one <= 1'b1;
        2'd2 : out_two <= 1'b1;
        2'd3 : out_thr <= 1'b1;
      endcase
    end
    

    【讨论】:

    • 是的,这基本上就是我问这个问题的原因,因为我的默认输出只在某些状态下改变
    • "...verilog 规范不保证或涵盖这一点"。不正确:SystemVerilog IEEE1800-2017 第 4.6 节指出“开始-结束块中的语句应按照它们在该开始-结束块中出现的顺序执行”
    【解决方案2】:

    在您的代码中,A 的最终值没有任何不确定性,不是用于模拟,也不是用于综合。

    但是,确切地说,如果设计包含A 上的触发器,则可能存在仿真综合不匹配。考虑以下示例:

    module test(input clk, output reg a, b);
      always @(posedge clk) begin
        a <= 0;
        a <= 1;
      end
    
      initial b = 0;
      always @(posedge a) begin
        b <= !b;
      end
    endmodule
    

    还有一个测试台:

    module tb;
      reg clk = 0;
      always #5 clk = ~clk;
    
      wire a, b;
      test uut (clk, a, b);
    
      initial begin
        $monitor("clk=%b a=%b b=%b", clk, a, b);
        repeat (100) @(posedge clk);
        $finish;
      end
    endmodule
    

    在模拟过程中,a &lt;= 0a &lt;= 1 都被推送到 NBA 赛事区域并按顺序执行,因此a 总是会被设置。然而,由于a &lt;= 0 也被执行,每个时钟周期在a 上都有一个宽度为零的负脉冲。该脉冲触发第二个始终阻塞。这是模拟输出(使用 Icarus Verilog 和 Modelsim 测试):

    clk=0 a=x b=0
    clk=1 a=1 b=1
    clk=0 a=1 b=1
    clk=1 a=1 b=0
    clk=0 a=1 b=0
    clk=1 a=1 b=1
    clk=0 a=1 b=1
    clk=1 a=1 b=0
    clk=0 a=1 b=0
    clk=1 a=1 b=1
    clk=0 a=1 b=1
    clk=1 a=1 b=0
    clk=0 a=1 b=0
    ...
    

    但是,在综合中,这将简单地将a 分配给常量值 1,将b 分配给常量值 0。 (使用 Yosys 和 Xilinx Vivado 测试。)所以综合后仿真输出如下所示:

    clk=0 a=1 b=0
    clk=1 a=1 b=0
    clk=0 a=1 b=0
    clk=1 a=1 b=0
    clk=0 a=1 b=0
    clk=1 a=1 b=0
    clk=0 a=1 b=0
    clk=1 a=1 b=0
    clk=0 a=1 b=0
    clk=1 a=1 b=0
    clk=0 a=1 b=0
    clk=1 a=1 b=0
    clk=0 a=1 b=0
    clk=1 a=1 b=0
    

    (理论上第一行仍然可以写成a=x,但是每个像样的综合工具都会优化a-flip-flop,就像测试中的两个工具一样。)

    除了该代码没有潜在问题之外,正如@Morgan 在他的回答中正确指出的那样,这是一种非常常用的编码技术,用于在使用条件编码特殊情况之前定义输出信号的“默认值”分配(使用if 和/或case)。

    【讨论】:

      【解决方案3】:

      根据 IEEE 标准(例如 1800-2009)中的“确定性”部分,如果这些语句位于开始-结束块中,则 A 在模拟中将始终被赋值为 2。

      但是,Std 不保证如何合成代码。结果门可能取决于综合工具。但是,一个好的 RTL linting 工具会识别出这种糟糕的编码。 Cadence 的 Hal lint 工具发出警告。

      【讨论】:

        【解决方案4】:

        从 RTL 的角度来看。 "A" 将被分配 1 和 2,它可以先是 1,然后是 2,反之亦然,但你无法真正知道在 begin-end 块的末尾将分配哪个值,它可以是 1 或 2(如分配的第二个值)。

        【讨论】:

          猜你喜欢
          • 2021-12-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-02-05
          相关资源
          最近更新 更多