Skip to content

Commit f8718e4

Browse files
authored
Merge pull request #10542 from The-OpenROAD-Project-staging/rsz-repair-design-reroute
RSZ: repair design reroute for slew fix
2 parents 75d6372 + 2d2df96 commit f8718e4

18 files changed

Lines changed: 306 additions & 40 deletions

src/grt/include/grt/GlobalRouter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ class GlobalRouter
317317
float getLayerResistance(int layer, int length, odb::dbNet* net);
318318
float getViaResistance(int from_layer, int to_layer);
319319
float getFRNetResistance(odb::dbNet* db_net);
320-
float getFRNetResistanceOnMinClockLayer(odb::dbNet* db_net);
320+
float getFRNetResistanceOnMinResistanceLayer(odb::dbNet* db_net);
321321
double dbuToMicrons(int dbu);
322322
float estimatePathResistance(odb::dbObject* pin1,
323323
odb::dbObject* pin2,

src/grt/src/GlobalRouter.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3829,12 +3829,28 @@ float GlobalRouter::getFRNetResistance(odb::dbNet* db_net)
38293829
return fastroute_->getNetResistance(db_net);
38303830
}
38313831

3832-
float GlobalRouter::getFRNetResistanceOnMinClockLayer(odb::dbNet* db_net)
3833-
{
3834-
int min_layer = getMinLayerForClock() > 0 ? getMinLayerForClock()
3835-
: getMinRoutingLayer();
3832+
float GlobalRouter::getFRNetResistanceOnMinResistanceLayer(odb::dbNet* db_net)
3833+
{
3834+
const int min_routing_layer = getMinRoutingLayer();
3835+
const int max_routing_layer = getMaxRoutingLayer();
3836+
int min_res_layer = min_routing_layer;
3837+
float min_res_per_width = std::numeric_limits<float>::max();
3838+
for (const auto& [layer_idx, tech_layer] : routing_layers_) {
3839+
if (layer_idx < min_routing_layer || layer_idx > max_routing_layer) {
3840+
continue;
3841+
}
3842+
const float width = static_cast<float>(tech_layer->getWidth());
3843+
const float resistance = static_cast<float>(tech_layer->getResistance());
3844+
if (width > 0 && resistance > 0) {
3845+
const float res_per_width = resistance / width;
3846+
if (res_per_width < min_res_per_width) {
3847+
min_res_per_width = res_per_width;
3848+
min_res_layer = layer_idx;
3849+
}
3850+
}
3851+
}
38363852
// FastRouteCore uses 0-based layer indices; routing layer numbers are 1-based
3837-
return fastroute_->getNetResistanceOnLayer(db_net, min_layer - 1);
3853+
return fastroute_->getNetResistanceOnLayer(db_net, min_res_layer - 1);
38383854
}
38393855

38403856
float GlobalRouter::estimatePathResistance(odb::dbObject* pin1,

src/rsz/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ repair_design
149149
[-pre_placement]
150150
[-buffer_gain float_value] (deprecated)
151151
[-match_cell_footprint]
152+
[-reroute]
152153
[-verbose]
153154
```
154155

@@ -163,6 +164,7 @@ repair_design
163164
| `-pre_placement` | Enables performing an initial pre-placement sizing and buffering round. |
164165
| `-buffer_gain` | Deprecated alias for `-pre_placement`. The passed value is ignored. |
165166
| `-match_cell_footprint` | Obey the Liberty cell footprint when swapping gates. |
167+
| `-reroute` | Enable resistance-aware wire rerouting to fix slew violations post-GRT (experimental). |
166168
| `-verbose` | Enable verbose logging on progress of the repair. |
167169

168170
#### Instance Name Prefixes

src/rsz/include/rsz/Resizer.hh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,8 +427,15 @@ class Resizer : public sta::dbStaState, public sta::dbNetworkObserver
427427
double cap_margin, // 0.0-1.0
428428
double buffer_gain,
429429
bool match_cell_footprint,
430+
bool reroute,
430431
bool verbose);
431432
int repairDesignBufferCount() const;
433+
// Try to reroute the net driven by drvr_pin to a lower-resistance layer.
434+
// Returns true if the reroute was accepted (net marked dirty for incremental
435+
// global re-routing and parasitics invalidated). Returns false if the net
436+
// was already rerouted, doesn't exist, or the expected resistance reduction
437+
// is below the threshold.
438+
bool tryRerouteNet(const sta::Pin* drvr_pin);
432439
// for debugging
433440
void repairNet(sta::Net* net,
434441
double max_wire_length, // meters
@@ -760,6 +767,7 @@ class Resizer : public sta::dbStaState, public sta::dbNetworkObserver
760767
// Return values.
761768
sta::Delay& delay,
762769
sta::Slew& slew);
770+
float getRerouteResistanceReduction();
763771

764772
protected:
765773
void makeWireParasitic(sta::Net* net,
@@ -1048,6 +1056,9 @@ class Resizer : public sta::dbStaState, public sta::dbNetworkObserver
10481056

10491057
std::shared_ptr<ResizerObserver> graphics_;
10501058

1059+
// Reroute
1060+
const float kMinResistanceReduction = 0.50f;
1061+
10511062
int accepted_move_count_ = 0;
10521063
int rejected_move_count_ = 0;
10531064

src/rsz/src/RepairDesign.cc

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ void RepairDesign::computeSlewRCFactor()
135135
slew_rc_factor_ = factor * (1 + pessimism);
136136
}
137137

138+
bool RepairDesign::rerouteEnabled() const
139+
{
140+
return reroute_;
141+
}
142+
138143
// Repair long wires, max slew, max capacitance, max fanout violations
139144
// The whole enchilada.
140145
// max_wire_length zero for none (meters)
@@ -301,6 +306,7 @@ void RepairDesign::repairDesign(
301306
repaired_net_count = 0;
302307
inserted_buffer_count_ = 0;
303308
resize_count_ = 0;
309+
rerouted_nets_ = 0;
304310
resizer_->resized_multi_output_insts_.clear();
305311

306312
sta_->checkSlewsPreamble();
@@ -1100,21 +1106,44 @@ void RepairDesign::repairNet(sta::Net* net,
11001106
delayAsString(max_slew1, 3, this));
11011107

11021108
slew_violation = true;
1103-
if (repairDriverSlew(corner1, drvr_pin)) {
1104-
resize_count_++;
1109+
1110+
// Try rerouting to a lower-resistance layer first. If the reroute
1111+
// reduces wire resistance enough, it may fix the slew violation
1112+
// without requiring driver resizing or buffer insertion.
1113+
if (rerouteEnabled() && resizer_->tryRerouteNet(drvr_pin)) {
1114+
rerouted_nets_++;
11051115
estimate_parasitics_->updateParasitics();
11061116
sta_->findDelays(drvr);
11071117
checkSlew(drvr_pin, slew1, max_slew1, slew_slack1, corner1);
1118+
debugPrint(logger_,
1119+
RSZ,
1120+
"repair_net",
1121+
2,
1122+
"after reroute: drvr slew pin={} slew={} max_slew={}",
1123+
network_->name(drvr_pin),
1124+
delayAsString(slew1, 3, this),
1125+
delayAsString(max_slew1, 3, this));
11081126
}
11091127

1110-
// sta::Slew violation persists after resizing the driver, derive
1111-
// the max cap we need to apply to remove the slew violation
1128+
// If slew violation persists after reroute, fall back to driver
1129+
// resizing and, if still needed, buffer insertion.
11121130
if (slew_slack1 < 0.0f) {
1113-
sta::LibertyPort* drvr_port = network_->libertyPort(drvr_pin);
1114-
if (drvr_port) {
1115-
max_cap = findSlewLoadCap(drvr_port, max_slew1, corner1);
1116-
corner = corner1;
1117-
repair_cap = true;
1131+
if (repairDriverSlew(corner1, drvr_pin)) {
1132+
resize_count_++;
1133+
estimate_parasitics_->updateParasitics();
1134+
sta_->findDelays(drvr);
1135+
checkSlew(drvr_pin, slew1, max_slew1, slew_slack1, corner1);
1136+
}
1137+
1138+
// sta::Slew violation persists after resizing the driver, derive
1139+
// the max cap we need to apply to remove the slew violation
1140+
if (slew_slack1 < 0.0f) {
1141+
sta::LibertyPort* drvr_port = network_->libertyPort(drvr_pin);
1142+
if (drvr_port) {
1143+
max_cap = findSlewLoadCap(drvr_port, max_slew1, corner1);
1144+
corner = corner1;
1145+
repair_cap = true;
1146+
}
11181147
}
11191148
}
11201149
}
@@ -1133,6 +1162,7 @@ void RepairDesign::repairNet(sta::Net* net,
11331162
network_->name(drvr_pin),
11341163
delayAsString(slew1, 3, this),
11351164
delayAsString(max_slew1, 3, this));
1165+
11361166
slew_violation = true;
11371167
repair_load_slew = true;
11381168
// If repair_cap is true, corner is already set to correspond
@@ -1141,8 +1171,24 @@ void RepairDesign::repairNet(sta::Net* net,
11411171
corner = corner1;
11421172
}
11431173
} else if (corner_w_load_slew_viol) {
1144-
// There's a violation hidden by an annotation. Repair still
1174+
// There's a violation hidden by an annotation. The forward pass
1175+
// clamped the load pin slew to the limit, so checkLoadSlews above
1176+
// saw slack==0 and didn't fire. Try rerouting before falling back
1177+
// to buffer insertion. Even though we can't re-verify the slew here
1178+
// (the annotation is still active), an improved parasitic from
1179+
// rerouting will reduce how many buffers are needed.
11451180
slew_violation = true;
1181+
if (rerouteEnabled() && resizer_->tryRerouteNet(drvr_pin)) {
1182+
rerouted_nets_++;
1183+
estimate_parasitics_->updateParasitics();
1184+
sta_->findDelays(drvr);
1185+
debugPrint(logger_,
1186+
RSZ,
1187+
"repair_net",
1188+
2,
1189+
"rerouted annotated-slew net {}",
1190+
network_->name(drvr_pin));
1191+
}
11461192
repair_load_slew = true;
11471193
if (!repair_cap) {
11481194
corner = corner_w_load_slew_viol;
@@ -2407,6 +2453,9 @@ void RepairDesign::reportViolationCounters(bool invalidate_driver_vertices,
24072453
if (resize_count_ > 0) {
24082454
logger_->info(utl::RSZ, 39, "Resized {} instances.", resize_count_);
24092455
}
2456+
if (rerouted_nets_ > 0) {
2457+
logger_->info(utl::RSZ, 44, "Rerouted {} nets.", rerouted_nets_);
2458+
}
24102459
if (inserted_buffer_count_ > 0) {
24112460
logger_->info(utl::RSZ,
24122461
invalidate_driver_vertices ? 55 : 38,

src/rsz/src/RepairDesign.hh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class RepairDesign : sta::dbStaState
6666
int& cap_violations,
6767
int& fanout_violations,
6868
int& length_violations);
69+
bool rerouteEnabled() const;
6970
int insertedBufferCount() const { return inserted_buffer_count_; }
7071
void repairNet(sta::Net* net,
7172
double max_wire_length,
@@ -266,6 +267,9 @@ class RepairDesign : sta::dbStaState
266267
double cap_margin_ = 0;
267268
const sta::Scene* corner_ = nullptr;
268269

270+
bool reroute_ = false;
271+
int rerouted_nets_ = 0;
272+
269273
int resize_count_ = 0;
270274
int inserted_buffer_count_ = 0;
271275
const sta::MinMax* min_ = sta::MinMax::min();

src/rsz/src/Resizer.cc

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "boost/multi_array.hpp"
4545
#include "db_sta/dbSta.hh"
4646
#include "est/EstimateParasitics.h"
47+
#include "grt/GRoute.h"
4748
#include "grt/GlobalRouter.h"
4849
#include "odb/PtrSetMap.h"
4950
#include "odb/db.h"
@@ -4810,6 +4811,7 @@ void Resizer::repairDesign(double max_wire_length,
48104811
double cap_margin,
48114812
double buffer_gain,
48124813
bool match_cell_footprint,
4814+
bool reroute,
48134815
bool verbose)
48144816
{
48154817
utl::Timer timer;
@@ -4822,6 +4824,7 @@ void Resizer::repairDesign(double max_wire_length,
48224824
== est::ParasiticsSrc::kDetailedRouting) {
48234825
opendp_->initMacrosAndGrid();
48244826
}
4827+
utl::SetAndRestore set_reroute(repair_design_->reroute_, reroute);
48254828
repair_design_->repairDesign(
48264829
max_wire_length, slew_margin, cap_margin, buffer_gain, verbose);
48274830
logger_->info(RSZ, 504, "Runtime: {:.2f}s", timer.elapsed());
@@ -4832,6 +4835,90 @@ int Resizer::repairDesignBufferCount() const
48324835
return repair_design_->insertedBufferCount();
48334836
}
48344837

4838+
float Resizer::getRerouteResistanceReduction()
4839+
{
4840+
return kMinResistanceReduction;
4841+
}
4842+
4843+
bool Resizer::tryRerouteNet(const sta::Pin* drvr_pin)
4844+
{
4845+
// Res-aware rerouting only makes sense with global-routing parasitics.
4846+
if (estimate_parasitics_->getParasiticsSrc()
4847+
!= est::ParasiticsSrc::kGlobalRouting) {
4848+
return false;
4849+
}
4850+
4851+
sta::Net* net = network_->net(drvr_pin);
4852+
if (net == nullptr || dontTouch(drvr_pin)) {
4853+
return false;
4854+
}
4855+
4856+
odb::dbNet* db_net = db_network_->flatNet(net);
4857+
if (db_net == nullptr || db_net->isSpecial()) {
4858+
return false;
4859+
}
4860+
4861+
// Already scheduled for res-aware routing in a prior iteration.
4862+
if (global_router_->isNetResAware(db_net)) {
4863+
return false;
4864+
}
4865+
4866+
// Unconstrained nets have no timing path; res-aware routing will waste
4867+
// valuable resources.
4868+
const sta::Slack slack = sta_->slack(graph_->pinDrvrVertex(drvr_pin), max_);
4869+
if (slack == sta::INF) {
4870+
return false;
4871+
}
4872+
4873+
// Short nets (<=3 gcells) have negligible resistance; skip the reroute.
4874+
const int kShortNetGCellThreshold = 3;
4875+
const int tile_size = global_router_->getTileSize();
4876+
if (tile_size > 0) {
4877+
const grt::NetRouteMap& routes = global_router_->getRoutes();
4878+
auto it = routes.find(db_net);
4879+
if (it != routes.end()) {
4880+
int gcell_length = 0;
4881+
for (const grt::GSegment& seg : it->second) {
4882+
if (!seg.isVia()) {
4883+
gcell_length += seg.length() / tile_size;
4884+
}
4885+
}
4886+
if (gcell_length <= kShortNetGCellThreshold) {
4887+
return false;
4888+
}
4889+
}
4890+
}
4891+
4892+
// Only reroute if moving to the lowest-resistance layer saves enough
4893+
// resistance to justify the disruption.
4894+
const float resistance = global_router_->getFRNetResistance(db_net);
4895+
const float estimated_resistance
4896+
= global_router_->getFRNetResistanceOnMinResistanceLayer(db_net);
4897+
float reduction_ratio = 0.0f;
4898+
if (resistance > 0.0f) {
4899+
reduction_ratio = (resistance - estimated_resistance) / resistance;
4900+
}
4901+
4902+
if (reduction_ratio < kMinResistanceReduction) {
4903+
return false;
4904+
}
4905+
4906+
global_router_->setResistanceAware(true);
4907+
global_router_->addDirtyNet(db_net);
4908+
global_router_->setNetIsResAware(db_net, true);
4909+
estimate_parasitics_->parasiticsInvalid(db_net);
4910+
4911+
debugPrint(logger_,
4912+
utl::RSZ,
4913+
"reroute",
4914+
1,
4915+
"RepairDesign rerouting net {} (resistance {} -> {} estimated)",
4916+
db_net->getName(),
4917+
resistance,
4918+
estimated_resistance);
4919+
return true;
4920+
}
4921+
48354922
void Resizer::repairNet(sta::Net* net,
48364923
double max_wire_length,
48374924
double slew_margin,

src/rsz/src/Resizer.i

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ repair_design_cmd(double max_length,
309309
double cap_margin,
310310
bool pre_placement,
311311
bool match_cell_footprint,
312+
bool reroute,
312313
bool verbose)
313314
{
314315
ensureLinked();
@@ -318,6 +319,7 @@ repair_design_cmd(double max_length,
318319
cap_margin,
319320
pre_placement,
320321
match_cell_footprint,
322+
reroute,
321323
verbose);
322324
}
323325

src/rsz/src/Resizer.tcl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,13 @@ sta::define_cmd_args "repair_design" {[-max_wire_length max_wire_length] \
148148
[-buffer_gain gain] \
149149
[-pre_placement] \
150150
[-match_cell_footprint] \
151+
[-reroute] \
151152
[-verbose]}
152153

153154
proc repair_design { args } {
154155
sta::parse_key_args "repair_design" args \
155156
keys {-max_wire_length -max_utilization -slew_margin -cap_margin -buffer_gain} \
156-
flags {-match_cell_footprint -verbose -pre_placement}
157+
flags {-match_cell_footprint -verbose -pre_placement -reroute}
157158

158159
set max_wire_length [rsz::parse_max_wire_length keys]
159160
set slew_margin [rsz::parse_percent_margin_arg "-slew_margin" keys]
@@ -171,8 +172,9 @@ proc repair_design { args } {
171172
set max_wire_length [rsz::check_max_wire_length $max_wire_length false]
172173
set match_cell_footprint [info exists flags(-match_cell_footprint)]
173174
set verbose [info exists flags(-verbose)]
175+
set reroute [info exists flags(-reroute)]
174176
rsz::repair_design_cmd $max_wire_length $slew_margin $cap_margin \
175-
$pre_placement $match_cell_footprint $verbose
177+
$pre_placement $match_cell_footprint $reroute $verbose
176178
}
177179

178180
sta::define_cmd_args "repair_clock_nets" {[-max_wire_length max_wire_length]}

0 commit comments

Comments
 (0)