1. Level-Sensitive vs Edge-Triggered
The fundamental difference between a latch and a flip-flop is when they sample data. A flip-flop samples on a clock edge — typically the rising edge — and holds that value until the next edge regardless of what happens to D in between. A latch is transparent for an entire clock level: while EN (or CLK) is high, the output Q tracks the input D continuously with only propagation delay.
| Property | D Latch | D Flip-Flop |
|---|---|---|
| Trigger | Level (CLK=1 → transparent) | Edge (rising or falling) |
| Transparent window | Full high phase of CLK | ~nanoseconds around edge |
| Glitch immunity | None during enable | Full — glitches settle before edge |
| STA analysis | Open timing paths, complex | Clean setup/hold model |
| Power (vs FF) | Fewer transistors, lower cap | Higher transistor count |
| Synthesis intent | always_latch | always_ff |
2. Unintentional Latch Inference
The most dangerous property of latches is that they appear in code without being invited. In SystemVerilog, whenever an always_comb block assigns a signal for some inputs but not all, the synthesizer must preserve the previous value of that signal — which requires a latch. The compiler cannot invent a value out of thin air.
// Missing else → latch on out always_comb begin if (enable) out = data_in; // No else branch! end
// Else closes the path → no latch always_comb begin if (enable) out = data_in; else out = 8'h00; end
The same hazard appears in case statements without a default branch. A latch inferred in a block of 10 million gates can cause failures that pass functional simulation (simulators often model latches correctly) but fail silicon validation due to glitch-sensitive paths that only appear at speed.
always_comb begin case (sel) 2'b00: y = a; 2'b01: y = b; 2'b10: y = c; // 2'b11 unspecified! endcase end
always_comb begin case (sel) 2'b00: y = a; 2'b01: y = b; 2'b10: y = c; default: y = '0; endcase end
3. Glitch Propagation and Transparency
While a latch is transparent (EN=1), any glitch in the combinational logic feeding it passes directly to its output Q. In flip-flop based design, glitches that occur between clock edges are irrelevant — they settle before the next rising edge samples the stable value. In latch-based design, a glitch during the transparency window corrupts the output immediately.
Cascaded transparency hazard: When multiple latches share the same clock, a glitch on the input of the first latch can ripple through every subsequent transparent latch in the chain before the clock falls. A single noise spike on a wire becomes data corruption across four pipeline stages in a single nanosecond window.
Why STA Struggles with Latches
Static Timing Analysis (STA) checks flip-flop paths with a well-defined model: data must arrive before setup time, and hold time must not be violated. The launch and capture edges are both known. With latches, the "start" of a timing path can be any point during the transparent window — the effective launch time is a range, not a point. This creates open timing paths that STA tools must bound pessimistically, often leading to false failures or missed violations.
4. Time Borrowing — When Latches Win
The very property that makes latches dangerous (transparency) is what makes them powerful in high-performance pipelines. If a critical combinational path takes 1.1× the clock period, a flip-flop design fails. A latch design can let the slow data "leak" into the next clock cycle's time — borrowing from the next stage.
Apple, Intel, and AMD use time borrowing in their highest-frequency CPU pipeline stages. A well-designed latch-based pipeline can close timing at 5–10% higher frequency than an equivalent flip-flop design, without changing gate count. The tradeoff is verification complexity — every borrowed-time path needs careful analysis that STA alone cannot easily automate.
The ICG Latch
The most common intentional latch in CMOS RTL design is inside the Integrated Clock Gating (ICG) cell. A simple AND gate between the clock and an enable signal creates glitches whenever enable changes while the clock is high. The ICG cell solves this with a latch that captures enable during the clock-low phase — so the gated clock always starts and stops on a clean low-to-high transition, never mid-cycle.
// ICG inference (latch + AND, tool maps to library cell) always_latch if (!clk) latch_en <= en; // capture on low phase assign gclk = clk & latch_en; // glitch-free gated clock
5. RTL Best Practices
- Use
always_fffor all registers — never plainalways @(posedge clk) - Use
always_combfor combinational logic — synthesizer errors if a latch is inferred - Use
always_latchonly when a latch is intentional (e.g., ICG cells, explicit documentation) - Provide an
elsefor everyifand adefaultfor everycasein combinational blocks - Treat synthesis warning "Latch inferred" as a lint error — fix before PR review
- Enable lint tools (Spyglass, Jasper, Verific) with latch-check rules in CI
| RTL Rule | Pass | Fail |
|---|---|---|
| Register blocks | always_ff | always @(posedge clk) |
| Comb logic blocks | always_comb | always @(*) |
| Intentional latch | always_latch | always @(en) |
| if without else | Illegal in comb blocks | Infers latch |
| case without default | Illegal in comb blocks | Infers latch on all outputs |
6. Latch RTL Checklist
- All combinational always blocks use
always_comb - Every
ifinalways_combhas a matchingelse - Every
casehas adefaultor isfull_case-annotated with linting - Synthesis lint runs as part of CI gate
- Intentional latches documented with
always_latch - Using plain
always @(*)for combinational logic - Relying on simulation to catch latch inference
- Suppressing synthesis latch warnings without code fix
Toggle Data, pulse the clock, and inject a glitch to see how the D Latch propagates noise while the D Flip-Flop stays immune until the next rising edge.
Signal Stimulus
Frequently Asked Questions
always_comb block is assigned for some input conditions but not others — an if without an else, or a case without a default. The synthesizer must hold the previous value for the unspecified condition, which requires a level-sensitive storage element (a latch).always_latch to document the design intent.Latches in Professional ASIC Design — When They Belong
The Indispensable Latch: Inside ICG Cells
Despite the blanket "no latches" rule that most RTL coding guidelines enforce, one latch is present in virtually every modern SoC: the latch inside an Integrated Clock Gating (ICG) cell. A clock gating cell takes two inputs — a clock and an enable signal — and produces a glitch-free gated clock. The enable is sampled through a negative-level-sensitive latch on the falling edge of the clock, so that the enable transition is captured during the low phase. The latch output feeds an AND gate with the clock. Because the latch only updates when the clock is low, the AND output can only transition when the clock is already low — meaning the rising edge of the gated clock is always clean, never a partial glitch that would corrupt downstream flip-flops. Without the latch, a late-arriving enable change could clip the clock pulse and produce a narrow glitch that slips through to the data path. This is why the ICG latch is not a design mistake but a structural requirement: it is the only storage topology that gives this glitch masking guarantee at the cell boundary.
Time Borrowing in High-Performance CPU Pipelines
At GHz clock rates, holding every combinational path strictly within one cycle is expensive in area and power because it forces worst-case sizing across all paths. IBM's POWER series and various ARM Cortex-A microarchitectures have historically used latch-based pipelines for selected critical pipeline stages to relax this constraint. The mechanism, called time borrowing (or cycle stealing), works as follows: a slow path in pipeline stage N is allowed to finish slightly after the clock edge, because the downstream latch at the stage boundary remains transparent during the high phase of the clock. The late-arriving data passes through immediately rather than waiting for the next cycle. Stage N+1 then has a correspondingly shorter combinational window — it "pays back" the borrowed time. As long as the sum of consecutive stage delays is bounded by two clock periods rather than one, the pipeline closes timing at a frequency that a flip-flop design could not reach with the same library cells. This technique can provide 5–15% frequency headroom in cache and integer execution pipelines without resizing any standard cells.
STA Analysis Challenges with Intentional Latches
Static timing analysis for latch-based designs is fundamentally more complex than for flip-flop pipelines. In a purely flip-flop design, every timing arc is bounded between launch and capture edges one cycle apart. When latches are introduced, the STA tool must solve what is called a "time borrowing" or "half-cycle path" problem: the analysis must determine how much time each latch borrows and ensure the debt is repaid before any path closes to a point where the borrowed time cannot be returned. Primetime and Tempus handle this by modeling latch transparency windows and propagating arrival times through transparent elements, but they require the designer to set correct `set_multicycle_path` and `set_false_path` exceptions explicitly. Failure to annotate these exceptions correctly results in either pessimistic over-constraining (tools flag false violations) or optimistic under-constraining (real violations go undetected until post-silicon). For open timing paths through latches — paths where the endpoint timing is bounded only at one end — the tools report an OTP (open timing path) warning that must be reviewed and explicitly waived or constrained. Every intentional latch in a design adds SDC maintenance burden that must be carried through each PnR iteration.
Synthesis Pragmas and Design Review Protocol
In SystemVerilog, any combinational block that holds state for unspecified input conditions synthesizes to a latch. The compiler warnings for this are often buried in a sea of messages and missed during large block synthesis runs. The professional countermeasure is twofold. First, use always_latch instead of always @* for every intentional latch — the keyword signals the intent to both the synthesizer and every future reader, and most lint tools (Spyglass, Ascent Lint) have explicit checks for always_comb blocks that infer latches. Second, establish a design review gate: every latch in the synthesized netlist must appear in an approved latch list maintained in the block's design specification. During gate-level review, running report_cells -filter "is_latch==true" in Synopsys DC and comparing the output against the approved list catches any unintentional inference that slipped past RTL lint. Any latch not on the approved list is flagged as a design escape, not a lint suggestion. This dual-layer process — coding discipline at RTL, structural audit at netlist — is how mature ASIC teams prevent the most common source of functional bugs in combinational logic blocks.