如何在Verilog中解释阻塞与非阻塞分配?

如何在Verilog中解释阻塞与非阻塞分配?,verilog,system-verilog,Verilog,System Verilog,在绘制硬件图时,我对如何解释阻塞和非阻塞分配有点困惑。我们是否必须推断非阻塞分配给我们一个寄存器?然后根据这句话c首先要弄清楚阻塞和非阻塞分配之间的区别肯定有点棘手。但不要害怕——有一个简便的经验法则: 如果您想用总是块推断组合逻辑,请使用块分配(=)。如果您想要顺序逻辑,请使用带非阻塞分配的带时钟的始终块(传统的Verilog智慧完全错误。对局部变量使用阻塞分配没有问题。但是,您不应该对同步通信使用阻塞分配,因为这是不确定的 时钟始终块中的非阻塞分配将始终根据语义推断触发器 时钟始终块中的阻塞

在绘制硬件图时,我对如何解释阻塞和非阻塞分配有点困惑。我们是否必须推断非阻塞分配给我们一个寄存器?然后根据这句话
c首先要弄清楚阻塞和非阻塞分配之间的区别肯定有点棘手。但不要害怕——有一个简便的经验法则:


如果您想用
总是
块推断组合逻辑,请使用块分配(
=
)。如果您想要顺序逻辑,请使用带非阻塞分配的带时钟的
始终
块(
传统的Verilog智慧完全错误。对局部变量使用阻塞分配没有问题。但是,您不应该对同步通信使用阻塞分配,因为这是不确定的

时钟始终块中的非阻塞分配将始终根据语义推断触发器


时钟始终块中的阻塞赋值是否推断触发器完全取决于它的使用方式。如果可能在赋值之前读取变量,则将推断触发器。否则,这就像一个临时变量,将导致一些组合逻辑。

只想添加到Jan Decaluwe的答案。似乎在野外很少有真正使用Jan Decauwe描述的代码,尽管这是绝对正确的。多亏了卡明斯先生,混合使用阻塞和非阻塞语句现在是一种禁忌


问题是,大多数地方都避免对局部变量使用阻塞语句,而Google的即时搜索空间中几乎没有代码,这似乎给出了一个例子。我找到Jan提到的编码风格的唯一地方是。而这一点,我意外地遇到了

我为此付出了艰辛也是

但首先,您应该了解,非阻塞或阻塞实际上与是否创建闩锁/ff无关

对于他们的差异,你可以简单地理解(在开始)至此:i.如果使用阻塞,则在阻塞语句LHS赋值之前,它后面的语句无法执行,因为如果使用变量,它的LHS更改内容可以更新并使用。但是,对于非阻塞,它不会像与后面的语句平行一样阻塞后面的语句(实际上,应该首先进行RHS计算,但没关系,混淆时忽略它)。对于这次执行,LHS不会更改/更新(下次总是块触发时更新)。下面的句子使用旧值,因为它在执行周期结束时更新

a = 0; b= 0;
a = 1;
b = a;
--> output a = 1, b = 1;
a = 0; b= 0;
a <= 1;
b = a;
--> output a = 1, b = 0;
以下内容也可能会创建闩锁/ff:

always @(*) begin
    if(in) a = 1;
    else b = 1;
end
-->为in=1、b无分配、in=0无分配创建的闩锁/ffs


此外,当您感测clk的posedge
always@(posedge clk)时
,它必然以闩锁/ff结尾。因为,对于clk来说,必须存在负边缘,而您什么也不做,闩锁/ff的创建是为了保留所有旧值!

请您始终可以在数字域中解释verilog,只需您必须了解,如果您编写的相同代码将在门级转换,将会发生什么情况,i per通常不要遵循在seq中使用非阻塞或在组合中使用阻塞的规则,这会限制你的思维 下面是如果您的代码被转换为门级代码将会发生的情况,请看您是否只需要它

  • 首先是全加器——输入a和b
  • 输出将转到触发器,创建与clk同步的输出
  • 现在,由于分配是阻塞的,因此新的a将应用于下一个完整添加,并将此新的a和c作为输入,它的输出将转到dffcsync以clk创建新的b
  • 既然b=c+a;有没有阻塞状态,所以b被更新为这个新的b

  • 现在我可以回答你的问题了,但我认为一篇论文最好,所以我建议你读一下Clifford Cummings的这篇论文。它将消除你所有的疑问,此外,它将加强你对verilog的理解


    我推荐EDA传奇人物做此演示:
    a = 0; b= 0;
    a = 1;
    b = a;
    --> output a = 1, b = 1;
    a = 0; b= 0;
    a <= 1;
    b = a;
    --> output a = 1, b = 0;
    
    always @(*) begin
        if(in) out = 1;
        else out = 0;
    end
    --> this end without latch/ff
    always @(*) begin
        if(in) out = 1;
    end
    --> this end with one latch/ff to keep value when in = 0, as it might happen and you didn't assign value to out as in=1 do. 
    
    always @(*) begin
        if(in) a = 1;
        else b = 1;
    end