在下面显示的测试平台代码中,我观察到时钟信号clk
没有按预期切换。
时钟在时间5从低到高变化,但在此之后不会切换。
module tb();
reg clk;
initial begin
clk = 'b0;
#100 $finish;
end
always@* #5 clk = ~clk;
endmodule
但是,如果我从@*
语句中删除always@*
,则时钟会按预期每5ns切换一次。我的问题是为什么在第一次更改后没有触发流程块always@*
?
注意:我已经在NCSIM和VCS中测试了代码,我不认为这是模拟器问题。
答案 0 :(得分:3)
接受的答案是错误的 - always
最初是由initial
块中的0分配触发的,因此您有一个完全有效的问题,这就是always
块的原因它在第一次运行后没有触发(它显然已经运行,因为clk
设置为1)。
运行下面的代码 - 如果您将阻止分配更改为非阻塞分配,或者如果使用分配内延迟而不是延迟控制({{1),您将看到它按预期工作}})。所以,这是一个调度问题。您可能直观地期望您的流程只会触发一次,因为最终的阻塞分配和流程评估实际上在同一个增量中发生,因此阻塞分配可能会丢失。但是,我无法在LRM中看到具体的理由。延迟控制变为未来的非活动事件,调度程序最终执行它,创建更新事件,更新clk = #5 ~clk
(您看到这种情况发生一次)。然后,这应该为流程创建评估事件,因为它对clk
敏感,但它没有这样做。调度部分(非常)粗糙,并没有真正涵盖这一点。如果你问他们,导师可能会给你他们的版本。 VHDL通过使所有信号分配无阻塞来避免此问题。
clk
答案 1 :(得分:2)
时钟发生器通常以两种方式之一实现:
使用没有敏感列表的always
,正如您已经尝试过的那样:
always #5 clk = ~clk;
没有敏感性列表的always
块将永远循环,并且如果内部没有#delays,则会导致模拟挂起。虽然后者使它非常适合时钟发生器。
在initial
块中使用forever循环:
initial begin
forever
#5 clk = ~clk;
end
上述代码的工作方式与之前的always
相同。
答案 2 :(得分:1)
问题始终是@(*)对其中写入的信号不敏感。所以在你的情况下,always块的隐含敏感性中没有“clk”。相反,它根本不对任何信号敏感。