Tutorial 06 · Verilog Series

Blocking vs Non-Blocking Assignment

The = vs <= distinction is the most common source of bugs for Verilog beginners and a frequent interview topic. Understanding the Verilog event scheduler and the golden rule will save you hours of debugging race conditions.

= (blocking) <= (non-blocking) Race Condition Event Scheduler Shift Register Bug NBA Queue
Blocking = executes sequentially a = b; → a updates NOW. Next statement sees new a. c = a + 1; → uses UPDATED value of a (the old b) Result: a has new value during block ✓ Use in combinational always @(*) Non-Blocking <= schedules updates in NBA queue a <= b; → schedules update. a still holds OLD value. c <= a + 1; → uses OLD value of a (correct!) All updates applied simultaneously at end ✓ Use in sequential always @(posedge clk) Verilog Event Scheduler handles both — they differ in WHEN the update is applied
Blocking (=) updates immediately; non-blocking (<=) schedules updates to the end of the timestep — all flip-flops update simultaneously.

⚡ The Golden Rule

Use = in always @(*) combinational blocks  ·  Use <= in always @(posedge clk) sequential blocks
Never mix them in the same always block.

1. Blocking Assignment (=)

Blocking assignments execute in order, like C code. The next statement in the block sees the updated value.

verilog — blocking in combinational block (correct)
always @(*) begin
    temp = a & b;     // temp updates immediately
    out  = temp | c;  // out sees the new temp — correct
end

The sequential execution of blocking assignments in @(*) is intentional and useful — it lets you use intermediate variables without ambiguity. The final combinational output is purely a function of current inputs.

2. Non-Blocking Assignment (<=)

Non-blocking assignments schedule an update to the NBA (non-blocking assignment update) queue. The RHS is evaluated immediately, but the LHS is not updated until all active events for the current timestep are done.

verilog — non-blocking in sequential block (correct)
always @(posedge clk) begin
    b <= a;    // RHS evaluated: captures current a
    c <= b;    // RHS evaluated: captures current b (OLD value)
    // At end of timestep: b gets old a, c gets old b simultaneously
end

3. The Verilog Event Scheduler

Understanding the simulation scheduler explains why non-blocking works. Within each simulation timestep:

  1. Active region: all blocking = assignments execute; always blocks triggered by events run
  2. NBA region: all pending <= updates are applied simultaneously
  3. Postponed region: $strobe and final monitoring

Because all <= updates happen in the NBA region (after all active events), every flip-flop in a clocked block reads the pre-update values of other flip-flops — exactly how real hardware works. All flip-flops clock simultaneously.

4. Race Condition Example

Two always blocks that share a signal and use blocking assignment can race against each other:

⚠️ RACE CONDITION — blocking in clocked blocks
// Two separate always blocks — order of execution is undefined!
always @(posedge clk) a = b;   // blocking
always @(posedge clk) b = a;   // blocking
// Depending on simulator execution order:
// Option A: a gets old b, b gets new a (already updated)
// Option B: b gets old a, a gets new b (already updated)
// → Simulation result is UNDEFINED and tool-dependent!
✓ CORRECT — non-blocking eliminates the race
always @(posedge clk) a <= b;  // schedule: a ← old b
always @(posedge clk) b <= a;  // schedule: b ← old a
// NBA region applies both simultaneously:
// a gets old b, b gets old a → correct swap, order-independent

5. Shift Register Bug (Classic Interview Question)

This is the most famous Verilog pitfall. Three flip-flops in series — a 3-stage shift register:

⚠️ BUG: blocking = in clocked block
always @(posedge clk) begin
    b = a;   // b gets new a immediately
    c = b;   // c gets NEW b (which is already new a!)
    // Result: both b and c get value of a in ONE clock
    // Simulates as a 1-stage shift, not 3-stage!
end

// Starting: a=1, b=0, c=0
// After clk↑: b=1, c=1 — WRONG! (should be b=1, c=0)
✓ CORRECT: non-blocking <=
always @(posedge clk) begin
    b <= a;  // schedule: b ← old a
    c <= b;  // schedule: c ← old b (not the new b!)
    // NBA region: b gets old a, c gets old b → correct 3-stage shift
end

// Starting: a=1, b=0, c=0
// After clk↑: b=1, c=0 — CORRECT!
Why this matters: The buggy version will pass simple directed tests that only check a few clock cycles, but fail in pipelined designs where the exact delay of each stage matters. It causes simulation/synthesis mismatch — the synthesized circuit is 3 flip-flops, but simulation acts like 1.

6. Variable Swap

Non-blocking makes swapping two flip-flop values elegant — no temporary variable needed:

verilog — swap two registers
// Swap a and b every clock (ping-pong)
always @(posedge clk) begin
    a <= b;  // a gets old b
    b <= a;  // b gets old a → clean swap
end

// With blocking =, you'd need a temp:
// always @(posedge clk) begin
//     temp = a;   // can't do this cleanly with = in seq block
// end

7. Summary Table

FeatureBlocking =Non-Blocking <=
ExecutionImmediate, sequentialScheduled, simultaneous at end of timestep
Next statement seesUpdated valueOld value (from before the always block fired)
Use in combinational @(*)✅ Correct❌ Incorrect (causes simulation issues)
Use in sequential @(posedge clk)❌ Race condition risk✅ Correct
Mix in same always block❌ Never mix = and <= in the same block
ModelsCombinational logic / intermediate varsFlip-flop behavior
Synthesizes toCombinational (in @(*))Flip-flop (in @(posedge clk))

8. Complete Rule Set

  1. Use <= for all assignments in always @(posedge clk) or always @(negedge clk)
  2. Use = for all assignments in always @(*)
  3. Never drive the same signal from two different always blocks
  4. Never mix = and <= in the same always block
  5. Use = freely in initial blocks (simulation-only testbench code)
  6. RHS of <= is always evaluated with the old values — use this to your advantage for clean pipeline and shift register code
Interview tip: If asked "what is the difference between = and <= in Verilog?", describe the shift register example. Then state the golden rule. This demonstrates you understand the hardware semantics, not just the syntax.