In SystemVerilog, assignment statements are essential for defining the behavior of variables in a procedural block. There are two main types of assignments: blocking assignments and non-blocking assignments. These two types control the execution of statements differently, which can lead to varying results in simulation. Let’s take a closer look at both.
What is Blocking Assignment?
In SystemVerilog, blocking assignments are made using the =
operator. When using blocking assignments, the next statement in a procedural block cannot execute until the current statement finishes. This means that each statement runs sequentially, one after another, in the order it is written.
Blocking Assignment Example:
module tb;
reg [7:0] a, b, c, d, e;
initial begin
a = 8'hDA;
$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
b = 8'hF1;
$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
c = 8'h30;
$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
end
initial begin
d = 8'hAA;
$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
e = 8'h55;
$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
end
endmodule
Simulation Log for Blocking Assignment:
ncsim> run
[0] a=0xda b=0xx c=0xx
[0] a=0xda b=0xf1 c=0xx
[0] a=0xda b=0xf1 c=0x30
[0] d=0xaa e=0xx
[0] d=0xaa e=0x55
ncsim: *W,RNQUIE: Simulation is complete.
How Blocking Assignments Work
In this example, two initial
blocks run in parallel when the simulation starts. Within each block, statements execute sequentially, meaning each statement waits for the previous one to finish.
For example:
- First, variable
a
is assigned8'hDA
. - Then, the
display
statement prints the current values ofa
,b
, andc
. - Next, the
b
variable is assigned8'hF1
, followed by another display statement.
Notice that in the first display output, b
and c
are still unassigned (0x
), because the assignment statements for b
and c
have not been executed yet.
What is Non-Blocking Assignment?
In contrast, non-blocking assignments use the <=
operator. This type of assignment allows multiple statements to be executed without waiting for the current one to finish. The right-hand side (RHS) value of the assignment is captured at the current time step and assigned to the left-hand side (LHS) variable only at the end of the time step.
Non-Blocking Assignment Example:
module tb;
reg [7:0] a, b, c, d, e;
initial begin
a <= 8'hDA;
$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
b <= 8'hF1;
$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
c <= 8'h30;
$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
end
initial begin
d <= 8'hAA;
$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
e <= 8'h55;
$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
end
endmodule
Simulation Log for Non-Blocking Assignment:
ncsim> run
[0] a=0xx b=0xx c=0xx
[0] a=0xx b=0xx c=0xx
[0] a=0xx b=0xx c=0xx
[0] d=0xx e=0xx
[0] d=0xx e=0xx
ncsim: *W,RNQUIE: Simulation is complete.
How Non-Blocking Assignments Work
In this case:
- When
a <= 8'hDA
is executed, the RHS value (8'hDA
) is noted but not immediately assigned. - The
display
statement printsa=0x
because the assignment toa
has not yet taken place. - Similarly, for
b
andc
, their RHS values are noted, but the assignments only happen at the end of the time step.
Blocking vs Non-Blocking: Key Differences
Feature | Blocking Assignment (= ) | Non-Blocking Assignment (<= ) |
---|---|---|
Execution Order | Sequential execution (one after another) | Parallel execution (does not block) |
RHS Assignment Timing | Assigned immediately | Assigned at the end of the time step |
Use in Sequential Logic | Suitable for simple sequential operations | Suitable for clocked processes and pipelines |
Simulation Output Timing | Variables are updated instantly in the order they are written | Variables are updated only at the end of the time step |
Impact on Parallel Execution | Blocks parallel execution | Allows parallel execution without blocking |
Example with Delays in Blocking Assignment
In the next example, we add some delays in the blocking assignment to see how it behaves in simulation.
module tb;
reg [7:0] a, b, c, d, e;
initial begin
a = 8'hDA;
$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
#10 b = 8'hF1;
$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
c = 8'h30;
$display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
end
initial begin
#5 d = 8'hAA;
$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
#5 e = 8'h55;
$display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
end
endmodule
Simulation Log with Delays:
ncsim> run
[0] a=0xda b=0xx c=0xx
[5] d=0xaa e=0xx
[10] a=0xda b=0xf1 c=0xx
[10] a=0xda b=0xf1 c=0x30
[10] d=0xaa e=0x55
ncsim: *W,RNQUIE: Simulation is complete.
Conclusion: When to Use Blocking or Non-Blocking Assignments?
- Blocking assignments are useful when you need operations to execute sequentially.
- Non-blocking assignments are ideal when you want to allow parallel execution or when you’re working with clocked processes.
By understanding the differences between these two types of assignments, you can control how your simulation behaves, ensuring that your designs operate as intended.