Verilog:总是@ *阻止不被触发

问题描述 投票:2回答:3

在下面显示的测试平台代码中,我观察到时钟信号clk没有按预期切换。时钟在时间5从低到高变化,但在此之后不会切换。

module tb();
  reg clk;
  initial begin
     clk = 'b0;
     #100 $finish;
  end
  always@* #5 clk = ~clk;
endmodule

但是,如果我从@*语句中删除always@*,则时钟会按预期每5ns切换一次。我的问题是为什么在第一次更改后进程阻止always@*被触发?

注意:我已经在NCSIM和VCS中测试了代码,我不认为这是一个模拟器问题。

verilog system-verilog
3个回答
3
投票

接受的答案是错误的 - always最初是由initial区块中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

2
投票

时钟发生器通常以两种方式之一实现:

  1. 使用没有灵敏度列表的always,正如您已经尝试过的那样: always #5 clk = ~clk;

没有灵敏度列表的always块将永远循环,如果内部没有#delays,则会导致模拟挂起。虽然后者使它非常适合时钟发生器。

  1. 在你的initial块中使用forever循环: initial begin forever #5 clk = ~clk; end

上面的代码与上一个always的工作方式相同。


1
投票

问题是@(*)总是对写在其中的信号不敏感。所以在你的情况下,always块的隐含敏感性中没有“clk”。相反,它根本不对任何信号敏感。

© www.soinside.com 2019 - 2024. All rights reserved.