Logo
All chapters
Volume II: Digital Logic  ›  Register Transfer Level Design

Race-Free Design (Software Race Conditions)

Why blocking vs non-blocking assignment order in HDL can cause simulation races — and how to avoid them.

PrevDesign with Multiplexers
NextLatch-Free Design

Description

A software race in HDL happens when the simulated result depends on the order procedural assignments execute. The fix is disciplined assignment: non-blocking (<=) for sequential (clocked) logic and blocking (=) for combinational logic, so updates are deterministic and simulation matches synthesis.

  • Blocking (=) executes immediately, affecting later statements in the block.
  • If two clocked regs use blocking and read each other, the result depends on order.
  • Non-blocking (<=) samples RHS first, updates all at edge end — order-independent.
  • Mixing them in one block creates ambiguous behavior.
  • Sim may differ from synthesized hardware.
  • Sequential (posedge) blocks: non-blocking <= only.
  • Combinational (@*) blocks: blocking = only.
  • Don't assign the same variable in two blocks.
  • Keep next-state logic separate.
  • These rules make behavior deterministic.

At a glance

What

Order-dependent, nondeterministic behavior from mixing assignment types.

Why

Races cause sim/synthesis mismatch and intermittent bugs.

How

Non-blocking for clocked logic, blocking for combinational; never mix in one block.

Where

All sequential HDL.

When

Whenever multiple registers update on the same edge.

Think of it like…

Blocking is people updating a shared whiteboard one-by-one (order matters); non-blocking is everyone writing on sticky notes, then posting simultaneously (order-proof).

The race

  • Blocking (=) executes immediately, affecting later statements in the block.
  • If two clocked regs use blocking and read each other, the result depends on order.
  • Non-blocking (<=) samples RHS first, updates all at edge end — order-independent.
  • Mixing them in one block creates ambiguous behavior.
  • Sim may differ from synthesized hardware.

The rules

  • Sequential (posedge) blocks: non-blocking <= only.
  • Combinational (@*) blocks: blocking = only.
  • Don't assign the same variable in two blocks.
  • Keep next-state logic separate.
  • These rules make behavior deterministic.

Assignment discipline

BlockUse
posedge clknon-blocking <=
@(*) combblocking =
mixedAVOID

HDL — Verilog · VHDL · SystemVerilog

// CORRECT (non-blocking): true swap
always @(posedge clk) begin a <= b; b <= a; end
// WRONG (blocking): both end up = b
// always @(posedge clk) begin a = b; b = a; end

Right vs wrong: swap two registers on a clock edge.

Real-world applications

All RTLPipelinesShift/swap logic

The 5 Whys

  1. 1

    Why races happen? Order-dependent blocking updates.

  2. 2

    Why non-blocking for clocked? Simultaneous, order-proof updates.

  3. 3

    Why blocking for comb? Matches dataflow evaluation.

  4. 4

    Why not mix? Ambiguous, mismatched behavior.

  5. 5

    Root cause: matching assignment type to logic type makes results deterministic.

Cheat sheet

Working principle

  • Non-blocking for clocked logic, blocking for combinational; never mix in one block.
  • Order-dependent, nondeterministic behavior from mixing assignment types.

Formulas & Boolean expressions

  • Blocking (=) executes immediately, affecting later statements in the block.
  • Non-blocking (<=) samples RHS first, updates all at edge end — order-independent.
  • Sequential (posedge) blocks: non-blocking <= only.
  • Combinational (@*) blocks: blocking = only.
  • posedge clk = non-blocking <=
  • @(*) comb = blocking =
  • mixed = AVOID

Key facts

  • Blocking (=) executes immediately, affecting later statements in the block.
  • Sequential (posedge) blocks: non-blocking <= only.

Why it exists

  • Root cause: matching assignment type to logic type makes results deterministic.
PrevDesign with Multiplexers
NextLatch-Free Design