Skip to content

Commit fdc0fa7

Browse files
committed
Merge remote-tracking branch 'origin/master' into odb-database-chip
2 parents 5ccb32a + 528a7d1 commit fdc0fa7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1455
-902
lines changed

include/ord/OpenRoad.hh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ class ICeWall;
101101

102102
namespace utl {
103103
class Logger;
104-
}
104+
class CallBackHandler;
105+
} // namespace utl
105106

106107
namespace dst {
107108
class Distributed;
@@ -137,6 +138,7 @@ class OpenRoad
137138

138139
Tcl_Interp* tclInterp() { return tcl_interp_; }
139140
utl::Logger* getLogger() { return logger_; }
141+
utl::CallBackHandler* getCallBackHandler() { return callback_handler_; }
140142
odb::dbDatabase* getDb() { return db_; }
141143
sta::dbSta* getSta() { return sta_; }
142144
sta::dbNetwork* getDbNetwork();
@@ -256,6 +258,7 @@ class OpenRoad
256258
dst::Distributed* distributer_ = nullptr;
257259
stt::SteinerTreeBuilder* stt_builder_ = nullptr;
258260
dft::Dft* dft_ = nullptr;
261+
utl::CallBackHandler* callback_handler_ = nullptr;
259262

260263
int threads_ = 1;
261264

src/OpenRoad.cc

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include "tap/MakeTapcell.h"
5555
#include "triton_route/MakeTritonRoute.h"
5656
#include "upf/MakeUpf.h"
57+
#include "utl/CallBackHandler.h"
5758
#include "utl/Logger.h"
5859
#include "utl/MakeLogger.h"
5960
#include "utl/Progress.h"
@@ -116,6 +117,7 @@ OpenRoad::~OpenRoad()
116117
dft::deleteDft(dft_);
117118
delete logger_;
118119
delete verilog_reader_;
120+
delete callback_handler_;
119121
}
120122

