Verilog · Chapter 14.5.2 · Behavioural Modeling
Case Statements in Verilog — case, casez, casex & the default Rule
The case statement is behavioural logic's parallel branch. It selects among the values of an expression, such as an opcode, an FSM state, or a mux select, with cases that are normally mutually exclusive, synthesizing to a parallel mux or decoder. Three variants exist: plain case for exact matches, casez which treats z and question mark as don't-cares and is the safe way to write priority and range patterns, and casex which treats both x and z as don't-cares and is dangerous because an x in the expression silently matches and can mask real bugs. This page drills all three, the all-important default that prevents an inferred latch, the use of casez for don't-care patterns, and why casex should be avoided in favour of casez. The case statement is the backbone of FSM state decoding and value-based selection.
Foundation14 min readVerilogcasecasezcasexdefaultFSM
Chapter 14 · Section 14.5.2 · Behavioural Modeling
1. The Engineering Problem
case selects on a value and is the natural construct for opcodes, states, and selects — but it carries the same latch hazard as if, plus a variant trap:
A
casewithout adefaultinfers a latch (incomplete assignment); andcasex(which treatsxas a don't-care) can silently mask bugs — prefercasezwith?for don't-cares.
This page drills case/casez/casex, the default rule, and the casex hazard.
2. Mental Model — Parallel Value Selection; default Completes It
3. The case Statement
always @(*)
case (op)
2'b00: y = a + b;
2'b01: y = a - b;
2'b10: y = a & b;
2'b11: y = a | b;
default: y = 8'h00; // covers any unexpected value (incl. x/z)
endcase- The expression
opis matched against each case value (exact match); the first matching case executes. - The
defaultcovers all unlisted values — and even a fully-enumerated case should include adefaultto handlex/zon the expression and to avoid a latch. casereads more clearly than a longif/else ifchain for value selection, and synthesizes to a parallel structure.
Visual A — case is parallel selection; if/else is priority
case → one parallel mux; if/else → a priority cascade
data flow4. The default Rule — Latch Avoidance
As with if, a combinational case must assign every output on every path. A missing default (with unlisted values, or x/z inputs) leaves an unassigned path → a latch:
// LATCH — no default, sel=2'd3 unassigned:
always @(*)
case (sel)
2'd0: y = a;
2'd1: y = b;
2'd2: y = c;
endcase
// FIX — default:
always @(*)
case (sel)
2'd0: y = a;
2'd1: y = b;
2'd2: y = c;
default: y = 0; // covers 2'd3 and x/z → no latch
endcaseAlways include a default in a combinational case. Even when all values are enumerated, the default handles x/z on the expression and documents the intent. (Or use the default-first pattern: assign y before the case.)
5. casez and casex — Don't-Cares
casez and casex allow don't-care bits in the case values — but they differ critically:
// casez — z and ? are don't-cares (the SAFE way to write patterns):
casez (req)
4'b1???: grant = 2'd3; // req[3]=1, others don't-care (priority)
4'b01??: grant = 2'd2;
4'b001?: grant = 2'd1;
4'b0001: grant = 2'd0;
default: grant = 2'd0;
endcase
// casex — x AND z are don't-cares (DANGEROUS):
casex (sel)
2'b1x: ... // an x in 'sel' also matches → masks bugs
endcasecaseztreatszand?(the preferred don't-care symbol) as don't-cares in the case values — useful for priority encoders and range matching (the4'b1???pattern). Safe and common.casextreats bothxandzas don't-cares — and crucially, anxin the case expression (a real unknown, often a bug) will match acasexpattern, silently hiding the unknown. This masks bugs, socasexis avoided in modern RTL; usecasez(with?) instead.
The discipline: casez with ? for don't-cares, never casex. (Note casez/casex build priority structures when patterns overlap, unlike plain case.)
Visual B — case variants
case / casez / casex
data flow6. Common Mistakes
- Missing
default— infers a latch (and mishandlesx/z); always include it (§4, DebugLab 1). - Using
casex— its x-matching masks bugs; usecasezwith?(§5, DebugLab 2). - Using
if/elsefor value selection —caseis clearer for selecting on a value (§3). - Overlapping
caseitems — plaincaseexpects mutual exclusion; overlap makes it priority-like (§5). full_case/parallel_casepragmas — promise synthesis something the simulator ignores, creating a sim/synth mismatch; make the case genuinely complete instead (DebugLab 3, 14.5.3).
7. Debugging Lab
Three case-statement debug post-mortems
8. Interview Q&A
9. Exercises
Exercise 1 — Add the default
Add a default to a 4-state FSM case that decodes state into out, so it is latch-free.
Exercise 2 — casez vs casex
For a priority decoder with don't-care patterns, which variant do you use and why? What does the other one do with a real x input?
Exercise 3 — case or if?
For (a) selecting on a 3-bit opcode and (b) a prioritized error/interrupt decision, which construct (case or if/else) fits each?
10. Summary
The case statement is parallel value selection:
- Parallel — mutually-exclusive cases; synthesizes to a parallel mux/decoder.
default— covers unlisted values andx/z; required for latch avoidance in combinational blocks.casez—z/?don't-cares; the safe way to write patterns/priority encoders.casex—xandzdon't-cares; avoid (a realxmatches, masking bugs).
The discipline: always a default; casez with ? for don't-cares, never casex.
The last branching sub-topic covers the synthesis pragmas and advanced patterns: Chapter 14.5.3 Multiway Advanced Techniques drills full_case/parallel_case (and their dangers), don't-care handling, and priority vs parallel structures.
Related Tutorials
- if/else Statements — Chapter 14.5.1; the priority-branching alternative.
- Multiway Branching — Chapter 14.5; the branching overview and latch discipline.
- Equality Operators — Chapter 10.8; the case-equality (
===) semantics behindcasematching. - Generate case — Chapter 14.7.3; the elaboration-time counterpart — a runtime
casebuilds all branches, agenerate casebuilds only the selected structure. - Dataflow Practical Examples — Chapter 13.2; muxes and decoders at the dataflow level.