Day 59: Never infer a latch: complete assignments and default cases
Never infer a latch
A latch is inferred when a combinational always @(*) block *fails to assign an output on some path* — the synthesizer, needing to 'remember' the old value, inserts a level-sensitive latch (Stage 0, Day 22). That's almost never what you want: latches are hard to time, glitch-prone, and a lint error waiting to happen. The cause is always an incomplete if/case.
// BUG: 'y' is not assigned when sel==0 -> inferred latch
always @(*)
if (sel) y = a; // what is y when !sel? -> latch holds old y
// FIX 1: assign a default before the conditional
always @(*) begin
y = 1'b0; // default
if (sel) y = a;
end
// FIX 2: make every branch assign every output; full case + default
always @(*) begin
case (sel)
1'b1: y = a;
default: y = b; // no missing path -> no latch
endcase
endThe habit that eliminates the bug
Two rules make inferred latches impossible: (1) assign a *default value* to every output at the top of a combinational block, and (2) always include a default in case. Do both reflexively and the linter (Verilator -Wall, Day 94) will never flag a latch in your code. This is the discipline that separates clean RTL from the rest.
Key terms
- Inferred latch
- A level-sensitive latch created when a combinational block leaves an output unassigned on some path.
- Default assignment
- Setting every output to a known value at the top of a combinational block to prevent latches.
- Full case
- A case statement covering all inputs (or with a default) so no path is missing.
- Lint
- Static analysis (e.g. Verilator -Wall) that flags latch inference and other structural bugs.
Before moving on, you should be able to
What causes a synthesizer to infer an unwanted latch from a combinational always block?