Skip to content

Commit 72ed7af

Browse files
authored
Merge pull request #8107 from The-OpenROAD-Project-staging/secure-hold-buffering-fix
rsz: Fixed RepairHold::makeHoldDelay() to resolve ORD-2030 errors in multiple hierarchical designs
2 parents 79a7613 + 60a295a commit 72ed7af

File tree

5 files changed

+103
-129
lines changed

5 files changed

+103
-129
lines changed

src/dbSta/src/dbEditHierarchy.cc

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,12 +236,34 @@ void dbEditHierarchy::hierarchicalConnect(dbITerm* source_pin,
236236

237237
dlogHierConnStart(source_pin, dest_pin, connection_name);
238238

239-
// 1. Get the scope (dbModule*) of the source and destination pins
240-
dbModule* source_db_module = source_pin->getInst()->getModule();
241-
dbModule* dest_db_module = dest_pin->getInst()->getModule();
242-
// it is possible that one or other of the pins is not involved
243-
// in hierarchy, which is ok, and the source/dest modnet will be null
244-
dbModNet* source_db_mod_net = source_pin->getModNet();
239+
//
240+
// 1. Connect source and dest pins directly in flat flow
241+
//
242+
dbNet* source_db_net = source_pin->getNet();
243+
dbNet* dest_db_net = dest_pin->getNet();
244+
if (db_network_->hierarchy_ == false) {
245+
// If both source pin and dest pin do not have a corresponding flat net,
246+
// Create a new net and connect it with source pin.
247+
if (source_db_net == nullptr && dest_db_net == nullptr) {
248+
Net* new_net = db_network_->makeNet(
249+
connection_name,
250+
db_network_->parent(db_network_->dbToSta(source_pin->getInst())),
251+
odb::dbNameUniquifyType::IF_NEEDED);
252+
source_db_net = db_network_->staToDb(new_net);
253+
source_pin->connect(source_db_net);
254+
}
255+
256+
// Connect
257+
if (source_db_net) {
258+
dest_pin->connect(source_db_net);
259+
} else {
260+
assert(dest_db_net);
261+
source_pin->connect(dest_db_net);
262+
}
263+
264+
dlogHierConnDone();
265+
return; // Done here in a flat flow
266+
}
245267

246268
//
247269
// 2. Make sure there is a direct flat net connection
@@ -250,7 +272,6 @@ void dbEditHierarchy::hierarchicalConnect(dbITerm* source_pin,
250272
// co-existing, something we respect even when making
251273
// new hierarchical connections.
252274
//
253-
dbNet* source_db_net = source_pin->getNet();
254275
if (!source_db_net) {
255276
dlogHierConnCreateFlatNet(connection_name);
256277
Net* new_net = db_network_->makeNet(
@@ -271,6 +292,13 @@ void dbEditHierarchy::hierarchicalConnect(dbITerm* source_pin,
271292
// 3. Make the hierarchical connection.
272293
// in case when pins in different modules
273294
//
295+
296+
// Get the scope (dbModule*) of the source and destination pins
297+
dbModule* source_db_module = source_pin->getInst()->getModule();
298+
dbModule* dest_db_module = dest_pin->getInst()->getModule();
299+
// it is possible that one or other of the pins is not involved
300+
// in hierarchy, which is ok, and the source/dest modnet will be null
301+
dbModNet* source_db_mod_net = source_pin->getModNet();
274302
if (source_db_module != dest_db_module) {
275303
//
276304
// 3.1. Attempt to factor connection (minimize punch through), and return

src/dbSta/src/dbNetwork.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,7 @@ ObjectId dbNetwork::id(const Net* net) const
15781578
const dbObject* obj = reinterpret_cast<const dbObject*>(net);
15791579
return getDbNwkObjectId(obj);
15801580
}
1581+
assert(dnet != nullptr);
15811582
return dnet->getId();
15821583
}
15831584

src/odb/src/db/dbModNet.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ const char* dbModNet::getName() const
166166
void dbModNet::rename(const char* new_name)
167167
{
168168
_dbModNet* obj = (_dbModNet*) this;
169+
if (strcmp(obj->_name, new_name) == 0) {
170+
return;
171+
}
172+
169173
_dbBlock* block = (_dbBlock*) obj->getOwner();
170174
_dbModule* parent = block->_module_tbl->getPtr(obj->_parent);
171175
parent->_modnet_hash.erase(obj->_name);

src/rsz/src/RepairHold.cc

Lines changed: 54 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -680,140 +680,78 @@ void RepairHold::makeHoldDelay(Vertex* drvr,
680680
const Point& loc)
681681
{
682682
Pin* drvr_pin = drvr->pin();
683-
odb::dbModNet* mod_drvr_net = nullptr; // hierarchical driver, default none
684-
dbNet* db_drvr_net = nullptr; // regular flat driver
685-
686-
Instance* parent = nullptr;
687-
if (db_network_->hasHierarchy()) {
688-
// get the nets on the driver pin (possibly both flat and hierarchical)
689-
db_network_->net(drvr_pin, db_drvr_net, mod_drvr_net);
690-
// Get the parent instance (owning the instance of the driver pin)
691-
// we will put the new buffer in that parent
692-
parent = db_network_->getOwningInstanceParent(drvr_pin);
693-
// exception case: drvr pin is a top level, fix the db_drvr_net to be
694-
// the lower level net. Explictly get the "flat" net.
695-
if (network_->isTopLevelPort(drvr_pin)) {
696-
db_drvr_net = db_network_->flatNet(db_network_->term(drvr_pin));
697-
}
698-
} else {
699-
// original flat code (which handles exception case at top level &
700-
// defaults to top level instance as parent).
701-
db_drvr_net = db_network_->staToDb(
702-
network_->isTopLevelPort(drvr_pin)
703-
? db_network_->net(db_network_->term(drvr_pin))
704-
: db_network_->net(drvr_pin));
705-
parent = db_network_->topInstance();
706-
}
707-
Net *in_net = nullptr, *out_net = nullptr;
708-
709-
if (loads_have_out_port) {
710-
// Verilog uses nets as ports, so the net connected to an output port has
711-
// to be preserved.
712-
// Move the driver pin over to gensym'd net.
683+
dbNet* db_drvr_net = db_network_->findFlatDbNet(drvr_pin);
684+
odb::dbModNet* mod_drvr_net = db_network_->hierNet(drvr_pin);
685+
Instance* parent = db_network_->getOwningInstanceParent(drvr_pin);
686+
687+
// If output port is in load pins, do "Driver pin buffering".
688+
// - Verilog uses nets as ports, so the net connected to an output port has
689+
// - to be preserved.
690+
// - Move the driver pin over to gensym'd net.
691+
// Otherwise, do "Load pin buffering".
692+
bool driver_pin_buffering = loads_have_out_port;
693+
Net* buf_input_net = nullptr;
694+
Net* buf_output_net = nullptr;
695+
if (driver_pin_buffering) {
696+
// Do "Driver pin buffering": Buffer drives the existing net.
713697
//
714-
in_net = db_network_->makeNet();
698+
// driver --- (new_net) --- new_buffer ---- (existing_net) ---- loads
699+
//
700+
buf_input_net = db_network_->makeNet(parent); // New net
715701
Port* drvr_port = network_->port(drvr_pin);
716702
Instance* drvr_inst = network_->instance(drvr_pin);
717703
sta_->disconnectPin(drvr_pin);
718-
sta_->connectPin(drvr_inst, drvr_port, in_net);
719-
out_net = db_network_->dbToSta(db_drvr_net);
704+
sta_->connectPin(drvr_inst, drvr_port, buf_input_net);
705+
buf_output_net = db_network_->dbToSta(db_drvr_net);
720706
} else {
721-
in_net = db_network_->dbToSta(db_drvr_net);
722-
// make the output net, put in same module as buffer
723-
out_net = db_network_->makeNet(parent);
724-
}
725-
726-
dbNet* in_net_db = db_network_->staToDb(in_net);
727-
728-
// Disconnect the original drvr pin from everything (hierarchical nets
729-
// and flat nets).
730-
odb::dbITerm* drvr_pin_iterm;
731-
odb::dbBTerm* drvr_pin_bterm;
732-
odb::dbModITerm* drvr_pin_moditerm;
733-
db_network_->staToDb(
734-
drvr_pin, drvr_pin_iterm, drvr_pin_bterm, drvr_pin_moditerm);
735-
if (drvr_pin_iterm) {
736-
// disconnect the iterm from both the modnet and the dbnet
737-
// note we will rewire the drvr_pin to connect to the new buffer later.
738-
drvr_pin_iterm->disconnect();
739-
drvr_pin_iterm->connect(in_net_db);
740-
}
741-
if (drvr_pin_moditerm) {
742-
drvr_pin_moditerm->disconnect();
707+
// Do "Load pin buffering": The existing net drives the new buffer.
708+
//
709+
// driver --- (existing_net) --- new_buffer ---- (new_net) ---- loads
710+
//
711+
buf_input_net = db_network_->dbToSta(db_drvr_net);
712+
buf_output_net = db_network_->makeNet(parent); // New net
743713
}
744714

745-
LibertyPort *input, *output;
746-
buffer_cell->bufferPorts(input, output);
747-
748-
// drvr_pin->drvr_net->hold_buffer->net2->load_pins
749-
750-
// make the buffer in the driver pin's parent
715+
// Make the buffer in the driver pin's parent hierarchy
751716
Instance* buffer = resizer_->makeBuffer(buffer_cell, "hold", parent, loc);
752717
inserted_buffer_count_++;
753718
debugPrint(
754719
logger_, RSZ, "repair_hold", 3, " insert {}", network_->name(buffer));
755720

756-
// wire in the buffer
757-
sta_->connectPin(buffer, input, in_net);
758-
sta_->connectPin(buffer, output, out_net);
759-
760-
// Now patch in the output of the new buffer to the original hierarchical
761-
// net,if any, from the original driver
762-
if (mod_drvr_net != nullptr) {
763-
Pin* ip_pin = nullptr;
764-
Pin* op_pin = nullptr;
765-
resizer_->getBufferPins(buffer, ip_pin, op_pin);
766-
(void) ip_pin;
767-
if (op_pin) {
768-
// get the iterm of the op_pin of the buffer (a dbInst)
769-
// and connect to the hierarchical net.
770-
odb::dbITerm* iterm;
771-
odb::dbBTerm* bterm;
772-
odb::dbModITerm* moditerm;
773-
db_network_->staToDb(op_pin, iterm, bterm, moditerm);
774-
// we only need to look at the iterm, the buffer is a dbInst
775-
if (iterm) {
776-
// hook up the hierarchical net
777-
iterm->connect(mod_drvr_net);
778-
}
779-
}
721+
LibertyPort *input, *output;
722+
buffer_cell->bufferPorts(input, output);
723+
Pin* buffer_in_pin = network_->findPin(buffer, input);
724+
Pin* buffer_out_pin = network_->findPin(buffer, output);
725+
726+
// Connect input and output of the new buffer
727+
sta_->connectPin(buffer, input, buf_input_net);
728+
sta_->connectPin(buffer, output, buf_output_net);
729+
730+
// TODO: Revisit this. Looks not good.
731+
if (mod_drvr_net) {
732+
// The input of the buffer is a new load on the original hierarchical net.
733+
db_network_->connectPin(buffer_in_pin, (Net*) mod_drvr_net);
780734
}
781735

782-
// hook up loads to buffer
783-
for (const Pin* load_pin : load_pins) {
784-
if (resizer_->dontTouch(load_pin)) {
785-
continue;
786-
}
787-
dbNet* db_load_net = network_->isTopLevelPort(load_pin)
788-
? db_network_->flatNet(network_->term(load_pin))
789-
: db_network_->flatNet(load_pin);
790-
Net* load_net = db_network_->dbToSta(db_load_net);
791-
792-
if (load_net != out_net) {
793-
Instance* load = db_network_->instance(load_pin);
794-
Port* load_port = db_network_->port(load_pin);
795-
// record the original connections
796-
odb::dbModNet* original_mod_net = nullptr;
797-
odb::dbNet* original_flat_net = nullptr;
798-
db_network_->net(load_pin, original_flat_net, original_mod_net);
799-
(void) original_flat_net;
800-
// Remove all the connections on load_pin
801-
sta_->disconnectPin(const_cast<Pin*>(load_pin));
802-
// Connect it to the correct output driver net
803-
sta_->connectPin(load, load_port, out_net);
804-
// connect the original load modnet (hierarchical net), if any,
805-
// on the iterm of the buffer created.
806-
odb::dbITerm* iterm;
807-
odb::dbBTerm* bterm;
808-
odb::dbModITerm* moditerm;
809-
db_network_->staToDb(load_pin, iterm, bterm, moditerm);
810-
if (iterm && original_mod_net) {
811-
iterm->connect(original_mod_net);
736+
// Buffering target load pins.
737+
// - No need in driver pin buffering case
738+
if (driver_pin_buffering == false) {
739+
// Do load pins buffering
740+
for (const Pin* load_pin : load_pins) {
741+
if (resizer_->dontTouch(load_pin)) {
742+
continue;
812743
}
744+
745+
// Disconnect the load pin
746+
db_network_->disconnectPin(const_cast<Pin*>(load_pin));
747+
748+
// Connect with the buffer output
749+
db_network_->hierarchicalConnect(db_network_->flatPin(buffer_out_pin),
750+
db_network_->flatPin(load_pin));
813751
}
814752
}
815753

816-
Pin* buffer_out_pin = network_->findPin(buffer, output);
754+
// Update RC and delay. Resize if necessary
817755
Vertex* buffer_out_vertex = graph_->pinDrvrVertex(buffer_out_pin);
818756
estimate_parasitics_->updateParasitics();
819757
// Sta::checkMaxSlewCap does not force dcalc update so do it explicitly.

src/rsz/test/repair_hold1_hier_out.vok

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,27 @@ module top (clk,
3434
.Q(out));
3535
BUF_X1 u1 (.A(r2q),
3636
.Z(u1z));
37-
AND2_X1 u2 (.A1(r1q),
37+
AND2_X1 u2 (.A1(net_o),
3838
.A2(u1z),
3939
.ZN(u2z));
40-
hier1 h1 (.in1(in1),
40+
hier1 h1 (.net_o(net_o),
41+
.in1(in1),
4142
.i1z(i1z),
4243
.op(r1q));
4344
endmodule
44-
module hier1 (in1,
45+
module hier1 (net_o,
46+
in1,
4547
i1z,
4648
op);
49+
output net_o;
4750
input in1;
4851
input i1z;
4952
output op;
5053

5154

52-
CLKBUF_X1 hold1 (.A(r1q),
53-
.Z(op));
55+
CLKBUF_X1 hold1 (.A(op),
56+
.Z(net_o));
5457
DFF_X1 r1 (.D(in1),
5558
.CK(i1z),
56-
.Q(r1q));
59+
.Q(op));
5760
endmodule

0 commit comments

Comments
 (0)