FPGA

Blocking vs Non Blocking Verilog

By CourseTron Team ·  1 min read ·  Updated Oct 2026 💬 𝕏 in f
Table of Contents
    ? Print / Save as PDF

    In short: Use non-blocking (<=) in clocked always blocks to model flip-flops, and blocking (=) in combinational blocks — mixing them wrongly causes race conditions and simulation-vs-synthesis mismatches.

    Few topics trip up RTL designers as reliably as the difference between blocking and non-blocking assignments in Verilog. The syntax difference is a single character — = versus <= — but the semantics reach deep into how an event-driven simulator (Synopsys VCS, Cadence Xcelium, Siemens Questa) schedules updates. Get it wrong and your gate-level netlist behaves differently from your RTL, or your testbench passes while the silicon fails. This guide explains the scheduling model and the golden rules used in production design flows.

    Two assignment operators, two intents

    A blocking assignment (a = b;) executes immediately and in order. The statement "blocks" the ones after it until its right-hand side (RHS) is evaluated and its left-hand side (LHS) is updated. It behaves like a sequential statement in C.

    A non-blocking assignment (a <= b;) samples all RHS values at the current time step, then defers the LHS update to the end of the time step. Every non-blocking assignment in a block sees the old values of its inputs, which is exactly how real edge-triggered flip-flops behave: they all sample the data present just before the clock edge.

    Blocking = "compute and update now." Non-blocking = "sample now, update later." That one sentence resolves 90% of beginner confusion.

    The Verilog event scheduler and regions

    The IEEE 1364 (and 1800 for SystemVerilog) scheduling model divides each simulation time step into ordered regions. The two that matter here are the Active region and the NBA (non-blocking assignment) region. Blocking assignments and RHS evaluations happen in the Active region. The LHS updates of non-blocking assignments are queued and applied later, in the NBA region, after every Active event at that time has drained.

    One simulation time stepActive regionblocking =, RHS evalNBA region<= LHS updatesNext timeadvance clockNon-blocking LHS updates wait until every blocking statementat this time has finished. That deferral prevents flip-flopshoot-through and inter-block races.CourseTron · coursetron.com
    How a simulator orders assignment updates within a single time step.

    Why a shift register needs non-blocking

    Consider three flops forming a shift register on posedge clk:

    always @(posedge clk) begin
      q1 <= d;
      q2 <= q1;
      q3 <= q2;
    end

    With non-blocking assignments, all three RHS values are sampled first using the pre-edge values, so data advances one stage per clock — a correct 3-stage shift register. Now swap to blocking:

    always @(posedge clk) begin
      q1 = d;   // q1 updated immediately
      q2 = q1;  // sees the NEW q1
      q3 = q2;  // sees the NEW q2
    end

    Here d races straight through to q3 in a single clock: the block collapses to a single flop feeding two buffers. Simulation shows one flop; synthesis in Synopsys Design Compiler may infer something different depending on optimization, producing a classic RTL-vs-gate mismatch.

    One clock edge, d = 1 and q1 = q2 = q3 = 0 before the edgeNon-blocking: q1 <= d; q2 <= q1q1 after edge1q2 after edge0q3 after edge0Result3-stage shiftBlocking: q1 = d; q2 = q1; ...q1 after edge1q2 after edge1q3 after edge1Resultone flop, collapsedCourseTron · coursetron.com
    Values after one clock edge: non-blocking advances one stage, blocking collapses the chain.

    Why combinational logic needs blocking

    For pure combinational logic you want the intermediate values to propagate within the same evaluation, so blocking is correct:

    always @(*) begin
      sum   = a ^ b ^ cin;
      carry = (a & b) | (cin & (a ^ b));
    end

    If you used non-blocking here and a downstream statement depended on an earlier result, it would read the stale value and require an extra delta cycle to settle — harmless for a simple adder but a frequent source of simulation slowdowns and subtle glitches in larger combinational chains. For more on structuring these processes, see our Verilog always block guide.

    The animated race: blocking vs non-blocking

    Non-blocking: one stage advance per clock edgeq1q2q3dclk edge 1clk edge 2clk edge 3CourseTron · coursetron.com
    With <= the bit moves exactly one flop per clock — the behaviour of real hardware.

    Golden rules (what senior designers enforce)

    • Sequential logic (always @(posedge clk)): use only non-blocking <=.
    • Combinational logic (always @(*)): use only blocking =.
    • Never mix blocking and non-blocking to the same variable in one block.
    • Do not drive the same variable from more than one always block.
    • Latch/level-sensitive logic follows the combinational rule — blocking.

    These five rules come straight from Cliff Cummings' well-known SNUG guidance and are baked into most corporate RTL linting decks (Siemens, Synopsys SpyGlass). Teams building verified flows — like the design-services group at Avecas — treat a violation as a blocking lint error, not a warning.

    AspectBlocking =Non-blocking <=
    Update timingImmediate, in orderDeferred to NBA region
    RHS samplingCurrent (possibly updated)Pre-edge values
    ModelsCombinational / latchEdge-triggered flop
    Typical bugAccidental flop collapseExtra delta-cycle delay

    A single = inside a clocked block is one of the most common causes of a "passes in sim, fails on FPGA" bug report filed against junior engineers.

    Want to drill these rules with real waveform labs on Questa and VCS? Our CourseTron RTL & FPGA track walks you from assignment semantics to timing closure with hands-on projects.

    Reading waveforms to diagnose it

    When you suspect a blocking/non-blocking bug, dump VCD or FSDB and look at the edge. If a register value changes on the same edge as its input and skips the expected one-cycle latency, you almost certainly used blocking where you needed non-blocking. For deeper debug technique, pair this with our Verilog testbench essentials.

    FAQ

    Can I use non-blocking in a combinational always block?

    Functionally it can produce the right result after extra delta cycles, but it is bad practice, slows simulation, and confuses linters. Stick to blocking for combinational logic.

    Why do all my flops sample old values with non-blocking?

    Because every RHS is evaluated in the Active region before any LHS update is applied in the NBA region. All non-blocking statements therefore see the values present at the start of the time step — exactly like hardware flip-flops sampling just before the clock edge.

    Is this the same in SystemVerilog?

    Yes. IEEE 1800 keeps the same Active/NBA scheduling. SystemVerilog adds always_ff and always_comb, which let tools enforce the golden rules automatically — a strong reason to use them.

    Does the single-character difference really matter for synthesis?

    Absolutely. The operator changes which logic the tool infers. A blocking assignment in a clocked block can collapse flops or create unintended combinational paths, yielding a netlist that no longer matches your intended behaviour.

    Advertisement