121123
sta::dbNetwork* OpenRoad::getDbNetwork()
@@ -160,6 +162,7 @@ void OpenRoad::init(Tcl_Interp* tcl_interp,
160162
// Make components.
161163
utl::Progress::setBatchMode(batch_mode);
162164
logger_ = utl::makeLogger(log_filename, metrics_filename);
165+
callback_handler_ = new utl::CallBackHandler(logger_);
163166
db_->setLogger(logger_);
164167
sta_ = sta::makeDbSta();
165168
verilog_network_ = makeDbVerilogNetwork();
@@ -219,6 +222,7 @@ void OpenRoad::init(Tcl_Interp* tcl_interp,
219222
opendp_,
220223
stt_builder_,
221224
logger_,
225+
callback_handler_,
222226
tcl_interp);
223227
initTritonCts(tritonCts_,
224228
db_,
@@ -240,8 +244,13 @@ void OpenRoad::init(Tcl_Interp* tcl_interp,
240244
initOpenRCX(extractor_, db_, logger_, getVersion(), tcl_interp);
241245
initICeWall(icewall_, db_, logger_, tcl_interp);
242246
initRestructure(restructure_, logger_, sta_, db_, resizer_, tcl_interp);
243-
initTritonRoute(
244-
detailed_router_, db_, logger_, distributer_, stt_builder_, tcl_interp);
247+
initTritonRoute(detailed_router_,
248+
db_,
249+
logger_,
250+
callback_handler_,
251+
distributer_,
252+
stt_builder_,
253+
tcl_interp);
245254
initPDNSim(pdnsim_, logger_, db_, sta_, resizer_, opendp_, tcl_interp);
246255
initAntennaChecker(antenna_checker_, db_, logger_, tcl_interp);
247256
initPartitionMgr(

src/dbSta/include/db_sta/dbNetwork.hh

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,16 @@ class dbNetwork : public ConcreteNetwork
6767
void clear() override;
6868
CellPortIterator* portIterator(const Cell* cell) const override;
6969

70-
void AxiomCheck();
70+
// sanity checkers
71+
void checkAxioms();
72+
void checkSanityModBTerms();
73+
void checkSanityModITerms();
74+
void checkSanityModuleInsts();
75+
void checkSanityModInstTerms();
76+
void checkSanityUnusedModules();
77+
void checkSanityTermConnectivity();
78+
void checkSanityNetConnectivity();
79+
7180
void readLefAfter(dbLib* lib);
7281
void readDefAfter(dbBlock* block);
7382
void readDbAfter(dbDatabase* db);

src/dbSta/src/dbNetwork.cc

Lines changed: 189 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4163,12 +4163,16 @@ void dbNetwork::accumulateFlatLoadPinsOnNet(
41634163
visitConnectedPins(net, rp, visited_nets);
41644164
}
41654165

4166-
void dbNetwork::AxiomCheck()
4166+
// Use this API to check if flat & hier connectivities are ok
4167+
void dbNetwork::checkAxioms()
41674168
{
4168-
dbSet<dbModNet> mod_nets = block()->getModNets();
4169-
for (auto mod_net : mod_nets) {
4170-
findRelatedDbNet(mod_net);
4171-
}
4169+
checkSanityModBTerms();
4170+
checkSanityModITerms();
4171+
checkSanityModuleInsts();
4172+
checkSanityModInstTerms();
4173+
checkSanityUnusedModules();
4174+
checkSanityTermConnectivity();
4175+
checkSanityNetConnectivity();
41724176
}
41734177

41744178
Net* dbNetwork::getFlatNet(Net* net) const
@@ -4186,4 +4190,184 @@ Net* dbNetwork::getFlatNet(Net* net) const
41864190
return dbToSta(db_net);
41874191
}
41884192

4193+
void dbNetwork::checkSanityModBTerms()
4194+
{
4195+
if (block_ == nullptr) {
4196+
return;
4197+
}
4198+
for (odb::dbModule* module : block_->getModules()) {
4199+
std::set<std::string> bterm_names;
4200+
for (odb::dbModBTerm* bterm : module->getModBTerms()) {
4201+
const std::string bterm_name = bterm->getName();
4202+
if (bterm_names.find(bterm_name) != bterm_names.end()) {
4203+
logger_->error(
4204+
ORD,
4205+
2036,
4206+
"SanityCheck: Duplicate dbModBTerm name '{}' in module '{}'.",
4207+
bterm_name,
4208+
module->getName());
4209+
}
4210+
bterm_names.insert(bterm_name);
4211+
}
4212+
}
4213+
}
4214+
4215+
void sta::dbNetwork::checkSanityModITerms()
4216+
{
4217+
if (block_ == nullptr) {
4218+
return;
4219+
}
4220+
for (odb::dbModInst* mod_inst : block_->getModInsts()) {
4221+
std::set<std::string> iterm_names;
4222+
for (odb::dbModITerm* iterm : mod_inst->getModITerms()) {
4223+
const std::string iterm_name = iterm->getName();
4224+
if (iterm_names.find(iterm_name) != iterm_names.end()) {
4225+
logger_->error(ORD,
4226+
2037,
4227+
"SanityCheck: Duplicate dbModITerm name '{}' in module "
4228+
"instance '{}'.",
4229+
iterm_name,
4230+
mod_inst->getName());
4231+
}
4232+
iterm_names.insert(iterm_name);
4233+
}
4234+
}
4235+
}
4236+
4237+
void dbNetwork::checkSanityModuleInsts()
4238+
{
4239+
for (odb::dbModule* module : block_->getModules()) {
4240+
if (module->getModInsts().empty() && module->getInsts().empty()) {
4241+
logger_->warn(ORD,
4242+
2038,
4243+
"SanityCheck: Module '{}' has no instances.",
4244+
module->getHierarchicalName());
4245+
}
4246+
}
4247+
}
4248+
4249+
void dbNetwork::checkSanityModInstTerms()
4250+
{
4251+
for (odb::dbModInst* mod_inst : block_->getModInsts()) {
4252+
odb::dbModule* master = mod_inst->getMaster();
4253+
if (master) {
4254+
if (mod_inst->getModITerms().size() != master->getModBTerms().size()) {
4255+
logger_->warn(
4256+
ORD,
4257+
2042,
4258+
"SanityCheck: Module instance '{}' has {} ITerms, but its "
4259+
"master '{}' has {} BTerms.",
4260+
mod_inst->getHierarchicalName(),
4261+
mod_inst->getModITerms().size(),
4262+
master->getHierarchicalName(),
4263+
master->getModBTerms().size());
4264+
}
4265+
}
4266+
}
4267+
}
4268+
4269+
void dbNetwork::checkSanityUnusedModules()
4270+
{
4271+
if (block_ == nullptr) {
4272+
return;
4273+
}
4274+
4275+
// 1. Collect all modules from the top block and its children.
4276+
// Unused modules may be placed in child blocks.
4277+
std::vector<odb::dbModule*> all_modules;
4278+
for (odb::dbModule* module : block_->getModules()) {
4279+
all_modules.push_back(module);
4280+
}
4281+
for (odb::dbBlock* child_block : block_->getChildren()) {
4282+
for (odb::dbModule* module : child_block->getModules()) {
4283+
all_modules.push_back(module);
4284+
}
4285+
}
4286+
4287+
// 2. Create a set of all instantiated module masters.
4288+
std::set<odb::dbModule*> instantiated_masters;
4289+
for (odb::dbModule* module : all_modules) {
4290+
for (odb::dbModInst* mod_inst : module->getModInsts()) {
4291+
instantiated_masters.insert(mod_inst->getMaster());
4292+
}
4293+
}
4294+
4295+
// 3. Iterate through all collected modules to check for usage.
4296+
odb::dbModule* top_module = block_->getTopModule();
4297+
for (odb::dbModule* module : all_modules) {
4298+
// A module is unused if it's not the top module and it's not a master
4299+
// for any module instance.
4300+
if (module != top_module
4301+
&& instantiated_masters.find(module) == instantiated_masters.end()) {
4302+
logger_->warn(
4303+
ORD,
4304+
2043,
4305+
"SanityCheck: Module '{}' is defined but never instantiated.",
4306+
module->getName());
4307+
}
4308+
}
4309+
}
4310+
4311+
void dbNetwork::checkSanityTermConnectivity()
4312+
{
4313+
for (odb::dbBTerm* bterm : block_->getBTerms()) {
4314+
if (bterm->getIoType() != dbIoType::INPUT && bterm->getNet() == nullptr) {
4315+
logger_->error(
4316+
ORD,
4317+
2040,
4318+
"SanityCheck: non-input BTerm '{}' is not connected to any net.",
4319+
bterm->getName());
4320+
}
4321+
}
4322+
4323+
for (odb::dbInst* inst : block_->getInsts()) {
4324+
for (odb::dbITerm* iterm : inst->getITerms()) {
4325+
if (iterm->getIoType() != dbIoType::OUTPUT
4326+
&& iterm->getNet() == nullptr) {
4327+
logger_->error(ORD,
4328+
2041,
4329+
"SanityCheck: non-output ITerm '{}/{}' is not connected "
4330+
"to any net.",
4331+
inst->getName(),
4332+
iterm->getMTerm()->getName());
4333+
}
4334+
}
4335+
}
4336+
}
4337+
4338+
void dbNetwork::checkSanityNetConnectivity()
4339+
{
4340+
// Check for hier net and flat net connectivity
4341+
dbSet<dbModNet> mod_nets = block()->getModNets();
4342+
for (auto mod_net : mod_nets) {
4343+
findRelatedDbNet(mod_net);
4344+
}
4345+
4346+
// Check for incomplete flat net connections
4347+
for (odb::dbNet* net : block_->getNets()) {
4348+
const auto iterm_count = net->getITerms().size();
4349+
const auto bterm_count = net->getBTerms().size();
4350+
if (iterm_count + bterm_count >= 2) {
4351+
continue;
4352+
}
4353+
4354+
if (iterm_count == 1) {
4355+
odb::dbITerm* iterm = *(net->getITerms().begin());
4356+
if (iterm->getIoType() == odb::dbIoType::OUTPUT) {
4357+
continue; // OK: Unconnected output pin
4358+
}
4359+
} else if (bterm_count == 1) { // This is a top level port
4360+
odb::dbBTerm* bterm = *(net->getBTerms().begin());
4361+
if (bterm->getIoType() == odb::dbIoType::INPUT) {
4362+
continue; // OK: Unconnected input port
4363+
}
4364+
}
4365+
4366+
logger_->error(ORD,
4367+
2039,
4368+
"SanityCheck: Net '{}' has less than 2 connections.",
4369+
net->getName());
4370+
}
4371+
}
4372+
41894373
} // namespace sta

src/dbSta/src/dbSta.i

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// SPDX-License-Identifier: BSD-3-Clause
22
// Copyright (c) 2019-2025, The OpenROAD Authors
33

4+
// clang-format off
5+
46
%{
57

68
#include "odb/db.h"
@@ -214,4 +216,17 @@ replace_hier_module_cmd(odb::dbModInst* mod_inst, odb::dbModule* module)
214216
(void) db_network->replaceHierModule(mod_inst, module);
215217
}
216218

219+
220+
namespace sta {
221+
222+
void check_axioms_cmd()
223+
{
224+
ord::OpenRoad* openroad = ord::getOpenRoad();
225+
sta::dbSta *sta = openroad->getSta();
226+
sta->ensureLinked();
227+
sta->getDbNetwork()->checkAxioms();
228+
}
229+
230+
} // namespace sta
231+
217232
%} // inline

src/dbSta/src/dbSta.tcl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,5 +140,11 @@ proc get_hier_module { arg } {
140140
}
141141
interp alias {} get_design {} get_hier_module
142142

143+
define_cmd_args "check_axioms" {}
144+
proc check_axioms { args } {
145+
check_argc_eq0 "check_axioms" $args
146+
check_axioms_cmd
147+
}
148+
143149
# namespace
144150
}

