Reading Tool Warnings

A compact guide to classifying inferred-latch, width-mismatch, unused-or-undriven, and combinational-loop warnings, with a worked fix for each.

Updated 2026-07-26

A tool warning is evidence about a suspicious hardware structure. Classify the message before editing code so the first investigation follows the actual clue.

Lesson 6.6 stops at classification on purpose. This page carries the fixes, so you can come back to it whenever a real warning log needs a next move.

Inferred latch

An inferred-latch warning usually means a signal assigned in a combinational block is not assigned on every path, so the hardware has to remember the old value.

// Warned: grant keeps its old value when req is low.
always @(*) begin
  if (req) grant = 1'b1;
end
// Fixed: a default assignment covers every path.
always @(*) begin
  grant = 1'b0;
  if (req) grant = 1'b1;
end

Inspect the default assignment first, then every branch. A case needs a default for the same reason.

Width mismatch

A width-mismatch warning means a source expression and its destination use different bit counts, so bits are being dropped or padded silently.

// Warned: a + b needs 5 bits, sum holds 4.
wire [3:0] a, b;
wire [3:0] sum;
assign sum = a + b;
// Fixed: give the carry bit a home.
wire [3:0] a, b;
wire [4:0] sum;
assign sum = {1'b0, a} + {1'b0, b};

Decide whether extension or truncation was intended, and whether a carry or sign bit is being lost.

Unused or undriven signal

An unused signal has no consumer. An undriven signal has no source. Both usually mean a connection you meant to make is missing.

// Warned: done is declared and never driven.
module stage(input clk, output reg done);
  reg busy;
  always @(posedge clk) busy <= ~busy;
endmodule
// Fixed: drive the output from the state it was meant to report.
module stage(input clk, output reg done);
  reg busy;
  always @(posedge clk) begin
    busy <= ~busy;
    done <= ~busy;
  end
endmodule

Trace the intended data route before adding or deleting anything. Assigning a constant to silence the message hides the missing connection instead of fixing it.

Combinational loop

A combinational-loop warning means a combinational result feeds back into itself with no clocked register separating updates, so the value has no settled answer.

// Warned: ready depends on ready with nothing in between.
always @(*) ready = ready & ~stall;
// Fixed: the feedback crosses a clock edge.
always @(posedge clk) ready <= ready & ~stall;

Trace the feedback route and decide whether storage or a different expression was intended.

The habit

Do not silence warnings mechanically. Record the class, the affected signal, and the first structure you would inspect. That turns a long log into a short debugging queue.