@@ -5905,7 +5905,14 @@ void Resizer::computeSkewBudget(const SkewBudgetOptions& opts)
59055905 sta_->findRequireds ();
59065906 }
59075907 std::vector<float > initial_latency (ck_pins.size (), 0 .0f );
5908- std::vector<bool > initial_pin_latency_set (ck_pins.size (), false );
5908+ // Full original pin-level latency per (rise/fall, min/max) so an asymmetric
5909+ // annotation is restored exactly instead of being collapsed to one value.
5910+ // initial_latency[] keeps only the rise/max baseline the LP shifts.
5911+ using PinLatency = std::array<std::array<float , 2 >, 2 >;
5912+ using PinLatencySet = std::array<std::array<bool , 2 >, 2 >;
5913+ std::vector<PinLatency> orig_pin_latency (ck_pins.size (), PinLatency{});
5914+ std::vector<PinLatencySet> orig_pin_latency_set (ck_pins.size (),
5915+ PinLatencySet{});
59095916 for (int i = 0 ; i < static_cast <int >(ck_pins.size ()); ++i) {
59105917 if (ck_propagated[i]) {
59115918 // Max rise *clock-path* arrival at the CK pin. Sta::arrival()
@@ -5938,11 +5945,19 @@ void Resizer::computeSkewBudget(const SkewBudgetOptions& opts)
59385945 float val = 0 .0f ;
59395946 bool exists = false ;
59405947 sdc->clockLatency (ck_clocks[i], ck_pins[i], rf_rise, mm_max, val, exists);
5941- initial_pin_latency_set[i] = exists;
59425948 if (!exists) {
59435949 sdc->clockLatency (ck_clocks[i], rf_rise, mm_max, val, exists);
59445950 }
59455951 initial_latency[i] = val;
5952+ for (const sta::RiseFall* rf : sta::RiseFall::range ()) {
5953+ for (const sta::MinMax* mm : sta::MinMax::range ()) {
5954+ float lat = 0 .0f ;
5955+ bool lat_exists = false ;
5956+ sdc->clockLatency (ck_clocks[i], ck_pins[i], rf, mm, lat, lat_exists);
5957+ orig_pin_latency_set[i][rf->index ()][mm->index ()] = lat_exists;
5958+ orig_pin_latency[i][rf->index ()][mm->index ()] = lat;
5959+ }
5960+ }
59465961 }
59475962
59485963 // 4. Cutting-plane iteration.
@@ -6358,18 +6373,37 @@ void Resizer::computeSkewBudget(const SkewBudgetOptions& opts)
63586373 // budget never leaves the cutting-plane's tentative set_clock_latency
63596374 // annotations in the SDC. Without this, an abort would corrupt downstream
63606375 // timing with skew that was computed but never realized.
6376+ // Put one CK pin back to its exact pre-LP SDC state: drop the clock/pin
6377+ // latency the LP wrote, then re-apply each original per-(rise/fall, min/max)
6378+ // value only if removing the LP's annotation also dropped it. A
6379+ // clock-agnostic pin latency survives removeClockLatency, so re-applying it
6380+ // would duplicate the original as a clock-specific annotation.
6381+ auto restore_pin_latency = [&](int i) {
6382+ sta_->removeClockLatency (ck_clocks[i], ck_pins[i], sdc);
6383+ for (const sta::RiseFall* rf : sta::RiseFall::range ()) {
6384+ for (const sta::MinMax* mm : sta::MinMax::range ()) {
6385+ const size_t ri = rf->index ();
6386+ const size_t mi = mm->index ();
6387+ if (!orig_pin_latency_set[i][ri][mi]) {
6388+ continue ;
6389+ }
6390+ float cur = 0 .0f ;
6391+ bool cur_exists = false ;
6392+ sdc->clockLatency (ck_clocks[i], ck_pins[i], rf, mm, cur, cur_exists);
6393+ if (!cur_exists || cur != orig_pin_latency[i][ri][mi]) {
6394+ sta_->setClockLatency (ck_clocks[i],
6395+ const_cast <sta::Pin*>(ck_pins[i]),
6396+ rf->asRiseFallBoth (),
6397+ mm->asMinMaxAll (),
6398+ orig_pin_latency[i][ri][mi],
6399+ sdc);
6400+ }
6401+ }
6402+ }
6403+ };
63616404 auto restore_initial_latencies = [&]() {
63626405 for (int i = 0 ; i < static_cast <int >(ck_pins.size ()); ++i) {
6363- if (initial_pin_latency_set[i]) {
6364- sta_->setClockLatency (ck_clocks[i],
6365- const_cast <sta::Pin*>(ck_pins[i]),
6366- sta::RiseFallBoth::riseFall (),
6367- sta::MinMaxAll::all (),
6368- initial_latency[i],
6369- sdc);
6370- } else {
6371- sta_->removeClockLatency (ck_clocks[i], ck_pins[i], sdc);
6372- }
6406+ restore_pin_latency (i);
63736407 }
63746408 sta_->findRequireds ();
63756409 };
@@ -6555,16 +6589,7 @@ void Resizer::computeSkewBudget(const SkewBudgetOptions& opts)
65556589 // and double-count once CTS inserts the delay buffers). The schedule
65566590 // survives only as the useful_skew_target property — a timing-inert
65576591 // signal CTS reads to decide whether to realize the skew.
6558- if (initial_pin_latency_set[i]) {
6559- sta_->setClockLatency (ck_clocks[i],
6560- const_cast <sta::Pin*>(ck_pins[i]),
6561- sta::RiseFallBoth::riseFall (),
6562- sta::MinMaxAll::all (),
6563- initial_latency[i],
6564- sdc);
6565- } else {
6566- sta_->removeClockLatency (ck_clocks[i], ck_pins[i], sdc);
6567- }
6592+ restore_pin_latency (i);
65686593
65696594 if (std::fabs (ti) >= opts.emit_threshold ) {
65706595 odb::dbITerm* ck_iterm = nullptr ;
0 commit comments