src/dbSta/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ or_integration_tests(
22
"dbSta"
33
TESTS
44
block_sta1
5+
check_axioms
56
clock_pin
67
constant1
78
find_clks1

src/dbSta/test/check_axioms.ok

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias, 135 library cells
2+
[WARNING ORD-2038] SanityCheck: Module 'i_empty' has no instances.
3+
[WARNING ORD-2038] SanityCheck: Module 'u1' has no instances.
4+
[WARNING ORD-2038] SanityCheck: Module 'u2' has no instances.
5+
[ERROR ORD-2039] SanityCheck: Net 'out_unconnected' has less than 2 connections.

src/dbSta/test/check_axioms.tcl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Test for sanity checker APIs (sta::check_axioms)
2+
source "helpers.tcl"
3+
4+
# Setup
5+
read_liberty Nangate45/Nangate45_typ.lib
6+
read_lef Nangate45/Nangate45.lef
7+
read_verilog check_axioms.v
8+
link_design top
9+
10+
# Run the checks and capture output.
11+
# The 'catch' command is used because sta::check_axioms will exit with an
12+
# error, and we want to continue to check all messages.
13+
set status [catch { sta::check_axioms } msg]
14+
15+
# check_axioms cannot detect unused_module.
16+
# - It is because odb does not keep unused modules in its database.
17+
18+
# Check for expected messages.
19+
#[WARNING ORD-2038] SanityCheck: Module i_empty has no instances.
20+
#[WARNING ORD-2038] SanityCheck: Module u1 has no instances.
21+
#[WARNING ORD-2038] SanityCheck: Module u2 has no instances.
22+
#[ERROR ORD-2039] SanityCheck: Net out_unconnected has less than 2 connections.

0 commit comments

Comments
 (0)