Skip to article

Debugging, Timing, and Synthesis

Common Combinational Bugs

The four bug classes behind most combinational mistakes — wrong operator, missing default, wrong case item, and width mistake — and how each shows up in failing output.

2 min read · Updated


Four common classes of combinational mistake are worth knowing on sight.

Wrong operator. Using & where the design needs |, or the reverse. The result looks almost right — it matches the correct behavior for some inputs and flips for others, specifically the inputs where the two operators disagree.

Missing default. An output is left unassigned on some path inside always @(*), so the synthesizer infers a latch to hold the old value. This is the same accidental-latch trap covered in Module 2; the fix is the same default-at-top pattern.

Wrong case item. A case item is mistyped, or a value is accidentally listed twice. Verilog's case statement runs only the first item whose value equals the selector, so the second occurrence of a duplicated value never runs. The value that should have been listed matches no item: it gets the default item if there is one, and otherwise whatever the block assigned before the case.

Width mistake. A result passes through a signal or a sized value with too few bits, so its top bits are dropped. When an addition is assigned directly to a signal wide enough for the carry, Verilog evaluates it at that width and the carry survives (Lesson 5.8). The carry is lost when the sum first lands in a narrower intermediate signal, or sits inside a concatenation, which sizes it by its own operands. Widening a later signal cannot restore a bit that was already dropped.

Each class tends to show up differently in a failing testbench: wrong operator fails exactly the inputs where the two operators disagree, missing default holds a stale value instead of updating, wrong case item gives one input value the fixed value assigned before the case (or the default), and width mistake fails only the results large enough to need the dropped bits. Reading which inputs fail — and which pass — before opening the RTL usually narrows the search to a first hypothesis among these four. Treat that hypothesis as a starting point: the RTL and a rerun are what actually confirm it.