From 2b5f5a4dbff02351672d08105721fc27056f83f5 Mon Sep 17 00:00:00 2001 From: zxy Date: Mon, 6 Jul 2026 09:03:58 +0800 Subject: [PATCH 1/9] Use OpenROAD equivalent cells for sizing Build sizing candidate groups from OpenROAD equivalent-cell classes and add -equiv_cell_sort to choose drive-resistance or leakage ordering. Keep non-core and Liberty-less DB instances in the design as dont-touch cells, and skip OpenSTA DB pins that do not map to Liberty ports when collecting cap/slew data. --- .gitignore | 1 + README.md | 13 +++++ src/analyze_timing.cpp | 19 ++++++- src/calc.cpp | 27 +++++++++- src/ckt.cpp | 115 ++++++++++++++++++++++++++--------------- src/lib_parser.cpp | 58 +++++---------------- src/sizer.cpp | 64 ++++++++++++++++++++++- src/sizer.h | 7 +++ src/timer.cpp | 54 +++++++++++++------ submit/cmd_base_file | 3 +- 10 files changed, 252 insertions(+), 109 deletions(-) diff --git a/.gitignore b/.gitignore index 9b72def..aa93835 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ *.app build +build-*/ .vscode .cache .codex diff --git a/README.md b/README.md index c8d253c..13401a8 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,19 @@ These files may contain benchmark-specific paths or contest-flow assumptions. Before running on a new design, update the Liberty, LEF, Verilog, SDC, DEF, SPEF, output, and top-module settings for your local benchmark environment. +Equivalent-cell candidates are grouped through OpenROAD/OpenSTA equivalence +classes. Candidate order can be selected in the command file or environment +file: + +```text +-equiv_cell_sort drive_resistance +-equiv_cell_sort leakage +``` + +The default is `drive_resistance`, which follows the OpenSTA equivalent-cell +order. The `leakage` mode sorts candidates in each equivalence class by leakage +power first. + ## Submodule Notes The top-level repository tracks OpenROAD as a submodule. OpenROAD then tracks diff --git a/src/analyze_timing.cpp b/src/analyze_timing.cpp index 2073a28..d894677 100644 --- a/src/analyze_timing.cpp +++ b/src/analyze_timing.cpp @@ -458,6 +458,8 @@ void designTiming::getTranVio(double &tot, double &max, int &num) { _tclInputString = "OSGetTranVio "; double begin = cpuTime(); auto design = _sizer->_ckt->_ord_design; + sta::dbNetwork* network = + _sizer->_ckt->_ord_timing->getSta()->getDbNetwork(); ofstream ofs("opensta_tran_vio.txt"); for(auto inst : design->getBlock()->getInsts()) { for(auto pin_ : inst->getITerms()) { @@ -465,6 +467,12 @@ void designTiming::getTranVio(double &tot, double &max, int &num) { pin_->getNet()->getSigType() != "GROUND" && pin_->getNet()->getSigType() != "CLOCK") { auto m_term = pin_->getMTerm(); + sta::Port* port = network->dbToSta(m_term); + sta::LibertyPort* lib_port = + port ? network->libertyPort(port) : nullptr; + if(lib_port == nullptr) { + continue; + } double r_slew = _sizer->_ckt->_ord_timing->getPinSlew( pin_, ord::Timing::Rise); double f_slew = _sizer->_ckt->_ord_timing->getPinSlew( @@ -517,6 +525,8 @@ void designTiming::getCapVio(double &tot, double &max, int &num) { auto design = _sizer->_ckt->_ord_design; ofstream ofs("opensta_cap_vio.txt"); auto corner = _sizer->_ckt->_ord_timing->getCorners()[0]; + sta::dbSta *sta = _sizer->_ckt->_ord_timing->getSta(); + sta::dbNetwork* network = sta->getDbNetwork(); for(auto inst : design->getBlock()->getInsts()) { for(auto pin_ : inst->getITerms()) { if(pin_->getNet() && pin_->getNet()->getSigType() != "POWER" && @@ -524,11 +534,16 @@ void designTiming::getCapVio(double &tot, double &max, int &num) { pin_->getNet()->getSigType() != "CLOCK" && pin_->isOutputSignal()) { auto m_term = pin_->getMTerm(); + sta::Port* port = network->dbToSta(m_term); + sta::LibertyPort* lib_port = + port ? network->libertyPort(port) : nullptr; + if(lib_port == nullptr) { + continue; + } float pin_cap; float wire_cap; - sta::dbSta *sta = _sizer->_ckt->_ord_timing->getSta(); sta::Net *sta_net = - sta->getDbNetwork()->dbToSta(pin_->getNet()); + network->dbToSta(pin_->getNet()); _sizer->_sta->connectedCap( sta_net, corner, sta::MinMax::max(), pin_cap, wire_cap); wire_cap /= _sizer->cap_unit; diff --git a/src/calc.cpp b/src/calc.cpp index 74fb1d3..ce33cce 100644 --- a/src/calc.cpp +++ b/src/calc.cpp @@ -644,12 +644,19 @@ void Sizer::UpdateCapsFromCells() { string pin_name = getFullPinName(pins[view][input_j]); auto pin_ = _ckt->_ord_design->getBlock()->findITerm2( pin_name.c_str()); + if(pin_ == nullptr) { + continue; + } sta::dbSta* sta = _ckt->_ord_timing->getSta(); sta::dbNetwork* network = sta->getDbNetwork(); sta::Port* port = network->dbToSta(pin_->getMTerm()); - sta::LibertyPort* lib_port = network->libertyPort(port); + sta::LibertyPort* lib_port = + port ? network->libertyPort(port) : nullptr; sta::LibertyLibrary* lib = network->defaultLibertyLibrary(); + if(lib_port == nullptr) { + continue; + } pins[view][input_j].cap = lib_port->capacitance() / cap_unit; lib_cell_info->pins[pins[view][input_j].lib_pin] @@ -689,6 +696,17 @@ double Sizer::CalcCapViolation(unsigned view) { getFullPinName(pins[view][cells[i].outpins[k]]); auto pin_ = _ckt->_ord_design->getBlock()->findITerm2( pin_name.c_str()); + if(pin_ == nullptr) { + continue; + } + sta::dbSta* sta = _ckt->_ord_timing->getSta(); + sta::dbNetwork* network = sta->getDbNetwork(); + sta::Port* port = network->dbToSta(pin_->getMTerm()); + sta::LibertyPort* lib_port = + port ? network->libertyPort(port) : nullptr; + if(lib_port == nullptr) { + continue; + } double cap_limit = _ckt->_ord_timing->getMaxCapLimit(pin_->getMTerm()) / cap_unit; @@ -748,6 +766,13 @@ double Sizer::CalcCapViolation(unsigned view) { } float pin_cap2; float wire_cap2; + sta::dbNetwork* network = sta->getDbNetwork(); + sta::Port* port = network->dbToSta(pin_->getMTerm()); + sta::LibertyPort* lib_port = + port ? network->libertyPort(port) : nullptr; + if(lib_port == nullptr) { + continue; + } sta->connectedCap(sta_net, _corner, sta::MinMax::max(), pin_cap2, wire_cap2); wire_cap2 /= cap_unit; diff --git a/src/ckt.cpp b/src/ckt.cpp index 3e898d0..ea98c9b 100644 --- a/src/ckt.cpp +++ b/src/ckt.cpp @@ -136,30 +136,44 @@ void Circuit::Parser(string benchmark) { ifstream infile; _ord_timing->makeEquivCells(); int maxx = 0; + _sizer->cellName2EquaivaID.clear(); + _sizer->cellName2EquivOrder.clear(); + _sizer->EquaivaID2cellNames.clear(); for(auto lib : _ord_tech->getDB()->getLibs()) { for(auto master : lib->getMasters()) { - auto dbmaster = - _ord_tech->getDB()->findMaster(master->getName().c_str()); + auto dbmaster = master; auto equicCells = _ord_timing->equivCells(dbmaster); - string eq_name = equicCells.at(0)->getName(); - if(_sizer->cellName2EquaivaID.count(eq_name) > 0) { + vector< odb::dbMaster* > valid_equiv_cells; + for(auto equicCell : equicCells) { + if(equicCell != nullptr) { + valid_equiv_cells.push_back(equicCell); + } + } + if(valid_equiv_cells.empty()) { continue; } - for(auto equicCell : equicCells) { - _sizer->cellName2EquaivaID.insert( - make_pair(equicCell->getName(), maxx)); + + bool already_seen = false; + for(auto equicCell : valid_equiv_cells) { + if(_sizer->cellName2EquaivaID.count(equicCell->getName()) > 0) { + already_seen = true; + break; + } + } + if(already_seen) { + continue; + } + + _sizer->EquaivaID2cellNames.push_back(vector< string >()); + for(unsigned order = 0; order < valid_equiv_cells.size(); ++order) { + string cell_name = valid_equiv_cells[order]->getName(); + _sizer->cellName2EquaivaID.insert(make_pair(cell_name, maxx)); + _sizer->cellName2EquivOrder.insert(make_pair(cell_name, order)); + _sizer->EquaivaID2cellNames.back().push_back(cell_name); } maxx++; } } - - _sizer->EquaivaID2cellNames.resize(maxx + 1); - for(auto it = _sizer->cellName2EquaivaID.begin(); - it != _sizer->cellName2EquaivaID.end(); ++it) { - string cell_name = it->first; - unsigned cell_id = it->second; - _sizer->EquaivaID2cellNames[cell_id].push_back(cell_name); - } infile.close(); if(!_sizer->mmmcOn) { for(unsigned i = 0; i < _sizer->libLibs.size(); ++i) { @@ -257,7 +271,7 @@ void Circuit::Parser(string benchmark) { } auto& list = _sizer->func_lib_cell_list[t_corner][it->first]; list.sort([&](LibCellInfo* c1, LibCellInfo* c2) { - return c1->leakagePower < c2->leakagePower; + return _sizer->compareEquivCellsForSizing(c1, c2); }); std::sort(cap_vec.begin(), cap_vec.end(), [&](LibCellInfo* c1, LibCellInfo* c2) { @@ -498,18 +512,17 @@ void Circuit::assignLibPinId() { CELL& cell = g_cells[pin->owner]; // cout << pin->name << " " << pin2id[cell.name+"/"+pin->name] << " // " << pin->owner << endl; - LibCellInfo* lib_cell_info = - &(_sizer->libs[corner].find(cell.type)->second); // Resize the rdelay/fdelay vector size pin->rdelay.resize(cell.outpins.size(), 0.0); pin->fdelay.resize(cell.outpins.size(), 0.0); pin->bb_checked_delay.resize(cell.outpins.size(), false); - if(lib_cell_info == NULL) { - cout << "Error: cell " << cell.type << " not found in lib" - << endl; - assert(0); + auto lib_cell_iter = _sizer->libs[corner].find(cell.type); + if(lib_cell_iter == _sizer->libs[corner].end()) { + cell.isDontTouch = true; + cell.isChanged = 0; continue; } + LibCellInfo* lib_cell_info = &(lib_cell_iter->second); if((temp_iter = lib_cell_info->lib_pin2id_map.find(pin->name)) != lib_cell_info->lib_pin2id_map.end()) { pin->lib_pin = temp_iter->second; @@ -522,6 +535,11 @@ void Circuit::assignLibPinId() { else if(pin->name.find("]") != std::string::npos) { string new_pin_name = pin->name.substr(0, pin->name.find("[")); temp_iter = lib_cell_info->lib_pin2id_map.find(new_pin_name); + if(temp_iter == lib_cell_info->lib_pin2id_map.end()) { + cout << "Error: pin " << pin->name << " not found in cell " + << cell.type << endl; + assert(0); + } pin->lib_pin = temp_iter->second; pin->cap = lib_cell_info->pins[pin->lib_pin].capacitance; // assert(pin->cap < 1e31); @@ -845,10 +863,11 @@ void Circuit::createLibCellTable(LibCellTable& lib_cell_table, return; // exit(0); } - // If multiple high-Vt cells exist, sort them by leakage. + // If multiple equivalent cells exist, use the configured candidate order. // list size first std::set< string > lib_cell_size_set; - printf("sort by leakage candidate_cell_info->name list: "); + printf("sort by %s candidate_cell_info->name list: ", + _sizer->equivCellSortModeName().c_str()); for(auto candidate_cell_info : candidate_list) { // slowest vt first // if((*it)->c_vtype != 0) { @@ -2063,31 +2082,33 @@ void Circuit::readDesign_opensta(sta::dbSta* _sta) { string viewName = strViewName; string libPath = _sizer->benchname; - int gateNum = network->instanceCount(); + auto* db_network = _sta->getDbNetwork(); + auto* block = _ord_design->getBlock(); + int gateNum = block->getInsts().size(); // read in the gates - InstanceChildIterator* inst_it = - network->childIterator(network->topInstance()); int iter_i = 0; - while(inst_it->hasNext()) { - Instance* inst = inst_it->next(); + for(auto* db_inst : block->getInsts()) { if(iter_i % 1000 == 0) { printf("Read %d / %d Instances\n", iter_i, gateNum); + fflush(stdout); } iter_i++; - string str_cell_name = ""; - if(network->libertyCell(inst) == nullptr) { - // printf("Error: %s\n", network->pathName(inst)); - continue; - } - else { - str_cell_name = network->libertyCell(inst)->name(); - } + auto* master = db_inst->getMaster(); + assert(master != nullptr); + auto* liberty_cell = db_network->libertyCell(db_inst); + string str_cell_name = liberty_cell != nullptr ? liberty_cell->name() + : master->getName(); + // NEW CELL CELL tmpCell; tmpCell.type = str_cell_name; - tmpCell.name = network->pathName(inst); + tmpCell.name = db_inst->getName(); tmpCell.isFF = false; + if(liberty_cell == nullptr || !master->isCore()) { + tmpCell.isDontTouch = true; + tmpCell.isChanged = 0; + } if(_sizer->numVt == 3) { if(cellName.find(_sizer->suffixLVT.c_str()) != std::string::npos) { @@ -2122,7 +2143,7 @@ void Circuit::readDesign_opensta(sta::dbSta* _sta) { unsigned tmpCellId = _sizer->_ckt->g_cells.size(); _sizer->_ckt->cell2id.insert( - pair< string, unsigned >(network->pathName(inst), tmpCellId)); + pair< string, unsigned >(tmpCell.name, tmpCellId)); // cout << "Name and ID: " << network->pathName(inst) << " : " << // tmpCellId << endl; @@ -2189,7 +2210,8 @@ void Circuit::readDesign_opensta(sta::dbSta* _sta) { int net_pin_num = 0; for(auto instTerms_iter : net->getITerms()) { net_pin_num++; - string instGateName = instTerms_iter->getInst()->getName(); + auto* db_inst = instTerms_iter->getInst(); + string instGateName = db_inst ? db_inst->getName() : ""; char tmpName[2000]; strcpy(tmpName, instGateName.c_str()); @@ -2199,8 +2221,19 @@ void Circuit::readDesign_opensta(sta::dbSta* _sta) { _sizer->_ckt->cell2id.end()) gateId = _sizer->_ckt->cell2id[tmpName]; - if(gateId >= _sizer->_ckt->g_cells.size() || gateId < 0) + if(gateId >= _sizer->_ckt->g_cells.size() || gateId < 0) { printf("error gate id %d\n", gateId); + printf("unmapped iterm: net=%s inst=%s pin=%s\n", + netName.c_str(), instGateName.c_str(), + instTerms_iter->getName().c_str()); + if(db_inst != nullptr && db_inst->getMaster() != nullptr) { + auto* master = db_inst->getMaster(); + printf("unmapped master: name=%s is_block=%d\n", + master->getName().c_str(), master->isBlock()); + } + fflush(stdout); + assert(false && "ITerm instance is missing from cell2id"); + } CELL& cell = _sizer->_ckt->g_cells[gateId]; diff --git a/src/lib_parser.cpp b/src/lib_parser.cpp index 28dc0e4..64cc28d 100644 --- a/src/lib_parser.cpp +++ b/src/lib_parser.cpp @@ -303,7 +303,7 @@ void Circuit::parse_pin(sta::LibertyLibrary* sta_lib, // Direction auto dir = sta_port->direction(); out_pin.isInput = dir->isInput() || dir->isBidirect(); - out_pin.isOutput = dir->isOutput() || dir->isBidirect(); + out_pin.isOutput = dir->isOutput() || dir->isBidirect() || dir->isTristate(); if(!out_pin.isInput && !out_pin.isOutput && !dir->isInternal()) { assert(false && "Unknown pin direction!"); } @@ -324,46 +324,6 @@ void Circuit::parse_pin(sta::LibertyLibrary* sta_lib, } } -// Extract footprint according to technology-node naming rules. -static std::string determine_footprint(Sizer* sizer, - const std::string& cell_name) { - if(ASAP7) { - return std::to_string(sizer->cellName2EquaivaID.at(cell_name)); - } - - // Extract the substring between two underscores. - auto extract_mid = [](std::string& s) { - size_t p1 = s.find('_'); - if(p1 == string::npos) { - return; - } - size_t p2 = s.find('_', p1 + 1); - if(p2 != string::npos) { - s = s.substr(p1 + 1, p2 - p1 - 1); - } - }; - - std::string fp = cell_name; - - if(STM28) { - // Extract STM28-style suffix: _X... - size_t x_pos = fp.find_last_of('X'); - if(x_pos != string::npos) { - fp.erase(x_pos); - } - extract_mid(fp); - return fp; - } - - if(C40) { - extract_mid(fp); - return fp; - } - - size_t u_pos = fp.find_first_of('_'); - return (u_pos != string::npos) ? fp.substr(0, u_pos) : "NA"; -} - // Determine Vt type. static cell_vtypes determine_vt_type(const std::string& name, Sizer* sizer) { if(sizer->numVt == 3) { @@ -389,11 +349,13 @@ void Circuit::parse_cell(sta::LibertyLibrary* sta_lib, out_cell.name = sta_cell->name(); out_cell.libname = sta_lib->name(); - // Footprint - out_cell.footprint = sta_cell->footprint(); - if(out_cell.footprint.empty() || NO_FOOTPRINT) { - out_cell.footprint = determine_footprint(_sizer, out_cell.name); + auto equiv_iter = _sizer->cellName2EquaivaID.find(out_cell.name); + if(equiv_iter == _sizer->cellName2EquaivaID.end()) { + cout << "Error: OpenROAD equivalent-cell class not found for " + << out_cell.name << endl; + exit(1); } + out_cell.footprint = std::to_string(equiv_iter->second); // Vt Type out_cell.c_vtype = determine_vt_type(out_cell.name, _sizer); @@ -429,6 +391,10 @@ void Circuit::parse_cell(sta::LibertyLibrary* sta_lib, sta::LibertyCellPortIterator port_iter(sta_cell); while(port_iter.hasNext()) { auto* sta_port = port_iter.next(); + auto* dir = sta_port->direction(); + if(dir->isPowerGround() || dir->isUnknown()) { + continue; + } LibPinInfo pin; parse_pin(sta_lib, sta_port, out_cell, pin); @@ -634,7 +600,7 @@ void Circuit::lib_parser(string filename, unsigned corner) { lib_cell_info->partial_order = partial_order / partial_count; } (it->second).sort([&](LibCellInfo* c1, LibCellInfo* c2) { - return c1->leakagePower < c2->leakagePower; + return _sizer->compareEquivCellsForSizing(c1, c2); }); } #endif diff --git a/src/sizer.cpp b/src/sizer.cpp index 563df61..b925015 100644 --- a/src/sizer.cpp +++ b/src/sizer.cpp @@ -637,6 +637,7 @@ void Sizer::ReportOptions() { cout << "SUFFIX LVT : " << suffixLVT << endl; cout << "SUFFIX HVT : " << suffixHVT << endl; cout << "SUFFIX : " << suffix << endl; + cout << "EQUIV CELL SORT: " << equivCellSortModeName() << endl; cout << "--------------------------------------" << endl; cout << "DONT TOUCH LIST : "; @@ -658,6 +659,59 @@ void Sizer::ReportOptions() { cout << endl; } +void Sizer::setEquivCellSortMode(const string& mode) { + if(mode == "leakage") { + sortEquivCellsByLeakage = true; + return; + } + if(mode == "drive_resistance" || mode == "drive_resitance" || + mode == "drive_res" || mode == "drive") { + sortEquivCellsByLeakage = false; + return; + } + + cout << "Error: unsupported -equiv_cell_sort mode '" << mode + << "'. Use drive_resistance or leakage." << endl; + exit(1); +} + +string Sizer::equivCellSortModeName() const { + return sortEquivCellsByLeakage ? "leakage" : "drive_resistance"; +} + +int Sizer::equivCellDriveOrder(const string& cell_name) const { + auto iter = cellName2EquivOrder.find(cell_name); + if(iter == cellName2EquivOrder.end()) { + return std::numeric_limits< int >::max(); + } + return iter->second; +} + +bool Sizer::compareEquivCellsForSizing(const LibCellInfo* lhs, + const LibCellInfo* rhs) const { + if(sortEquivCellsByLeakage && + lhs->leakagePower != rhs->leakagePower) { + return lhs->leakagePower < rhs->leakagePower; + } + + int lhs_order = equivCellDriveOrder(lhs->name); + int rhs_order = equivCellDriveOrder(rhs->name); + if(lhs_order != rhs_order) { + return lhs_order < rhs_order; + } + + if(!sortEquivCellsByLeakage && + lhs->leakagePower != rhs->leakagePower) { + return lhs->leakagePower < rhs->leakagePower; + } + + if(lhs->partial_order != rhs->partial_order) { + return lhs->partial_order < rhs->partial_order; + } + + return lhs->name < rhs->name; +} + LibCellInfo *Sizer::getLibCellInfo(int main_lib_cell_id, cell_sizes size, cell_vtypes vtype, unsigned corner) { LibCellTable *lib_cell_table = NULL; @@ -698,12 +752,15 @@ LibCellInfo *Sizer::getLibCellInfo(CELL &cell, unsigned corner) { // assert(cell.type != ""); // unordered_map< string, LibCellInfo >::iterator temp_iter = // libs[corner].find(cell.type); + if(cell.main_lib_cell_id < 0) { + return nullptr; + } if(isff(cell) && cell.clock_pin == UINT_MAX) { return nullptr; } assert(main_lib_cell_tables.size()); return getLibCellInfo(cell.main_lib_cell_id, cell.c_size, - static_cast< cell_vtypes >(cell.c_vtype)); + static_cast< cell_vtypes >(cell.c_vtype), corner); } LibCellInfo *Sizer::getLibCellInfo(string type, unsigned corner) { @@ -9243,6 +9300,9 @@ void Sizer::readEnvFile(string envFileStr) { if(line.find("-suffix_all ") != string::npos) { suffix = getTokenS(line, "-suffix_all "); } + if(line.find("-equiv_cell_sort ") != string::npos) { + setEquivCellSortMode(getTokenS(line, "-equiv_cell_sort ")); + } } file.close(); } @@ -9341,6 +9401,8 @@ void Sizer::readCmdFile(string cmdFileStr) { min_route_layer = getTokenS(line, "-min_route_layer "); if(line.find("-max_route_layer ") != string::npos) max_route_layer = getTokenS(line, "-max_route_layer "); + if(line.find("-equiv_cell_sort ") != string::npos) + setEquivCellSortMode(getTokenS(line, "-equiv_cell_sort ")); if(line.find("-sdc ") != string::npos) sdcFile = getTokenS(line, "-sdc "); if(line.find("-timerSdc ") != string::npos) diff --git a/src/sizer.h b/src/sizer.h index eb83a4e..2968366 100644 --- a/src/sizer.h +++ b/src/sizer.h @@ -425,10 +425,17 @@ class Sizer { bool use_slew_margin = true; designTiming **T; std::map< string, int > cellName2EquaivaID; + std::map< string, int > cellName2EquivOrder; std::vector< std::vector< string > > EquaivaID2cellNames; void runOrdTO(); string min_route_layer = "METAL1"; string max_route_layer = "METAL7"; + bool sortEquivCellsByLeakage = false; + void setEquivCellSortMode(const string& mode); + string equivCellSortModeName() const; + int equivCellDriveOrder(const string& cell_name) const; + bool compareEquivCellsForSizing(const LibCellInfo* lhs, + const LibCellInfo* rhs) const; private: double tnsPenalty = 10, slewPenalty = 20, capPenalty = 20; diff --git a/src/timer.cpp b/src/timer.cpp index 7ebb475..25ce7e4 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -45,6 +45,7 @@ #include #include #include "ckt.h" +#include "db_sta/dbNetwork.hh" #include "ord/Timing.h" #include "sizer.h" #include @@ -246,25 +247,36 @@ double Sizer::GetCellTran(CELL &cell, unsigned view) { double Sizer::GetCellCapVio(CELL &cell, unsigned view) { double tot_tran = 0; + LibCellInfo *lib_cell_info = getLibCellInfo(cell); + if(lib_cell_info == nullptr) { + return 0.0; + } for(unsigned i = 0; i < cell.outpins.size(); ++i) { if(cell.outpins[i] == UINT_MAX) continue; double maxCap = 0.0; - LibCellInfo *lib_cell_info = getLibCellInfo(cell); - if(lib_cell_info) { - maxCap = lib_cell_info->pins[pins[view][cell.outpins[i]].lib_pin] - .maxCapacitance; - if(maxCap == std::numeric_limits< double >::max()) { - string pin_name = getFullPinName(pins[view][cell.outpins[i]]); - auto pin_ = - _ckt->_ord_design->getBlock()->findITerm2(pin_name.c_str()); - double cap_limit = - _ckt->_ord_timing->getMaxCapLimit(pin_->getMTerm()) / - cap_unit; - lib_cell_info->pins[pins[view][cell.outpins[i]].lib_pin] - .maxCapacitance = cap_limit; - maxCap = cap_limit; + maxCap = lib_cell_info->pins[pins[view][cell.outpins[i]].lib_pin] + .maxCapacitance; + if(maxCap == std::numeric_limits< double >::max()) { + string pin_name = getFullPinName(pins[view][cell.outpins[i]]); + auto pin_ = + _ckt->_ord_design->getBlock()->findITerm2(pin_name.c_str()); + if(pin_ == nullptr) { + continue; } + sta::dbNetwork* network = + _ckt->_ord_timing->getSta()->getDbNetwork(); + sta::Port* port = network->dbToSta(pin_->getMTerm()); + sta::LibertyPort* lib_port = + port ? network->libertyPort(port) : nullptr; + if(lib_port == nullptr) { + continue; + } + double cap_limit = + _ckt->_ord_timing->getMaxCapLimit(pin_->getMTerm()) / cap_unit; + lib_cell_info->pins[pins[view][cell.outpins[i]].lib_pin] + .maxCapacitance = cap_limit; + maxCap = cap_limit; } if(use_margin) { maxCap *= cap_margin; @@ -920,7 +932,7 @@ unsigned Sizer::FindAvailablePreCell(unsigned prev_cell_input_pin, arc_error = true; } - if(arc->fromPin != pins[view][in_pin].name) { + else if(arc->fromPin != pins[view][in_pin].name) { if(VERBOSE >= 3) cout << "timing arc error : " << arc->fromPin << " != " << pins[view][in_pin].name << endl; @@ -3652,7 +3664,7 @@ void Sizer::LookupSTLoad(CELL &cell, double &rtran, double &ftran, arc_error = true; } - if(arc->fromPin != pins[view][curpin].name) { + else if(arc->fromPin != pins[view][curpin].name) { if(VERBOSE >= 3) cout << "timing arc error : " << arc->fromPin << " != " << pins[view][curpin].name << endl; @@ -3740,7 +3752,7 @@ void Sizer::LookupSTTran(CELL &cell, vector< double > in_rtrans, arc_error = true; } - if(arc->fromPin != pins[view][curpin].name) { + else if(arc->fromPin != pins[view][curpin].name) { if(VERBOSE >= 3) cout << "timing arc error : " << arc->fromPin << " != " << pins[view][curpin].name << endl; @@ -6334,11 +6346,19 @@ void Sizer::GetMaxTranConst(unsigned view) { } #endif auto design = this->_ckt->_ord_design; + sta::dbNetwork* network = + this->_ckt->_ord_timing->getSta()->getDbNetwork(); for(auto pin_ : design->getBlock()->getITerms()) { if(pin_->getNet() && pin_->getNet()->getSigType() != "POWER" && pin_->getNet()->getSigType() != "GROUND" && pin_->getNet()->getSigType() != "CLOCK") { auto mterm = pin_->getMTerm(); + sta::Port* port = network->dbToSta(mterm); + sta::LibertyPort* lib_port = + port ? network->libertyPort(port) : nullptr; + if(lib_port == nullptr) { + continue; + } double slew_limit = this->_ckt->_ord_timing->getMaxSlewLimit(mterm); slew_limit /= this->time_unit; bool is_input = false; diff --git a/submit/cmd_base_file b/submit/cmd_base_file index 4dfdb0c..2b61b22 100644 --- a/submit/cmd_base_file +++ b/submit/cmd_base_file @@ -14,6 +14,8 @@ # -tcf ./test.tcf -ptLog -useOpenSTA +# Equivalent-cell candidate order: drive_resistance (default) or leakage. +# -equiv_cell_sort drive_resistance -alpha 0.0 -dont_touch_cell TIEL -dont_touch_cell TIEH @@ -39,4 +41,3 @@ # -gtr_input /home/zhaoxueyan/code/gpu_gate_sizing/build/NV_NVDLA_partition_m.prft.sizes # -test ALL_TEST # -dont_use_lis - From b1af70d955d27283ef158dc28d8e036003d06242 Mon Sep 17 00:00:00 2001 From: zxy Date: Thu, 9 Jul 2026 18:26:51 +0800 Subject: [PATCH 2/9] update ideal clock --- README.md | 6 ++++++ src/ckt.cpp | 4 ++-- thirdparty/OpenROAD | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 13401a8..188eeb1 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,12 @@ The default is `drive_resistance`, which follows the OpenSTA equivalent-cell order. The `leakage` mode sorts candidates in each equivalence class by leakage power first. +For single-VT libraries, `leakage` sorting is usually a good starting point +because the timing spread within an equivalence class is relatively limited and +lower-leakage candidates can improve the power/timing tradeoff. For multi-VT +libraries, `drive_resistance` sorting is recommended because candidate ordering +should preserve timing convergence before favoring lower-leakage, slower cells. + ## Submodule Notes The top-level repository tracks OpenROAD as a submodule. OpenROAD then tracks diff --git a/src/ckt.cpp b/src/ckt.cpp index ea98c9b..48b5f21 100644 --- a/src/ckt.cpp +++ b/src/ckt.cpp @@ -2008,8 +2008,8 @@ void Circuit::init_opensta() { _ord_design->evalTclString("set_wire_rc -clock -layer " + _sizer->min_route_layer); _ord_design->evalTclString("estimate_parasitics -placement"); - _ord_design->evalTclString("repair_clock_nets"); - _ord_design->evalTclString("set_propagated_clock [all_clocks]"); + // _ord_design->evalTclString("repair_clock_nets"); + // _ord_design->evalTclString("set_propagated_clock [all_clocks]"); // _sizer->_ckt->_ord_design->writeDef(_sizer->resultDefFile); // _sizer->_ckt->_ord_design->evalTclString("write_verilog " + diff --git a/thirdparty/OpenROAD b/thirdparty/OpenROAD index 300dfb0..fea5072 160000 --- a/thirdparty/OpenROAD +++ b/thirdparty/OpenROAD @@ -1 +1 @@ -Subproject commit 300dfb0e878aa3c37961c7e41e4ae31038a4e47e +Subproject commit fea5072fe0ab728dcf2ddf2ac0e0bfebbd8ac5b5 From 26e8cdab6f4ed84842be3af21db91d5800ff2891 Mon Sep 17 00:00:00 2001 From: zxy Date: Fri, 10 Jul 2026 20:57:10 +0800 Subject: [PATCH 3/9] add use gr rc parameters --- README.md | 10 ++++++ src/ckt.cpp | 84 +++++++++++++++++++++----------------------- src/ckt.h | 2 +- src/sizer.cpp | 79 +++++++++++++++++++++++------------------ src/sizer.h | 1 + submit/cmd_base_file | 2 ++ 6 files changed, 99 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 188eeb1..a238a98 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,16 @@ The default is `drive_resistance`, which follows the OpenSTA equivalent-cell order. The `leakage` mode sorts candidates in each equivalence class by leakage power first. +Parasitic estimation defaults to placement RC. Set the following command-file +option to run global routing and estimate RC from the routed topology after +detailed placement: + +```text +-use_gr_rc 1 +``` + +The accepted values are `0` and `1`; the default is `0`. + For single-VT libraries, `leakage` sorting is usually a good starting point because the timing spread within an equivalence class is relatively limited and lower-leakage candidates can improve the power/timing tradeoff. For multi-VT diff --git a/src/ckt.cpp b/src/ckt.cpp index 48b5f21..40dfa38 100644 --- a/src/ckt.cpp +++ b/src/ckt.cpp @@ -1819,53 +1819,51 @@ void Circuit::runGR(int gr_overflow_iterations, bool fast, int slack_max_iter) { _ord_design->evalTclString(string(padding_str)); _ord_design->evalTclString("detailed_placement"); double begin = cpuTime(); -#ifdef USE_GR_RC - // _ord_design->evalTclString("detailed_placement_debug"); - // _ord_design->getOpendp()->VERBOSE - // _ord_design->getOpendp()->detailedPlacement(500, 500, "./dp.log"); - // Global Route and Estimate Global Route RC - auto db_tech = _ord_design->getTech()->getDB()->getTech(); - auto signal_low_layer = - db_tech->findLayer(_sizer->min_route_layer.c_str())->getRoutingLevel(); - auto signal_high_layer = - db_tech->findLayer(_sizer->max_route_layer.c_str())->getRoutingLevel(); - auto clk_low_layer = - db_tech->findLayer(_sizer->min_route_layer.c_str())->getRoutingLevel(); - auto clk_high_layer = - db_tech->findLayer(_sizer->max_route_layer.c_str())->getRoutingLevel(); - auto grt = _ord_design->getGlobalRouter(); - grt->clear(); - grt->setAllowCongestion(true); - grt->setMinRoutingLayer(signal_low_layer); - grt->setMaxRoutingLayer(signal_high_layer); - grt->setMinLayerForClock(clk_low_layer); - grt->setMaxLayerForClock(clk_high_layer); - grt->setAdjustment(0.5); - grt->setVerbose(true); - grt->setCongestionIterations(gr_overflow_iterations); - printf("Run Global Routing...\n"); - grt->globalRoute(false, false, false); - int iter = 0; + if(_sizer->use_gr_rc) { + // Global Route and estimate global-route RC. + auto db_tech = _ord_design->getTech()->getDB()->getTech(); + auto signal_low_layer = + db_tech->findLayer(_sizer->min_route_layer.c_str())->getRoutingLevel(); + auto signal_high_layer = + db_tech->findLayer(_sizer->max_route_layer.c_str())->getRoutingLevel(); + auto clk_low_layer = + db_tech->findLayer(_sizer->min_route_layer.c_str())->getRoutingLevel(); + auto clk_high_layer = + db_tech->findLayer(_sizer->max_route_layer.c_str())->getRoutingLevel(); + auto grt = _ord_design->getGlobalRouter(); + grt->clear(); + grt->setAllowCongestion(true); + grt->setMinRoutingLayer(signal_low_layer); + grt->setMaxRoutingLayer(signal_high_layer); + grt->setMinLayerForClock(clk_low_layer); + grt->setMaxLayerForClock(clk_high_layer); + grt->setAdjustment(0.5); + grt->setVerbose(true); + grt->setCongestionIterations(gr_overflow_iterations); + printf("Run Global Routing...\n"); + grt->globalRoute(false); + int iter = 0; #if 0 - if(use_gr_correlation) { - for(auto db_inst : block->getInsts()) { - string old_type = old_master_map[iter]; - string new_libcell_str = old_type; - auto new_master = _ord_design->getTech()->getDB()->findMaster( - new_libcell_str.c_str()); - if(!db_inst->isBlock() && - !_ord_design->isSequential(db_inst->getMaster())) { - db_inst->swapMaster(new_master); + if(use_gr_correlation) { + for(auto db_inst : block->getInsts()) { + string old_type = old_master_map[iter]; + string new_libcell_str = old_type; + auto new_master = _ord_design->getTech()->getDB()->findMaster( + new_libcell_str.c_str()); + if(!db_inst->isBlock() && + !_ord_design->isSequential(db_inst->getMaster())) { + db_inst->swapMaster(new_master); + } + iter++; } - iter++; } - } -#endif - printf("Run Global Routing Time %f\n", cpuTime() - begin); - _ord_design->evalTclString("estimate_parasitics -global_routing"); -#else - _ord_design->evalTclString("estimate_parasitics -placement"); #endif + printf("Run Global Routing Time %f\n", cpuTime() - begin); + _ord_design->evalTclString("estimate_parasitics -global_routing"); + } + else { + _ord_design->evalTclString("estimate_parasitics -placement"); + } _sta->findRequireds(); _ord_design->evalTclString("report_tns"); printf("Estimate Global Route RC Time %f\n", cpuTime() - begin); diff --git a/src/ckt.h b/src/ckt.h index 956aba3..28ce0c0 100644 --- a/src/ckt.h +++ b/src/ckt.h @@ -78,7 +78,7 @@ #include "ord/Tech.h" #include "ord/Design.h" -// #define USE_GR_RC +// Global-routing RC is controlled by the -use_gr_rc command-file option. #define NUM_VTS 3 #define NUM_SIZES 10 diff --git a/src/sizer.cpp b/src/sizer.cpp index b925015..e8d116c 100644 --- a/src/sizer.cpp +++ b/src/sizer.cpp @@ -1590,11 +1590,9 @@ void Sizer::UpdatePTSizes(vector< CELL > &cells, unsigned option) { // cells[i].static_power = // this->_ckt->_ord_timing->staticPower(inst, corner); } -#ifdef USE_GR_RC - _ckt->_ord_design->evalTclString("estimate_parasitics -global_routing"); -#else - _ckt->_ord_design->evalTclString("estimate_parasitics -placement"); -#endif + _ckt->_ord_design->evalTclString( + use_gr_rc ? "estimate_parasitics -global_routing" + : "estimate_parasitics -placement"); _sta->findRequireds(); T[0]->pt_time += cpuTime() - begin; } @@ -6152,36 +6150,36 @@ void Sizer::FinalReport() { _ord_design->evalTclString(string(padding_str)); _ord_design->evalTclString("detailed_placement"); -#ifdef USE_GR_RC - // Global Route and Estimate Global Route RC - double begin = cpuTime(); - auto db_tech = _ord_design->getTech()->getDB()->getTech(); - auto signal_low_layer = - db_tech->findLayer(min_route_layer.c_str())->getRoutingLevel(); - auto signal_high_layer = - db_tech->findLayer(max_route_layer.c_str())->getRoutingLevel(); - auto clk_low_layer = - db_tech->findLayer(min_route_layer.c_str())->getRoutingLevel(); - auto clk_high_layer = - db_tech->findLayer(max_route_layer.c_str())->getRoutingLevel(); - auto grt = _ord_design->getGlobalRouter(); - grt->setCongestionIterations(10); - grt->clear(); - grt->setAllowCongestion(true); - grt->setMinRoutingLayer(signal_low_layer); - grt->setMaxRoutingLayer(signal_high_layer); - grt->setMinLayerForClock(clk_low_layer); - grt->setMaxLayerForClock(clk_high_layer); - grt->setAdjustment(0.5); - grt->setVerbose(true); - printf("Run Global Routing...\n"); - grt->globalRoute(false, false); - printf("Run Global Routing Time %f\n", cpuTime() - begin); - begin = cpuTime(); - _ord_design->evalTclString("estimate_parasitics -global_routing"); -#else - _ord_design->evalTclString("estimate_parasitics -placement"); -#endif + if(use_gr_rc) { + // Global Route and estimate global-route RC. + double begin = cpuTime(); + auto db_tech = _ord_design->getTech()->getDB()->getTech(); + auto signal_low_layer = + db_tech->findLayer(min_route_layer.c_str())->getRoutingLevel(); + auto signal_high_layer = + db_tech->findLayer(max_route_layer.c_str())->getRoutingLevel(); + auto clk_low_layer = + db_tech->findLayer(min_route_layer.c_str())->getRoutingLevel(); + auto clk_high_layer = + db_tech->findLayer(max_route_layer.c_str())->getRoutingLevel(); + auto grt = _ord_design->getGlobalRouter(); + grt->setCongestionIterations(10); + grt->clear(); + grt->setAllowCongestion(true); + grt->setMinRoutingLayer(signal_low_layer); + grt->setMaxRoutingLayer(signal_high_layer); + grt->setMinLayerForClock(clk_low_layer); + grt->setMaxLayerForClock(clk_high_layer); + grt->setAdjustment(0.5); + grt->setVerbose(true); + printf("Run Global Routing...\n"); + grt->globalRoute(false); + printf("Run Global Routing Time %f\n", cpuTime() - begin); + _ord_design->evalTclString("estimate_parasitics -global_routing"); + } + else { + _ord_design->evalTclString("estimate_parasitics -placement"); + } _sta->findRequireds(); _ckt->readSpef_opensta(_sta); int corner = 0; @@ -9362,6 +9360,7 @@ void Sizer::readCmdFile(string cmdFileStr) { timerTestCnt = 0; timerTestCell = 0; timerTestMove = 0; + use_gr_rc = false; bool set_margin = false; bool GWTW_flag = false; @@ -9401,6 +9400,14 @@ void Sizer::readCmdFile(string cmdFileStr) { min_route_layer = getTokenS(line, "-min_route_layer "); if(line.find("-max_route_layer ") != string::npos) max_route_layer = getTokenS(line, "-max_route_layer "); + if(line.find("-use_gr_rc ") != string::npos) { + const int use_gr_rc_value = getTokenI(line, "-use_gr_rc "); + if(use_gr_rc_value != 0 && use_gr_rc_value != 1) { + cout << "Error: -use_gr_rc must be 0 or 1." << endl; + exit(1); + } + use_gr_rc = use_gr_rc_value == 1; + } if(line.find("-equiv_cell_sort ") != string::npos) setEquivCellSortMode(getTokenS(line, "-equiv_cell_sort ")); if(line.find("-sdc ") != string::npos) @@ -10022,6 +10029,8 @@ void Sizer::readCmdFile(string cmdFileStr) { if(noSPEF) { WIRE_METRIC = ND; } + cout << "Parasitics mode: " + << (use_gr_rc ? "global_routing" : "placement") << endl; } void Sizer::main(unsigned thread_id, bool postGTR) { diff --git a/src/sizer.h b/src/sizer.h index 2968366..8b2d8b4 100644 --- a/src/sizer.h +++ b/src/sizer.h @@ -430,6 +430,7 @@ class Sizer { void runOrdTO(); string min_route_layer = "METAL1"; string max_route_layer = "METAL7"; + bool use_gr_rc = false; bool sortEquivCellsByLeakage = false; void setEquivCellSortMode(const string& mode); string equivCellSortModeName() const; diff --git a/submit/cmd_base_file b/submit/cmd_base_file index 2b61b22..d2da0c0 100644 --- a/submit/cmd_base_file +++ b/submit/cmd_base_file @@ -16,6 +16,8 @@ -useOpenSTA # Equivalent-cell candidate order: drive_resistance (default) or leakage. # -equiv_cell_sort drive_resistance +# Use global-routing RC instead of placement RC after detailed placement. +# -use_gr_rc 1 -alpha 0.0 -dont_touch_cell TIEL -dont_touch_cell TIEH From ef3af0eae03200c28166a6621a3dfcca4a2549d8 Mon Sep 17 00:00:00 2001 From: zxy Date: Sun, 12 Jul 2026 22:22:55 +0800 Subject: [PATCH 4/9] synchronize incremental GR parasitics --- src/ckt.cpp | 9 +- src/sizer.cpp | 342 ++++++++++++++++++++++++-------------------- src/sizer.h | 3 + src/timer.cpp | 3 - thirdparty/OpenROAD | 2 +- 5 files changed, 197 insertions(+), 162 deletions(-) diff --git a/src/ckt.cpp b/src/ckt.cpp index 40dfa38..6f5bd43 100644 --- a/src/ckt.cpp +++ b/src/ckt.cpp @@ -1821,6 +1821,10 @@ void Circuit::runGR(int gr_overflow_iterations, bool fast, int slack_max_iter) { double begin = cpuTime(); if(_sizer->use_gr_rc) { // Global Route and estimate global-route RC. + // Post-CTS DEFs can omit routing-layer geometry for top-level pins. + // Rebuild pin access points before invoking the global router. + _ord_design->evalTclString( + "place_pins -hor_layers {MET5} -ver_layers {MET4} -annealing"); auto db_tech = _ord_design->getTech()->getDB()->getTech(); auto signal_low_layer = db_tech->findLayer(_sizer->min_route_layer.c_str())->getRoutingLevel(); @@ -1838,10 +1842,13 @@ void Circuit::runGR(int gr_overflow_iterations, bool fast, int slack_max_iter) { grt->setMinLayerForClock(clk_low_layer); grt->setMaxLayerForClock(clk_high_layer); grt->setAdjustment(0.5); + grt->setResistanceAware(false); grt->setVerbose(true); grt->setCongestionIterations(gr_overflow_iterations); printf("Run Global Routing...\n"); - grt->globalRoute(false); + _ord_design->evalTclString( + "global_route -congestion_iterations " + + to_string(gr_overflow_iterations) + " -allow_congestion -verbose"); int iter = 0; #if 0 if(use_gr_correlation) { diff --git a/src/sizer.cpp b/src/sizer.cpp index e8d116c..3acd4c8 100644 --- a/src/sizer.cpp +++ b/src/sizer.cpp @@ -39,6 +39,7 @@ #include "rsz/Resizer.hh" #include "dpl/Opendp.h" +#include "est/EstimateParasitics.h" #include "sizer.h" #include @@ -1538,6 +1539,83 @@ void Sizer::InitPowerBeforeUpdate(vector< CELL > &c) { } } +void Sizer::refreshOpenStaParasitics(bool verbose_global_route) { + auto design = _ckt->_ord_design; + auto sta = _ckt->_ord_timing->getSta(); + + if(!use_gr_rc) { + design->evalTclString("estimate_parasitics -placement"); + sta->findRequireds(); + return; + } + + // Master swaps invalidate timing data before timing-aware global routing + // asks STA for net slacks. Use placement RC only as a complete routing + // seed, then replace it with freshly routed parasitics. + design->evalTclString("estimate_parasitics -placement"); + + auto db_tech = design->getTech()->getDB()->getTech(); + auto signal_low_layer = + db_tech->findLayer(min_route_layer.c_str())->getRoutingLevel(); + auto signal_high_layer = + db_tech->findLayer(max_route_layer.c_str())->getRoutingLevel(); + auto grt = design->getGlobalRouter(); + grt->clear(); + grt->setAllowCongestion(true); + grt->setMinRoutingLayer(signal_low_layer); + grt->setMaxRoutingLayer(signal_high_layer); + grt->setMinLayerForClock(signal_low_layer); + grt->setMaxLayerForClock(signal_high_layer); + grt->setAdjustment(0.5); + grt->setResistanceAware(false); + grt->setVerbose(verbose_global_route); + grt->setCongestionIterations(10); + printf("Run Global Routing after size update...\n"); + design->evalTclString( + verbose_global_route + ? "global_route -congestion_iterations 10 -allow_congestion " + "-verbose" + : "global_route -congestion_iterations 10 -allow_congestion"); + design->evalTclString("estimate_parasitics -global_routing"); + sta->findRequireds(); +} + +void Sizer::applyOpenStaDbChanges( + const std::function< void() > &apply_changes) { + auto design = _ckt->_ord_design; + auto sta = _ckt->_ord_timing->getSta(); + + if(!use_gr_rc) { + apply_changes(); + design->evalTclString("estimate_parasitics -placement"); + sta->findRequireds(); + return; + } + + auto grt = design->getGlobalRouter(); + auto resizer = design->getResizer(); + auto estimate_parasitics = resizer->getEstimateParasitics(); + + // The incremental API requires a routed GR parasitics seed. This fallback + // is only for callers that reach a size update before the normal GR setup. + if(estimate_parasitics->getParasiticsSrc() != + est::ParasiticsSrc::kGlobalRouting) { + refreshOpenStaParasitics(false); + } + + if(estimate_parasitics->isIncrementalParasiticsEnabled()) { + apply_changes(); + resizer->updateParasiticsAndTiming(); + return; + } + + est::IncrementalParasiticsGuard parasitics_guard(estimate_parasitics); + grt->startIncremental(); + apply_changes(); + resizer->updateParasiticsAndTiming(); + grt->endIncremental(); +} + void Sizer::UpdatePTSizes(vector< CELL > &cells, unsigned option) { std::cerr << "Update PT sizes... " << std::endl; std::cerr << "numcell = " << cells.size() << std::endl; @@ -1552,48 +1630,35 @@ void Sizer::UpdatePTSizes(vector< CELL > &cells, unsigned option) { continue; count++; } - auto sta_ = _ckt->_ord_timing->getSta(); - auto db_network_ = sta_->getDbNetwork(); - auto global_router_ = _ckt->_ord_design->getGlobalRouter(); - printf("Update PT sizes changed count %d\n", count); - std::unordered_set< odb::dbNet * > parasitics_invalid_; - // UnorderedSet< const Net *, NetHash > parasitics_invalid_; if(count > 0) { double begin = cpuTime(); - // this->_sta->networkChanged(); - auto corner = this->_ckt->_ord_timing->getCorners()[0]; - for(unsigned i = 0; i < cells.size(); i++) { - LibCellInfo *lib_cell_info = getLibCellInfo(cells[i]); - if(lib_cell_info == NULL || cells[i].isDontTouch) - continue; - if(!PT_FULL_UPDATE && !cells[i].isChanged) - continue; - auto inst = block->findInst(cells[i].name.c_str()); - // inst->swapMaster(); - assert(inst); - auto new_master = db->findMaster(cells[i].type.c_str()); - if(new_master) { - inst->swapMaster(new_master); - cells[i].isChanged = 0; - cells[i].isStaticChanged = true; + applyOpenStaDbChanges([&]() { + for(unsigned i = 0; i < cells.size(); i++) { + LibCellInfo *lib_cell_info = getLibCellInfo(cells[i]); + if(lib_cell_info == NULL || cells[i].isDontTouch) + continue; + if(!PT_FULL_UPDATE && !cells[i].isChanged) + continue; + auto inst = block->findInst(cells[i].name.c_str()); + assert(inst); + auto new_master = db->findMaster(cells[i].type.c_str()); + if(new_master) { + inst->swapMaster(new_master); + cells[i].isChanged = 0; + cells[i].isStaticChanged = true; + } + else { + string type = inst->getMaster()->getName(); + std::cerr << "Error: cannot find master " << cells[i].type + << " for cell " << cells[i].name + << ", current master is " << type << std::endl; + cells[i].type = type; + cells[i].isChanged = 0; + cells[i].isStaticChanged = true; + } } - else { - string type = inst->getMaster()->getName(); - std::cerr << "Error: cannot find master " << cells[i].type - << " for cell " << cells[i].name - << ", current master is " << type << std::endl; - cells[i].type = type; - cells[i].isChanged = 0; - cells[i].isStaticChanged = true; - } - // cells[i].static_power = - // this->_ckt->_ord_timing->staticPower(inst, corner); - } - _ckt->_ord_design->evalTclString( - use_gr_rc ? "estimate_parasitics -global_routing" - : "estimate_parasitics -placement"); - _sta->findRequireds(); + }); T[0]->pt_time += cpuTime() - begin; } @@ -1754,52 +1819,35 @@ void Sizer::UpdatePTSizes(unsigned option, int &count) { count++; } auto sta_ = _ckt->_ord_timing->getSta(); - auto db_network_ = sta_->getDbNetwork(); - auto global_router_ = _ckt->_ord_design->getGlobalRouter(); - printf("Update PT sizes changed count %d\n", count); - std::unordered_set< odb::dbNet * > parasitics_invalid_; - // UnorderedSet< const Net *, NetHash > parasitics_invalid_; if(count > 0) { double begin = cpuTime(); - // this->_sta->networkChanged(); - auto corner = this->_ckt->_ord_timing->getCorners()[0]; - for(unsigned i = 0; i < numcells; i++) { - LibCellInfo *lib_cell_info = getLibCellInfo(cells[i]); - if(lib_cell_info == NULL || cells[i].isDontTouch) - continue; - if(!PT_FULL_UPDATE && !cells[i].isChanged) - continue; - auto inst = block->findInst(cells[i].name.c_str()); - assert(inst); - auto new_master = db->findMaster(cells[i].type.c_str()); - if(new_master == NULL) { - string type = inst->getMaster()->getName(); - std::cerr << "Error: cannot find master " << cells[i].type - << " for cell " << cells[i].name - << ", current master is " << type << std::endl; - cells[i].type = type; - cells[i].isChanged = 0; - cells[i].isStaticChanged = true; - } - else { - inst->swapMaster(new_master); - cells[i].isChanged = 0; - cells[i].isStaticChanged = true; + applyOpenStaDbChanges([&]() { + for(unsigned i = 0; i < numcells; i++) { + LibCellInfo *lib_cell_info = getLibCellInfo(cells[i]); + if(lib_cell_info == NULL || cells[i].isDontTouch) + continue; + if(!PT_FULL_UPDATE && !cells[i].isChanged) + continue; + auto inst = block->findInst(cells[i].name.c_str()); + assert(inst); + auto new_master = db->findMaster(cells[i].type.c_str()); + if(new_master == NULL) { + string type = inst->getMaster()->getName(); + std::cerr << "Error: cannot find master " << cells[i].type + << " for cell " << cells[i].name + << ", current master is " << type << std::endl; + cells[i].type = type; + cells[i].isChanged = 0; + cells[i].isStaticChanged = true; + } + else { + inst->swapMaster(new_master); + cells[i].isChanged = 0; + cells[i].isStaticChanged = true; + } } - // cells[i].static_power = - // this->_ckt->_ord_timing->staticPower(inst, corner); - } - // incr_groute_->updateRoutes(false); - // _ckt->_ord_design->evalTclString("estimate_parasitics - // -global_routing"); - parasitics_invalid_.clear(); -#if 0 - _ckt->_ord_design->evalTclString("estimate_parasitics -global_routing"); -#else - _ckt->_ord_design->evalTclString("estimate_parasitics -placement"); -#endif - sta_->findRequireds(); + }); T[0]->pt_time += cpuTime() - begin; } // else cout << "No cell has been changed." << endl; @@ -6093,94 +6141,74 @@ void Sizer::FinalReport() { auto _ord_design = _ckt->_ord_design; auto block = _ord_design->getBlock(); auto _sta = ord::OpenRoad::openRoad()->getSta(); - // _sta->networkChanged(); - int inst_iter = 0; - for(unsigned i = 0; i < numcells; i++) { - LibCellInfo *lib_cell_info = getLibCellInfo(best_cells_poweropt[i]); - if(lib_cell_info == NULL || best_cells_poweropt[i].isDontTouch) - continue; - auto inst = block->findInst(best_cells_poweropt[i].name.c_str()); - auto new_master = _ord_design->getTech()->getDB()->findMaster( - best_cells_poweropt[i].type.c_str()); - if(inst->getMaster()->getName() != best_cells_poweropt[i].type) { - if(new_master) { - printf("Change %s %s\n", inst->getMaster()->getName().c_str(), - best_cells_poweropt[i].type.c_str()); - inst->swapMaster(new_master); + applyOpenStaDbChanges([&]() { + for(unsigned i = 0; i < numcells; i++) { + LibCellInfo *lib_cell_info = getLibCellInfo(best_cells_poweropt[i]); + if(lib_cell_info == NULL || best_cells_poweropt[i].isDontTouch) + continue; + auto inst = block->findInst(best_cells_poweropt[i].name.c_str()); + auto new_master = _ord_design->getTech()->getDB()->findMaster( + best_cells_poweropt[i].type.c_str()); + if(inst->getMaster()->getName() != best_cells_poweropt[i].type) { + if(new_master) { + printf("Change %s %s\n", + inst->getMaster()->getName().c_str(), + best_cells_poweropt[i].type.c_str()); + inst->swapMaster(new_master); + } + else { + printf("Change %s %s not found\n", + inst->getMaster()->getName().c_str(), + best_cells_poweropt[i].type.c_str()); + } + best_cells_poweropt[i].isStaticChanged = true; } else { - printf("Change %s %s not found\n", - inst->getMaster()->getName().c_str(), - best_cells_poweropt[i].type.c_str()); + best_cells_poweropt[i].isStaticChanged = false; } - best_cells_poweropt[i].isStaticChanged = true; + best_cells_poweropt[i].isChanged = 1; } - else { - best_cells_poweropt[i].isStaticChanged = false; + + if(spefFile != "") { + return; } - best_cells_poweropt[i].isChanged = 1; - } + + int inst_iter = 0; + for(auto db_inst : block->getInsts()) { + int inst_x, inst_y; + int old_x, old_y; + db_inst->getLocation(old_x, old_y); + if((old_x != _ckt->old_localtion_x[inst_iter] || + old_y != _ckt->old_localtion_y[inst_iter]) && + !db_inst->getPlacementStatus().isFixed()) { + db_inst->setLocation(_ckt->old_localtion_x[inst_iter], + _ckt->old_localtion_y[inst_iter]); + } + inst_iter++; + } + + char padding_str[100]; + sprintf(padding_str, + "set_placement_padding -global -left %d -right %d", + dp_padding, + dp_padding); + _ord_design->evalTclString(string(padding_str)); + _ord_design->evalTclString("detailed_placement"); + }); + if(spefFile != "") { return; } - for(auto db_inst : block->getInsts()) { - int inst_x, inst_y; - int old_x, old_y; - db_inst->getLocation(old_x, old_y); - if((old_x != _ckt->old_localtion_x[inst_iter] || - old_y != _ckt->old_localtion_y[inst_iter]) && - !db_inst->getPlacementStatus().isFixed()) { - db_inst->setLocation(_ckt->old_localtion_x[inst_iter], - _ckt->old_localtion_y[inst_iter]); - // cout << "Move " << db_inst->getName() << " from (" << old_x - // << ", " << old_y << ") to (" - // << _ckt->old_localtion_x[inst_iter] << ", " - // << _ckt->old_localtion_y[inst_iter] << ")" << endl; - } - inst_iter++; - } - // auto site = _ord_design->getBlock()->getRows().begin()->getSite(); - // auto max_disp_x = int(_ord_design->micronToDBU(0.1) / site->getWidth()); - // auto max_disp_y = int(_ord_design->micronToDBU(0.1) / site->getHeight()); - // _sta = ord::OpenRoad::openRoad()->getSta(); - // _ord_design->getOpendp()->detailedPlacement(max_disp_x, max_disp_y); - char padding_str[100]; - sprintf(padding_str, "set_placement_padding -global -left %d -right %d", - dp_padding, dp_padding); - _ord_design->evalTclString(string(padding_str)); - _ord_design->evalTclString("detailed_placement"); + double begin = cpuTime(); if(use_gr_rc) { - // Global Route and estimate global-route RC. - double begin = cpuTime(); - auto db_tech = _ord_design->getTech()->getDB()->getTech(); - auto signal_low_layer = - db_tech->findLayer(min_route_layer.c_str())->getRoutingLevel(); - auto signal_high_layer = - db_tech->findLayer(max_route_layer.c_str())->getRoutingLevel(); - auto clk_low_layer = - db_tech->findLayer(min_route_layer.c_str())->getRoutingLevel(); - auto clk_high_layer = - db_tech->findLayer(max_route_layer.c_str())->getRoutingLevel(); - auto grt = _ord_design->getGlobalRouter(); - grt->setCongestionIterations(10); - grt->clear(); - grt->setAllowCongestion(true); - grt->setMinRoutingLayer(signal_low_layer); - grt->setMaxRoutingLayer(signal_high_layer); - grt->setMinLayerForClock(clk_low_layer); - grt->setMaxLayerForClock(clk_high_layer); - grt->setAdjustment(0.5); - grt->setVerbose(true); - printf("Run Global Routing...\n"); - grt->globalRoute(false); - printf("Run Global Routing Time %f\n", cpuTime() - begin); - _ord_design->evalTclString("estimate_parasitics -global_routing"); - } - else { - _ord_design->evalTclString("estimate_parasitics -placement"); + // Post-CTS DEFs can omit routing-layer geometry for top-level pins. + // Rebuild pin access points before invoking the global router. + _ord_design->evalTclString( + "place_pins -hor_layers {MET5} -ver_layers {MET4} -annealing"); } - _sta->findRequireds(); + refreshOpenStaParasitics(true); + printf("Run Global Routing Time %f\n", cpuTime() - begin); _ckt->readSpef_opensta(_sta); int corner = 0; ofstream ofs("net_changed.log"); diff --git a/src/sizer.h b/src/sizer.h index 8b2d8b4..2bfbef4 100644 --- a/src/sizer.h +++ b/src/sizer.h @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -458,6 +459,8 @@ class Sizer { unsigned thread_id, double toler, unsigned view); bool replaceCell(odb::dbInst *dinst, odb::dbMaster *new_master, std::unordered_set< odb::dbNet * > ¶sitics_invalid_); + void applyOpenStaDbChanges(const std::function< void() > &apply_changes); + void refreshOpenStaParasitics(bool verbose_global_route = false); inline bool isMin(const CELL &cell) { return (cell.c_size == 0); } diff --git a/src/timer.cpp b/src/timer.cpp index 25ce7e4..be1cdf5 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -3043,9 +3043,6 @@ double Sizer::CalSens(CELL &cell, int steps, int dir, int option, double gamma, else if(option == 16) { double delta_delay = EstDeltaDelay(cell, steps, dir, view); ulong cell_npath = GetCellNPathsLessThanSlack(cell); - if(VERBOSE >= 1) { - cout << "SF 16 " << 1 / (delta_delay * cell_npath) << endl; - } return 1 / (delta_delay * cell_npath); } else { diff --git a/thirdparty/OpenROAD b/thirdparty/OpenROAD index fea5072..27141a7 160000 --- a/thirdparty/OpenROAD +++ b/thirdparty/OpenROAD @@ -1 +1 @@ -Subproject commit fea5072fe0ab728dcf2ddf2ac0e0bfebbd8ac5b5 +Subproject commit 27141a72a3ce0c43b63b1784689c2537c789d3c9 From 11fa6b761023c71f432b83ddf0f4274eb7ffbc03 Mon Sep 17 00:00:00 2001 From: zxy Date: Tue, 14 Jul 2026 13:25:51 +0800 Subject: [PATCH 5/9] add final gr estimate --- src/sizer.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/sizer.cpp b/src/sizer.cpp index 3acd4c8..ce0720e 100644 --- a/src/sizer.cpp +++ b/src/sizer.cpp @@ -5484,6 +5484,13 @@ void Sizer::runOrdTO() { _ckt->_ord_design->evalTclString("repair_timing -setup -setup_margin " + to_string(setup_margin) + " -verbose"); _ckt->_ord_design->evalTclString("detailed_placement"); + if(use_gr_rc) { + // repair_* and detailed placement change the final DB state. Rebuild + // GR parasitics once so the in-process final report matches the + // exported design state. + printf("Run final global-routing RC refresh after runOrdTO...\n"); + refreshOpenStaParasitics(true); + } double wns = T[view]->getWorstSlack(clk_name[worst_corner]); double tns = T[view]->getTNS(clk_name[worst_corner]); @@ -5501,15 +5508,15 @@ void Sizer::runOrdTO() { cap_tot = cap_max = 0.0; int cap_num = 0; T[view]->getCapVio(cap_tot, cap_max, cap_num); - cout << "[view " << view << "] Initial WNS from Timer : " << wns << " ps" + cout << "[view " << view << "] Final WNS after runOrdTO : " << wns << " ns" << endl; - cout << "[view " << view << "] Initial TNS : " << tns << " ps" + cout << "[view " << view << "] Final TNS after runOrdTO : " << tns << " ns" << endl; // cout << "[view " << view << "] Initial Leakage Power : " << leak // << endl; // cout << "[view " << view << "] Initial Total Power : " << tot // << endl; - cout << "[view " << view << "] Initial Tran : " << tran_tot + cout << "[view " << view << "] Final Tran after runOrdTO : " << tran_tot << " ps " << tran_num << " " << tran_max << " ps" << endl; } void Sizer::Parallel_Sizer_Launcher() { From 2ef53df724699dd803ea378384f61e4717e9de69 Mon Sep 17 00:00:00 2001 From: zxy Date: Thu, 6 Aug 2026 20:54:32 +0800 Subject: [PATCH 6/9] Align OpenROAD submodule tracking branch --- .gitmodules | 2 +- thirdparty/OpenROAD | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index eb46d79..ce22d07 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "thirdparty/OpenROAD"] path = thirdparty/OpenROAD url = git@github.com:zhaoxueyan1/OpenROAD.git - branch = ecc-sizer + branch = merge-upstream-master diff --git a/thirdparty/OpenROAD b/thirdparty/OpenROAD index 27141a7..a5bee17 160000 --- a/thirdparty/OpenROAD +++ b/thirdparty/OpenROAD @@ -1 +1 @@ -Subproject commit 27141a72a3ce0c43b63b1784689c2537c789d3c9 +Subproject commit a5bee170f2d7a9e3c60745a5237e7cccbff04970 From 5da2ba76ad3eec3a344d6b3d42f16dde0b985654 Mon Sep 17 00:00:00 2001 From: Forrest <32609532+zhaoxueyan1@users.noreply.github.com> Date: Thu, 6 Aug 2026 21:02:31 +0800 Subject: [PATCH 7/9] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/sizer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sizer.cpp b/src/sizer.cpp index ce0720e..756bcca 100644 --- a/src/sizer.cpp +++ b/src/sizer.cpp @@ -665,8 +665,8 @@ void Sizer::setEquivCellSortMode(const string& mode) { sortEquivCellsByLeakage = true; return; } - if(mode == "drive_resistance" || mode == "drive_resitance" || - mode == "drive_res" || mode == "drive") { + if(mode == "drive_resistance" || mode == "drive_res" || + mode == "drive") { sortEquivCellsByLeakage = false; return; } From 7863387dfc2ba4fe379e21866fdd4b434237127f Mon Sep 17 00:00:00 2001 From: Forrest <32609532+zhaoxueyan1@users.noreply.github.com> Date: Thu, 6 Aug 2026 21:03:21 +0800 Subject: [PATCH 8/9] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/sizer.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/sizer.cpp b/src/sizer.cpp index 756bcca..66c931a 100644 --- a/src/sizer.cpp +++ b/src/sizer.cpp @@ -1555,10 +1555,15 @@ void Sizer::refreshOpenStaParasitics(bool verbose_global_route) { design->evalTclString("estimate_parasitics -placement"); auto db_tech = design->getTech()->getDB()->getTech(); - auto signal_low_layer = - db_tech->findLayer(min_route_layer.c_str())->getRoutingLevel(); - auto signal_high_layer = - db_tech->findLayer(max_route_layer.c_str())->getRoutingLevel(); + auto* low_layer = db_tech->findLayer(min_route_layer.c_str()); + auto* high_layer = db_tech->findLayer(max_route_layer.c_str()); + if(low_layer == nullptr || high_layer == nullptr) { + cout << "Error: invalid routing layer(s): min=" << min_route_layer + << " max=" << max_route_layer << endl; + exit(1); + } + auto signal_low_layer = low_layer->getRoutingLevel(); + auto signal_high_layer = high_layer->getRoutingLevel(); auto grt = design->getGlobalRouter(); grt->clear(); grt->setAllowCongestion(true); From 0f121c6fb5c4ab34712bb063b01ea2aeb4ebb61f Mon Sep 17 00:00:00 2001 From: Forrest <32609532+zhaoxueyan1@users.noreply.github.com> Date: Thu, 6 Aug 2026 21:04:03 +0800 Subject: [PATCH 9/9] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/ckt.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/ckt.cpp b/src/ckt.cpp index 6f5bd43..37d00e6 100644 --- a/src/ckt.cpp +++ b/src/ckt.cpp @@ -1826,14 +1826,18 @@ void Circuit::runGR(int gr_overflow_iterations, bool fast, int slack_max_iter) { _ord_design->evalTclString( "place_pins -hor_layers {MET5} -ver_layers {MET4} -annealing"); auto db_tech = _ord_design->getTech()->getDB()->getTech(); - auto signal_low_layer = - db_tech->findLayer(_sizer->min_route_layer.c_str())->getRoutingLevel(); - auto signal_high_layer = - db_tech->findLayer(_sizer->max_route_layer.c_str())->getRoutingLevel(); - auto clk_low_layer = - db_tech->findLayer(_sizer->min_route_layer.c_str())->getRoutingLevel(); - auto clk_high_layer = - db_tech->findLayer(_sizer->max_route_layer.c_str())->getRoutingLevel(); + auto* low_layer = db_tech->findLayer(_sizer->min_route_layer.c_str()); + auto* high_layer = db_tech->findLayer(_sizer->max_route_layer.c_str()); + if(low_layer == nullptr || high_layer == nullptr) { + printf("Error: invalid routing layer(s): min=%s max=%s\n", + _sizer->min_route_layer.c_str(), + _sizer->max_route_layer.c_str()); + exit(1); + } + auto signal_low_layer = low_layer->getRoutingLevel(); + auto signal_high_layer = high_layer->getRoutingLevel(); + auto clk_low_layer = signal_low_layer; + auto clk_high_layer = signal_high_layer; auto grt = _ord_design->getGlobalRouter(); grt->clear(); grt->setAllowCongestion(true);