← RTL Design Interviews

Interview Question · Concept

Why Synthesis Builds a Latch

L0 FresherL1 JuniorL2 Mid-Levellatchescombinational logicsynthesis

The Question

The interviewer asks

What makes synthesis infer a latch from combinational code, and how do you stop it?

Reveal the Model Answer

A combinational block must give every output a value on every path. If one path assigns nothing, the output must keep its old value. Keeping a value needs memory, so synthesis builds a level-sensitive latch. Fix it by assigning every output on every path: a default at the top, an else, or a default arm. Then write the block as always_comb, so lint and synthesis report any path you missed.

What Synthesis Built from the Incomplete BlockThe shift builds the one-hot value from sel. Because y has no value when en is 0, the result goes through a latch whose enable is en. While en is 1 the latch follows the shift; when en falls it holds.
What synthesis built from the incomplete blockThe shift builds the one-hot value from sel. Because y has no value when en is 0, the result goes through a latch whose enable is en. While en is 1 the latch follows the shift; when en falls it holds. manager sel[1:0] input manager en input bus 1 << sel four gates: theone-hot value bridge latch x4 enable = en; holdswhen en is 0 completer y[3:0] output selectdataenableheld or following
  1. Enable high

    en is 1: the latch is open, y follows the shift. Every test cycle looked like this.

    Follow the calls, values and waits
    1. data 1000: 1 << sel → latch x4
    2. data 1000: latch x4 → y[3:0]
  2. Enable falls

    en is 0: the latch closes and keeps the last one-hot value. sel can change; nothing reaches y.

    Follow the calls, values and waits
    1. call 1000: en → latch x4
  3. With the else

    The fixed block has a value for en = 0, so the latch is gone: six gates decode en and sel, and y is 0000.

Read the diagram as text
  • sel[1:0]: input
  • en: input
  • 1 << sel: four gates: the one-hot value
  • latch x4: enable = en; holds when en is 0
  • y[3:0]: output
  • sel[1:0] → 1 << sel: select
  • 1 << sel → latch x4: data
  • en → latch x4: enable
  • latch x4 → y[3:0]: held or following

The latch is the direct picture of "keep the old value". Removing the hold from the code removes the cell from the netlist.

  1. Find the paths

    Each if without else, and each case value with no arm, is a path through the block.

  2. Check every output on every path

    An output with no assignment on a path must hold its value there.

  3. Hold means memory

    In a block with no clock, that memory is a latch: transparent while its enable is active.

  4. Close the paths

    Assign a default first, or add the missing else or arm. The latch count goes to zero.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Fresher)

A good fresher answer traces each path of a small if or case block. It names the output that some path leaves unassigned.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

