Gating failures are glitch risks, so they are never ignored. Their causes are few and recognisable, and the fix is almost always on the enable path or the gate choice.
Symptom | Cause | Fix |
|---|---|---|
Gating setup violated | Enable logic too slow for the available phase | Reduce enable logic, retime the enable, use an ICG |
Gating hold violated | Enable changes too early, while the clock is in the sensitive phase | Add delay, or launch from the other edge |
Check missing for a gate | Gate not recognised (a custom structure) or checks disabled | Define the check or use a recognised cell |
Large skew between gate and enable launch clocks | Unbalanced clock tree | Balance the tree through the gate |
Multiple clocks into the gate | Clock mux feeding the gate | Define the gating relationship per clock |
checks = [("g1", 0.85, 0.40), ("g2", -0.12, 0.30), ("g3", 0.60, -0.05), ("g4", 1.2, 0.9)] # (gate, setup slack, hold slack)
fails = {g: ("setup" if s < 0 else "") + ("hold" if h < 0 else "") for g, s, h in checks if s < 0 or h < 0}
assert fails == {"g2": "setup", "g3": "hold"}
assert len(fails) == 2
print("PASS: failing gating checks:", fails)Two of four gates fail, one on setup and one on hold. The two need different fixes: g2's enable is too slow (reduce logic, retime), g3's enable is too fast (add delay or change the launch edge). Fixing hold with a delay can recreate a setup problem, so both are re-checked together.
Gating setup and hold are both zero-violation at signoff in all corners.
Any fix on the enable path is re-checked for the opposite check and for the data paths it shares.
Gates without a recognised check are listed and justified.
The enable changes while the clock is still high (just after its rising edge), so for an AND-type gate the output can glitch or truncate the pulse. The enable needs more delay or a different launch edge so it changes in the low phase.