Compared to the conventional simualtion that we see in procedural program execution lilke C/C++, HDL simulators exist to model a real world hardware circuit. This means that the programming language needed constructs which enabled scheduling value assignments and statement execution. Hence the verilog regions and the non blocking assignment constructs were introduced.
One key aspect that must be remembered in case of non blocking assignments is that, the RHS part of the assignment is run and evaluated but never assigned immideately. Instead, this assignment is scheduled to happen in the NBA region. You can assume the RHS is assigned to a temp variable which is the same type as the actual LHS variable. Then, later in the NBA region, this temp variable is assigned to the actual LHS variable.
Conside the following simple NBA assignment.
module top; integer a; initial begin a <= 100; end endmodule
The simulator internally simplifies this in this manner ( we will not see it, but this is something the simulator will do internally )
module top; integer a; initial begin a <= 100; // No changes take place in "a" /* a_temp = 100; // Schedule this to execute in NBA | this is internally done my the simulator */ end /* NBA Region Code Execution ------------------------- a = a_temp; */ endmodule
LHS <= RHS
Consider this slightly more complex example and understand how the verilog regions and NBA scheduling togather work.
module top; integer a,b; initial begin a = 1; b = 2; a <= 3; b <= a; a = b; b <= a + b; a = 5; b = 6; end endmodule
This can be simplified in the following manner to better understand.
module top; integer a,b; initial begin a = 1; // a updates to 1 in Active Region b = 2; // b updates to 2 in Active Region a <= 3; // a_temp_1 = 3 updates in Active Region | a = a_temp_1 is scheduled into NBA Region b <= a; // b_temp_1 = a ( a is 1 right now in Active Region ) updates in Active Region | b = b_temp_1 is scheduled into NBA Region a = b; // a updates to 2 ( since b is 2 right now in Active Region ) b <= a + b; // b_temp_2 = a + b ( 2 + 2 ) | b = b_temp_2 is scheduled into NBA Region a = 5; // a updates to 5 in Active Region b = 6; // b updates to 6 in Active Region end /* NBA Region Code Execution ( based on the scheduled order ) ---------------------------------------------------------- a = a_temp_1; // a_temp_1 is 3 b = b_temp_1; // b_temp_1 is 1 b = b_temp_2; // b_temp_2 is 4 // The above statements become a = 3; b = 1; b = 4; // After executing these in order, by the end of NBA, a is 3 and b is 4 ( you can check this in postponed region using $strobe ) */ initial begin $strobe( "a : %0d, b : %0d", a, b ); end endmodule
module top; integer a,b; initial begin a = 100; b <= 10; a = 50; end endmodule
module top; integer a,b; initial begin a = 100; b = 200; a <= 10; b <= 20; a <= b; b = 50; end endmodule
module top; integer a,b,c,d; initial begin a = 100; b = 200; c <= 0; a <= 10; b <= 20; a <= b; b = 50; end initial begin #0; b <= a; a <= b; a <= 100; a = 20; b = 300; end endmodule
module top; integer a = 100, b = 200; initial begin $display( "Before -> a : %d, b : %d", a, b ); a <= b; b <= a; $display( "After -> a : %d, b : %d", a, b ); end endmodule