Verilog inter vs intra delay

I have a fundamental verilog event region question that I want clarification on.

The following piece of code (#1) results in the simulator hanging :

module top();
  
  reg clk;

  always clk <= #5 ~clk;
  
  initial begin
    clk = 0;
    $monitor($time, " Monitor clk=%0d", clk);

    #50;
    $finish;
  end

endmodule // top

However, if I change the delay to be an inter-assignment delay, I get a successful clock generation. What gives ?

module top(); //Successful clock generation   
  
  reg clk;

  always #5 clk <= ~clk;
  
  initial begin
    clk = 0;
    $monitor($time, " Monitor clk=%0d", clk);

    #50;
    $finish;
  end

endmodule // top

In reply to DVJoe:
Hi,

You can generate clock with an intra-assignment delay with some active event as shown below.


module top();
 
  reg clk;
 
  always @(clk)
     clk <= #5 ~clk;
 
  initial begin
    clk = 0;
    $monitor($time, " Monitor clk=%0d", clk);
 
    #50;
    $finish;
  end
 
endmodule // top

Putta Satish

In reply to puttasatish:

Non-blocking assignments is not a good way to write clock generator—you get extra events, and you have a potential race condition. If the initial starts executing before the always, the @(clk) will hang.

DVJoe, your first example hangs at time 0 because you have an always construct with no blocking statements. It goes into an infinite because time never has a chance to advance.

Your second always construct has a simple procedural blocking delay. It is not an intra-assignment delay. Time must advance by 5 for each loop of the always. The non-blocking assignment (NBA) is superfluous. Use a blocking assignment

always #5 clk = !clk;

always clk = #5 !clk; // this is intra-assigment (blocking) delay