At a single endpoint, adding delay to the data path costs setup slack and gains hold slack by the same amount; removing delay does the opposite. The sum of setup slack and hold slack is therefore unchanged in the same corner: an inserted cell is slower in the slow corner than in the fast one, so the sum differs between scenarios. If the sum is below the margins needed, no amount of delay change fixes both, and the endpoint needs a structural fix. The feasibility window must therefore be computed per scenario. Finding those endpoints first sets the order of work.
m = 0.005 # margin wanted on both checks, ns
endpoints = {"A": (-0.030, 0.060), "B": (0.010, -0.025), "C": (-0.010, 0.030), "D": (0.050, 0.030)} # (setup, hold)
out = {}
for n, (s, h) in endpoints.items():
total = round(s + h, 3)
lo, hi = m - h, s - m # delay change x must satisfy: hold + x >= m and setup - x >= m
out[n] = (total, round(lo, 3), round(hi, 3), lo <= hi + 1e-12)
assert out == {"A": (0.03, -0.055, -0.035, True), "B": (-0.015, 0.03, 0.005, False), "C": (0.02, -0.025, -0.015, True), "D": (0.08, -0.025, 0.045, True)}
infeasible = [n for n, r in out.items() if not r[3]]
assert infeasible == ["B"]
print("PASS: endpoints that delay change cannot fix:", infeasible, "; windows (ns) for the rest", {n: (r[1], r[2]) for n, r in out.items() if r[3]})Endpoint | Setup | Hold | Sum | Allowed delay change x (ns) | Fixable by delay? |
|---|---|---|---|---|---|
A | -0.030 | +0.060 | +0.030 | -0.055 to -0.035 (speed up) | Yes, by speeding the path |
B | +0.010 | -0.025 | -0.015 | none (needs x ≥ 0.030, but the setup check allows at most x ≤ 0.005) | No |
C | -0.010 | +0.030 | +0.020 | -0.025 to -0.015 (speed up) | Yes, by speeding the path |
D | +0.050 | +0.030 | +0.080 | -0.025 to +0.045 | Already passing, with room |
A is failing setup with plenty of hold slack, so speeding the data path by 35 to 55 ps fixes it. C is similar. B passes setup with 10 ps and fails hold by 25 ps; delay insertion needs at least 30 ps, but the setup check allows at most 5 ps: the sum is negative (-0.015 ns), so B is impossible to fix by delay alone. B's data paths are too far apart (the longest and shortest differ too much, or skew is unfavourable), so it needs a structural fix: reduce the spread between long and short paths, rebalance the clock, or use useful skew. A speed-up that is cheap in terms of area (A, C) goes first; hold insertion uses what remains.
Step | Action | Why here |
|---|---|---|
1 | Compute setup + hold slack per endpoint; list the negative sums | These need structural fixes and drive the schedule |
2 | Fix large setup violations by speed-ups and shared-segment changes | Speed-ups reduce hold slack a little, so they come before hold fixes |
3 | Fix hold by delay insertion at endpoints within the allowed window | Uses only the setup slack that remains |
4 | Re-run all scenarios and compare before and after | Fixes interact; verify the whole |
A list of endpoints with negative setup-plus-hold sums, with the structural fix chosen for each.
Hold insertion normally comes after setup speed-ups, because speed-ups erode hold; either order is acceptable if every fix is checked against each scenario's allowed window.
A final run of the whole matrix: the order only matters if the result is verified.
The sum is +0.008, below the 0.010 needed for both margins (2 × 0.005), so no: the window is empty. It would need a structural fix or a smaller margin.