Assignment Statements

Blocking Assignment

A blocking assignment evaluates the expression on its right hand side and then immediately assigns the value to the variable on its left hand side:

a = b + c;

It is also possible to add delay to a blocking assignment. For example:

a = #10 b + c;

In this case, the expression on the right hand side is evaluated and the value is held for 10 units of time. During this time, the execution of the code is blocked in the middle of the assignment statement. After the 10 units of time, the value is stored in the variable on the left

Nonblocking Assignment

A nonblocking assignment evaluates the expression on its right hand side without immediately assigning the value to the variable on the left. Instead the value is cached and execution is allowed to continue onto the next statement without performing the assignment. The assignment is deferred until the next blocking statement is encountered. In the example below, on the positive edge of clk the right-hand side of the first nonblocking assignment is evaluated and the value cached without changing a. Then the right-hand side of the second nonblocking assignment statement is evaluated is also cached without changing b. Execution continues until it returns to the event statement, once there the execution of the process blocks until the next positive edge of the clk. Just before the process blocks, the cached values finally assigned to the target variables. In this way, the following code swaps the values in a and b on every positive edge of clk:

always @(posedge clk) begin
   a <= b;
   b <= a;

Adding delay to nonblocking assignments is done as follows:

always @(*)
    a <= #10 b + c;

Using nonblocking assignment with delay in this manner is a way of implementing transport delay, as shown below:


Blocking versus Nonblocking Assignment

Nonblocking statements allow you to schedule assignments without blocking the procedural flow. You can use the nonblocking procedural statement whenever you want to make several register assignments within the same time step without regard to order or dependence upon each other. It means that nonblocking statements resemble actual hardware more than blocking assignments.

Generally you would use nonblocking assignment whenever assigning to variables that are shared between multiple initial or always processes if the statements that access the variable could execute at the same time. Doing so resolves race conditions.

Blocking assignment is used to assign to temporary variables when breaking up large calculations into multiple assignment statements. For example:

always @(posedge clk) begin
   t1 = b + c;
   t2 = d + e;
   a <= t1*t2;

Procedural Continuous Assignment

Two types of continuous assignment are available in initial and always processes: assign and force.

The target of an assign statement must be a register or a concatenation of registers. The value is continuously driven onto its target and that value takes priority over values assigned in procedural assignments. Once a value is assigned with an assign statement, it can only be changed with another assign statement or with a force statement. Execution of deassign releases the continuous assignment, meaning that the value of the register can once again be changed with procedural assignments. For example, the following implements a D-type flip-flop with set and reset:

module dff(q, qb, c, d, r, s);
output q, qb;
input c, d, r, s;
reg q;

assign qb = ~q;

always @(posedge c) q <= d;

always @(r or s) begin
   if (r)
      assign q=0;
   else if (s)
      assign q=1;
      deassign q;

Assign statements are used to implement set and reset because they dominate over the non-blocking assignment used to update q upon positive edges of the clock c. If instead a simple procedural assignment were used instead, then a positive edge on the clock could change q even if r or s were high.

A force statement is similar to assign, except that it can be applied to both registers and nets. It overrides all other assignments until the release statement is executed. Force is often used in testbenches to eliminate initial x-values in the DUT or to place it in a particular state. For example:

module dff_tb;
reg c = 0, d = 1, r = 0, s = 0;
wire q, qb;

dff FF1 (q, qb, c, d, r, s);

initial begin
    #1 force FF1.q = 0;
    #1 release FF1.q;
    #1 c = 1;
    #1 $strobe(q ? "pass" : "FAIL");