If implementation is consistently optimistic, the usual remedy is a margin: pretend each path has a little less slack than the implementation tool computes. Too little margin leaves escapes. Too much over-fixes paths that were fine, costing area, power and time. The measured differences give the trade-off.
impl = {"e1": 0.10, "e2": 0.05, "e3": 0.02, "e4": 0.15, "e5": -0.01, "e6": 0.07}
signoff = {"e1": 0.06, "e2": -0.03, "e3": -0.01, "e4": 0.12, "e5": -0.05, "e6": 0.03}
def outcome(margin):
flagged = {e for e in impl if impl[e] - margin < 0}
failing = {e for e in impl if signoff[e] < 0}
return sorted(failing - flagged), sorted(flagged - failing) # (escapes, false alarms)
assert outcome(0.00) == (["e2", "e3"], [])
assert outcome(0.04) == (["e2"], [])
assert outcome(0.06) == ([], [])
assert outcome(0.08) == ([], ["e6"])
needed = max(impl[e] for e in impl if signoff[e] < 0)
assert abs(needed - 0.05) < 1e-9
print("PASS: margin 0 ->", outcome(0.0), "; 0.04 ->", outcome(0.04), "; 0.06 ->", outcome(0.06), "; 0.08 ->", outcome(0.08))Margin (ns) | Escapes | Over-fixed endpoints |
|---|---|---|
0.00 | e2, e3 | none |
0.04 | e2 | none |
0.06 | none | none |
0.08 | none | e6 |
Any margin above 0.05 ns, the largest implementation slack among the endpoints that fail signoff, removes every escape: a margin of 0.06 ns leaves no escapes and no over-fixed endpoints on this sample. The largest observed gap across all endpoints is 0.08 ns (at e2), so it is a conservative bound rather than the required size: a margin of 0.08 ns also removes every escape but flags e6, which actually passes signoff with 0.03 ns. A margin of 0.04 ns removes one of two escapes at no cost on this small sample. A real decision uses thousands of endpoints and looks at the distribution of the gaps, not only the maximum.
Approach | When it fits |
|---|---|
Maximum observed gap (a conservative bound) | Small designs, safety first; most over-fixing |
A high percentile of gaps | Large designs; accept a few escapes and fix them in a signoff ECO |
Margin by path class | Gaps differ by clock domain, length or layer; use separate margins |
The margin has a number, a source and an owner; it is recorded in the closure plan.
The margin is removed or revalidated when the extraction flow or the view list changes.
Escapes after the margin are reported and fixed at signoff, not argued away.
The maximum gap is sufficient but not necessary: here 0.06 ns already removes every escape, while 0.08 ns also flags e6, which passes signoff. Treating every endpoint as the worst case costs area, power and time for paths that were fine.