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
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
    • Parameterization and Generate Hub
    • Top-Level Integration Hub
    • Synthesis Intent Hub
      • Inference-focused coding style
      • Inferring flip-flops and RAM
      • Latch avoidance and case semantics
      • Reading a synthesis report
    • Style and Static Checks Hub
    • Assertions in RTL Hub
    • Formal Verification Basics Hub
    • Reusable SystemVerilog for RTL
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Synthesis Intent Hub
  1. Topics
  2. RTL Design
  3. Advanced RTL
  4. Synthesis Intent Hub
  5. Latch avoidance and case semantics

Part 8 · Advanced · Advanced

Latch avoidance and case semantics

Default assignments, plain versus unique case, and the ban on full_case pragmas.

On this page

    Why this matters

    A combinational block that skips one path holds its old value, and synthesis builds a latch for it. A full_case pragma can hide the gap, because the tool believes the claim and simulation does not.

    After this lesson you can: assign every output on every path, choose between plain, unique and priority case, and explain why full_case and parallel_case are left out.

    Assign every output on every path

    A combinational block must drive each output on all paths. A skipped path holds the old value, which synthesizes a latch.

    Legacy pragmas full_case and parallel_case can hide such bugs when their assumptions are wrong. The rules below express the same intent in code that simulation and synthesis both honor.

    latch_bad.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // yosys: latch
    module latch_bad (
      input logic en,
      input logic [7:0] d,
      output logic [7:0] q
    );
      always_comb begin
        if (en) q = d;                             // missing else: q holds when en is low
      end
    endmodule

    The fix assigns a default before the branch. It carries // yosys: ok, so the build fails if a latch ever appears there.

    latch_fixed.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // yosys: ok
    module latch_fixed (
      input logic en,
      input logic [7:0] d,
      output logic [7:0] q
    );
      always_comb begin
        q = '0;                                    // default first: every path assigns q
        if (en) q = d;
      end
    endmodule

    A case follows the same rule: a default item covers every selector value not listed, so no path is left unassigned.

    mux_plain.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // yosys: ok
    module mux_plain (
      input logic [1:0] sel,
      input logic [7:0] a, b, c, d,
      output logic [7:0] y
    );
      always_comb begin
        case (sel)
          2'd0:    y = a;
          2'd1:    y = b;
          2'd2:    y = c;
          default: y = d;
        endcase
      end
    endmodule

    Plain, unique and priority case

    Plain case with a default is the safe choice. Every selector value maps somewhere, so no latch is inferred, and an X or Z select also lands in the default branch, because case compares with === and no branch label matches.

    Form

    Meaning

    Rule

    Plain case with default

    Every value maps somewhere

    Default choice for decoders and muxes

    unique case without default

    Requires exactly one matching item: no-match and multiple-match checks

    Prove legal-input completeness and exclusivity; an unmatched RTL path with no prior assignment holds y

    unique case with default

    Legal: default handles no match; multiple matching explicit items still violate uniqueness

    Use when a fallback is part of the contract and overlap checking remains useful

    priority case

    Requires at least one match unless default exists; first matching item wins

    Plain case also chooses the first match. Priority adds completeness intent, not a new execution order

    mux_unique.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    module mux_unique (
      input logic [1:0] sel,
      input logic [7:0] a, b, c, d,
      output logic [7:0] y
    );
      always_comb begin
        unique case (sel)                          // no default: the branches cover all four values
          2'd0: y = a;
          2'd1: y = b;
          2'd2: y = c;
          2'd3: y = d;
        endcase
      end
    endmodule

    Leave full_case and parallel_case out

    These pragmas tell the tool that all cases are covered and none overlap. Simulation still evaluates every branch, so a wrong pragma makes synthesis disagree with simulation.

    Simulation executes the first matching item for plain, unique and priority case. Without a match or default, no assignment occurs: absent a preceding assignment, y retains its previous four-state RTL value. A preceding default assignment instead supplies that value. Unique/priority add match-count diagnostics (tool support varies) and synthesis assumptions about legal inputs; behavior outside those assumptions can differ in a synthesized netlist. A default removes the no-match check, not unique's overlap check.

    design.sv
    1
    2
    3
    4
    5
    // snippet: legacy pragmas that hide missing cases from the tool; do not use
    //   case (sel) // synthesis full_case parallel_case
    //     2'd0: y = a;
    //     2'd1: y = b;
    //   endcase

    Common mistakes

    Common pitfall

    Unique plus default is legal and useful when fallback behavior is intentional. Plain case plus default is this mux's local style choice, not a universal ban on unique/default. A deterministic fallback for an X/Z select is a digital RTL behavior, not physical CDC or metastability protection.

    Interview

    Likely question: “When is unique case safe?”

    • Match count: explicit items must be mutually exclusive for the legal input space.

    • Completeness: without default, require a match; with default, unmatched inputs take the fallback and no no-match warning is required.

    • Evidence: a four-selector binary sweep checks this finite decode space, not all system reachability assumptions. Verify diagnostics separately and constrain synthesis assumptions to the real protocol.

    Check yourself A case covers three of four selector values and has no default. What does synthesis build for the missing value?

    A latch. The output must hold its old value, so the tool infers storage. Assign a default first or add the missing branch.

    Check yourself What does priority case add to plain case?

    Both execute the first matching item. Priority additionally declares that some item must match unless default is provided; it does not prohibit overlaps. Use that completeness contract only when justified, and treat synthesis assumptions separately from RTL fallback behavior.

    Testbench

    The finite bench checks all four binary selectors and 16 selected data patterns, then X/Z selectors in a four-state simulator. It checks plain/default and legal unique/default fallback, and bare unique's retained previous value separately; warning support is tool-dependent, but the missing assignment's RTL hold is not. The labels are disjoint: this bench does not exercise an overlap warning. A two-state simulation cannot check these unknown-input obligations.

    mux_plain.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
    40
    41
    42
    43
    44
    module mux_plain (
      input logic [1:0] sel,
      input logic [7:0] a, b, c, d,
      output logic [7:0] y
    );
      always_comb begin
        case (sel)
          2'd0:    y = a;
          2'd1:    y = b;
          2'd2:    y = c;
          default: y = d;
        endcase
      end
    endmodule
    
    module mux_unique (
      input logic [1:0] sel,
      input logic [7:0] a, b, c, d,
      output logic [7:0] y
    );
      always_comb begin
        unique case (sel)
          2'd0: y = a;
          2'd1: y = b;
          2'd2: y = c;
          2'd3: y = d;
        endcase
      end
    endmodule
    
    module mux_unique_default (
      input logic [1:0] sel,
      input logic [7:0] a, b, c, d,
      output logic [7:0] y
    );
      always_comb begin
        unique case (sel)
          2'd0: y = a;
          2'd1: y = b;
          2'd2: y = c;
          default: y = d;
        endcase
      end
    endmodule
    

    Remember

    • Assign a default before the branch, or add the missing branch; otherwise a latch is inferred.

    • Plain case with a default is the safe choice, and an X or Z select lands in the default.

    • Unique and priority add match-count diagnostics and synthesis assumptions; a default removes the no-match check, not unique's overlap check.

    Rule of thumb: every output gets a value on every path before the case starts.

    How this was checked

    The bench checks all four binary selectors and 16 selected data patterns, then X and Z selectors in a four-state simulator, so it is simulation evidence. It is not synthesised-netlist equivalence. Warning support for unique and priority is tool-dependent. It does not exercise an overlap warning.

    Keep going

    • Practice: Incomplete case and unique0: simulation versus synthesis

    • Practice: Level-sensitive latch: when it is risky

    • Interview: run a mock interview on this topic

    Related topics

    • Canonical unique/default and mux semantics

    • RTL recovery versus mapped recovery guarantees

    • Reading a synthesis report

    Previous

    254 / 350

    Next: Reading a synthesis report

    Up next

    Up nextReading a synthesis report

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Inference-focused coding style