WhyWhat IfProve ItBreak ItCompareScale It

  1. Why Synthesis Builds a Latch
  2. WhyWhy an Unwanted Latch Is a ProblemL1 JuniorL2 Mid-Level

    Why is an unintended latch a real problem and not just a lint warning?

    Reveal the Model Answer

    The latch is memory the spec never asked for, so the output can show a stale value. While its enable is active the latch is transparent, so glitches on its input pass straight through. Static timing and test tools treat latches specially, so many teams avoid them to keep those steps simple. The design may work in RTL simulation and still fail in the lab.

    Self-Check

    Tick each key point you covered in your answer.

    Missed Corner

    "It passed the tests, so the latch is harmless."

    Tests pass when they never take the unassigned path. In lesson R1.3 the bench never dropped the enable, so the stale output was never seen.

    Source Sutherland, RTL Modeling with SystemVerilog (2017) ch. 9.2 Unintentional latch inference

  3. CompareA Latch Next to a Flip-FlopL1 JuniorL2 Mid-Level

    Compare a latch and a flip-flop fed the same data. What does this print?

    systemverilog
    module tb;
      logic clk = 0, d = 0, q_latch, q_flop;
      always_latch if (clk) q_latch = d;          // transparent while clk is high
      always_ff @(posedge clk) q_flop <= d;       // samples only at the rising edge
      always #10 clk = ~clk;                      // rising edges at 10, 30
      initial begin
        #12 d = 1;                                // d rises while clk is high
        #1 $display("t=13 (clk high): latch=%b flop=%b", q_latch, q_flop);
        #4 d = 0;
        #1 $display("t=18 (clk high): latch=%b flop=%b", q_latch, q_flop);
        #4 d = 1;                                 // t=22: clk is low now
        #1 $display("t=23 (clk low):  latch=%b flop=%b", q_latch, q_flop);
        #8 $display("t=31 (after edge): latch=%b flop=%b", q_latch, q_flop);
        $finish;
      end
    endmodule
    
    Reveal the Model Answer

    The latch follows d while the clock is high, so it shows 1 at t=13 and 0 at t=18. The flop changes only at rising edges. It took 0 at t=10 and holds it until t=30, when it takes 1. When the clock is low, the latch holds. Designers use latches on purpose in clock gating cells and in some latch-based pipelines.

    RUNIcarus Verilog · in your browser
    Edit the code, then run it
    Expected: t=13 (clk high): latch=1 flop=0 t=18 (clk high): latch=0 flop=0 t=23 (clk low): latch=0 flop=0 t=31 (after edge): latch=1 flop=1

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "A latch is a flop that triggers on a level."

    A flop samples once per edge. A latch passes its input through for the whole active level, so several changes in one phase all reach the output.

    Source Sutherland, RTL Modeling with SystemVerilog (2017) ch. 9.1 Modeling latches

  4. What IfAlways_comb and a Missing AssignmentL1 JuniorL2 Mid-Level

    Asked if they say always_comb prevents latches

    What if the decoder is written with always_comb instead of always @*? Is the latch gone?

    Reveal the Model Answer

    No. Simulation behaves the same, and the output still holds its value when en is low. The difference is in the tools that read the intent. Lint names the latch, and many synthesizers warn or stop. On this site's flow, synthesis refuses the block with a logic-loop error. Either way, you still have to add the missing assignment yourself.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "always_comb and always @* simulate differently here."

    For this code both wake on any input change and both hold y when nothing assigns it. The difference shows only in lint and synthesis.

    Source Sutherland, RTL Modeling with SystemVerilog (2017) ch. 7.2 The always and always_comb procedures

    Tool as Truth

    "Our synthesizer accepted it, so it is not a latch."

    Tools differ: some build the latch and only warn. The report, not a clean exit, tells you what was built.

    Source Lesson R1.3 claims: the plain Yosys front end stops with "Latch inferred"; the slang front end reports a logic loop

  5. Break ItWhen a Default Assignment Hides a BugL2 Mid-Level

    How can the "assign a default at the top" fix itself hide a functional bug?

    Reveal the Model Answer

    The default removes the latch, but it also gives a value to any arm you forgot. A missing arm then outputs the default quietly, often zero, and no tool complains. Choose a default that the spec allows, and make the testbench cover every input value. Some teams use unique case, so that simulation reports a value no arm matches.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "No latch in the report means the decode is complete."

    The report only says every path assigns something. It cannot say the value on each path is the right one.

  6. Scale ItA Team Rule for Latch-Free Combinational CodeL3 Senior

    You lead an RTL team. What rules and checks keep unintended latches out of every block?

    Reveal the Model Answer

    Make always_comb mandatory for combinational blocks and always_latch for the rare intended latch. Run lint on every commit, with a latch inference message as an error. Make the synthesis latch count a gate in the flow, with a reviewed waiver list for intended latches. Review default values against the spec, because removing a latch can hide a missing case.

    Self-Check

    Tick each key point you covered in your answer.

    What Interviewers Listen For (Senior)

    A good senior answer turns the coding rule into automatic gates: lint severity, a latch-count check in synthesis, and a waiver review. It names who owns each gate.

    Wrong Altitude

    "We tell people to be careful with if statements."

    Advice does not scale. A senior answer puts the check in the flow, so a latch fails the build before review.

  7. Prove ItSolve R1.3.1: The Decoder That RememberedSimulator-graded

    Show it, don't just say it: this Silicon Lab problem is graded by the simulator.

    Open Problem R1.3.1

What People Get Wrong

Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.

Misconception

"A missing else only matters in simulation. Synthesis fills in zero."

Synthesis builds exactly the hold that simulation shows. The twin synthesizes four latches, and with en low the output keeps its last value.

Run It

A 2-to-4 decoder with no else: simulated, and synthesized on the pinned Yosys flow.

RUNIcarus Verilog · in your browser
Edit the code, then run it
Expected: en=0: y=0100 FAIL: synthesis does not fill in zero; y held 0100, the latch keeps the old value
See the Fix
module dec (input logic en, input logic [1:0] sel, output logic [3:0] y);
  always @* begin
    if (en) y = 4'b0001 << sel;
    else    y = 4'b0000;           // the fix: every path assigns y
  end
endmodule
module tb;
  logic en; logic [1:0] sel; logic [3:0] y;
  dec d (.en(en), .sel(sel), .y(y));
  initial begin
    en = 1; sel = 2; #1;
    en = 0; #1;
    $display("en=0: y=%b", y);
    if (y !== 4'b0000) $display("FAIL: synthesis does not fill in zero; y held 0100, the latch keeps the old value");
    else $display("PASS: y is 0000 whenever en is 0");
  end
endmodule

Prints: en=0: y=0000 PASS: y is 0000 whenever en is 0

Half-Truth

"Writing always_comb stops latches."

always_comb states an intent that tools can check. It does not add the missing assignment, and simulation still holds the value. The fix is still your code.

Source IEEE 1800-2017 §9.2.2.2

Buzzword Without Mechanism

"Latches are bad because they are asynchronous."

That names a word, not a problem. The real costs are a transparent path that passes glitches, harder timing and test, and memory nobody asked for.

Learn It, Then Prove It