Why does an ECO that fixes one endpoint's hold violation sometimes create a new one nearby?
From PDVerse STA Mentor Guide · pdVerse Mentor Guide
Short Answer
A hold fix, whether a resized cell or an inserted buffer, adds delay onto a net that other logic may also depend on, and that added delay can push a neighboring path that used to have a little hold margin into a violation of its own. Fixing one endpoint in isolation, without checking what else shares that net or driver, can trade one violation for another instead of clearing it.
Technical Explanation
- A buffer inserted to fix a hold violation adds delay to every downstream pin on that net, not just the specific endpoint the ECO was aimed at, if the net fans out to more than one register.
- Resizing a driving cell to slow down one path changes the delay seen by every other net that same cell drives, since the cell's output characteristics change for all its loads at once.
- A neighboring path that shares the same launch clock and driver, and that already had only a few picoseconds of hold margin, can be pushed past zero by exactly the extra delay meant to fix the original endpoint.
- This is why an ECO fix is re-verified with
report_timing -delay_type min -nworst N(PT) scoped to the affected clock or fan-out group after the change, not just the single originally-reported endpoint. report_global_timing(PT) run before and after the fix is one way to catch this pattern across the whole design, since a flat or worse aggregate violation count after a "fix" is a sign a new violation appeared somewhere else.- Choosing a fix that touches the fewest shared nets and cells, for example a small buffer on a single-fanout branch rather than resizing a shared driver, reduces the chance of this side effect in the first place.
Common Mistake
The Trap: Verifying only the specific endpoint named in the original violation report after applying the fix, and declaring the ECO complete.
- The same fix's added delay can quietly create a new violation at a sibling endpoint on the same net or driver, one that never appears in the check unless the fan-out group is re-reported as a whole.
Follow-up Question & Model Response
If a fix must avoid touching shared logic, how do you find which paths actually share a driver or net before applying an ECO?
Candidate Model Response: all_fanout and related PrimeTime query commands can list every pin and endpoint downstream of a given net or driving cell, showing exactly which other paths would be affected before any ECO command is applied. Reviewing that fan-out list against the current hold slack of each affected endpoint, using report_timing -delay_type min (PT) on each one, shows whether any of them are close enough to zero that the planned fix could tip them over. If a shared driver reaches several tight endpoints, a more targeted fix, such as buffering a single branch instead of resizing the shared cell, avoids pushing delay onto endpoints that were never part of the original violation. This upfront check is what separates a one-shot ECO fix from a cycle of chasing newly created violations round after round.
Practical Example
insert_buffer (PT) fixes a -6ps hold violation at FF20/D by adding 9ps of delay on a net that also fans out to FF21/D. FF21's hold check, previously at +4ps, drops to -5ps after the same fix, discovered only when the team reruns report_timing -delay_type min (PT) across the whole fan-out group rather than just re-checking FF20.
Complete STA Handbook
Master Signoff-Ready Static Timing Analysis
Get the complete 10-chapter STA handbook covering setup/hold margins, clock modeling, OCV/POCV, crosstalk noise, and PrimeTime closure.

Continue practising