@@ -881,8 +881,8 @@ void RepairDesign::checkDriverArcSlew(const sta::Scene* corner,
881881 float in_slew
882882 = use_ideal_clk_slew
883883 ? sta_->cmdMode ()->clkNetwork ()->idealClkSlew (in_pin, in_rf, max_)
884- : float (graph_-> slew (
885- graph_->pinLoadVertex (in_pin), in_rf, dcalc_ap));
884+ : float (
885+ graph_-> slew ( graph_->pinLoadVertex (in_pin), in_rf, dcalc_ap));
886886 const sta::Pvt* pvt = corner->sdc ()->pvt (inst, max_);
887887 if (pvt == nullptr ) {
888888 pvt = corner->sdc ()->operatingConditions (max_);
@@ -1075,6 +1075,8 @@ void RepairDesign::repairNet(sta::Net* net,
10751075 estimate_parasitics_->ensureWireParasitic (drvr_pin, net);
10761076 graph_delay_calc_->findDelays (drvr);
10771077
1078+ drvr_resized_ = false ;
1079+
10781080 if (check_slew) {
10791081 bool slew_violation = false ;
10801082
@@ -1096,7 +1098,7 @@ void RepairDesign::repairNet(sta::Net* net,
10961098
10971099 slew_violation = true ;
10981100 if (repairDriverSlew (corner1, drvr_pin)) {
1099- resize_count_++ ;
1101+ drvr_resized_ = true ;
11001102 estimate_parasitics_->updateParasitics ();
11011103 sta_->findDelays (drvr);
11021104 checkSlew (drvr_pin, slew1, max_slew1, slew_slack1, corner1);
@@ -1181,6 +1183,10 @@ void RepairDesign::repairNet(sta::Net* net,
11811183 }
11821184 }
11831185
1186+ if (drvr_resized_) {
1187+ resize_count_++;
1188+ }
1189+
11841190 if (repaired_net) {
11851191 repaired_net_count++;
11861192 }
@@ -1499,6 +1505,7 @@ void RepairDesign::repairNetWire(
14991505 // offset from instance origin to pin and detailed placement movement.
15001506 constexpr double length_margin = .05 ;
15011507 bool split_wire = false ;
1508+ const char * split_reason = " " ;
15021509 // Distance from repeater to ref_.
15031510 // length
15041511 // from----------------------------to/ref
@@ -1518,6 +1525,7 @@ void RepairDesign::repairNetWire(
15181525 units_->distanceUnit ()->asString (dbuToMeters (max_length_), 1 ));
15191526 split_length = min (max (max_length_ - wire_length_ref, 0 ), length / 2 );
15201527 split_wire = true ;
1528+ split_reason = " wire_length" ;
15211529 }
15221530 if (wire_cap > 0.0 && load_cap > max_cap_) {
15231531 debugPrint (logger_,
@@ -1532,6 +1540,7 @@ void RepairDesign::repairNetWire(
15321540 split_length = min (split_length,
15331541 max (metersToDbu ((max_cap_ - ref_cap) / wire_cap), 0 ));
15341542 split_wire = true ;
1543+ split_reason = " wire_cap" ;
15351544 }
15361545 if (load_slew > max_load_slew_margined) {
15371546 debugPrint (logger_,
@@ -1543,44 +1552,54 @@ void RepairDesign::repairNetWire(
15431552 level,
15441553 delayAsString (load_slew, 3 , this ),
15451554 delayAsString (max_load_slew_margined, 3 , this ));
1546- // We are inserting a buffer to cut this wire segment short.
1547- // The slew at the end of the wire segment is a quadratic polynomial
1548- // in terms of the wire segment's length (in Elmore approx.).
1549- //
1550- // We solve a quadratic eq. to find the maximum conforming length.
1551- float a = wire_res * wire_cap / 2 ;
1552- float b = (r_drvr * wire_cap) + (wire_res * ref_cap);
1553- float c
1554- = (r_drvr * ref_cap) - (max_load_slew_margined / (*slew_rc_factor_));
1555- float l = 0.0 ;
1556- if (a > 1e-12 ) { // Quadratic case
1557- const float discriminant = b * b - 4 * a * c;
1558- if (discriminant >= 0.0 ) {
1559- l = (-b + sqrt (discriminant)) / (2 * a);
1560- }
1561- } else if (b > 1e-12 ) {
1562- // a * l^2 + b * l + c = 0 becomes
1563- // b * l + c = 0 when a is very small
1564- l = -c / b;
1565- }
1566- if (l >= 0.0 ) {
1567- split_length = min (split_length, metersToDbu (l));
1555+
1556+ // Check if we can upsize the driver to meet the slew requirement without
1557+ // inserting a buffer. Don't bother if we anyways insert a buffer for
1558+ // length or capacitance reasons.
1559+ if (!split_wire
1560+ && tryUpsizeDriver (level, load_cap, max_load_slew_margined)) {
1561+ r_drvr = resizer_->driveResistance (drvr_pin_);
15681562 } else {
1569- split_length = 0 ;
1563+ // We are inserting a buffer to cut this wire segment short.
1564+ // The slew at the end of the wire segment is a quadratic polynomial
1565+ // in terms of the wire segment's length (in Elmore approx.).
1566+ //
1567+ // We solve a quadratic eq. to find the maximum conforming length.
1568+ float a = wire_res * wire_cap / 2 ;
1569+ float b = (r_drvr * wire_cap) + (wire_res * ref_cap);
1570+ float c = (r_drvr * ref_cap)
1571+ - (max_load_slew_margined / (*slew_rc_factor_));
1572+ float l = 0.0 ;
1573+ if (a > 1e-12 ) { // Quadratic case
1574+ const float discriminant = b * b - 4 * a * c;
1575+ if (discriminant >= 0.0 ) {
1576+ l = (-b + sqrt (discriminant)) / (2 * a);
1577+ }
1578+ } else if (b > 1e-12 ) {
1579+ // a * l^2 + b * l + c = 0 becomes
1580+ // b * l + c = 0 when a is very small
1581+ l = -c / b;
1582+ }
1583+ if (l >= 0.0 ) {
1584+ split_length = min (split_length, metersToDbu (l));
1585+ } else {
1586+ split_length = 0 ;
1587+ }
1588+ split_wire = true ;
1589+ split_reason = " wire_slew" ;
15701590 }
1571- split_wire = true ;
15721591 }
15731592
15741593 if (split_wire) {
1575- debugPrint (
1576- logger_ ,
1577- RSZ ,
1578- " repair_net " ,
1579- 3 ,
1580- " {:{}s}split length={} " ,
1581- " " ,
1582- level ,
1583- units_-> distanceUnit ()-> asString ( dbuToMeters (split_length), 1 ) );
1594+ debugPrint (logger_,
1595+ RSZ ,
1596+ " repair_net " ,
1597+ 3 ,
1598+ " {:{}s}split length={} reason={} " ,
1599+ " " ,
1600+ level ,
1601+ units_-> distanceUnit ()-> asString ( dbuToMeters (split_length), 1 ) ,
1602+ split_reason );
15841603 // Distance from to_pt to repeater backward toward from_pt.
15851604 // Note that split_length can be longer than the wire length
15861605 // because it is the maximum value that satisfies max slew/cap.
@@ -1593,7 +1612,7 @@ void RepairDesign::repairNetWire(
15931612 int buf_x = to_x + d * dx;
15941613 int buf_y = to_y + d * dy;
15951614 float repeater_cap, repeater_fanout;
1596- if (!makeRepeater (" wire " ,
1615+ if (!makeRepeater (split_reason ,
15971616 odb::Point (buf_x, buf_y),
15981617 buffer_cell,
15991618 /* resize= */ true ,
@@ -1656,6 +1675,138 @@ float RepairDesign::maxSlewMargined(float max_slew)
16561675 return max_slew * (1.0 - slew_margin_ / 100.0 );
16571676}
16581677
1678+ bool RepairDesign::tryUpsizeDriver (const int level,
1679+ const float load_cap,
1680+ const float max_load_slew_margined)
1681+ {
1682+ if (network_->isTopLevelPort (drvr_pin_)) {
1683+ return false ;
1684+ }
1685+
1686+ sta::Instance* driver_inst = network_->instance (drvr_pin_);
1687+ if (resizer_->dontTouch (driver_inst)) {
1688+ return false ;
1689+ }
1690+
1691+ debugPrint (
1692+ logger_,
1693+ RSZ ,
1694+ " repair_net" ,
1695+ 3 ,
1696+ " {:{}s}considering resizing driver {} to meet slew/cap requirement "
1697+ " without buffering" ,
1698+ " " ,
1699+ level,
1700+ network_->pathName (drvr_pin_));
1701+
1702+ sta::LibertyCell* driver_cell = network_->libertyCell (driver_inst);
1703+ sta::LibertyCellSeq swappable_cells
1704+ = resizer_->getSwappableCells (driver_cell);
1705+
1706+ std::string driver_port_name = network_->portName (drvr_pin_);
1707+ const float orig_r_drvr = resizer_->driveResistance (drvr_pin_);
1708+
1709+ if (!swappable_cells.empty ()) {
1710+ std::ranges::sort (
1711+ swappable_cells,
1712+ [this , driver_port_name](sta::LibertyCell* a, sta::LibertyCell* b) {
1713+ sta::LibertyPort* port_a = a->findLibertyPort (driver_port_name);
1714+ sta::LibertyPort* port_b = b->findLibertyPort (driver_port_name);
1715+ return port_a->driveResistance () < port_b->driveResistance ();
1716+ });
1717+
1718+ sta::LibertyCell* upsized_driver_cell = nullptr ;
1719+ for (sta::LibertyCell* candidate_cell : swappable_cells) {
1720+ sta::LibertyPort* candidate_port
1721+ = candidate_cell->findLibertyPort (driver_port_name);
1722+
1723+ const float candidate_r_drvr = candidate_port->driveResistance ();
1724+
1725+ if (candidate_r_drvr >= orig_r_drvr) {
1726+ debugPrint (
1727+ logger_,
1728+ RSZ ,
1729+ " repair_net" ,
1730+ 3 ,
1731+ " {:{}s}candidate cell {} has drive resistance {} which is not "
1732+ " lower than current driver resistance {}, stopping search" ,
1733+ " " ,
1734+ level,
1735+ candidate_cell->name (),
1736+ units_->resistanceUnit ()->asString (candidate_r_drvr, 3 ),
1737+ units_->resistanceUnit ()->asString (orig_r_drvr, 3 ));
1738+ break ;
1739+ }
1740+
1741+ debugPrint (logger_,
1742+ RSZ ,
1743+ " repair_net" ,
1744+ 3 ,
1745+ " {:{}s}considering candidate cell {} with drive resistance {}" ,
1746+ " " ,
1747+ level,
1748+ candidate_cell->name (),
1749+ units_->resistanceUnit ()->asString (candidate_r_drvr, 3 ));
1750+
1751+ const float candidate_load_slew
1752+ = candidate_r_drvr * load_cap * (*slew_rc_factor_);
1753+
1754+ // Check that we do not violate the max output slew of the driver.
1755+ float candidate_max_output_slew = sta::INF ;
1756+ {
1757+ float max_output_slew = sta::INF ;
1758+ bool exists;
1759+ candidate_port->slewLimit (max_, max_output_slew, exists);
1760+ if (exists) {
1761+ candidate_max_output_slew = maxSlewMargined (max_output_slew);
1762+ }
1763+ }
1764+
1765+ if (candidate_load_slew <= max_load_slew_margined
1766+ && candidate_load_slew <= candidate_max_output_slew) {
1767+ debugPrint (
1768+ logger_,
1769+ RSZ ,
1770+ " repair_net" ,
1771+ 3 ,
1772+ " {:{}s}resizing driver to {} meets slew requirement with estimated "
1773+ " load slew {} <= {} and max output slew {} <= {}" ,
1774+ " " ,
1775+ level,
1776+ candidate_cell->name (),
1777+ delayAsString (candidate_load_slew, 3 , this ),
1778+ delayAsString (max_load_slew_margined, 3 , this ),
1779+ delayAsString (candidate_load_slew, 3 , this ),
1780+ delayAsString (candidate_max_output_slew, 3 , this ));
1781+ upsized_driver_cell = candidate_cell;
1782+ }
1783+ }
1784+
1785+ if (upsized_driver_cell) {
1786+ // We found a candidate cell that can be swapped to that meets the
1787+ // slew requirement
1788+ debugPrint (logger_,
1789+ RSZ ,
1790+ " repair_net" ,
1791+ 3 ,
1792+ " {:{}s}resizing driver from {} to {} to meet slew requirement "
1793+ " without buffering" ,
1794+ " " ,
1795+ level,
1796+ driver_cell->name (),
1797+ upsized_driver_cell->name ());
1798+ resizer_->replaceCell (driver_inst, upsized_driver_cell, true );
1799+
1800+ // Update drvr_pin_ to point to the new cell's output pin
1801+ drvr_pin_ = network_->findPin (driver_inst, driver_port_name);
1802+ drvr_resized_ = true ;
1803+ return true ;
1804+ }
1805+ }
1806+
1807+ return false ;
1808+ }
1809+
16591810void RepairDesign::repairNetJunc (
16601811 const BufferedNetPtr& bnet,
16611812 int level,
@@ -1756,15 +1907,23 @@ void RepairDesign::repairNetJunc(
17561907 level,
17571908 delayAsString (slew_slack_left, 3 , this ),
17581909 delayAsString (slew_slack_right, 3 , this ));
1910+
1911+ // Check if we can upsize the driver to meet the slew requirement without
1912+ // inserting a buffer.
1913+ bool fixed_by_resize
1914+ = tryUpsizeDriver (level, load_cap, max_load_slew_margined);
1915+
17591916 // Isolate the branch with the smaller slack.
1760- if (slew_slack_left < slew_slack_right) {
1761- repeater_left = true ;
1762- } else {
1763- repeater_right = true ;
1917+ if (!fixed_by_resize) {
1918+ if (slew_slack_left < slew_slack_right) {
1919+ repeater_left = true ;
1920+ } else {
1921+ repeater_right = true ;
1922+ }
1923+ repeater_reason = " load_slew" ;
17641924 }
1765- repeater_reason = " load_slew" ;
17661925 }
1767- bool cap_violation = (cap_left + cap_right) > max_cap_;
1926+ bool cap_violation = load_cap > max_cap_;
17681927 if (cap_violation) {
17691928 debugPrint (logger_, RSZ , " repair_net" , 3 , " {:{}s}cap violation" , " " , level);
17701929 if (cap_left > cap_right) {
0 commit comments