A clock constraint can look right and still fail to reach the flops it was meant for. The way to find out is to ask the tool, and to look at the answers: which clocks reach which pins, which sequential pins have none, and which have more than one.
Check | Finding | Typical cause |
|---|---|---|
Sequential pins with no clock | The pin's endpoint is unconstrained | Missing generated clock; broken case analysis; unconnected gate |
Pins with multiple clocks | Mixed or multiplexed clocks; a possible constraint error | Missing mux handling; a clock reconvergent path |
Clocks with no sinks | A defined clock that reaches no sequential pin | Wrong source point; typo in a port name |
Generated clocks without a master | Master not found or misdefined | Source pin wrong |
Combinational loops on clock nets | Unstable timing | A design problem |
# Audit counts for a clock report (illustrative numbers): every flop must have exactly one clock.
flops = 12000
by_clock = {"sys_clk": 9200, "div2": 2400, "scan_clk": 300}
no_clock = flops - sum(by_clock.values())
assert no_clock == 100
multi = 0
status = "clean" if no_clock == 0 and multi == 0 else "needs work"
assert status == "needs work"
print("PASS: audit finds", no_clock, "flops with no clock out of", flops)The counts add up to 11,900 clocked flops out of 12,000: 100 flops have no clock. A clean run is zero unclocked pins and zero multi-clock pins (or explained ones). This count is the first number to look at after loading constraints, before any slack.
Clock reports are part of every constraint review, with the unclocked and multi-clock counts at or explained to zero.
Each defined clock has the expected number of sinks; large deviations are investigated.
Re-running the checks after any change to clocks, dividers or muxes is a gate, not an option.
Whether the flops after the divider are clocked. A missing generated clock removes them from timing, so slack can improve because paths disappeared. Check the unclocked pin count.