Common Verilog Mistakes (Latches, Sensitivity Lists, Races)

Most Verilog bugs are not syntax errors — the code compiles, simulates, and then behaves differently in hardware. Here are the mistakes that cost beginners the most time, each with the fix.

1. Incomplete sensitivity list

Listing only some signals in always @(a) makes the simulator miss updates — and infers a latch. Always use always @(*) for combinational logic so the tool tracks every input.

2. Latch from a missing else / default

If a combinational always block does not assign an output on every path, Verilog must remember the old value — a latch. The example below shows the leak and the fix (assign a default first):

module latch_demo (input [1:0] sel, input a, b, output reg y_bad, output reg y_good);
  // BAD: no default -> y_bad holds its value when sel==2 or 3 (latch inferred)
  always @(*) case (sel)
    2'd0: y_bad = a;
    2'd1: y_bad = b;
  endcase
  // GOOD: default assignment on every path -> pure combinational
  always @(*) begin
    y_good = 1'b0;                 // default first
    case (sel)
      2'd0: y_good = a;
      2'd1: y_good = b;
    endcase
  end
endmodule

module tb;
  reg [1:0] sel; reg a,b; wire y_bad, y_good;
  latch_demo dut(.sel(sel), .a(a), .b(b), .y_bad(y_bad), .y_good(y_good));
  initial begin
    a=1; b=0; sel=2'd0; #1 $display("sel=0 y_bad=%b y_good=%b", y_bad, y_good);
    sel=2'd2;           #1 $display("sel=2 y_bad=%b y_good=%b (y_bad kept old value!)", y_bad, y_good);
    $finish;
  end
endmodule
sel=0 y_bad=1 y_good=1
sel=2 y_bad=1 y_good=0 (y_bad kept old value!)

3. Blocking assignment in clocked logic

Using = inside always @(posedge clk) creates races and sim-vs-synthesis mismatch. Always use <= there — see blocking vs non-blocking.

4. Width mismatches that silently truncate

Assigning a 9-bit sum to an 8-bit reg drops the carry with no warning. Size your nets for the widest intermediate value, and watch for the implicit extension in a + b.

5. Multiple drivers on one net

Two assigns (or two always blocks) writing the same wire produce x. One net, one driver.

▶ Try it in the ChipXpert Lab

Run the latch demo in the lab and watch y_bad keep its old value at sel=2. Add the default assignment and re-simulate to see the latch disappear.

Open the Simulator →

Check yourself

How do you spot an accidental latch in combinational logic?

Synthesis/lint warns ‘inferred latch’, and in simulation the output keeps its previous value on an unassigned path. The fix is to assign every output a default at the top of the always @(*) block, or cover every branch with a full case/else.

Why does <code>always @(a or b)</code> risk a bug when the logic also reads <code>c</code>?

The block will not re-evaluate when c changes, so the output goes stale and a latch may be inferred. always @(*) builds the sensitivity list automatically from everything the block reads, eliminating the class of bug.

Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.

Learn Verilog with mentors, labs and placement support

This free series is maintained by the ChipXpert training team in Hyderabad & Bengaluru. Go deeper with instructor-led courses on real EDA tools.

Explore VLSI Courses
Next batch starts 18th November 2026
Start your VLSI career with ChipXpert

Live online and classroom batches in Hyderabad & Bengaluru. Fill in your details and a counsellor will call you back.

  • Real EDA tools in your browser: industry-standard EDAReal EDA tools in your browser
  • Recorded sessions on the elearn portalRecorded sessions
  • Placement assistance: resume, mock interviewsPlacement assistance
  • Merit scholarship up to 60% · EMI optionsScholarship up to 60%
Hi! Ask me about courses, fees, batches or discounts. ×
BENGALURU
HYDERABAD