0
0
Verilogprogramming~15 mins

When to use non-blocking (sequential) in Verilog - Deep Dive

Choose your learning style9 modes available
Overview - When to use non-blocking (sequential)
What is it?
Non-blocking assignments in Verilog use the '<=' operator to update variables in a way that all right-hand side expressions are evaluated before any left-hand side updates happen. This means changes appear simultaneously at the end of a time step, making them ideal for modeling sequential logic like flip-flops. Unlike blocking assignments, which update immediately and in order, non-blocking assignments help avoid unintended dependencies in clocked processes.
Why it matters
Without non-blocking assignments, modeling sequential circuits can cause simulation mismatches and race conditions because variables update immediately and affect subsequent statements in the same time step. This can lead to incorrect hardware behavior and bugs that are hard to find. Using non-blocking assignments ensures that all registers update together, matching real hardware and making designs reliable and predictable.
Where it fits
Before learning non-blocking assignments, you should understand basic Verilog syntax, blocking assignments, and combinational logic modeling. After mastering non-blocking assignments, you can learn about clocking blocks, timing controls, and advanced sequential design techniques like pipelining and FSMs.
Mental Model
Core Idea
Non-blocking assignments update all variables simultaneously at the end of a time step, modeling hardware registers that change together on a clock edge.
Think of it like...
Imagine a group of friends taking a photo together: everyone poses first, then the camera clicks capturing all at once. Non-blocking assignments are like that photo click—everyone updates their state simultaneously, not one after another.
┌───────────────┐
│ Evaluate RHS  │
│ (read old    │
│ values first) │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Schedule LHS  │
│ updates for   │
│ end of time   │
│ step          │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Update all    │
│ LHS together  │
│ simultaneously│
└───────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding Blocking Assignments
🤔
Concept: Introduce blocking assignments and how they update variables immediately in order.
In Verilog, blocking assignments use '=' and update the left variable immediately. For example: reg a, b; always @(*) begin a = 1'b0; b = a; end Here, b gets the new value of a right away, so b becomes 0 immediately.
Result
b becomes 0 immediately after a is assigned 0.
Understanding blocking assignments shows how immediate updates can cause sequential statements to depend on each other's new values within the same time step.
2
FoundationBasics of Sequential Logic in Verilog
🤔
Concept: Explain how sequential logic uses clock edges and registers to store values.
Sequential logic updates values only on clock edges, like flip-flops storing bits. For example: always @(posedge clk) begin q <= d; end This means q takes the value of d only when the clock rises.
Result
q updates to d's value at the rising edge of clk.
Knowing that sequential logic updates on clock edges helps understand why simultaneous updates are needed to model hardware registers correctly.
3
IntermediateNon-blocking Assignments Syntax and Behavior
🤔
Concept: Introduce non-blocking assignments and how they defer updates until the end of the time step.
Non-blocking assignments use '<=' and schedule updates to happen after all right-hand sides are evaluated. For example: reg a, b; always @(posedge clk) begin a <= b; b <= a; end Here, a and b swap values simultaneously on the clock edge.
Result
a and b exchange their old values simultaneously at the clock edge.
Understanding that non-blocking assignments delay updates prevents unintended sequential dependencies and models hardware registers accurately.
4
IntermediateWhy Non-blocking Prevents Race Conditions
🤔Before reading on: do you think blocking or non-blocking assignments better prevent race conditions in sequential logic? Commit to your answer.
Concept: Explain how non-blocking assignments avoid race conditions by updating all registers together.
With blocking assignments, variables update immediately, so later statements see new values, causing races. Non-blocking assignments evaluate all right sides first, then update left sides together, so no statement sees partially updated data.
Result
Sequential logic behaves predictably without race conditions or glitches.
Knowing how non-blocking assignments avoid races helps prevent subtle bugs in clocked designs.
5
IntermediateCommon Mistakes Using Blocking in Sequential Logic
🤔Before reading on: do you think using blocking assignments inside clocked always blocks is good practice? Commit to your answer.
Concept: Show why blocking assignments inside clocked blocks cause simulation mismatches and incorrect hardware modeling.
Example: always @(posedge clk) begin a = b; b = a; end Here, b gets the new value of a immediately, so both a and b end up the same, not swapping as intended.
Result
Simulation shows incorrect behavior; hardware won't match simulation.
Recognizing this mistake helps avoid simulation-hardware mismatches and ensures correct sequential design.
6
AdvancedWhen to Use Non-blocking vs Blocking Assignments
🤔Before reading on: do you think non-blocking assignments should be used for combinational logic? Commit to your answer.
Concept: Clarify the proper contexts for non-blocking (sequential) and blocking (combinational) assignments.
Use non-blocking assignments inside clocked always blocks to model registers and flip-flops. Use blocking assignments in combinational always blocks to model logic that updates immediately. Mixing them incorrectly can cause simulation mismatches and hardware bugs.
Result
Clear separation of combinational and sequential logic with correct simulation and synthesis.
Understanding when to use each assignment type is key to writing correct and maintainable Verilog code.
7
ExpertSubtle Effects of Non-blocking in Complex Designs
🤔Before reading on: do you think multiple non-blocking assignments to the same variable in one block behave predictably? Commit to your answer.
Concept: Explore how multiple non-blocking assignments to the same variable in one clock cycle behave and how synthesis tools interpret them.
If you write: always @(posedge clk) begin a <= 1; a <= 0; end Only the last non-blocking assignment takes effect, so a becomes 0. This can cause confusion if not carefully managed. Also, non-blocking assignments can introduce delta delays in simulation, affecting event ordering subtly.
Result
Simulation shows the last assignment wins; synthesis tools optimize accordingly.
Knowing these subtleties prevents bugs in complex sequential logic and helps write clearer, more predictable code.
Under the Hood
At simulation time, when a clock edge triggers a sequential block, all right-hand side expressions of non-blocking assignments are evaluated using current variable values. Then, all left-hand side variables are updated simultaneously at the end of the time step. This models hardware registers that capture inputs on the clock edge and hold them until the next edge. The simulator uses an event queue with delta cycles to schedule these updates, ensuring no statement sees partially updated data within the same time step.
Why designed this way?
Non-blocking assignments were introduced to solve the problem of race conditions and incorrect simulation of sequential logic caused by immediate updates in blocking assignments. Hardware registers update all bits simultaneously on clock edges, so the language needed a way to reflect this behavior accurately. Alternatives like only blocking assignments caused simulation mismatches and made debugging difficult, so non-blocking assignments became the standard for sequential logic modeling.
┌───────────────┐
│ Clock Edge    │
└──────┬────────┘
       │ triggers
       ▼
