Skip to content

Commit c147750

Browse files
rsz: try to upsize driver when repairing load slew
Buffers created by repairNetWire now have a name dependant on their reason, similar to repairNetJunc Signed-off-by: Tobias Senti <git@tsenti.li>
1 parent a00a575 commit c147750

27 files changed

Lines changed: 417 additions & 234 deletions

src/rsz/src/RepairDesign.cc

Lines changed: 202 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
16591810
void 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) {

src/rsz/src/RepairDesign.hh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ class RepairDesign : sta::dbStaState
174174
// Return values.
175175
int& wire_length,
176176
sta::PinSeq& load_pins);
177+
bool tryUpsizeDriver(const int level,
178+
const float load_cap,
179+
const float max_load_slew_margined);
177180
float maxSlewMargined(float max_slew);
178181
double findSlewLoadCap(sta::LibertyPort* drvr_port,
179182
double slew,
@@ -258,6 +261,7 @@ class RepairDesign : sta::dbStaState
258261

259262
// Implicit arguments to repairNet bnet recursion.
260263
const sta::Pin* drvr_pin_ = nullptr;
264+
bool drvr_resized_ = false;
261265
float max_cap_ = 0;
262266
int max_length_ = 0;
263267
double slew_margin_ = 0;

0 commit comments

Comments
 (0)