← All guides

What causes inferred latches in VHDL?

This guide covers VHDL. There’s a Verilog version too.

A latch gets inferred whenever a combinational process has a path through it that doesn’t assign the output. VHDL’s simulation semantics say a signal that isn’t assigned keeps its previous value, and synthesis must build hardware that behaves the same way. Keeping a value needs storage, and with no clock edge in the process, that storage is a level-sensitive latch rather than a flip-flop.

See one get inferred

This process only drives grant_out while enable is '1'. When it’s '0', no assignment runs, so the old value must survive:

process (req, enable) is
begin
  if enable = '1' then
    grant_out <= req;  -- no else: grant_out must keep its value
  end if;
end process;

Here is that exact code, synthesized. The cell in the middle is a latch: storage you probably didn’t mean to build. Edit the code and press Run (try adding the else):

Interactive schematic by RapidRTL

Why it’s usually a bug

Deliberate latch design exists, but it should look deliberate, not like a forgotten else.

The fixes

1. Complete the if:

Interactive schematic by RapidRTL

The storage is gone. The netlist collapses to the AND gate this code meant all along.

2. Default assignment at the top of the process. The idiom that scales when a process drives many signals:

process (req, enable) is
begin
  grant_out <= '0';      -- default: every path now assigns
  if enable = '1' then
    grant_out <= req;
  end if;
end process;

Signal assignments in a process take the last value written before the process suspends, so the default costs nothing when the if overrides it.

3. Cover every choice in case. The same rule bites a case whose alternatives don’t all assign:

case sel is
  when "00"   => y <= a;
  when "01"   => y <= b;
  when "10"   => y <= c;
  when others => y <= '0';  -- without this arm: latch
end case;

VHDL forces you to write when others for coverage of choices, but it doesn’t force every arm to assign. An empty when others => null; still infers the latch. The wider case family, including VHDL-2008’s don’t-care case?, is compared in the case statement family guide.

The sensitivity-list trap next door

A related but different classic: a complete if/else with an incomplete sensitivity list (say, process (enable) while reading req). Synthesis tools generally build the combinational logic you meant anyway, but your simulation won’t match it, because the process never wakes on req changes. VHDL-2008’s process (all) ends that class of bug; use it where your flow supports it.

Unlike SystemVerilog, where always_comb turns a missing assignment into a hard error, VHDL has no process kind that outlaws the latch. That makes the warnings your tools print the main net: synthesis reports the inferred latch, and RapidRTL surfaces it as a warning naming the signal.

How to spot them