非阻塞分配的Verilog序列

时间:2013-03-30 11:48:39

标签: verilog synthesis

说出以下代码部分(同一块):

A <= 1
A <= 2

变量A总是被分配2吗?或是否会有竞争条件,将分配1或2?

我对非阻塞分配的理解是,在未来的时间由硬件来分配变量A,因此它可能是随机结果。但是,这不直观。模拟显示2总是被分配,但我想知道这是否肯定是硬件综合的情况。

4 个答案:

答案 0 :(得分:8)

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

我已经看到这种技术使用了很多,并且从未在合成后看到任何意外的结果,但正如其他人所提到的那样,这不是由verilog规范保证或涵盖的。

使用它可能是一个稀疏定义其输出的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

答案 1 :(得分:5)

在代码中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 <= 0a <= 1都会被推送到NBA事件区域并按顺序执行,因此a总是最终被设置。但是,当执行a <= 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分配给常数值零。 (经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 - 触发器,就像测试中的两个工具一样。)

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

答案 2 :(得分:0)

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

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

答案 3 :(得分:-3)

从RTL的角度来看。 “A”将被分配1和2,它可以是1,然后是2,反之亦然,但你不能真正知道在开始 - 结束块的末尾将分配哪个值,它可以是1或2(如分配的第二个值。