Debugging, Timing, and Synthesis
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.
3 min read · Updated
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: permit keeps its old value when req is low.
always @(*) begin
if (req) permit = 1'b1;
end// Fixed: a default assignment covers every path.
always @(*) begin
permit = 1'b0;
if (req) permit = 1'b1;
endInspect the default assignment first, then every branch. A case that does not list every possible value needs a default item or a default assignment before it, 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 5-bit value drives a 4-bit wire, so its top bit is dropped.
wire [3:0] a, b;
wire [4:0] full = a + b; // 5 bits: the carry lands in full[4]
wire [3:0] total = full; // 5 bits into 4// Fixed: make the destination as wide as the value it receives.
wire [3:0] a, b;
wire [4:0] full = a + b;
wire [4:0] total = full;Decide whether extension or truncation was intended, and whether a carry or sign bit is being lost. If dropping the top bit is intended, write the part-select full[3:0], so the truncation is stated rather than implied.
A narrow destination does not always produce this warning. In assign total = a + b; with all three signals four bits wide, Verilog sizes the addition to the widest value involved, including the destination, so the whole expression is four bits and the carry is lost with no mismatch to report. Lesson 5.8 covers that sizing rule.
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, input rst, output reg done);
reg busy;
always @(posedge clk)
if (rst) busy <= 1'b0;
else busy <= ~busy;
endmodule// Fixed: drive the output from the state it was meant to report.
module stage(input clk, input rst, output reg done);
reg busy;
always @(posedge clk)
if (rst) begin
busy <= 1'b0;
done <= 1'b0;
end else begin
busy <= ~busy;
done <= ~busy;
end
endmoduleTrace 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 its behavior depends on the logic and its gate delays: it may hold a value or keep toggling. An inferred latch also holds a value; the latch warning points at a path with no assignment, while the loop warning points at an assignment that reads its own result.
// Warned: armed depends on armed with nothing in between.
always @(*) armed = armed & ~clear;// Fixed: the feedback crosses a clock edge, and reset gives it a known start.
always @(posedge clk)
if (rst) armed <= 1'b1;
else armed <= armed & ~clear;Trace the feedback route and decide whether storage or a different expression was intended. Reading your own output through a register, as in an accumulator acc <= acc + d, is not a loop: the flip-flop holds the old value until the next edge.
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.