如何理解verilog中的阻塞和非阻塞语句?

Pra*_*gue 1 verilog hdl system-verilog vlsi

我了解了 Verilog 中阻塞语句和非阻塞语句之间的基本区别。但我仍然无法理解&何时何地使用阻塞和非阻塞语句会发生什么。例如,考虑简单的 d ff 代码:

module dff (clk, reset,d, q, qb);
input      clk;
input      reset;
input      d;
output     q;
output     qb;

reg        q;

assign qb = ~q;

always @(posedge clk or posedge reset)
begin
  if (reset) begin
    // Asynchronous reset when reset goes high
    q <= 1'b0;
  end else begin
    // Assign D to Q on positive clock edge
    q <= d;
  end
end
endmodule
Run Code Online (Sandbox Code Playgroud)

但是如果我使用两段编码技术编写完全相同的逻辑:

module dff(input wire d,
           clk,
           reset,
           en,
           output wire q);

reg q;
reg r_reg, r_next;

always @(posedge clk, posedge reset)
if(reset) 
  r_reg<=1'b0;
else
  r_reg<=r_next;

always @*
  if(en)
    r_reg=d;
  else
    r_reg=r_next;

assign q<=r_reg;
endmodule
Run Code Online (Sandbox Code Playgroud)

现在,在这段代码中,我只是不明白为什么在第一个总是块中使用以及为什么它们在第二个总是块中<=使用。=我还知道,在组合逻辑电路中=建议&按顺序使用<=,建议使用。但我仍然无法找到阻塞和非阻塞语句用法的答案。你能帮我么!?

Ser*_*rge 5

阻塞/非阻塞分配只是一个模拟工件。与人们的看法相反,verilog 并不描述硬件。Verilog 描述了硬件的期望行为,试图将其融入事件驱动的仿真方案。

下面是一个使用 2 个触发器的移位寄存器的简单示例:

    always @(posedge clk)
        out1 = in;
    always @(posedge clk)
        out2 = out1;
Run Code Online (Sandbox Code Playgroud)

现在,out2 的输出是什么?由于我们正在处理模拟,因此这取决于这两个语句的执行顺序。要么是 out1 的旧值,要么是新值(实际上是 in 的值);。

在硬件方面则没有这样的混乱。它将翻转 posege 时间存在的值,即out1 的值(好吧,除非时钟出现异常延迟)。

为了匹配这种行为,引入了非阻塞赋值。Verilog 仿真是在仿真节拍中完成的。每个刻度都是只要存在可能导致其他块重新评估的事件即可。非阻塞分配被安排在这样一个tick结束时用当前的rhs值执行(实际上有几个调度区域)。因此,请考虑以下事项:

    always @(posedge clk)
        out1 <= in;
    always @(posedge clk)
        out2 <= out1;
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,所有分配都将在刻度结束时发生。'out2` 将被分配一个 <= 时存在的值,因此,它将是 out1 的旧值。现在,它们的执行顺序并不重要。

因此,顶级建议是对组合逻辑使用阻塞赋值 (=),对状态设备、触发器和锁存器的所有输出使用非阻塞赋值 (<=)。请注意,状态设备内部的一些临时变量仅在内部使用,也应该分配阻塞。另外,切勿在时钟树中使用非阻塞分配。