┌─────────────────────────────┐
│ Evaluate all RHS expressions │
│ using old variable values    │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ Schedule all LHS updates     │
│ to happen simultaneously     │
│ at end of current time step  │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ Update all LHS variables     │
│ simultaneously (non-blocking)│
└─────────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do non-blocking assignments update variables immediately or at the end of the time step? Commit to your answer.
Common Belief:Non-blocking assignments update variables immediately like blocking assignments.
Tap to reveal reality
Reality:Non-blocking assignments defer updates until all right-hand sides are evaluated, then update simultaneously at the end of the time step.
Why it matters:Believing they update immediately leads to incorrect assumptions about simulation order and can cause bugs in sequential logic.
Quick: Is it good practice to use blocking assignments inside clocked always blocks? Commit to yes or no.
Common Belief:Using blocking assignments inside clocked always blocks is fine and common.
Tap to reveal reality
Reality:Blocking assignments inside clocked blocks cause simulation mismatches and race conditions; non-blocking assignments should be used instead.
Why it matters:Using blocking assignments here can cause hardware to behave differently than simulation, leading to hard-to-find bugs.
Quick: Can you use non-blocking assignments for combinational logic safely? Commit to yes or no.
Common Belief:Non-blocking assignments are safe and recommended for all types of logic.
Tap to reveal reality
Reality:Non-blocking assignments are intended for sequential logic; using them in combinational logic can cause simulation mismatches and unintended latches.
Why it matters:Misusing non-blocking assignments in combinational logic can cause incorrect hardware synthesis and simulation errors.
Quick: If you assign a variable multiple times with non-blocking assignments in one block, do all assignments take effect? Commit to yes or no.
Common Belief:All non-blocking assignments to the same variable in one block combine or accumulate.
Tap to reveal reality
Reality:Only the last non-blocking assignment to a variable in a block takes effect for that time step.
Why it matters:Assuming all assignments apply can cause unexpected behavior and bugs in complex sequential logic.
Expert Zone
1
Non-blocking assignments introduce delta cycle delays in simulation, which can affect event ordering and subtle timing behaviors.
2
Synthesis tools may optimize non-blocking assignments differently, so understanding how your tool interprets multiple assignments is crucial.
3
Mixing blocking and non-blocking assignments in the same always block can cause confusing simulation results and should be avoided.
When NOT to use
Do not use non-blocking assignments for combinational logic; instead, use blocking assignments to model immediate updates. For asynchronous logic or combinational always blocks, blocking assignments are clearer and synthesize better.
Production Patterns
In real-world designs, non-blocking assignments are used exclusively inside clocked always blocks to model registers and flip-flops. Designers separate combinational logic into blocking-assignment always blocks and sequential logic into non-blocking-assignment blocks to maintain clarity and avoid bugs. Complex pipelines and FSMs rely heavily on non-blocking assignments to ensure correct timing and state updates.
Connections
Event-driven simulation
Non-blocking assignments rely on event-driven simulation scheduling to defer updates until all right-hand sides are evaluated.
Understanding event-driven simulation helps grasp why non-blocking assignments update simultaneously and how delta cycles manage timing.
Hardware flip-flops
Non-blocking assignments model the behavior of hardware flip-flops that update outputs simultaneously on clock edges.
Knowing flip-flop operation clarifies why simultaneous updates are necessary and why non-blocking assignments reflect real hardware.
Database transaction commit
Like non-blocking assignments, database transactions collect changes and commit them all at once to maintain consistency.
Seeing non-blocking assignments as a commit step helps understand the importance of atomic updates to avoid partial or inconsistent states.
Common Pitfalls
#1Using blocking assignments inside clocked always blocks causes simulation mismatches.
Wrong approach:always @(posedge clk) begin a = b; b = a; end
Correct approach:always @(posedge clk) begin a <= b; b <= a; end
Root cause:Misunderstanding that blocking assignments update immediately, causing sequential dependencies within the same clock cycle.
#2Using non-blocking assignments in combinational logic leads to unintended latches.
Wrong approach:always @(*) begin a <= b & c; d <= a | e; end
Correct approach:always @(*) begin a = b & c; d = a | e; end
Root cause:Confusing the purpose of non-blocking assignments, which are meant for sequential logic, not combinational.
#3Assigning the same variable multiple times with non-blocking assignments expecting all to apply.
Wrong approach:always @(posedge clk) begin a <= 1; a <= 0; end
Correct approach:always @(posedge clk) begin a <= 0; // Only last assignment matters end
Root cause:Not realizing that only the last non-blocking assignment to a variable in a block takes effect.
Key Takeaways
Non-blocking assignments update variables simultaneously at the end of a time step, accurately modeling hardware registers.
Use non-blocking assignments inside clocked always blocks to avoid race conditions and simulation mismatches.
Blocking assignments update immediately and are best suited for combinational logic modeling.
Mixing blocking and non-blocking assignments incorrectly can cause subtle bugs and hardware mismatches.
Understanding the simulation scheduling and delta cycles behind non-blocking assignments is key to mastering sequential Verilog design.