Disable used in a forever loop

Hi,
I have a question regarding the behavior of disable statement in forever loop which I am observing in following code :

DUT:


module forever_cntr (clk, rst, cnt);
  input clk, rst;
  output[3:0] cnt;
  reg[3:0] cnt;
  always @ (posedge clk or posedge rst) begin : block2
    if (rst == 1) begin
      cnt <= 4'b0;
    end
    else begin
      cnt <= 4'b0;
      forever begin : block1
        if (cnt == 3) begin
           disable block1;
         end
        @ (posedge clk) cnt = cnt + 1;
      end
    end
  end
endmodule

TB:

module forever_cntr_tb;
  reg rst, clk;
  wire[3:0] cnt;
  forever_cntr DUT (.clk(clk), .rst(rst), .cnt(cnt));
  initial begin
    clk = 1;
    forever begin
      #5 clk = !clk;
    end
  end
  initial begin
    rst = 0;
    #1 rst = 1;
    #2 rst = 0;
    #2000 rst = 0;
  end
    initial begin
    $monitor("time = %g, clk = %b, rst = %b, cnt = %d", $time, clk, rst, cnt);
  end
 endmodule

When simulation is run, result is
time = 0, clk = 1, rst = 0, cnt = 0
time = 1, clk = 1, rst = 1, cnt = 0
time = 3, clk = 1, rst = 0, cnt = 0
time = 5, clk = 0, rst = 0, cnt = 0
time = 10, clk = 1, rst = 0, cnt = 1
time = 15, clk = 0, rst = 0, cnt = 1
time = 20, clk = 1, rst = 0, cnt = 2
time = 25, clk = 0, rst = 0, cnt = 2
Execution interrupted or reached maximum runtime.
Done

However, if i change the cnt = cnt + 1 statement to non blocking, cnt <= cnt + 1, result is
time = 0, clk = 1, rst = 0, cnt = 0
time = 1, clk = 1, rst = 1, cnt = 0
time = 3, clk = 1, rst = 0, cnt = 0
time = 5, clk = 0, rst = 0, cnt = 0
time = 10, clk = 1, rst = 0, cnt = 1
time = 15, clk = 0, rst = 0, cnt = 1
time = 20, clk = 1, rst = 0, cnt = 2
time = 25, clk = 0, rst = 0, cnt = 2
time = 30, clk = 1, rst = 0, cnt = 3
time = 35, clk = 0, rst = 0, cnt = 3

I am not clear why cnt = 3 is displayed in second case (when I use cnt <= cnt + 1, non-blocking statement. Can someone help to explain this behavior considering scheduling of verilog events.

thanks,
sunil

In reply to puranik.sunil@tcs.com:
The problem is once cnt == 3, your forever statement goes into an infinite no-delay loop. A disable block1 statement means “jump to the end of block1”; it does not get you out of the forever loop. You can see this better if I re-wrote your code t0 this equivalent

forever 
   begin : block1
     if (cnt == 3) 
        begin end // this branch will cause an infinite loop
     else 
        @ (posedge clk) cnt = cnt + 1;
    end

The difference between using a blocking and non-blocking assignment(NBA) is because your test is at the top of the loop, and the assignment is at the bottom of the loop. The is no delay between executing the bottom and top of the loop statements. When you use an NBA, cnt gets scheduled to be updated to 3 at the bottom of the loop, but the test at the top of the loop executes and cnt is still 3. So it waits for one more clock cycle, and then does an NBA to cnt to set it to 4. But then it goes back to the top of the loop, and cnt ==3 and hangs. It never has a chance to complete the assignment to 4.

I don’t think you want a forever loop in the first place.