Verilog:始终@*块未被触发
在下面显示的测试台代码中,我观察到时钟信号Verilog:始终@*块未被触发,verilog,system-verilog,Verilog,System Verilog,在下面显示的测试台代码中,我观察到时钟信号clk没有按预期切换。 时钟在时间5从低变高,但此后不会切换 module tb(); reg clk; initial begin clk = 'b0; #100 $finish; end always@* #5 clk = ~clk; endmodule 但是,如果我从始终@*语句中删除@*,时钟将按预期每5ns切换一次。我的问题是为什么进程块在第一次更改后不总是被触发 注意:我已经在NCSIM和VCS中测试了代
clk
没有按预期切换。
时钟在时间5从低变高,但此后不会切换
module tb();
reg clk;
initial begin
clk = 'b0;
#100 $finish;
end
always@* #5 clk = ~clk;
endmodule
但是,如果我从始终@*
语句中删除@*
,时钟将按预期每5ns切换一次。我的问题是为什么进程块在第一次更改后不总是被触发
注意:我已经在NCSIM和VCS中测试了代码,我不认为这是模拟器的问题。时钟生成器通常通过以下两种方式之一实现:
如您已尝试过的,始终在没有敏感度列表的情况下使用:
always #5 clk = ~clk;
无灵敏度列表的始终
块将永远循环,如果没有延迟,将导致模拟挂起。尽管后者使它成为时钟发生器的完美之选
在初始
块中使用永久循环:
initial begin
forever
#5 clk = ~clk;
end
上述代码的工作方式与前面的始终
相同。接受的答案是错误的-始终
最初是由初始
块中的0赋值触发的,因此您有一个完全有效的问题,这就是为什么always
块在第一次运行后不会自动触发(显然它确实运行了,因为clk
设置为1)
运行下面的代码-如果您将阻塞分配更改为非阻塞分配,或者如果您使用内部分配延迟而不是延迟控制(clk=#5~clk
),您将看到它按预期工作。所以,这是一个日程安排问题。您可能直觉地认为您的流程只会触发一次,因为最终的阻塞分配和流程评估实际上发生在同一个增量中,因此阻塞分配可能会丢失。然而,我在LRM中看不到具体的理由。延迟控制将变成一个未来的非活动事件,调度程序最终执行它,创建一个更新事件,更新clk
(这种情况只发生一次)。然后,这应该为流程创建一个评估事件,因为它对clk
敏感,但它没有这样做。日程安排部分(非常)杂乱无章,并没有真正涵盖这一点。如果你问他们,导师可能会告诉你他们对正在发生的事情的看法。VHDL通过使所有信号分配无阻塞来避免此问题
module tb();
reg clk1, clk2, clk3;
initial begin
$monitor($time,, "clk1 = %b; clk2 = %b, clk3 = %b", clk1, clk2, clk3);
clk1 = 1'b0;
clk2 = 1'b0;
clk3 = 1'b0;
#100 $finish;
end
always @*
#5 clk1 = ~clk1;
always @*
#5 clk2 <= ~clk2;
always @(clk3)
clk3 <= #5 ~clk3;
endmodule
moduletb();
注册号clk1、clk2、clk3;
初始开始
$monitor($time,,“clk1=%b;clk2=%b,clk3=%b”,clk1,clk2,clk3);
clk1=1'b0;
clk2=1'b0;
clk3=1'b0;
#100美元完成;
结束
始终@*
#5 clk1=~clk1;
总是@*
#5 clk2问题始终是@(*)对写入其中的信号不敏感。所以在您的例子中,always块的隐式敏感度没有“clk”。相反,它对任何信号都不敏感 有一件事:永远不要使用非阻塞分配来生成时钟。它是许多竞争问题的根源。如果我在灵敏度列表中明确添加clk信号,它是否有效?