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

  • Start Here6
  • SystemVerilog Language Foundations35
    • SystemVerilog Data Types
    • Arrays: Packed, Dynamic, Queues & Associative
    • Procedural Code & Scheduling
      • always_comb, always_ff, always_latch
      • Blocking vs Nonblocking Assignments
      • Tasks vs Functions
      • The Event Scheduler & Stratified Regions
      • initial, final & Startup Ordering
      • Loops & Flow Control
    • Operators, Expressions & Width Rules
    • Packages, Typedefs & Compilation
    • Interfaces, Modports & Clocking Blocks
  • Object-Oriented SystemVerilog for Verification35
  • Constraint Randomization — Interview-Critical Deep Dive66
  • SystemVerilog Assertions — Interview-Critical Deep Dive63
  • Functional Coverage in SystemVerilog28
  • Testbench Architecture in SystemVerilog38
  • Advanced Language & Integration30
  • Senior & Interview Preparation34
  • Principal-Level Verification28
Loading lesson

‹Procedural Code & Scheduling
  1. Topics
  2. SystemVerilog
  3. SystemVerilog Language Foundations
  4. Procedural Code & Scheduling
  5. Blocking vs Nonblocking Assignments

Part 1 · Language Foundations · Intermediate

Blocking vs Nonblocking Assignments

Blocking versus nonblocking assignments, the swap classic, shift pipelines and testbench rules.

On this page

    Why this matters

    Two registers were meant to swap on every clock edge, and both ended up holding the same value. The code was right except for one character: = where <= belonged.

    After this lesson you can: predict what blocking and nonblocking assignments do at a clock edge, and choose the right one in RTL and in testbench code.

    Two schedules

    A blocking assignment a = b updates the left side immediately, before the next statement runs. A nonblocking assignment a <= b evaluates the right side now, in the Active region, and commits the left side later, in the NBA region of the same slot.

    That split models a flip-flop. Every clocked process samples pre-edge values and all updates commit together, so process execution order is irrelevant.

    Aspect

    Blocking =

    Nonblocking <=

    Left side updates

    Immediately, in statement order

    In the NBA region, after all sampling

    Across processes

    Result can depend on process order

    Order-independent, every reader sees pre-edge values

    Use for

    Combinational blocks and testbench sequencing

    Every clocked state element

    The swap and the shift register

    Predict first a is 0 and b is 1. At a clock edge one block runs a = b; b = a; and another runs a <= b; b <= a; on its own copy. What does each pair hold afterwards?

    Blocking: both 1, because b = a reads the a that the first line just overwrote. Nonblocking: a is 1 and b is 0, because both right sides were read before either update landed.

    Two registers exchange on a clock edge with no temporary: both right-hand sides sample before either update lands. With blocking assignments the first line destroys the value the second line needs, and both end up holding the old b.

    The same principle pipelines data. Three nonblocking stages form a real 3-stage shift register; with blocking assignments the input would ripple through all three stages in one cycle.

    Watch a against b, then q1 through q3. The pair exchanges every edge while 1s fill the pipe one stage per edge.

    • Slot 0: a is 1 and b is 0 after the first exchange; q1 has the 1 while q2 and q3 are still 0.

    • Slot 1: a is 0 and b is 1; the 1 reaches q2 while q3 is still 0.

    • Slot 2: a is 1 and b is 0; the pipe reads 111 for the first time.

    • Slot 3: a is 0 and b is 1; the pipe holds 111.

    • Slot 4: a is 1 and b is 0; the pipe holds 111.

    • Slot 5: a is 0 and b is 1; the pipe holds 111.

    Rules for RTL and testbenches

    The discipline follows from the semantics. Use nonblocking for every clocked element, blocking inside combinational blocks so intermediate values propagate in order, and never mix the two on the same variable.

    Testbench sequencing defaults to blocking for its software-like order. Synchronous drives at a clock edge still use nonblocking, so the design samples old values exactly like a real upstream flop.

    Common pitfall

    Driving design inputs with blocking assignments right at @(posedge clk) from the testbench is a textbook race. A separate signal per discipline, or nonblocking drives throughout, removes it.

    Interview

    “Swap two registers with no temporary in RTL.”

    Two nonblocking assignments: a <= b; b <= a;. Both sides sample before either commits, so the values exchange.

    Check yourself Three stages write q1 <= d; q2 <= q1; q3 <= q2; with d held at 1. What do the stages read after the second edge?

    q1 and q2 read 1 while q3 still reads 0. Each stage sampled its pre-edge input, so the 1 advances one stage per edge.

    Check yourself A testbench drives data_in with = at one edge and <= at the next. What is wrong with this?

    Two disciplines share one variable. Later statements and the design can see different values depending on process order; one variable keeps one discipline.

    Testbench

    The correct swap, its blocking collapse as a negative check, and the 3-stage pipe, all self-checked.

    swap2.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
    38
    39
    module swap2 (
      input logic clk, rst,
      output logic a, b
    );
      always_ff @(posedge clk) begin
        if (rst) begin a <= 1'b0; b <= 1'b1; end
        else begin
          a <= b;
          b <= a;
        end
      end
    endmodule
    
    module swap2_blocking (
      input logic clk, rst,
      output logic a, b
    );
      always @(posedge clk) begin
        if (rst) begin a = 1'b0; b = 1'b1; end
        else begin
          a = b;
          b = a;
        end
      end
    endmodule
    
    module shift3 (
      input logic clk, rst,
      output logic q1, q2, q3
    );
      always_ff @(posedge clk) begin
        if (rst) begin q1 <= 1'b0; q2 <= 1'b0; q3 <= 1'b0; end
        else begin
          q1 <= 1'b1;
          q2 <= q1;
          q3 <= q2;
        end
      end
    endmodule
    
    Terminal
    PASS: nonblocking swap exchanges each edge and the pipe fills 111 while blocking collapses

    Remember

    • = updates at once, in statement order; <= reads now and updates in the NBA region.

    • Nonblocking makes every flop see pre-edge values, whatever order the blocks run in.

    • Use <= for clocked logic, = for combinational logic, and never both on one variable.

    Rule of thumb: clocked means <=, combinational means =.

    How this was checked

    Run with Verilator 5.048 (--binary --timing) on 2026-10-18; every bench printed the PASS line shown, with no warnings. Icarus 13 (-g2012) runs them too, with the same output.

    Related topics

    • Next: Tasks vs Functions

    Previous

    20 / 363

    Next: Tasks vs Functions

    Up next

    Up nextTasks vs Functions

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The Event Scheduler & Stratified Regions
    • initial, final & Startup Ordering
    • Loops & Flow Control
    clkabq1q2q3
    A 2-flop exchange beside a 3-stage shift pipe