我也曾经为此感到困惑。
但首先,你应该明白非阻塞或阻塞实际上与是否创建锁存器/触发器无关!
你可以从以下角度简单地理解它们的区别(起初):i. 如果使用阻塞,则在赋值语句的左侧被赋值之前,其后的语句将无法执行,因为如果变量被使用,那么更改为它的左侧的内容会更新并被使用。但是对于非阻塞,它不会像下面的语句一样阻塞,而是与下面的语句并行执行(实际上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;
一个关键点是查找你的代码(始终块)中是否有任何情况变量未分配值但可能发生。如果不向它传递值并且出现该情况,则会创建拉奇/触发器来保持该值。
例如,
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
--> 当in=1时,b没有赋值,当in=0时,a没有赋值,创建了latch/ffs。
另外,当你感应到clk的posedge时always @(posedge clk)
,它必须以latch/ff结尾。因为对于clk,必须存在负边缘,并且你没有做任何操作,所以创建了latch/ff来保留所有旧值!