Skip to content

Commit 2292048

Browse files
authored
Merge pull request #8684 from The-OpenROAD-Project-staging/secure-fix-swap-master
Fixed wrong netlist editing issues caused by dbModInst::swapMaster().
2 parents 0a9b58c + fed9ef3 commit 2292048

27 files changed

Lines changed: 118004 additions & 381 deletions

src/dbSta/include/db_sta/dbNetwork.hh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,14 @@ class dbNetwork : public ConcreteNetwork
7272
CellPortIterator* portIterator(const Cell* cell) const override;
7373

7474
// sanity checkers
75-
void checkAxioms() const;
75+
void checkAxioms(odb::dbObject* obj = nullptr) const;
7676
void checkSanityModBTerms() const;
7777
void checkSanityModITerms() const;
7878
void checkSanityModuleInsts() const;
7979
void checkSanityModInstTerms() const;
8080
void checkSanityUnusedModules() const;
8181
void checkSanityTermConnectivity() const;
82-
void checkSanityNetConnectivity() const;
82+
void checkSanityNetConnectivity(odb::dbObject* obj = nullptr) const;
8383
void checkSanityInstNames() const;
8484
void checkSanityNetNames() const;
8585
void checkSanityModNetNamesInModule(odb::dbModule* module) const;

src/dbSta/src/dbNetwork.cc

Lines changed: 82 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Recommended conclusion: use map for concrete cells. They are invariant.
6565
#include "odb/dbSet.h"
6666
#include "odb/dbTypes.h"
6767
#include "sta/Liberty.hh"
68+
#include "sta/Network.hh"
6869
#include "sta/NetworkClass.hh"
6970
#include "sta/PatternMatch.hh"
7071
#include "sta/PortDirection.hh"
@@ -4130,8 +4131,15 @@ void dbNetwork::accumulateFlatLoadPinsOnNet(
41304131
}
41314132

41324133
// Use this API to check if flat & hier connectivities are ok
4133-
void dbNetwork::checkAxioms() const
4134+
void dbNetwork::checkAxioms(odb::dbObject* obj) const
41344135
{
4136+
// Check with an object if provided
4137+
if (obj != nullptr) {
4138+
checkSanityNetConnectivity(obj);
4139+
return;
4140+
}
4141+
4142+
// Otherwise, check the whole design
41354143
checkSanityModBTerms();
41364144
checkSanityModITerms();
41374145
checkSanityModInstTerms();
@@ -4458,79 +4466,90 @@ void dbNetwork::checkSanityTermConnectivity() const
44584466
}
44594467
}
44604468

