For each hold endpoint, look at its setup slack too, in the same scenario. Delay insertion trades the two one for one, so an endpoint whose setup plus hold slack is below twice the margin cannot be fixed that way. Across corners the setup cost of inserted delay is larger, so the same-corner sum is only a screen. A sample of eight endpoints from the 214:
m = 0.005
rows = {"h1": (-0.012, 0.080), "h2": (-0.030, 0.090), "h3": (-0.020, 0.012), "h4": (-0.018, 0.050),
"h5": (-0.040, 0.020), "h6": (-0.008, 0.060), "h7": (-0.025, 0.140), "h8": (-0.015, 0.008)} # (hold slack, setup slack) in ns
out = {}
for n, (h, s) in rows.items():
total = round(s + h, 3)
need = round(m - h, 3) # delay to add so that hold reaches the margin
left = round(s - need, 3)
out[n] = (total, need, left, total >= 2 * m)
assert [n for n, r in out.items() if not r[3]] == ["h3", "h5", "h8"]
assert out["h1"] == (0.068, 0.017, 0.063, True) and out["h5"] == (-0.02, 0.045, -0.025, False)
print("PASS: structural cases in the sample:", [n for n, r in out.items() if not r[3]], "; sum and delay needed for h5:", out["h5"][:2])Endpoint | Hold | Setup | Sum | Delay needed | Setup left | Fixable by delay? |
|---|---|---|---|---|---|---|
h1 | -0.012 | +0.080 | 0.068 | 0.017 | 0.063 | Yes |
h3 | -0.020 | +0.012 | -0.008 | 0.025 | -0.013 | No |
h5 | -0.040 | +0.020 | -0.020 | 0.045 | -0.025 | No |
h7 | -0.025 | +0.140 | 0.115 | 0.030 | 0.110 | Yes |
h8 | -0.015 | +0.008 | -0.007 | 0.020 | -0.012 | No |
Three of the eight sample endpoints have a negative sum: at zero margin those cannot be fixed by delay insertion at the endpoint, since adding delay to fix hold would create a setup violation of at least 12 ps (the code screens below twice the margin, which is the same rule with a 5 ps margin on each check). Suppose the same screen over all 214 identifies 18 such endpoints (an illustrative figure). Those are the ones that decide whether the schedule holds, because they need a per-path or structural fix, not delay at the endpoints. The other 196 can be fixed by insertion at the endpoints, within their setup slack.
The removed gate level shortened the minimum paths into these flops, so hold fell. In that shortened cone the maximum paths shrank too, but not as much, so the spread between longest and shortest path there is wider than the clock relationship can absorb. The 31 setup violations sit in the other, deeper cone, where the added gate level lengthened the maximum paths.
Which of the 18 can take delay on the short branch only, and which need the logic to be restructured?
Its setup slack (0.012) is smaller than the delay needed (0.025): inserting that delay leaves -0.013 ns of setup.