Draft preview. Lessons are being written and reviewed.

Digital Design / Module 3: Verilog that means hardware

16. Accidental latches

Stop a very common synthesis surprise.

Lecture coming soon

See it move

The idea

Combinational logic has no memory, so its output must be defined for every possible input. If your code leaves a signal unassigned on some path, it has to keep its old value. Keeping a value requires storage, so the tool builds a .

always @(*) begin
  if (en) q = d;   // what happens when en is 0?
end

Nothing in this block says what q is when en is 0. So it must hold, and that is a latch. You probably wanted a mux or a flop.

Why it is a problem

Latches are transparent while enabled, which complicates timing analysis, and an unintended one usually signals a logic bug. Simulation may look fine because nothing exercised the hold path, and the surprise arrives only at synthesis.

Two fixes

Give a default at the top of the block. This is the most reliable habit:

always @(*) begin
  y = 1'b0;           // default on every path
  case (s)
    2'b00: y = a;
    2'b01: y = b;
  endcase
end

Or make sure every branch assigns every output, with else and default everywhere. With several outputs in a large block, the defaults method is much harder to get wrong.

Spotting them

Read the synthesis log: tools report inferred latches. Using always_comb and a tool turns this into an early warning instead of a late surprise.

Common mistake

Adding default to the case but forgetting that a block has several outputs. Each output needs a value on every path. If y is assigned in every branch but z in only one, z still becomes a latch.

Key ideas

  • Missing assignments on a path imply memory.
  • Assign defaults at the top of the block.
  • Complete case or a default closes the gap.

Your exercise

Find and fix the latch in a broken decoder.

Find the bug

This code has one deliberate bug. Read the symptom, then click the line you think is wrong.

What goes wrong: After s moves from 00 to 10, y keeps its old value instead of going to 0. Synthesis also reports an inferred latch.

Interview questions

coreHow is a latch inferred by accident?

basicIs always @(*) if (en) q = d; a flop, a latch or a gate?

basicName two ways to stop an always @(*) block from inferring a latch.

coreThis block has a default for y and a default case branch. Is it free of latches?

always @(*) begin
  y = 1'b0;
  case (s)
    2'b00: begin y = a; z = 1'b1; end
    2'b01: y = b;
    default: y = 1'b0;
  endcase
end

coreA case on a 2-bit select lists all four values, assigns the output in each, and has no default. Does synthesis infer a latch?

coreIs always @(posedge clk) if (en) q <= d; a latch, since q is not assigned when en is 0?

coreA designer silences a latch warning by writing else y = y;. Does that fix it?

advancedWhy do unintended latches make timing analysis harder than flops do?

advancedIs assign q = en ? d : q; a latch?

assign q = en ? d : q;

Practise these 9 questions with animations