非阻塞分配的Verilog序列

neh*_*ehz 7 verilog synthesis

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

A <= 1
A <= 2
Run Code Online (Sandbox Code Playgroud)

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

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

Mor*_*gan 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
Run Code Online (Sandbox Code Playgroud)


Cli*_*nna 6

关于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
Run Code Online (Sandbox Code Playgroud)

和测试台:

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
Run Code Online (Sandbox Code Playgroud)

在模拟两个更新a <= 0,并a <= 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
...
Run Code Online (Sandbox Code Playgroud)

但是,在合成中,这将简单地分配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
Run Code Online (Sandbox Code Playgroud)

(从理论上讲,第一行仍然可以说a=x,但是每个合适的综合工具都会优化a-flip-flop,因为测试中的两个工具都可以.)

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