3
votes

In the test-bench code shown below, I'm observing that the clock signal clk does not toggle as expected. The clock changes from low to high at time 5, but doesn't toggle after that.

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

However, if I remove @* from the always@* statement, the clock toggles every 5ns as expected. My question is why doesn't the process block always@* get triggered after the first change?

Note: I've tested the code in NCSIM and VCS, I don't think this a simulator issue.

3

3 Answers

4
votes

The accepted answer is wrong - the always is initially triggered by the assignment to 0 in the initial block, so you have a perfectly valid question, which is why the always block isn't triggering itself after it ran the first time (and it clearly did run, because clk is set to 1).

Run the code below - you'll see that it works as expected if you change the blocking assignment to a non-blocking one, or if you use an intra-assignment delay instead of your delay control (clk = #5 ~clk). So, this is a scheduling issue. You might intuitively expect that your process would only trigger once, because the eventual blocking assignment and the process evaluation effectively occur in the same delta, so the blocking assignment could potentially be lost. However, I can't see a specific justification in the LRM. The delay control turns into a future inactive event, and the scheduler eventually executes it, creating an update event, which updates clk (you see this happen once). This should then create an evaluation event for the process, because it's sensitive to clk, but it's not doing this. The scheduling section is (very) woolly, and doesn't really cover this. Mentor would probably give you their version of what's going on if you ask them. VHDL avoids this issue by making all signal assignments non-blocking.

   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
votes

clock generators are usually implemented in one of 2 ways:

  1. using always with no sensitivity list, as you already tried:

    always #5 clk = ~clk;
    

the always block without sensitivity list will loop forever and would cause your simulation to hang if it has no #delays inside. Though the latter make it perfect for the clock generator.

  1. use forever loops in your initial block:

    initial begin
        forever
            #5 clk = ~clk;
    end
    

the above code works the same way as the previous always.

1
votes

The problem is always@(*) will not be sensitive to signals written inside it. So in your case, the implicit sensitivity of the always block doesn't have "clk" in it. Rather it is not sensitive to any signal at all.