This post is about a generally seen practice in any testbench driver. Ever thought that why it is better to use Non-Blocking Assignments (NBA’s) in driver? Let’s see what difference does it create.
As we know that every simulation in Verilog/SV executes according to a pre-defined set of steps known as stratified event queues. These steps are repeated for each an every entity and every time stamp. Let’s first understand the term known as simulation time and time stamp/time slot.
The term simulation time is used to refer to the time value maintained by the simulator to model the actual time it would take for the system description being simulated. The term time is used interchangeably with simulation time.
A time slot encompasses all simulation activity that is processed in the event regions for each simulation time.
Following are the event regions that are executed in each timestamp:
Now let’s consider a D flipflop made using NBA’s and a driver class driving the stimulus. The overall architecture in the code below is as follows:
module dff(input D, input clk, input rst, output reg Q);
always @(posedge clk or negedge rst) begin
end else begin
Also consider the driver part as follows:
interface interfc(input clk);
virtual interfc intf;
intf.d = 0;
#1 intf.rst = 1;
#1 intf.rst = 0;
#1 intf.rst = 1;
intf.d <= $random; // Why use NBA over here?
And the top module that instantiates everything:
always #5 clk = ~clk;
clk = 0;
interfc intf (clk);
dr = new;
dr.intf = intf;
Please remember that all the blocking assignments and the RHS of NBA of modules executes in Active region.
In the given example, the RTL assignment Q<=D evaluates the RHS (i.e. the value of D) in Active region of module and schedules that assignment for NBA region. In the same region, d=$random also gets executed. So there is a race condition that which statement is executed first.
- If Q<=D executes first then Q will be scheduled to get previous value of D in the NBA region of same time slot. (No issues 🙂 )
- If d=$random executes first then the Q<=D gets updated value of D and Q will be scheduled to get updated value in NBA region of same time slot. (Big Problem!! 😦 )
Waveforms for Blocking assignments:
As we can see, while using blocking assignments to drive D, there happens a race condition between the code in testbench module and dff module. The value of Q is updated on the same clock pulse when D is updated. Henceforth the concept of flip-flop is compromised even though the RTL code seems to be correct!
Now, in order to tackle the situation, we use NBA while driving the stimulus.
By using NBA’s, we minimize the race condition between the TB and RTL. Here, it becomes certain that Q<=D is scheduling previous value of D in the Active region. Also, in the NBA region, the previous value of D is assigned to Q and D gets a new/updated random value.
Waveforms using Non-Blocking assignments:
Thus, using NBA’s, the actual intent of flip-flop is simulated correctly.
Using NBA’s is a good practice and simplest solution. There can be some alternatives to this:
- Use program block and drive everything in Reactive region set. This is not preferred option since in UVM based testbench, we may use module block as well.
- Use clocking blocks in interface. I personally don’t prefer clocking blocks due to complexity in understanding the wavedumps.
Note that NBA’s only minimizes the races, and it depends on the code about eliminiting races completely. The sample code is available on EDAPlayground here. Hope that the mystery of using NBA’s in drivers is now unleashed. Feel free to post in the comments section.