Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
    • Digital Logic for RTL Engineers
    • Number Systems for RTL Engineers
    • Verilog Fundamentals
      • Modules and Ports
      • Wire vs reg
      • assign vs always
      • The Two Process Templates
      • Blocking vs Non-blocking
      • From Code to Hardware
    • Verilog Operators and Types
    • SystemVerilog for RTL
    • Simulation and Testbenches
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Verilog Fundamentals
  1. Topics
  2. RTL Design
  3. RTL Foundations
  4. Verilog Fundamentals
  5. Blocking vs Non-blocking

Part 1 · Foundations · Beginner

Blocking vs Non-blocking

Blocking assignments update immediately and non-blocking assignments update together, as a shift register shows.

On this page

    Why this matters

    A three-stage shift register written with blocking assignments moves the 1 to the last stage in one edge, so it is a wire, not a shift register. With non-blocking assignments it takes three edges.

    After this lesson you can: explain how blocking and non-blocking assignments are scheduled, and say which to use where.

    Blocking and non-blocking in one experiment

    A three-stage shift register chains q1, q2, and q3. One version uses blocking =, and the other uses non-blocking <=.

    A 1 is driven into the input, and the outputs are compared after each edge. The full code sits under Testbench below.

    Shift register with non-blocking assignments versus collapsed structure with blocking assignments.
    With blocking assignments each statement sees the *updated* value of the previous one, so the chain collapses into three flops fed by the same signal.

    Slot k is the picture just after clock edge k, and edge 0 is the first edge, with d still low. The chain has three stages, so a real shift register needs three edges to carry the 1 to q3.

    • Slot 1: d is 1 for the first time at an edge. The blocking version copies it through all three variables inside one edge, so q3_b is 1 at once.

    • Slots 1 to 3: the non-blocking version moves the 1 one stage per edge: q1_n, then q2_n, then q3_n.

    • Slot 3: both versions end at 1, but the blocking one got there two edges earlier, because its three flops collapsed into one.

    How the simulator schedules updates

    A blocking assignment updates its variable immediately. The next statement already sees the new value.

    A non-blocking assignment evaluates its right-hand side when the statement runs and schedules the left-hand update in the NBA region at the same timestamp. With consistent clocked coding and stable inputs, every flop then samples the pre-edge value, and all outputs change together after it.

    Where

    Use

    Why

    Clocked (posedge) blocks

    `<=` non-blocking

    All flops sample old values, then update together, matching real flops and avoiding races between blocks.

    Combinational blocks (@(*))

    `=` blocking

    Later statements should see earlier results, like a chain of gates evaluated in order.

    Never

    Assign the same signal with both = and <=

    Lint flags it and synthesis tools may reject it. The simulated result no longer describes one clear piece of hardware.

    Avoid (style rule)

    Mix = and <= in one block

    Statements in one block run in written order, so this is deterministic. But a blocking temporary in a clocked block must stay local: if another process reads it, the result depends on scheduling and races.

    Common mistakes

    Common pitfall

    Using blocking assignments in a clocked block that communicates with another clocked block creates a race: whether the second block sees the old or new value depends on which process the simulator runs first. It can pass in one simulator and fail in another.

    A race needs competing processes

    blocking_process_race.v
    1
    2
    3
    4
    5
    6
    // bad-example: two processes depend on active-region execution order
    module blocking_process_race (input wire clk, d, output reg q);
      reg shared;
      always @(posedge clk) shared = d;
      always @(posedge clk) q = shared;
    endmodule

    Before edge: shared=0, q=0, d=1

    First process

    Second process

    q after edge

    Writer first

    shared becomes 1

    Reader copies new shared

    1

    Reader first

    Reader copies old shared=0

    Writer then makes shared=1

    0

    Both schedules are permitted; neither is a stable design contract. With shared <= d and q <= shared, both right-hand sides evaluate before these NBA updates, so q takes the old shared=0 in this disciplined example. By contrast, a=d; b=a; in one process always executes in that written order: it deterministically collapses a pipeline, not an interprocess scheduling race. The test below demonstrates that separate, deterministic effect.

    Interview

    Short answer for an interview: “Blocking assignments update immediately and are used for combinational logic. Non-blocking assignments evaluate now and update in the NBA region at the same timestamp, so with consistent coding all flip-flops sample the pre-edge values, and they are used in clocked logic.”

    Check yourself A clocked block contains a <= b; b <= a;. What does it do?

    It swaps a and b every clock edge, because both right-hand sides are evaluated before either update takes effect. With blocking assignments (a = b; b = a;) both variables would end up equal to the old b.

    Testbench

    One testbench runs the same shift register with blocking and non-blocking assignments.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    module tb_blocking;
      logic clk = 0, d = 0;
      logic q1_b, q2_b, q3_b;         // blocking version
      logic q1_n, q2_n, q3_n;         // non-blocking version
      int errors = 0;
    
      always @(posedge clk) begin     // BAD for sequential logic
        q1_b = d;  q2_b = q1_b;  q3_b = q2_b;
      end
    
      always @(posedge clk) begin     // correct
        q1_n <= d; q2_n <= q1_n; q3_n <= q2_n;
      end
    
      always #5 clk = ~clk;
    
      initial begin
        q1_n = 0; q2_n = 0; q3_n = 0;
        #1 d = 1;
    
        @(posedge clk); #1;
        $display("edge 1  blocking=%b%b%b  non-blocking=%b%b%b", q1_b, q2_b, q3_b, q1_n, q2_n, q3_n);
        if ({q1_b, q2_b, q3_b} !== 3'b111) errors++;     // collapsed in ONE edge
        if ({q1_n, q2_n, q3_n} !== 3'b100) errors++;     // shifted one stage
    
        @(posedge clk); #1;
        $display("edge 2  blocking=%b%b%b  non-blocking=%b%b%b", q1_b, q2_b, q3_b, q1_n, q2_n, q3_n);
        if ({q1_n, q2_n, q3_n} !== 3'b110) errors++;
    
        @(posedge clk); #1;
        $display("edge 3  blocking=%b%b%b  non-blocking=%b%b%b", q1_b, q2_b, q3_b, q1_n, q2_n, q3_n);
        if ({q1_n, q2_n, q3_n} !== 3'b111) errors++;
    
        if (errors == 0) $display("PASS: blocking collapses the pipeline; non-blocking shifts");
        $finish;
      end
    endmodule
    Diagram
    edge 1  blocking=111  non-blocking=100
    edge 2  blocking=111  non-blocking=110
    edge 3  blocking=111  non-blocking=111

    Remember

    • A blocking assignment updates now. A non-blocking one reads now and updates in the NBA region of the same timestamp.

    • Use <= in clocked blocks and = in combinational blocks.

    • Blocking assignments between clocked processes make a race: the result depends on process order.

    Rule of thumb: non-blocking in clocked blocks, blocking in combinational ones.

    Keep going

    • Practice: Blocking vs non-blocking in sequential logic

    • Interview: run a mock interview on this topic

    Related topics

    • The two process templates

    • Sequential design

    Previous

    17 / 350

    Next: From Code to Hardware

    Up next

    Up nextFrom Code to Hardware

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Modules and Ports
    • Wire vs reg
    • assign vs always
    clkdq1_nq2_nq3_nq3_b
    One 1 enters the chain at edge 1: the blocking q3_b is already 1 after that edge, while the non-blocking q1_n, q2_n and q3_n become 1 one edge apart