4461-
void dbNetwork::checkSanityNetConnectivity() const
4469+
void dbNetwork::checkSanityNetConnectivity(odb::dbObject* obj) const
44624470
{
4463-
// Check for hier net and flat net connectivity
4464-
dbSet<dbModNet> mod_nets = block()->getModNets();
4465-
for (dbModNet* mod_net : mod_nets) {
4466-
findRelatedDbNet(mod_net);
4467-
}
4468-
4469-
// Check for incomplete flat net connections
4470-
for (odb::dbNet* net_db : block_->getNets()) {
4471-
// Check for multiple drivers.
4472-
Net* net = dbToSta(net_db);
4473-
PinSeq loads;
4474-
PinSeq drvrs;
4475-
PinSet visited_drvrs(this);
4476-
FindNetDrvrLoads visitor(nullptr, visited_drvrs, loads, drvrs, this);
4477-
NetSet visited_nets(this);
4478-
visitConnectedPins(net, visitor, visited_nets);
4479-
4480-
if (drvrs.size() > 1) {
4481-
bool all_tristate = true;
4482-
for (const Pin* drvr : drvrs) {
4483-
LibertyPort* port = libertyPort(drvr);
4484-
if (!port || !port->direction()->isAnyTristate()) {
4485-
all_tristate = false;
4486-
break;
4471+
//
4472+
// Check for a specific object if provided
4473+
//
4474+
if (obj != nullptr) {
4475+
// Collect relevant nets from the provided object
4476+
std::set<odb::dbNet*> nets_to_check;
4477+
std::set<odb::dbModNet*> mod_nets_to_check;
4478+
4479+
auto const obj_type = obj->getObjectType();
4480+
if (obj_type == odb::dbNetObj) {
4481+
nets_to_check.insert(static_cast<odb::dbNet*>(obj));
4482+
} else if (obj_type == odb::dbModNetObj) {
4483+
mod_nets_to_check.insert(static_cast<odb::dbModNet*>(obj));
4484+
} else if (obj_type == odb::dbInstObj) {
4485+
auto inst = static_cast<odb::dbInst*>(obj);
4486+
for (auto iterm : inst->getITerms()) {
4487+
if (iterm->getNet() != nullptr) {
4488+
nets_to_check.insert(iterm->getNet());
4489+
}
4490+
if (iterm->getModNet() != nullptr) {
4491+
mod_nets_to_check.insert(iterm->getModNet());
44874492
}
44884493
}
4489-
4490-
if (!all_tristate) {
4491-
std::string drivers_str;
4492-
for (const Pin* drvr : drvrs) {
4493-
drivers_str += " " + std::string(pathName(drvr));
4494+
} else if (obj_type == odb::dbModInstObj) {
4495+
auto mod_inst = static_cast<odb::dbModInst*>(obj);
4496+
for (auto mod_iterm : mod_inst->getModITerms()) {
4497+
if (mod_iterm->getModNet() != nullptr) {
4498+
mod_nets_to_check.insert(mod_iterm->getModNet());
44944499
}
4495-
logger_->error(
4496-
ORD,
4497-
2049,
4498-
"SanityCheck: Net '{}' has multiple non-tristate drivers:{}",
4499-
name(net),
4500-
drivers_str);
45014500
}
4502-
}
4503-
const uint iterm_count = net_db->getITerms().size();
4504-
const uint bterm_count = net_db->getBTerms().size();
4505-
if (iterm_count + bterm_count >= 2) {
4506-
continue;
4501+
} else if (obj_type == odb::dbITermObj) {
4502+
auto iterm = static_cast<odb::dbITerm*>(obj);
4503+
if (iterm->getNet() != nullptr) {
4504+
nets_to_check.insert(iterm->getNet());
4505+
}
4506+
if (iterm->getModNet() != nullptr) {
4507+
mod_nets_to_check.insert(iterm->getModNet());
4508+
}
4509+
} else if (obj_type == odb::dbBTermObj) {
4510+
auto bterm = static_cast<odb::dbBTerm*>(obj);
4511+
if (bterm->getNet() != nullptr) {
4512+
nets_to_check.insert(bterm->getNet());
4513+
}
4514+
if (bterm->getModNet() != nullptr) {
4515+
mod_nets_to_check.insert(bterm->getModNet());
4516+
}
4517+
} else if (obj_type == odb::dbModITermObj) {
4518+
auto mod_iterm = static_cast<odb::dbModITerm*>(obj);
4519+
if (mod_iterm->getModNet() != nullptr) {
4520+
mod_nets_to_check.insert(mod_iterm->getModNet());
4521+
}
4522+
} else if (obj_type == odb::dbModBTermObj) {
4523+
auto mod_bterm = static_cast<odb::dbModBTerm*>(obj);
4524+
if (mod_bterm->getModNet() != nullptr) {
4525+
mod_nets_to_check.insert(mod_bterm->getModNet());
4526+
}
45074527
}
45084528

4509-
// Skip power/ground net
4510-
if (net_db->getSigType().isSupply()) {
4511-
continue; // OK: Unconnected power/ground net
4529+
// Now run checks on the collected nets.
4530+
for (odb::dbModNet* mod_net : mod_nets_to_check) {
4531+
findRelatedDbNet(mod_net);
45124532
}
45134533

4514-
// A net connected to 1 terminal
4515-
if (iterm_count == 1) {
4516-
odb::dbITerm* iterm = *(net_db->getITerms().begin());
4517-
if (iterm->getIoType() == odb::dbIoType::OUTPUT) {
4518-
continue; // OK: Unconnected output pin
4519-
}
4520-
} else if (bterm_count == 1) { // This is a top level port
4521-
odb::dbBTerm* bterm = *(net_db->getBTerms().begin());
4522-
if (bterm->getIoType() == odb::dbIoType::INPUT) {
4523-
continue; // OK: Unconnected input port
4524-
}
4534+
for (odb::dbNet* net_db : nets_to_check) {
4535+
net_db->checkSanity();
45254536
}
4537+
return;
4538+
}
45264539

4527-
logger_->warn(ORD,
4528-
2039,
4529-
"SanityCheck: Net '{}' has less than 2 connections (# of "
4530-
"ITerms = {}, # of BTerms = {}).",
4531-
net_db->getName(),
4532-
iterm_count,
4533-
bterm_count);
4540+
//
4541+
// Check for all nets in the design
4542+
//
4543+
4544+
// Check for hier net and flat net connectivity
4545+
dbSet<dbModNet> mod_nets = block()->getModNets();
4546+
for (dbModNet* mod_net : mod_nets) {
4547+
findRelatedDbNet(mod_net);
4548+
}
4549+
4550+
// Check for incomplete flat net connections
4551+
for (odb::dbNet* net_db : block()->getNets()) {
4552+
net_db->checkSanity();
45344553
}
45354554
}
45364555

src/dbSta/test/check_axioms.ok

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias, 135 library cells
2-
[WARNING ORD-2039] SanityCheck: Net 'out_unconnected' has less than 2 connections (# of ITerms = 0, # of BTerms = 1).
3-
[WARNING ORD-2039] SanityCheck: Net 'single_conn_wire' has less than 2 connections (# of ITerms = 0, # of BTerms = 0).
4-
[WARNING ORD-2039] SanityCheck: Net 'w2' has less than 2 connections (# of ITerms = 0, # of BTerms = 1).
2+
[WARNING ORD-0011] Hierarchical flow (-hier) is currently in development and may cause multiple issues. Do not use in production environments.
3+
[WARNING ODB-0050] SanityCheck: dbNet 'out_unconnected' has no driver.
4+
[WARNING ODB-0051] SanityCheck: dbNet 'out_unconnected' is dangling. It has less than 2 connections (# of ITerms = 0, # of BTerms = 1).
5+
[WARNING ODB-0051] SanityCheck: dbNet 'single_conn_wire' is dangling. It has less than 2 connections (# of ITerms = 0, # of BTerms = 0).
6+
[WARNING ODB-0050] SanityCheck: dbNet 'w2' has no driver.
7+
[WARNING ODB-0051] SanityCheck: dbNet 'w2' is dangling. It has less than 2 connections (# of ITerms = 0, # of BTerms = 1).
58
[WARNING ORD-2038] SanityCheck: Module 'i_empty' has no instances.
69
[WARNING ORD-2038] SanityCheck: Module 'u1' has no instances.
710
[WARNING ORD-2038] SanityCheck: Module 'u2' has no instances.

src/dbSta/test/check_axioms.tcl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ source "helpers.tcl"
55
read_liberty Nangate45/Nangate45_typ.lib
66
read_lef Nangate45/Nangate45.lef
77
read_verilog check_axioms.v
8-
link_design top
8+
link_design top -hier
99

1010
# Run the checks and capture output.
1111
# The 'catch' command is used because sta::check_axioms will exit with an

src/dbSta/test/check_axioms.v

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// A standard cell definition for the test.
2-
// Defined as a blackbox to prevent yosys from optimizing it away.
32
module and2 (input A, input B, output Z);
43
endmodule
54

@@ -19,18 +18,19 @@ module top (
1918
output out_unconnected // For ORD-2040
2019
);
2120

22-
// For ORD-2038: An instance of a module that has no instances inside.
21+
// [WARNING ORD-2038] SanityCheck: Module 'i_empty' has no instances.
2322
empty_module i_empty();
2423

25-
// For ORD-2041: non-output ITerm not connected.
24+
// [ODB-0050] SanityCheck: 'w2' has no driver.
25+
// [ODB-0051] SanityCheck: 'w2' has less than 2 connections
2626
wire w1, w2;
2727
and2 u1 (.A(w1), .B(), .Z(w2));
2828

29-
// For ORD-2039: Net with < 2 connections.
29+
// [ODB-0051] SanityCheck: 'single_conn_wire' has less than 2 connections
3030
wire single_conn_wire;
3131
and2 u2 (.A(single_conn_wire), .B(top_in), .Z());
3232

33-
wire dangling_wire; // another case for ORD-2039
33+
wire dangling_wire;
3434

3535
// Normal connection to make the design valid for linking.
3636
assign top_out = w2;

src/odb/include/odb/db.h

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,7 @@ class dbBlock : public dbObject
943943
/// A hierarchy delimiter can only be set at the time
944944
/// a block is created.
945945
///
946-
char getHierarchyDelimiter();
946+
char getHierarchyDelimiter() const;
947947

948948
///
949949
/// Set the bus name delimiters
@@ -1306,6 +1306,8 @@ class dbBlock : public dbObject
13061306
const dbNameUniquifyType& uniquify
13071307
= dbNameUniquifyType::ALWAYS);
13081308

1309+
const char* getBaseName(const char* full_name) const;
1310+
13091311
///
13101312
/// return the regions of this design
13111313
///
@@ -1845,7 +1847,7 @@ class dbNet : public dbObject
18451847
///
18461848
/// Get the Regular Wiring of a net (TODO: per path)
18471849
///
1848-
dbWireType getWireType();
1850+
dbWireType getWireType() const;
18491851

18501852
///
18511853
/// Set the Regular Wiring of a net (TODO: per path)
@@ -1855,7 +1857,7 @@ class dbNet : public dbObject
18551857
///
18561858
/// Get the signal type of this block-net.
18571859
///
1858-
dbSigType getSigType();
1860+
dbSigType getSigType() const;
18591861

18601862
///
18611863
/// Get the signal type of this block-net.
@@ -1964,7 +1966,7 @@ class dbNet : public dbObject
19641966
///
19651967
/// Returns true if the don't-touch flag is set.
19661968
///
1967-
bool isDoNotTouch();
1969+
bool isDoNotTouch() const;
19681970

19691971
///
19701972
/// Get the block this net belongs to.
@@ -2028,7 +2030,7 @@ class dbNet : public dbObject
20282030
/// Returns true if this dbNet is marked as special. Special nets/iterms are
20292031
/// declared in the SPECIAL NETS section of a DEF file.
20302032
///
2031-
bool isSpecial();
2033+
bool isSpecial() const;
20322034

20332035
///
20342036
/// Mark this dbNet as special.
@@ -2501,6 +2503,16 @@ class dbNet : public dbObject
25012503
/// related to this flat net.
25022504
///
25032505
void renameWithModNetInHighestHier();
2506+
2507+
///
2508+
/// Check issues such as multiple drivers, no driver, or dangling net
2509+
///
2510+
void checkSanity() const;
2511+
2512+
///
2513+
/// Dump dbNet info for debugging
2514+
///
2515+
void dump() const;
25042516
};
25052517

25062518
///////////////////////////////////////////////////////////////////////////////
@@ -8380,6 +8392,12 @@ class dbModNet : public dbObject
83808392
void disconnectAllTerms();
83818393
void dump() const;
83828394

8395+
// Find the flat net (dbNet) associated with this hierarchical net (dbModNet).
8396+
// A dbModNet should be associated with a single dbNet.
8397+
// This function traverses the terminals connected to this dbModNet
8398+
// and returns the first dbNet it finds.
8399+
dbNet* findRelatedNet() const;
8400+
83838401
static dbModNet* getModNet(dbBlock* block, uint id);
83848402
static dbModNet* create(dbModule* parentModule, const char* base_name);
83858403
static dbSet<dbModNet>::iterator destroy(dbSet<dbModNet>::iterator& itr);
@@ -8408,15 +8426,15 @@ class dbModule : public dbObject
84088426

84098427
dbBlock* getOwner();
84108428

8411-
dbSet<dbModInst> getChildren();
8412-
dbSet<dbModInst> getModInsts();
8429+
dbSet<dbModInst> getChildren() const;
8430+
dbSet<dbModInst> getModInsts() const;
84138431
dbSet<dbModNet> getModNets();
84148432
// Get the ports of a module (STA world uses ports, which contain members).
84158433
dbSet<dbModBTerm> getPorts();
84168434
// Get the leaf level connections on a module (flat connected view).
84178435
dbSet<dbModBTerm> getModBTerms() const;
84188436
dbModBTerm* getModBTerm(uint id);
8419-
dbSet<dbInst> getInsts();
8437+
dbSet<dbInst> getInsts() const;
84208438

84218439
dbModInst* findModInst(const char* name);
84228440
dbInst* findDbInst(const char* name);
@@ -8430,6 +8448,8 @@ class dbModule : public dbObject
84308448
const dbModBTerm* getHeadDbModBTerm() const;
84318449
bool canSwapWith(dbModule* new_module) const;
84328450
bool isTop() const;
8451+
bool containsDbInst(dbInst* inst) const;
8452+
bool containsDbModInst(dbModInst* inst) const;
84338453

84348454
static dbModule* create(dbBlock* block, const char* name);
84358455

src/odb/src/db/dbBlock.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2164,7 +2164,7 @@ int64_t dbBlock::micronsAreaToDbu(const double micronsArea)
21642164
return static_cast<int64_t>(std::round(dbuArea));
21652165
}
21662166

2167-
char dbBlock::getHierarchyDelimiter()
2167+
char dbBlock::getHierarchyDelimiter() const
21682168
{
21692169
_dbBlock* block = (_dbBlock*) this;
21702170
return block->_hier_delimiter;
@@ -3855,4 +3855,17 @@ std::string dbBlock::makeNewInstName(dbModInst* parent,
38553855
parent, base_name, uniquify, block->_unique_inst_index, exists);
38563856
}
38573857

3858+
const char* dbBlock::getBaseName(const char* full_name) const
3859+
{
3860+
// If name contains the hierarchy delimiter, use the partial string
3861+
// after the last occurrence of the hierarchy delimiter.
3862+
// This prevents a very long term/net name creation when the name
3863+
// begins with a back-slash as "\soc/module1/instance_a/.../clk_port"
3864+
const char* last_hier_delimiter = strrchr(full_name, getHierarchyDelimiter());
3865+
if (last_hier_delimiter != nullptr) {
3866+
return last_hier_delimiter + 1;
3867+
}
3868+
return full_name;
3869+
}
3870+
38583871
} // namespace odb

0 commit comments

Comments
 (0)