REASON FOR TIME DELAY

module adder(a,b,c);
input [15:0]a;
input [15:0]b;
output [16:0]c;
assign c = a + b;
endmodule


`include "adder.v"
module top;
  reg [15:0]a;
  reg [15:0]b;
  wire [16:0]c;
  adder DUT(a,b,c);
  initial
  //begin
    repeat(5)
    begin
      a = $random;
      b = $random;
      #10;
      if(a+b != c)
        $display("THE ADDER'S FUNCTIONALITY IS NOT CORRECT");
      else
        $display("THE ADDER'S FUNCTIONALITY IS CORRECT");
    end
  //end
endmodule

I want to know the reason why my code works as expected only if the #10 is present.

In reply to Ravi007:

With no delay in your repeat loop, you have a zero-delay race condition - either branch could be taken. That is because an assign statement is a concurrent process, and the order of execution between independent processes is indeterminate.

Normally, most event driven simulators execute a single process until that process hits a blocking statement before switching to another process. So all 5 iterations of the repeat loop could execute before c gets updated. But some simulators optimize continuous assignments so that c updates immediately as soon as a and b change.

In reply to Ravi007:

a <= $random;
b <= $random;

could help break race, as this is in NBA region and assigns in active region.
works in VCS, but that is not a proof there is no race - could be simulator specific…

In reply to ssureshg_:
You still need a delay in the repeat loop. Otherwise the values of a, b, and c will all be unknown at the time the if expression evaluates.

In reply to dave_59:

Hello Dave/Suresh/Ravi,
Thank you for explanation.
Do you have a consolidated example, where each single action would describe relevant event region in log file or through comment, actions may include sinlge action from every event region(such as always, initial, #, =, <=, assertion, program, etc,.)

May be, do you have a documentation which depicts with a figure , relevant actions for each event region? along with its consolidated example?

In reply to W I Master:

google Clifford Cummings paper on
“SystemVerilog Event Regions,Race Avoidance & Guidelines”
good place to start.

also you can enable delta cycles in your simulator to see sequence of events in wave…

In reply to W I Master:

I believe you need a good understanding of the active, inactive, and NBA regions before trying to understand the other regions. You do not need to be aware of the other regions for most of the other code you write.

In the code shown below, all statements execute in an active region. Statements schedule future events for the current region, or the inactive, or NBA regions. When its time to execute another region, that region becomes the active region, and process repeats itself.

module top;
   bit a,b,c;
/*
   always @(a) $display("a changed ",a); 
   always @(b) $display("b changed ",b);
   always @(c) $display("c changed ",c);
*/
   always begin
      $display("begin of always block a");
      @(a) $display("a changed ",a);
   end
   always begin
      $display("begin of always block b");
      @(b) $display("a changed ",b);
   end
   always begin
      $display("begin of always block c");
      @(c) $display("a changed ",c);
   end
   
   initial begin
      $display("begin of initial block");
      $display("First active region");
      $display("blocking assignment");
      a = 1;
      $display("non-blocking assignment");
      b <= 1;
      $display("inactive delay statement");
      #0
      $display("second active region");
      $display("blocking assignment");
	c = 1;
      $display("inactive delay statement");
      #0
      $display("third active region");
      $display("end of initial block");
   end
endmodule

All three always blocks and the initial block start as 4 processes in the first active region. The starting order of blocks is indeterminate.

The first active region continues until all four processes have blocked or terminated. When the blocking assignment is made to a, the always @(a) block could resume at any time while the initial block is still executing statements in the first active region. But it must execute before the #0 resumes, starting the second active region. The non-blocking assignment executes in the first active region and schedules an NBA update to b.

When the blocking assignment to c is made in the second active region, the always @(c) block must execute within the current active region. Again, the ordering of statement execution of parallel processes within the same active region is indeterminate.

Then, the initial block process terminates in the third active region. All three always blocks are suspended, so there a re no more active, or inactive events scheduled. So now the NBA update to be executes in the fourth active region, causing the always @(b) block to resume. It executes its display statement and blocks waiting for another change on b.

Finally, all blocks are suspended with no other events to become active, so the simulation terminates.