Boundary constraints are numerous, hand-written and rarely re-read, so errors accumulate. An audit that counts ports by category turns "did we constrain the I/O?" into a number that must be zero.
Check | Problem it finds |
|---|---|
Input ports with no input delay | Unconstrained input paths |
Output ports with no output delay | Unconstrained output paths |
Ports with only -max (or only -min) | One-sided: the other check is unconstrained |
Ports tied to an internal clock when the interface is external | Wrong reference: port timing follows the internal waveform, gating and tree |
Min greater than max | A typo; the analysis is meaningless |
Clock ports and static control ports | Should be excluded or constrained as constants, not given data delays |
ports = {
"din": {"max": 4.0, "min": 1.0},
"valid":{"max": 4.0}, # missing min
"cfg_data": {}, # no constraint
"dout": {"max": 3.0, "min": -0.5},
"bad": {"max": 1.0, "min": 2.0}, # min > max
}
unconstrained = [p for p, v in ports.items() if not v]
one_sided = [p for p, v in ports.items() if v and ("max" not in v or "min" not in v)]
inverted = [p for p, v in ports.items() if "max" in v and "min" in v and v["min"] > v["max"]]
assert unconstrained == ["cfg_data"] and one_sided == ["valid"] and inverted == ["bad"]
print("PASS: unconstrained", unconstrained, "one-sided", one_sided, "inverted", inverted)The audit finds three different problems in five ports. Each category has a different fix: add the missing constraint, supply the missing side, correct the typo. The goal is the whole list empty (or each entry explained), and the audit is rerun on every constraint change. A static control pin such as a mode select is covered by case analysis, not an input delay.
The audit counts are zero or each exception is signed off, with the audit output archived with the signoff package.
Constants (mode pins, test pins) are constrained as case analysis, not given arbitrary data delays.
Interfaces between blocks are audited from both sides together.
A max of zero says data is launched at the clock edge with no external delay, which is rarely true, and with no -min the hold check from that port is unconstrained rather than checked against zero. Both look like defaults, not an interface specification.