diff --git a/CMakeLists.txt b/CMakeLists.txt index bf2529a0..06b55cde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14) cmake_policy(SET CMP0086 NEW) endif() -project(STA VERSION 3.0.0 +project(STA VERSION 3.0.1 LANGUAGES CXX ) @@ -89,13 +89,17 @@ endif() set(STA_SOURCE app/StaMain.cc - dcalc/ArcDelayCalc.cc dcalc/ArcDcalcWaveforms.cc + dcalc/ArcDelayCalc.cc dcalc/ArnoldiDelayCalc.cc dcalc/ArnoldiReduce.cc dcalc/CcsCeffDelayCalc.cc + dcalc/Delay.cc dcalc/DelayCalc.cc dcalc/DelayCalcBase.cc + dcalc/DelayNormal.cc + dcalc/DelayScalar.cc + dcalc/DelaySkewNormal.cc dcalc/DmpCeff.cc dcalc/DmpDelayCalc.cc dcalc/FindRoot.cc @@ -106,9 +110,6 @@ set(STA_SOURCE dcalc/PrimaDelayCalc.cc dcalc/UnitDelayCalc.cc - graph/DelayFloat.cc - graph/DelayNormal1.cc - graph/DelayNormal2.cc graph/Graph.cc graph/GraphCmp.cc @@ -206,6 +207,7 @@ set(STA_SOURCE search/PathEnum.cc search/PathExpanded.cc search/PathGroup.cc + search/PocvMode.cc search/Property.cc search/ReportPath.cc search/Search.cc @@ -408,12 +410,18 @@ find_package(Threads) find_package(Eigen3 REQUIRED) -include(cmake/FindCUDD.cmake) - -if("${SSTA}" STREQUAL "") - set(SSTA 0) +# fmt library: fallback when std::format is not available (e.g. GCC 11 on Ubuntu 22.04) +find_package(fmt QUIET) +if(NOT fmt_FOUND) + include(FetchContent) + FetchContent_Declare(fmt + GIT_REPOSITORY https://github.com/fmtlib/fmt.git + GIT_TAG 10.2.1 + ) + FetchContent_MakeAvailable(fmt) endif() -message(STATUS "SSTA: ${SSTA}") + +include(cmake/FindCUDD.cmake) # configure a header file to pass some of the CMake settings configure_file(${STA_HOME}/util/StaConfig.hh.cmake @@ -528,6 +536,7 @@ target_sources(OpenSTA target_link_libraries(OpenSTA Eigen3::Eigen + fmt::fmt ${TCL_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${CUDD_LIB} @@ -561,7 +570,7 @@ endif() # common to gcc/clang set(CXX_FLAGS -Wall -Wextra -pedantic -Wcast-qual -Wredundant-decls - -Wformat-security -Werror=misleading-indentation) + -Wformat-security -Werror=misleading-indentation -Wundef) if(ENABLE_TSAN) message(STATUS "Thread sanitizer: ${ENABLE_TSAN}") diff --git a/app/StaMain.cc b/app/StaMain.cc index a7147ab0..079112e1 100644 --- a/app/StaMain.cc +++ b/app/StaMain.cc @@ -96,11 +96,10 @@ sourceTclFile(const char *filename, bool verbose, Tcl_Interp *interp) { - std::string cmd; - stringPrint(cmd, "sta::include_file %s %s %s", - filename, - echo ? "1" : "0", - verbose ? "1" : "0"); + std::string cmd = sta::format("sta::include_file {} {} {}", + filename, + echo ? "1" : "0", + verbose ? "1" : "0"); int code = Tcl_Eval(interp, cmd.c_str()); const char *result = Tcl_GetStringResult(interp); if (result[0] != '\0') diff --git a/dcalc/ArcDcalcWaveforms.cc b/dcalc/ArcDcalcWaveforms.cc index 4c0fe95b..00f1e3bb 100644 --- a/dcalc/ArcDcalcWaveforms.cc +++ b/dcalc/ArcDcalcWaveforms.cc @@ -60,8 +60,9 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg, bool vdd_exists; library->supplyVoltage("VDD", vdd, vdd_exists); if (!vdd_exists) - report->error(1751, "VDD not defined in library %s", library->name()); - Waveform in_waveform = driver_waveform->waveform(delayAsFloat(in_slew)); + report->error(1751, "VDD not defined in library {}", library->name()); + float slew1 = delayAsFloat(in_slew, min_max, sta); + Waveform in_waveform = driver_waveform->waveform(slew1); // Delay time axis. FloatSeq time_values; for (float time : in_waveform.axis1()->values()) diff --git a/dcalc/ArcDelayCalc.cc b/dcalc/ArcDelayCalc.cc index a17ab9a9..86759411 100644 --- a/dcalc/ArcDelayCalc.cc +++ b/dcalc/ArcDelayCalc.cc @@ -94,24 +94,24 @@ makeArcDcalcArg(const char *inst_name, else { const Network *network = sta->network(); const Instance *inst = network->instance(in_pin); - report->warn(2100, "no timing arc for %s input/driver pins.", + report->warn(2100, "no timing arc for {} input/driver pins.", network->pathName(inst)); } } else - report->warn(2101, "%s not a valid rise/fall.", drvr_rf_name); + report->warn(2101, "{} not a valid rise/fall.", drvr_rf_name); } else - report->warn(2102, "Pin %s/%s not found.", inst_name, drvr_port_name); + report->warn(2102, "Pin {}/{} not found.", inst_name, drvr_port_name); } else - report->warn(2103, "%s not a valid rise/fall.", in_rf_name); + report->warn(2103, "{} not a valid rise/fall.", in_rf_name); } else - report->warn(2104, "Pin %s/%s not found.", inst_name, in_port_name); + report->warn(2104, "Pin {}/{} not found.", inst_name, in_port_name); } else - report->warn(2105, "Instance %s not found.", inst_name); + report->warn(2105, "Instance {} not found.", inst_name); return ArcDcalcArg(); } @@ -257,18 +257,18 @@ ArcDcalcResult::ArcDcalcResult(size_t load_count) : } void -ArcDcalcResult::setGateDelay(ArcDelay gate_delay) +ArcDcalcResult::setGateDelay(const ArcDelay &gate_delay) { gate_delay_ = gate_delay; } void -ArcDcalcResult::setDrvrSlew(Slew drvr_slew) +ArcDcalcResult::setDrvrSlew(const Slew &drvr_slew) { drvr_slew_ = drvr_slew; } -ArcDelay +const ArcDelay & ArcDcalcResult::wireDelay(size_t load_idx) const { return wire_delays_[load_idx]; @@ -276,7 +276,7 @@ ArcDcalcResult::wireDelay(size_t load_idx) const void ArcDcalcResult::setWireDelay(size_t load_idx, - ArcDelay wire_delay) + const ArcDelay &wire_delay) { wire_delays_[load_idx] = wire_delay; } @@ -288,7 +288,7 @@ ArcDcalcResult::setLoadCount(size_t load_count) load_slews_.resize(load_count); } -Slew +const Slew & ArcDcalcResult::loadSlew(size_t load_idx) const { return load_slews_[load_idx]; @@ -296,7 +296,7 @@ ArcDcalcResult::loadSlew(size_t load_idx) const void ArcDcalcResult::setLoadSlew(size_t load_idx, - Slew load_slew) + const Slew &load_slew) { load_slews_[load_idx] = load_slew; } diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc index 970c91f1..c85d1998 100644 --- a/dcalc/ArnoldiDelayCalc.cc +++ b/dcalc/ArnoldiDelayCalc.cc @@ -237,7 +237,6 @@ private: ArnoldiReduce *reduce_; delay_work *delay_work_; std::vector unsaved_parasitics_; - bool pocv_enabled_; }; ArcDelayCalc * @@ -397,7 +396,6 @@ ArnoldiDelayCalc::gateDelay(const Pin *drvr_pin, ConcreteParasitic *cparasitic = reinterpret_cast(const_cast(parasitic)); rcmodel_ = dynamic_cast(cparasitic); - pocv_enabled_ = variables_->pocvEnabled(); GateTableModel *table_model = arc->gateTableModel(scene, min_max); if (table_model && rcmodel_) { const Pvt *pvt = pinPvt(drvr_pin, scene, min_max); @@ -453,8 +451,8 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell, auto load_idx_itr = load_pin_index_map.find(load_pin); if (load_idx_itr != load_pin_index_map.end()) { size_t load_idx = load_idx_itr->second; - ArcDelay wire_delay = _delayV[i] - _delayV[0]; - Slew load_slew = _slewV[i]; + double wire_delay = _delayV[i] - _delayV[0]; + double load_slew = _slewV[i]; thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); dcalc_result.setWireDelay(load_idx, wire_delay); dcalc_result.setLoadSlew(load_idx, load_slew); @@ -1158,7 +1156,7 @@ ra_hinv(double y, ex = exp(-x); f = x+ex-1.0-y; if (f<-1e-8 || f>1e-8) - debugPrint(debug, "arnoldi", 1, "y f %g %g", y, f); + debugPrint(debug, "arnoldi", 1, "y f {:g} {:g}", y, f); return x; } @@ -1292,7 +1290,7 @@ ArnoldiDelayCalc::ra_solve_for_s(delay_work *D, s = s - f/df; if (std::abs(f)>.5e-12) // .5ps - debugPrint(debug_, "arnoldi", 1, "ra_solve_for_s p %g tlohi %s err %s", + debugPrint(debug_, "arnoldi", 1, "ra_solve_for_s p {:g} tlohi {} err {}", p, units_->timeUnit()->asString(tlohi), units_->timeUnit()->asString(f)); @@ -1325,9 +1323,8 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D, float c1; double tlohi,r; c1 = ctot; - ArcDelay d1; - Slew s1; - tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1); + float d1, s1; + tab->table->gateDelay(tab->pvt, tab->in_slew, c1, d1, s1); tlohi = slew_derate*delayAsFloat(s1); r = tlohi/(c_log*c1); if (rdelay>0.0 && r > rdelay) @@ -1346,9 +1343,8 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D, double c_log = con->vlg; double c_smin = con->smin; double tlohi,smin,s; - ArcDelay d1; - Slew s1; - tab->table->gateDelay(tab->pvt, tab->in_slew, c, pocv_enabled_, d1, s1); + float d1, s1; + tab->table->gateDelay(tab->pvt, tab->in_slew, c, d1, s1); tlohi = slew_derate*delayAsFloat(s1); smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi); if (c_log*r*c >= tlohi) { @@ -1378,10 +1374,9 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab, float c2 = 0.5*c1; if (c1==c2) return 0.0; - ArcDelay d1, d2; - Slew s1, s2; - tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1); - tab->table->gateDelay(tab->pvt, tab->in_slew, c2, pocv_enabled_, d2, s2); + float d1, d2, s1, s2; + tab->table->gateDelay(tab->pvt, tab->in_slew, c1, d1, s1); + tab->table->gateDelay(tab->pvt, tab->in_slew, c2, d2, s2); double dt50 = delayAsFloat(d1)-delayAsFloat(d2); if (dt50 <= 0.0) return 0.0; @@ -1402,10 +1397,9 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, double vlo = con->vlo; double ctot = mod->ctot; double ceff,tlohi,t50_sy,r,s,t50_sr,rdelay; - ArcDelay df; - Slew sf; + float df, sf; - debugPrint(debug_, "arnoldi", 1, "ctot=%s", + debugPrint(debug_, "arnoldi", 1, "ctot={}", units_->capacitanceUnit()->asString(ctot)); rdelay = ra_rdelay_1(tab,ctot); @@ -1427,24 +1421,23 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, if (debug_->check("arnoldi", 1)) { double p = 1.0/(r*ctot); double thix,tlox; - debugPrint(debug_, "arnoldi", 1, "at r=%s s=%s", + debugPrint(debug_, "arnoldi", 1, "at r={} s={}", units_->resistanceUnit()->asString(r), units_->timeUnit()->asString(s)); thix = ra_solve_for_t(p,s,vhi); tlox = ra_solve_for_t(p,s,vlo); - tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, pocv_enabled_, df, sf); - debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s", + tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, df, sf); + debugPrint(debug_, "arnoldi", 1, "table slew (in_slew {} ctot {}) = {}", units_->timeUnit()->asString(tab->in_slew), units_->capacitanceUnit()->asString(ctot), delayAsString(sf, this)); tlohi = slew_derate*delayAsFloat(sf); - debugPrint(debug_, "arnoldi", 1, "tlohi %s %s", + debugPrint(debug_, "arnoldi", 1, "tlohi {} {}", units_->timeUnit()->asString(tlohi), units_->timeUnit()->asString(tlox-thix)); } ceff = ctot; - tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_, - df, sf); + tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, df, sf); t50_sy = delayAsFloat(df); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); @@ -1475,17 +1468,17 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, // new mvs at ceff s = ra_get_s(D,tab,r,ceff); - debugPrint(debug_, "arnoldi", 1, "new mvs s = %s", + debugPrint(debug_, "arnoldi", 1, "new mvs s = {}", units_->timeUnit()->asString(s)); } } - debugPrint(debug_, "arnoldi", 1, "r %s s %s ceff_time %s ceff %s", + debugPrint(debug_, "arnoldi", 1, "r {} s {} ceff_time {} ceff {}", units_->resistanceUnit()->asString(r), units_->timeUnit()->asString(s), units_->timeUnit()->asString(ceff_time), units_->capacitanceUnit()->asString(ceff)); - tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_, df, sf); + tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, df, sf); t50_sy = delayAsFloat(df); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); for (j=0;jn;j++) { diff --git a/dcalc/ArnoldiReduce.cc b/dcalc/ArnoldiReduce.cc index 5fee6823..046e8e8d 100644 --- a/dcalc/ArnoldiReduce.cc +++ b/dcalc/ArnoldiReduce.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. // (c) 2018 Nefelus, Inc. @@ -34,6 +34,7 @@ #include "Network.hh" #include "Units.hh" #include "Arnoldi.hh" +#include "Format.hh" #include "parasitics/ConcreteParasiticsPvt.hh" namespace sta { @@ -43,10 +44,7 @@ rcmodel::rcmodel() : { } -rcmodel::~rcmodel() -{ - free(pinV); -} +rcmodel::~rcmodel() { free(pinV); } float rcmodel::capacitance() const @@ -67,7 +65,7 @@ struct ts_point ParasiticNode *node_; int eN; bool is_term; - int tindex; // index into termV of corresponding term + int tindex; // index into termV of corresponding term ts_edge **eV; bool visited; ts_edge *in_edge; @@ -85,7 +83,6 @@ struct ts_edge //////////////////////////////////////////////////////////////// - const int ArnoldiReduce::ts_point_count_incr_ = 1024; const int ArnoldiReduce::ts_edge_count_incr_ = 1024; @@ -96,31 +93,32 @@ ArnoldiReduce::ArnoldiReduce(StaState *sta) : termNmax(256), dNmax(8) { - ts_pointV = (ts_point*)malloc(ts_pointNmax*sizeof(ts_point)); - ts_ordV = (int*)malloc(ts_pointNmax*sizeof(int)); - ts_pordV = (ts_point**)malloc(ts_pointNmax*sizeof(ts_point*)); - _u0 = (double*)malloc(ts_pointNmax*sizeof(double)); - _u1 = (double*)malloc(ts_pointNmax*sizeof(double)); - y = (double*)malloc(ts_pointNmax*sizeof(double)); - iv = (double*)malloc(ts_pointNmax*sizeof(double)); - r = (double*)malloc(ts_pointNmax*sizeof(double)); - c = (double*)malloc(ts_pointNmax*sizeof(double)); - par = (int*)malloc(ts_pointNmax*sizeof(int)); + ts_pointV = (ts_point *)malloc(ts_pointNmax * sizeof(ts_point)); + ts_ordV = (int *)malloc(ts_pointNmax * sizeof(int)); + ts_pordV = (ts_point **)malloc(ts_pointNmax * sizeof(ts_point *)); + _u0 = (double *)malloc(ts_pointNmax * sizeof(double)); + _u1 = (double *)malloc(ts_pointNmax * sizeof(double)); + y = (double *)malloc(ts_pointNmax * sizeof(double)); + iv = (double *)malloc(ts_pointNmax * sizeof(double)); + r = (double *)malloc(ts_pointNmax * sizeof(double)); + c = (double *)malloc(ts_pointNmax * sizeof(double)); + par = (int *)malloc(ts_pointNmax * sizeof(int)); - ts_edgeV = (ts_edge*)malloc(ts_edgeNmax*sizeof(ts_edge)); - ts_stackV = (ts_edge**)malloc(ts_edgeNmax*sizeof(ts_edge*)); - ts_eV = (ts_edge**)malloc(2*ts_edgeNmax*sizeof(ts_edge*)); + ts_edgeV = (ts_edge *)malloc(ts_edgeNmax * sizeof(ts_edge)); + ts_stackV = (ts_edge **)malloc(ts_edgeNmax * sizeof(ts_edge *)); + ts_eV = (ts_edge **)malloc(2 * ts_edgeNmax * sizeof(ts_edge *)); - pinV = (const Pin**)malloc(termNmax*sizeof(const Pin*)); - termV = (int*)malloc(termNmax*sizeof(int)); - outV = (int*)malloc(termNmax*sizeof(int)); + pinV = (const Pin **)malloc(termNmax * sizeof(const Pin *)); + termV = (int *)malloc(termNmax * sizeof(int)); + outV = (int *)malloc(termNmax * sizeof(int)); - d = (double*)malloc(dNmax*sizeof(double)); - e = (double*)malloc(dNmax*sizeof(double)); - U = (double**)malloc(dNmax*sizeof(double*)); - U0 = (double*)malloc(dNmax*termNmax*sizeof(double)); + d = (double *)malloc(dNmax * sizeof(double)); + e = (double *)malloc(dNmax * sizeof(double)); + U = (double **)malloc(dNmax * sizeof(double *)); + U0 = (double *)malloc(dNmax * termNmax * sizeof(double)); int h; - for (h=0;hparasitics(min_max); - parasitic_network_ = reinterpret_cast(parasitic); + parasitic_network_ = reinterpret_cast(parasitic); loadWork(); return makeRcmodelDrv(); @@ -200,7 +198,7 @@ ArnoldiReduce::loadWork() ts_edge *e; int tindex; - for (p = p0; p!=pend; p++) { + for (p = p0; p != pend; p++) { p->node_ = nullptr; p->eN = 0; p->is_term = false; @@ -246,14 +244,14 @@ ArnoldiReduce::loadWork() e++; } - for (p=p0;p!=pend;p++) { + for (p = p0; p != pend; p++) { if (p->node_) { p->eV = eV; eV += p->eN; p->eN = 0; } } - for (e=e0;e!=eend;e++) { + for (e = e0; e != eend; e++) { e->from->eV[e->from->eN++] = e; if (e->to != e->from) e->to->eV[e->to->eN++] = e; @@ -267,30 +265,33 @@ ArnoldiReduce::allocPoints() free(par); free(c); free(r); - free(iv); free(y); free(_u1); free(_u0); + free(iv); + free(y); + free(_u1); + free(_u0); free(ts_pordV); free(ts_ordV); free(ts_pointV); ts_pointNmax = ts_pointN + ts_point_count_incr_; - ts_pointV = (ts_point*)malloc(ts_pointNmax*sizeof(ts_point)); - ts_ordV = (int*)malloc(ts_pointNmax*sizeof(int)); - ts_pordV = (ts_point**)malloc(ts_pointNmax*sizeof(ts_point*)); - _u0 = (double*)malloc(ts_pointNmax*sizeof(double)); - _u1 = (double*)malloc(ts_pointNmax*sizeof(double)); - y = (double*)malloc(ts_pointNmax*sizeof(double)); - iv = (double*)malloc(ts_pointNmax*sizeof(double)); - r = (double*)malloc(ts_pointNmax*sizeof(double)); - c = (double*)malloc(ts_pointNmax*sizeof(double)); - par = (int*)malloc(ts_pointNmax*sizeof(int)); + ts_pointV = (ts_point *)malloc(ts_pointNmax * sizeof(ts_point)); + ts_ordV = (int *)malloc(ts_pointNmax * sizeof(int)); + ts_pordV = (ts_point **)malloc(ts_pointNmax * sizeof(ts_point *)); + _u0 = (double *)malloc(ts_pointNmax * sizeof(double)); + _u1 = (double *)malloc(ts_pointNmax * sizeof(double)); + y = (double *)malloc(ts_pointNmax * sizeof(double)); + iv = (double *)malloc(ts_pointNmax * sizeof(double)); + r = (double *)malloc(ts_pointNmax * sizeof(double)); + c = (double *)malloc(ts_pointNmax * sizeof(double)); + par = (int *)malloc(ts_pointNmax * sizeof(int)); } if (ts_edgeN > ts_edgeNmax) { free(ts_edgeV); free(ts_eV); free(ts_stackV); ts_edgeNmax = ts_edgeN + ts_edge_count_incr_; - ts_edgeV = (ts_edge*)malloc(ts_edgeNmax*sizeof(ts_edge)); - ts_stackV = (ts_edge**)malloc(ts_edgeNmax*sizeof(ts_edge*)); - ts_eV = (ts_edge**)malloc(2*ts_edgeNmax*sizeof(ts_edge*)); + ts_edgeV = (ts_edge *)malloc(ts_edgeNmax * sizeof(ts_edge)); + ts_stackV = (ts_edge **)malloc(ts_edgeNmax * sizeof(ts_edge *)); + ts_eV = (ts_edge **)malloc(2 * ts_edgeNmax * sizeof(ts_edge *)); } } @@ -302,65 +303,69 @@ ArnoldiReduce::allocTerms(int nterms) free(outV); free(termV); free(pinV); - termNmax = nterms+256; - pinV = (const Pin**)malloc(termNmax*sizeof(const Pin*)); - termV = (int*)malloc(termNmax*sizeof(int)); - outV = (int*)malloc(termNmax*sizeof(int)); + termNmax = nterms + 256; + pinV = (const Pin **)malloc(termNmax * sizeof(const Pin *)); + termV = (int *)malloc(termNmax * sizeof(int)); + outV = (int *)malloc(termNmax * sizeof(int)); - U0 = (double*)malloc(dNmax*termNmax*sizeof(double)); + U0 = (double *)malloc(dNmax * termNmax * sizeof(double)); int h; - for (h=0;h(node)]]; + return &ts_pointV[pt_map_[reinterpret_cast(node)]]; } rcmodel * ArnoldiReduce::makeRcmodelDrv() { ParasiticNode *drv_node = - parasitics_->findParasiticNode(parasitic_network_, drvr_pin_); + parasitics_->findParasiticNode(parasitic_network_, drvr_pin_); ts_point *pdrv = findPt(drv_node); makeRcmodelDfs(pdrv); getRC(); - if (ctot_ < 1e-22) // 1e-10ps + if (ctot_ < 1e-22) // 1e-10ps return nullptr; setTerms(pdrv); makeRcmodelFromTs(); return makeRcmodelFromW(); } -#define ts_orient( pp, ee) \ - if (ee->from!=pp) { ee->to = ee->from; ee->from = pp; } +#define ts_orient(pp, ee) \ + if (ee->from != pp) { \ + ee->to = ee->from; \ + ee->from = pp; \ + } void ArnoldiReduce::makeRcmodelDfs(ts_point *pdrv) { bool loop = false; int k; - ts_point *p,*q; + ts_point *p, *q; ts_point *p0 = ts_pointV; ts_point *pend = p0 + ts_pointN; - for (p=p0;p!=pend;p++) + for (p = p0; p != pend; p++) p->visited = 0; ts_edge *e; ts_edge **stackV = ts_stackV; int stackN = 1; stackV[0] = e = pdrv->eV[0]; - ts_orient(pdrv,e); + ts_orient(pdrv, e); pdrv->visited = 1; pdrv->in_edge = nullptr; pdrv->ts = 0; - ts_ordV[0] = pdrv-p0; + ts_ordV[0] = pdrv - p0; ts_pordV[0] = pdrv; ts_ordN = 1; - while (stackN>0) { - e = stackV[stackN-1]; + while (stackN > 0) { + e = stackV[stackN - 1]; q = e->to; if (q->visited) { @@ -368,47 +373,53 @@ ArnoldiReduce::makeRcmodelDfs(ts_point *pdrv) // ignore, and do not even set *loop if (e->to != e->from) loop = true; - } else { + } + else { // try to descend q->visited = 1; q->ts = ts_ordN++; ts_pordV[q->ts] = q; - ts_ordV[q->ts] = q-p0; + ts_ordV[q->ts] = q - p0; q->in_edge = e; - if (q->eN>1) { - for (k=0;keN;k++) if (q->eV[k] != e) break; + if (q->eN > 1) { + for (k = 0; k < q->eN; k++) + if (q->eV[k] != e) + break; e = q->eV[k]; - ts_orient(q,e); + ts_orient(q, e); stackV[stackN++] = e; - continue; // descent + continue; // descent } } // try to ascend - while (--stackN>=0) { + while (--stackN >= 0) { e = stackV[stackN]; p = e->from; // find e in p->eV - for (k=0;keN;k++) if (p->eV[k]==e) break; + for (k = 0; k < p->eN; k++) + if (p->eV[k] == e) + break; // if (k==p->eN) notice(0,"ERROR, e not found!\n"); ++k; - if (k>=p->eN) continue; + if (k >= p->eN) + continue; e = p->eV[k]; // check that next sibling is not the incoming edge - if (stackN>0 && e==stackV[stackN-1]) { - ++k; - if (k>=p->eN) continue; - e = p->eV[k]; + if (stackN > 0 && e == stackV[stackN - 1]) { + ++k; + if (k >= p->eN) + continue; + e = p->eV[k]; } - ts_orient(p,e); + ts_orient(p, e); stackV[stackN++] = e; break; } - } // while (stackN) + } // while (stackN) if (loop) - debugPrint(debug_, "arnoldi", 1, "net %s loop", - network_->pathName(drvr_pin_)); + debugPrint(debug_, "arnoldi", 1, "net {} loop", network_->pathName(drvr_pin_)); } // makeRcmodelGetRC @@ -418,13 +429,12 @@ ArnoldiReduce::getRC() ts_point *p, *p0 = ts_pointV; ts_point *pend = p0 + ts_pointN; ctot_ = 0.0; - for (p=p0;p!=pend;p++) { + for (p = p0; p != pend; p++) { p->c = 0.0; p->r = 0.0; if (p->node_) { ParasiticNode *node = p->node_; - double cap = parasitics_->nodeGndCap(node) - + pinCapacitance(node); + double cap = parasitics_->nodeGndCap(node) + pinCapacitance(node); if (cap > 0.0) { p->c = cap; ctot_ += cap; @@ -433,11 +443,9 @@ ArnoldiReduce::getRC() p->c = 0.0; if (p->in_edge && p->in_edge->resistor_) p->r = parasitics_->value(p->in_edge->resistor_); - if (!(p->r>=0.0 && p->r<100e+3)) { // 0 < r < 100kohm - debugPrint(debug_, "arnoldi", 1, - "R value %g out of range, drvr pin %s", - p->r, - network_->pathName(drvr_pin_)); + if (!(p->r >= 0.0 && p->r < 100e+3)) { // 0 < r < 100kohm + debugPrint(debug_, "arnoldi", 1, "R value {:g} out of range, drvr pin {}", + p->r, network_->pathName(drvr_pin_)); } } } @@ -466,7 +474,7 @@ ArnoldiReduce::pinCapacitance(ParasiticNode *node) LibertyPort *lib_port = network_->libertyPort(port); const Sdc *sdc = scene_->sdc(); if (lib_port) - pin_cap = sdc->pinCapacitance(pin,rf_, scene_, min_max_); + pin_cap = sdc->pinCapacitance(pin, rf_, scene_, min_max_); else if (network_->isTopLevelPort(pin)) pin_cap = sdc->portExtCap(port, rf_, min_max_); } @@ -479,13 +487,15 @@ ArnoldiReduce::setTerms(ts_point *pdrv) // termV: from drv-ordered to fixed order // outV: from drv-ordered to ts_pordV ts_point *p; - int k,k0; + int k, k0; termV[0] = k0 = pdrv->tindex; - for (k=1;kts; } @@ -498,38 +508,37 @@ ArnoldiReduce::makeRcmodelFromTs() ts_point *p, *p0 = ts_pointV; int n = ts_ordN; int nterms = termN; - int i,j,k,h; + int i, j, k, h; if (debug_->check("arnoldi", 1)) { - for (k=0;kts, - p-p0, + debugPrint(debug_, "arnoldi", 1, "T{} P{} c={}", p->ts, p - p0, units_->capacitanceUnit()->asString(p->c)); if (p->is_term) - debugPrint(debug_, "arnoldi", 1, " term %d", p->tindex); + debugPrint(debug_, "arnoldi", 1, " term {}", p->tindex); if (p->in_edge) - debugPrint(debug_, "arnoldi", 1, " from T%d,P%ld r=%s", - p->in_edge->from->ts, - p->in_edge->from-p0, + debugPrint(debug_, "arnoldi", 1, " from T{} P{} r={}", + p->in_edge->from->ts, p->in_edge->from - p0, units_->resistanceUnit()->asString(p->r)); } - for (i=0;ic; - for (j=1;jc; r[j] = p->r; @@ -537,92 +546,99 @@ ArnoldiReduce::makeRcmodelFromTs() } sum = 0.0; - for (j=0;jcapacitanceUnit()->asString(sum)); ctot_ = sum; sqc_ = sqrt(sum); - double sqrt_ctot_inv = 1.0/sqc_; - for (j=0;j0;j--) { - iv[j] += c[j]*u0[j]; + for (j = n - 1; j > 0; j--) { + iv[j] += c[j] * u0[j]; iv[par[j]] += iv[j]; } - iv[0] += c[0]*u0[0]; + iv[0] += c[0] * u0[0]; y[0] = 0.0; - for (j=1;jcheck("arnoldi", 1)) { - report_->reportLine("tridiagonal reduced matrix, drvr pin %s", - network_->pathName(drvr_pin_)); - report_->reportLine("order %d n %d",order,n); - for (h=0;hreportLine(" d[%d] %s e[%d] %s", - h, - units_->timeUnit()->asString(d[h]), - h, - units_->timeUnit()->asString(e[h])); + report_->report("tridiagonal reduced matrix, drvr pin {}", + network_->pathName(drvr_pin_)); + report_->report("order {} n {}", order, n); + for (h = 0; h < order; h++) { + if (h < order - 1) + report_->report(" d[{}] {} e[{}] {}", h, + units_->timeUnit()->asString(d[h]), h, + units_->timeUnit()->asString(e[h])); else - report_->reportLine(" d[%d] %s", - h, - units_->timeUnit()->asString(d[h])); - std::string line = stdstrPrint("U[%d]",h); - for (i=0;ireportLineString(line); + report_->report(" d[{}] {}", h, units_->timeUnit()->asString(d[h])); + std::string line = sta::format("U[{}]", h); + for (i = 0; i < nterms; i++) + line += sta::format(" {:6.2e}", U[h][i]); + report_->reportLine(line); } } } @@ -630,29 +646,33 @@ ArnoldiReduce::makeRcmodelFromTs() rcmodel * ArnoldiReduce::makeRcmodelFromW() { - int j,h; + int j, h; int n = termN; rcmodel *mod = new rcmodel(); mod->order = order; mod->n = n; - if (order>0) { - int totd = order + order - 1 + order*n; - mod->d = (double *)malloc(totd*sizeof(double)); - if (order>1) mod->e = mod->d + order; - else mod->e = nullptr; - mod->U = (double **)malloc(order*sizeof(double*)); + if (order > 0) { + int totd = order + order - 1 + order * n; + mod->d = (double *)malloc(totd * sizeof(double)); + if (order > 1) + mod->e = mod->d + order; + else + mod->e = nullptr; + mod->U = (double **)malloc(order * sizeof(double *)); mod->U[0] = mod->d + order + order - 1; - for (h=1;hU[h]=mod->U[0] + h*n; - for (h=0;hU[h] = mod->U[0] + h * n; + for (h = 0; h < order; h++) { mod->d[h] = d[h]; - if (he[h] = e[h]; - for (j=0;je[h] = e[h]; + for (j = 0; j < n; j++) mod->U[h][j] = U[h][j]; } } - mod->pinV = (const Pin **)malloc(n*sizeof(const Pin*)); - for (j=0;jpinV = (const Pin **)malloc(n * sizeof(const Pin *)); + for (j = 0; j < n; j++) { int k = termV[j]; mod->pinV[j] = pinV[k]; } @@ -662,4 +682,4 @@ ArnoldiReduce::makeRcmodelFromW() return mod; } -} // namespace +} // namespace sta diff --git a/dcalc/CcsCeffDelayCalc.cc b/dcalc/CcsCeffDelayCalc.cc index 95156145..0228df30 100644 --- a/dcalc/CcsCeffDelayCalc.cc +++ b/dcalc/CcsCeffDelayCalc.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "CcsCeffDelayCalc.hh" @@ -63,10 +63,7 @@ CcsCeffDelayCalc::CcsCeffDelayCalc(StaState *sta) : { } -CcsCeffDelayCalc::~CcsCeffDelayCalc() -{ - delete table_dcalc_; -} +CcsCeffDelayCalc::~CcsCeffDelayCalc() { delete table_dcalc_; } ArcDelayCalc * CcsCeffDelayCalc::copy() @@ -95,8 +92,8 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin, OutputWaveforms *output_waveforms = table_model->outputWaveforms(); Parasitics *parasitics = scene->parasitics(min_max); parasitics->piModel(parasitic, c2_, rpi_, c1_); - if (output_waveforms - && rpi_ > 0.0 && c1_ > 0.0 + if (output_waveforms && rpi_ > 0.0 + && c1_ > 0.0 // Bounds check because extrapolating waveforms does not work for shit. && output_waveforms->slewAxis()->inBounds(in_slew_) && output_waveforms->capAxis()->inBounds(c2_) @@ -107,22 +104,20 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin, drvr_rf_ = arc->toEdge()->asRiseFall(); drvr_library->supplyVoltage("VDD", vdd_, vdd_exists); if (!vdd_exists) - report_->error(1700, "VDD not defined in library %s", drvr_library->name()); + report_->error(1700, "VDD not defined in library {}", drvr_library->name()); vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_; vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_; vh_ = drvr_library->slewUpperThreshold(drvr_rf_) * vdd_; drvr_cell->ensureVoltageWaveforms(scenes_); - in_slew_ = delayAsFloat(in_slew); output_waveforms_ = output_waveforms; ref_time_ = output_waveforms_->referenceTime(in_slew_); - debugPrint(debug_, "ccs_dcalc", 1, "%s %s", - drvr_cell->name(), + debugPrint(debug_, "ccs_dcalc", 1, "{} {}", drvr_cell->name(), drvr_rf_->shortName()); - ArcDelay gate_delay; - Slew drvr_slew; + double gate_delay, drvr_slew; gateDelaySlew(drvr_library, drvr_rf_, gate_delay, drvr_slew); - return makeResult(drvr_library,drvr_rf_,gate_delay,drvr_slew,load_pin_index_map); + return makeResult(drvr_library, drvr_rf_, gate_delay, drvr_slew, + load_pin_index_map); } } return table_dcalc_->gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, @@ -133,8 +128,8 @@ void CcsCeffDelayCalc::gateDelaySlew(const LibertyLibrary *drvr_library, const RiseFall *rf, // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) + double &gate_delay, + double &drvr_slew) { initRegions(drvr_library, rf); findCsmWaveform(); @@ -142,19 +137,19 @@ CcsCeffDelayCalc::gateDelaySlew(const LibertyLibrary *drvr_library, gate_delay = region_times_[region_vth_idx_] - ref_time_; drvr_slew = std::abs(region_times_[region_vh_idx_] - region_times_[region_vl_idx_]); debugPrint(debug_, "ccs_dcalc", 2, - "gate_delay %s drvr_slew %s (initial)", + "gate_delay {} drvr_slew {} (initial)", delayAsString(gate_delay, this), delayAsString(drvr_slew, this)); - float prev_drvr_slew = delayAsFloat(drvr_slew); + float prev_drvr_slew = drvr_slew; constexpr int max_iterations = 5; for (int iter = 0; iter < max_iterations; iter++) { - debugPrint(debug_, "ccs_dcalc", 2, "iteration %d", iter); + debugPrint(debug_, "ccs_dcalc", 2, "iteration {}", iter); // Init drvr ramp model for vl. for (size_t i = 0; i <= region_count_; i++) { region_ramp_times_[i] = region_times_[i]; if (i < region_count_) region_ramp_slopes_[i] = (region_volts_[i + 1] - region_volts_[i]) - / (region_times_[i + 1] - region_times_[i]); + / (region_times_[i + 1] - region_times_[i]); } for (size_t i = 0; i < region_count_; i++) { @@ -174,20 +169,19 @@ CcsCeffDelayCalc::gateDelaySlew(const LibertyLibrary *drvr_library, double q2 = v2 * c2_ + c1_v2 * c1_; double ceff = (q2 - q1) / (v2 - v1); - debugPrint(debug_, "ccs_dcalc", 2, "ceff %s", + debugPrint(debug_, "ccs_dcalc", 2, "ceff {}", capacitance_unit_->asString(ceff)); region_ceff_[i] = ceff; } findCsmWaveform(); gate_delay = region_times_[region_vth_idx_] - ref_time_; drvr_slew = std::abs(region_times_[region_vh_idx_] - region_times_[region_vl_idx_]); - debugPrint(debug_, "ccs_dcalc", 2, - "gate_delay %s drvr_slew %s", + debugPrint(debug_, "ccs_dcalc", 2, "gate_delay {} drvr_slew {}", delayAsString(gate_delay, this), delayAsString(drvr_slew, this)); - if (std::abs(delayAsFloat(drvr_slew) - prev_drvr_slew) < .01 * prev_drvr_slew) + if (std::abs(drvr_slew - prev_drvr_slew) < .01 * prev_drvr_slew) break; - prev_drvr_slew = delayAsFloat(drvr_slew); + prev_drvr_slew = drvr_slew; } } @@ -217,68 +211,68 @@ CcsCeffDelayCalc::initRegions(const LibertyLibrary *drvr_library, double vth_vh = (vh_ - vth_); switch (region_count_) { - case 4: - region_vth_idx_ = 2; - region_volts_ = {0.0, vl_, vth_, vh_, vdd_}; - break; - case 5: { - region_vth_idx_ = 2; - double v1 = vth_ + .7 * vth_vh; - region_volts_ = {0.0, vl_, vth_, v1, vh_, vdd_}; - break; - } - case 6: { - region_vth_idx_ = 2; - double v1 = vth_ + .3 * vth_vh; - double v2 = vth_ + .6 * vth_vh; - region_volts_ = {0.0, vl_, vth_, v1, v2, vh_, vdd_}; - break; - } - case 7: { - region_vth_idx_ = 2; - region_vh_idx_ = 5; - double v1 = vth_ + .3 * vth_vh; - double v2 = vth_ + .6 * vth_vh; - double v3 = vh_ + .5 * (vdd_ - vh_); - region_volts_ = {0.0, vl_, vth_, v1, v2, vh_, v3, vdd_}; - break; - } - case 8: { - region_vth_idx_ = 2; - region_vh_idx_ = 6; - double v1 = vth_ + .25 * vth_vh; - double v2 = vth_ + .50 * vth_vh; - double v3 = vth_ + .75 * vth_vh; - double v4 = vh_ + .5 * (vdd_ - vh_); - region_volts_ = {0.0, vl_, vth_, v1, v2, v3, vh_, v4, vdd_}; - break; - } - case 9: { - region_vth_idx_ = 2; - region_vh_idx_ = 7; - double v1 = vth_ + .2 * vth_vh; - double v2 = vth_ + .4 * vth_vh; - double v3 = vth_ + .6 * vth_vh; - double v4 = vth_ + .8 * vth_vh; - double v5 = vh_ + .5 * (vdd_ - vh_); - region_volts_ = {0.0, vl_, vth_, v1, v2, v3, v4, vh_, v5, vdd_}; - break; - } - case 10: { - region_vth_idx_ = 2; - region_vh_idx_ = 7; - double v1 = vth_ + .2 * vth_vh; - double v2 = vth_ + .4 * vth_vh; - double v3 = vth_ + .6 * vth_vh; - double v4 = vth_ + .8 * vth_vh; - double v5 = vh_ + .3 * (vdd_ - vh_); - double v6 = vh_ + .6 * (vdd_ - vh_); - region_volts_ = {0.0, vl_, vth_, v1, v2, v3, v4, vh_, v5, v6, vdd_}; - break; - } - default: - report_->error(1701, "unsupported ccs region count."); - break; + case 4: + region_vth_idx_ = 2; + region_volts_ = {0.0, vl_, vth_, vh_, vdd_}; + break; + case 5: { + region_vth_idx_ = 2; + double v1 = vth_ + .7 * vth_vh; + region_volts_ = {0.0, vl_, vth_, v1, vh_, vdd_}; + break; + } + case 6: { + region_vth_idx_ = 2; + double v1 = vth_ + .3 * vth_vh; + double v2 = vth_ + .6 * vth_vh; + region_volts_ = {0.0, vl_, vth_, v1, v2, vh_, vdd_}; + break; + } + case 7: { + region_vth_idx_ = 2; + region_vh_idx_ = 5; + double v1 = vth_ + .3 * vth_vh; + double v2 = vth_ + .6 * vth_vh; + double v3 = vh_ + .5 * (vdd_ - vh_); + region_volts_ = {0.0, vl_, vth_, v1, v2, vh_, v3, vdd_}; + break; + } + case 8: { + region_vth_idx_ = 2; + region_vh_idx_ = 6; + double v1 = vth_ + .25 * vth_vh; + double v2 = vth_ + .50 * vth_vh; + double v3 = vth_ + .75 * vth_vh; + double v4 = vh_ + .5 * (vdd_ - vh_); + region_volts_ = {0.0, vl_, vth_, v1, v2, v3, vh_, v4, vdd_}; + break; + } + case 9: { + region_vth_idx_ = 2; + region_vh_idx_ = 7; + double v1 = vth_ + .2 * vth_vh; + double v2 = vth_ + .4 * vth_vh; + double v3 = vth_ + .6 * vth_vh; + double v4 = vth_ + .8 * vth_vh; + double v5 = vh_ + .5 * (vdd_ - vh_); + region_volts_ = {0.0, vl_, vth_, v1, v2, v3, v4, vh_, v5, vdd_}; + break; + } + case 10: { + region_vth_idx_ = 2; + region_vh_idx_ = 7; + double v1 = vth_ + .2 * vth_vh; + double v2 = vth_ + .4 * vth_vh; + double v3 = vth_ + .6 * vth_vh; + double v4 = vth_ + .8 * vth_vh; + double v5 = vh_ + .3 * (vdd_ - vh_); + double v6 = vh_ + .6 * (vdd_ - vh_); + region_volts_ = {0.0, vl_, vth_, v1, v2, v3, v4, vh_, v5, v6, vdd_}; + break; + } + default: + report_->error(1701, "unsupported ccs region count."); + break; } fill(region_ceff_.begin(), region_ceff_.end(), c2_ + c1_); } @@ -287,15 +281,15 @@ void CcsCeffDelayCalc::findCsmWaveform() { for (size_t i = 0; i < region_count_; i++) { - double t1 = output_waveforms_->voltageTime(in_slew_, region_ceff_[i], - region_volts_[i]); + double t1 = + output_waveforms_->voltageTime(in_slew_, region_ceff_[i], region_volts_[i]); double t2 = output_waveforms_->voltageTime(in_slew_, region_ceff_[i], region_volts_[i + 1]); region_begin_times_[i] = t1; region_end_times_[i] = t2; double time_offset = (i == 0) - ? 0.0 - : t1 - (region_end_times_[i - 1] - region_time_offsets_[i - 1]); + ? 0.0 + : t1 - (region_end_times_[i - 1] - region_time_offsets_[i - 1]); region_time_offsets_[i] = time_offset; if (i == 0) @@ -309,21 +303,18 @@ CcsCeffDelayCalc::findCsmWaveform() ArcDcalcResult CcsCeffDelayCalc::makeResult(const LibertyLibrary *drvr_library, const RiseFall *rf, - ArcDelay &gate_delay, - Slew &drvr_slew, + double &gate_delay, + double &drvr_slew, const LoadPinIndexMap &load_pin_index_map) { ArcDcalcResult dcalc_result(load_pin_index_map.size()); - debugPrint(debug_, "ccs_dcalc", 2, - "gate_delay %s drvr_slew %s", - delayAsString(gate_delay, this), - delayAsString(drvr_slew, this)); + debugPrint(debug_, "ccs_dcalc", 2, "gate_delay {} drvr_slew {}", + delayAsString(gate_delay, this), delayAsString(drvr_slew, this)); dcalc_result.setGateDelay(gate_delay); dcalc_result.setDrvrSlew(drvr_slew); for (const auto &[load_pin, load_idx] : load_pin_index_map) { - ArcDelay wire_delay; - Slew load_slew; + double wire_delay, load_slew; loadDelaySlew(load_pin, drvr_library, rf, drvr_slew, wire_delay, load_slew); dcalc_result.setWireDelay(load_idx, wire_delay); dcalc_result.setLoadSlew(load_idx, load_slew); @@ -335,23 +326,23 @@ void CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin, const LibertyLibrary *drvr_library, const RiseFall *rf, - Slew &drvr_slew, + double &drvr_slew, // Return values. - ArcDelay &wire_delay, - Slew &load_slew) + double &wire_delay, + double &load_slew) { wire_delay = 0.0; load_slew = drvr_slew; + bool elmore_exists = false; float elmore = 0.0; - if (parasitic_ - && parasitics_->isPiElmore(parasitic_)) + if (parasitic_ && parasitics_->isPiElmore(parasitic_)) parasitics_->findElmore(parasitic_, load_pin, elmore, elmore_exists); if (elmore_exists && (elmore == 0.0 // Elmore delay is small compared to driver slew. - || elmore < delayAsFloat(drvr_slew) * 1e-3)) { + || elmore < drvr_slew * 1e-3)) { wire_delay = elmore; load_slew = drvr_slew; } @@ -363,17 +354,17 @@ CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin, void CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin, - Slew &drvr_slew, + double &drvr_slew, float elmore, // Return values. - ArcDelay &delay, - Slew &slew) + double &delay, + double &slew) { for (size_t i = 0; i <= region_count_; i++) { region_ramp_times_[i] = region_times_[i]; if (i < region_count_) region_ramp_slopes_[i] = (region_volts_[i + 1] - region_volts_[i]) - / (region_times_[i + 1] - region_times_[i]); + / (region_times_[i + 1] - region_times_[i]); } vl_fail_ = false; @@ -389,10 +380,8 @@ CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin, slew = drvr_slew; fail("load delay threshold crossing"); } - debugPrint(debug_, "ccs_dcalc", 2, - "load %s delay %s slew %s", - network_->pathName(load_pin), - delayAsString(delay, this), + debugPrint(debug_, "ccs_dcalc", 2, "load {} delay {} slew {}", + network_->pathName(load_pin), delayAsString(delay, this), delayAsString(slew, this)); } @@ -457,12 +446,12 @@ CcsCeffDelayCalc::findVlTime(double v, double t_init = region_ramp_times_[0]; double t_final = region_ramp_times_[region_count_]; bool root_fail = false; - double time = findRoot([&] (double t, - double &y, - double &dy) { - vl(t, elmore, y, dy); - y -= v; - }, t_init, t_final + elmore * 3.0, .001, 20, root_fail); + double time = findRoot( + [&](double t, double &y, double &dy) { + vl(t, elmore, y, dy); + y -= v; + }, + t_init, t_final + elmore * 3.0, .001, 20, root_fail); vl_fail_ |= root_fail; return time; } @@ -487,7 +476,7 @@ PinSeq CcsCeffDelayCalc::watchPins() const { PinSeq pins; - for (const auto& [pin, values] : watch_pin_values_) + for (const auto &[pin, values] : watch_pin_values_) pins.push_back(pin); return pins; } @@ -523,8 +512,8 @@ CcsCeffDelayCalc::drvrWaveform() drvr_volts->push_back(v); } } - TableAxisPtr drvr_time_axis = std::make_shared(TableAxisVariable::time, - std::move(*drvr_times)); + TableAxisPtr drvr_time_axis = + std::make_shared(TableAxisVariable::time, std::move(*drvr_times)); delete drvr_times; Table drvr_table(drvr_volts, drvr_time_axis); return drvr_table; @@ -555,8 +544,8 @@ CcsCeffDelayCalc::loadWaveform(const Pin *load_pin) double v1 = (drvr_rf_ == RiseFall::rise()) ? v : vdd_ - v; load_volts->push_back(v1); } - TableAxisPtr load_time_axis = std::make_shared(TableAxisVariable::time, - std::move(*load_times)); + TableAxisPtr load_time_axis = std::make_shared( + TableAxisVariable::time, std::move(*load_times)); delete load_times; Table load_table(load_volts, load_time_axis); return load_table; @@ -578,10 +567,9 @@ CcsCeffDelayCalc::drvrRampWaveform(const Pin *in_pin, float elmore = 0.0; if (parasitic_) { parasitics_->findElmore(parasitic_, load_pin, elmore, elmore_exists); - bool dcalc_success = makeWaveformPreamble(in_pin, in_rf, drvr_pin, - drvr_rf, scene, min_max); - if (dcalc_success - && elmore_exists) { + bool dcalc_success = + makeWaveformPreamble(in_pin, in_rf, drvr_pin, drvr_rf, scene, min_max); + if (dcalc_success && elmore_exists) { FloatSeq *load_times = new FloatSeq; FloatSeq *load_volts = new FloatSeq; for (size_t j = 0; j <= region_count_; j++) { @@ -600,8 +588,8 @@ CcsCeffDelayCalc::drvrRampWaveform(const Pin *in_pin, double v1 = (drvr_rf == RiseFall::rise()) ? v : vdd_ - v; load_volts->push_back(v1); } - TableAxisPtr load_time_axis = std::make_shared(TableAxisVariable::time, - std::move(*load_times)); + TableAxisPtr load_time_axis = std::make_shared( + TableAxisVariable::time, std::move(*load_times)); delete load_times; Table load_table(load_volts, load_time_axis); return load_table; @@ -630,7 +618,7 @@ CcsCeffDelayCalc::makeWaveformPreamble(const Pin *in_pin, break; } if (edge) { - TimingArc *arc = nullptr; + TimingArc *arc = nullptr; for (TimingArc *arc1 : edge->timingArcSet()->arcs()) { if (arc1->fromEdge()->asRiseFall() == in_rf && arc1->toEdge()->asRiseFall() == drvr_rf) { @@ -645,9 +633,9 @@ CcsCeffDelayCalc::makeWaveformPreamble(const Pin *in_pin, if (parasitic_) { parasitics_->piModel(parasitic_, c2_, rpi_, c1_); LoadPinIndexMap load_pin_index_map = - graph_delay_calc_->makeLoadPinIndexMap(drvr_vertex); - gateDelay(drvr_pin, arc, in_slew, load_cap_, parasitic_, - load_pin_index_map, scene, min_max); + graph_delay_calc_->makeLoadPinIndexMap(drvr_vertex); + gateDelay(drvr_pin, arc, in_slew, load_cap_, parasitic_, load_pin_index_map, + scene, min_max); return true; } } @@ -671,12 +659,12 @@ CcsCeffDelayCalc::reportGateDelay(const Pin *drvr_pin, Parasitic *pi_elmore = nullptr; const RiseFall *rf = arc->toEdge()->asRiseFall(); if (parasitic && !parasitics_->isPiElmore(parasitic)) { - pi_elmore = parasitics_->reduceToPiElmore(parasitic, drvr_pin_, rf, - scene, min_max); + pi_elmore = + parasitics_->reduceToPiElmore(parasitic, drvr_pin_, rf, scene, min_max); } - std::string report = table_dcalc_->reportGateDelay(drvr_pin, arc, in_slew, load_cap, - pi_elmore, load_pin_index_map, - scene, min_max, digits); + std::string report = + table_dcalc_->reportGateDelay(drvr_pin, arc, in_slew, load_cap, pi_elmore, + load_pin_index_map, scene, min_max, digits); parasitics_->deleteDrvrReducedParasitics(drvr_pin); return report; } @@ -686,7 +674,7 @@ CcsCeffDelayCalc::fail(const char *reason) { // Report failures with a unique debug flag. if (debug_->check("ccs_dcalc", 1) || debug_->check("dcalc_error", 1)) - report_->reportLine("delay_calc: CCS failed - %s", reason); + report_->report("delay_calc: CCS failed - {}", reason); } -} // namespace +} // namespace sta diff --git a/dcalc/CcsCeffDelayCalc.hh b/dcalc/CcsCeffDelayCalc.hh index 83a72911..53a103bb 100644 --- a/dcalc/CcsCeffDelayCalc.hh +++ b/dcalc/CcsCeffDelayCalc.hh @@ -73,29 +73,29 @@ protected: void gateDelaySlew(const LibertyLibrary *drvr_library, const RiseFall *rf, // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew); + double &gate_delay, + double &drvr_slew); void initRegions(const LibertyLibrary *drvr_library, const RiseFall *rf); void findCsmWaveform(); ArcDcalcResult makeResult(const LibertyLibrary *drvr_library, const RiseFall *rf, - ArcDelay &gate_delay, - Slew &drvr_slew, + double &gate_delay, + double &drvr_slew, const LoadPinIndexMap &load_pin_index_map); void loadDelaySlew(const Pin *load_pin, const LibertyLibrary *drvr_library, const RiseFall *rf, - Slew &drvr_slew, + double &drvr_slew, // Return values. - ArcDelay &wire_delay, - Slew &load_slew); + double &wire_delay, + double &load_slew); void loadDelaySlew(const Pin *load_pin, - Slew &drvr_slew, + double &drvr_slew, float elmore, // Return values. - ArcDelay &delay, - Slew &slew); + double &delay, + double &slew); double findVlTime(double v, double elmore); bool makeWaveformPreamble(const Pin *in_pin, diff --git a/dcalc/Delay.cc b/dcalc/Delay.cc new file mode 100644 index 00000000..48c867a3 --- /dev/null +++ b/dcalc/Delay.cc @@ -0,0 +1,523 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#include "Delay.hh" + +#include + +#include "StaConfig.hh" +#include "Fuzzy.hh" +#include "Units.hh" +#include "StaState.hh" +#include "Variables.hh" + +namespace sta { + +static Delay delay_init_values[MinMax::index_count]; + +void +initDelayConstants() +{ + delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue(); + delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue(); +} + +Delay::Delay() : + values_{0.0, 0.0, 0.0, 0.0} +{ +} + +Delay::Delay(float mean) : + values_{mean, 0.0, 0.0, 0.0} +{ +} + +Delay::Delay(float mean, + float std_dev2) : + values_{mean, 0.0, std_dev2, 0.0} +{ +} + +Delay::Delay(float mean, + float mean_shift, + float std_dev2, + float skewness) : + values_{mean, mean_shift, std_dev2, skewness} +{ +} + +void +Delay::operator=(float delay) +{ + values_[0] = delay; + values_[1] = 0.0; + values_[2] = 0.0; + values_[3] = 0.0; +} + +void +Delay::setValues(float mean, + float mean_shift, + float std_dev2, + float skewnes) +{ + values_[0] = mean; + values_[1] = mean_shift; + values_[2] = std_dev2; + values_[3] = skewnes; +} + +void +Delay::setMean(float mean) +{ + values_[0] = mean; +} + +void +Delay::setMeanShift(float mean_shift) +{ + values_[1] = mean_shift; +} + +float +Delay::stdDev() const +{ + float std_dev2 = values_[2]; + if (std_dev2 < 0.0) + // std_dev is negative for crpr to offset std_dev in the common + // clock path. + return -std::sqrt(-std_dev2); + else + return std::sqrt(std_dev2); +} + +void +Delay::setStdDev(float std_dev) +{ + values_[2] = square(std_dev); +} + +void +Delay::setSkewness(float skewness) +{ + values_[3] = skewness; +} + +//////////////////////////////////////////////////////////////// + +DelayDbl::DelayDbl() : + values_{0.0, 0.0, 0.0, 0.0} +{ +} + +DelayDbl::DelayDbl(double mean) : + values_{mean, 0.0, 0.0, 0.0} +{ +} + +void +DelayDbl::setMean(double mean) +{ + values_[0] = mean; +} + +double +DelayDbl::stdDev() const +{ + float std_dev2 = values_[2]; + if (std_dev2 < 0.0) + // std_dev is negative for crpr to offset std_dev in the common + // clock path. + return -std::sqrt(-std_dev2); + else + return std::sqrt(std_dev2); +} + +void +DelayDbl::setValues(double mean, + double mean_shift, + double std_dev2, + double skewnes) +{ + values_[0] = mean; + values_[1] = mean_shift; + values_[2] = std_dev2; + values_[3] = skewnes; +} + +void +DelayDbl::operator=(double delay) +{ + values_[0] = delay; + values_[1] = 0.0; + values_[2] = 0.0; + values_[3] = 0.0; +} + +//////////////////////////////////////////////////////////////// + +Delay +makeDelay(float mean, + float mean_shift, + float std_dev, + float skewness) +{ + return Delay(mean, mean_shift, square(std_dev), skewness); +} + +Delay +makeDelay(float mean, + float std_dev) +{ + return Delay(mean, 0.0, square(std_dev), 0.0); +} + +Delay +makeDelay2(float mean, + float std_dev) +{ + return Delay(mean, 0.0, std_dev, 0.0); +} + +void +delaySetMean(Delay &delay, + float mean) +{ + delay.setMean(mean); +} + +//////////////////////////////////////////////////////////////// + +Delay +delayDblAsDelay(DelayDbl &delay) +{ + return Delay(delay.mean(), delay.meanShift(), delay.stdDev2(), delay.skewness()); +} + +std::string +delayAsString(const Delay &delay, + const StaState *sta) +{ + return delayAsString(delay, EarlyLate::late(), + sta->units()->timeUnit()->digits(), sta); +} + +std::string +delayAsString(const Delay &delay, + int digits, + const StaState *sta) +{ + return delayAsString(delay, EarlyLate::late(), digits, sta); +} + +std::string +delayAsString(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta) +{ + return delayAsString(delay, early_late, sta->units()->timeUnit()->digits(), sta); +} + +std::string +delayAsString(const Delay &delay, + const EarlyLate *early_late, + int digits, + const StaState *sta) +{ + const Unit *unit = sta->units()->timeUnit(); + float mean_std_dev = delayAsFloat(delay, early_late, sta); + return unit->asString(mean_std_dev, digits); +} + +std::string +delayAsString(const Delay &delay, + const EarlyLate *early_late, + bool report_variance, + int digits, + const StaState *sta) +{ + if (report_variance) + return sta->delayOps()->asStringVariance(delay, digits, sta); + else + return delayAsString(delay, early_late, digits, sta); +} + +float +delayAsFloat(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta) +{ + return sta->delayOps()->asFloat(delay, early_late, sta); +} + +float +delayAsFloat(const DelayDbl &delay, + const EarlyLate *early_late, + const StaState *sta) +{ + return sta->delayOps()->asFloat(delay, early_late, sta); +} + +float +delayAsFloat(const Delay &delay) +{ + return delay.mean(); +} + +const Delay & +delayInitValue(const MinMax *min_max) +{ + return delay_init_values[min_max->index()]; +} + +bool +delayIsInitValue(const Delay &delay, + const MinMax *min_max) +{ + return fuzzyEqual(delay.mean(), min_max->initValue()); +} + +bool +delayZero(const Delay &delay, + const StaState *sta) +{ + return sta->delayOps()->isZero(delay); +} + +bool +delayInf(const Delay &delay, + const StaState *sta) +{ + return sta->delayOps()->isInf(delay); +} + +bool +delayEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return sta->delayOps()->equal(delay1, delay2, sta); +} + +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return sta->delayOps()->less(delay1, delay2, sta); +} + +bool +delayLess(const DelayDbl &delay1, + const DelayDbl &delay2, + const StaState *sta) +{ + return sta->delayOps()->less(delay1, delay2, sta); +} + +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) +{ + if (min_max == MinMax::max()) + return sta->delayOps()->less(delay1, delay2, sta); + else + return sta->delayOps()->greater(delay1, delay2, sta); +} + +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return sta->delayOps()->lessEqual(delay1, delay2, sta); +} + +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) +{ + if (min_max == MinMax::max()) + return sta->delayOps()->lessEqual(delay1, delay2, sta); + else + return sta->delayOps()->greaterEqual(delay1, delay2, sta); +} + +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return sta->delayOps()->greater(delay1, delay2, sta); +} + +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) +{ + if (min_max == MinMax::max()) + return sta->delayOps()->greater(delay1, delay2, sta); + else + return sta->delayOps()->less(delay1, delay2, sta); +} + +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return sta->delayOps()->greaterEqual(delay1, delay2, sta); +} + +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) +{ + if (min_max == MinMax::max()) + return sta->delayOps()->greaterEqual(delay1, delay2, sta); + else + return sta->delayOps()->lessEqual(delay1, delay2, sta); +} + +Delay +delayRemove(const Delay &delay1, + const Delay &delay2) +{ + return makeDelay2(delay1.mean() - delay2.mean(), + delay1.stdDev2() - delay2.stdDev2()); +} + +Delay +delaySum(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return sta->delayOps()->sum(delay1, delay2); +} + +Delay +delaySum(const Delay &delay1, + float delay2, + const StaState *sta) +{ + return sta->delayOps()->sum(delay1, delay2); +} + +Delay +delayDiff(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return sta->delayOps()->diff(delay1, delay2); +} + +Delay +delayDiff(const Delay &delay1, + float delay2, + const StaState *sta) +{ + return sta->delayOps()->diff(delay1, delay2); +} + +Delay +delayDiff(float delay1, + const Delay &delay2, + const StaState *sta) +{ + return sta->delayOps()->diff(delay1, delay2); +} + +void +delayIncr(Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + sta->delayOps()->incr(delay1, delay2); +} + +void +delayIncr(DelayDbl &delay1, + const Delay &delay2, + const StaState *sta) +{ + sta->delayOps()->incr(delay1, delay2); +} + +void +delayIncr(Delay &delay1, + float delay2, + const StaState *sta) +{ + sta->delayOps()->incr(delay1, delay2); +} + +void +delayDecr(Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + sta->delayOps()->decr(delay1, delay2); +} + +void +delayDecr(DelayDbl &delay1, + const Delay &delay2, + const StaState *sta) +{ + sta->delayOps()->decr(delay1, delay2); +} + +Delay +delayProduct(const Delay &delay1, + float delay2, + const StaState *sta) +{ + return sta->delayOps()->product(delay1, delay2); +} + +Delay +delayDiv(float delay1, + const Delay &delay2, + const StaState *sta) +{ + return sta->delayOps()->div(delay1, delay2); +} + +float +delayStdDev2(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta) +{ + return sta->delayOps()->stdDev2(delay, early_late); +} + +} // namespace diff --git a/dcalc/DelayCalc.tcl b/dcalc/DelayCalc.tcl index 967039aa..3658c219 100644 --- a/dcalc/DelayCalc.tcl +++ b/dcalc/DelayCalc.tcl @@ -131,12 +131,10 @@ proc set_delay_calculator { alg } { if { [is_delay_calc_name $alg] } { set_delay_calculator_cmd $alg } else { - sta_error 195 "delay calculator $alg not found." + sta_error 2500 "delay calculator $alg not found." } } -define_cmd_args "set_pocv_sigma_factor" { factor } - ################################################################ define_cmd_args "set_assigned_delay" \ @@ -156,38 +154,38 @@ proc set_assigned_delay { args } { if [info exists keys(-from)] { set from_pins [get_port_pins_error "from_pins" $keys(-from)] } else { - sta_error 196 "set_assigned_delay missing -from argument." + sta_error 2501 "set_assigned_delay missing -from argument." } if [info exists keys(-to)] { set to_pins [get_port_pins_error "to_pins" $keys(-to)] } else { - sta_error 182 "set_assigned_delay missing -to argument." + sta_error 2502 "set_assigned_delay missing -to argument." } set delay [lindex $args 0] if {![string is double $delay]} { - sta_error 183 "set_assigned_delay delay is not a float." + sta_error 2503 "set_assigned_delay delay is not a float." } set delay [time_ui_sta $delay] if {[info exists flags(-cell)] && [info exists flags(-net)]} { - sta_error 184 "set_annotated_delay -cell and -net options are mutually excluive." + sta_error 2504 "set_annotated_delay -cell and -net options are mutually excluive." } elseif {[info exists flags(-cell)]} { if { $from_pins != {} } { set inst [[lindex $from_pins 0] instance] foreach pin $from_pins { if {[$pin instance] != $inst} { - sta_error 185 "set_assigned_delay pin [get_full_name $pin] is not attached to instance [get_full_name $inst]." + sta_error 2505 "set_assigned_delay pin [get_full_name $pin] is not attached to instance [get_full_name $inst]." } } foreach pin $to_pins { if {[$pin instance] != $inst} { - sta_error 186 "set_assigned_delay pin [get_full_name $pin] is not attached to instance [get_full_name $inst]" + sta_error 2506 "set_assigned_delay pin [get_full_name $pin] is not attached to instance [get_full_name $inst]" } } } } elseif {![info exists flags(-net)]} { - sta_error 187 "set_assigned_delay -cell or -net required." + sta_error 2508 "set_assigned_delay -cell or -net required." } foreach from_pin $from_pins { set from_vertices [$from_pin vertices] @@ -231,7 +229,7 @@ proc set_assigned_delay2 {from_vertex to_vertex to_rf scene min_max delay} { } $edge_iter finish if { !$matched } { - sta_error 193 "set_assigned_delay no timing arcs found between from/to pins." + sta_error 2509 "set_assigned_delay no timing arcs found between from/to pins." } } @@ -252,7 +250,7 @@ proc set_assigned_check { args } { if { [info exists keys(-from)] } { set from_pins [get_port_pins_error "from_pins" $keys(-from)] } else { - sta_error 188 "set_assigned_check missing -from argument." + sta_error 2510 "set_assigned_check missing -from argument." } set from_rf "rise_fall" if { [info exists keys(-clock)] } { @@ -261,14 +259,14 @@ proc set_assigned_check { args } { || $clk_arg eq "fall" } { set from_rf $clk_arg } else { - sta_error 189 "set_assigned_check -clock must be rise or fall." + sta_error 2511 "set_assigned_check -clock must be rise or fall." } } if { [info exists keys(-to)] } { set to_pins [get_port_pins_error "to_pins" $keys(-to)] } else { - sta_error 190 "set_assigned_check missing -to argument." + sta_error 2512 "set_assigned_check missing -to argument." } set to_rf [parse_rise_fall_flags flags] set scene [parse_scene keys] @@ -283,7 +281,7 @@ proc set_assigned_check { args } { } elseif { [info exists flags(-removal)] } { set role "removal" } else { - sta_error 191 "set_assigned_check missing -setup|-hold|-recovery|-removal check type.." + sta_error 2513 "set_assigned_check missing -setup|-hold|-recovery|-removal check type.." } set cond "" if { [info exists key(-cond)] } { @@ -291,7 +289,7 @@ proc set_assigned_check { args } { } set check_value [lindex $args 0] if { ![string is double $check_value] } { - sta_error 192 "set_assigned_check check_value is not a float." + sta_error 2514 "set_assigned_check check_value is not a float." } set check_value [time_ui_sta $check_value] @@ -343,7 +341,7 @@ proc set_assigned_check2 { from_vertex from_rf to_vertex to_rf \ } $edge_iter finish if { !$matched } { - sta_error 194 "set_assigned_check no check arcs found between from/to pins." + sta_error 2516 "set_assigned_check no check arcs found between from/to pins." } } @@ -364,7 +362,7 @@ proc set_assigned_transition { args } { set slew [lindex $args 0] if {![string is double $slew]} { - sta_error 210 "set_assigned_transition transition is not a float." + sta_error 2518 "set_assigned_transition transition is not a float." } set slew [time_ui_sta $slew] set pins [get_port_pins_error "pins" [lindex $args 1]] @@ -382,22 +380,31 @@ proc set_assigned_transition { args } { ################################################################ -define_cmd_args "report_slews" {[-scenes scenes] pin} +define_cmd_args "report_slews" {[-scenes scenes] [-digits digits]\ + [-report_variance] pin} proc report_slews { args } { global sta_report_default_digits - parse_key_args "report_slews" args keys {-corner -scenes} flags {} + parse_key_args "report_slews" args keys {-corner -scenes -digits} \ + flags {-report_variance} check_argc_eq1 "report_slews" $args set scenes [parse_scenes_or_all keys] set pin [get_port_pin_error "pin" [lindex $args 0]] - set digits $sta_report_default_digits + if [info exists keys(-digits)] { + set digits $keys(-digits) + check_positive_integer "-digits" $digits + } else { + set digits $sta_report_default_digits + } + set report_variance [info exists flags(-report_variance)] + foreach vertex [$pin vertices] { - set rise_min [format_time [$vertex slew_scenes rise $scenes min] $digits] - set rise_max [format_time [$vertex slew_scenes rise $scenes max] $digits] - set fall_min [format_time [$vertex slew_scenes fall $scenes min] $digits] - set fall_max [format_time [$vertex slew_scenes fall $scenes max] $digits] + set rise_min [$vertex slew_scenes_string rise $scenes min $report_variance $digits] + set rise_max [$vertex slew_scenes_string rise $scenes max $report_variance $digits] + set fall_min [$vertex slew_scenes_string fall $scenes min $report_variance $digits] + set fall_max [$vertex slew_scenes_string fall $scenes max $report_variance $digits] report_line "[vertex_path_name $vertex] [rise_short_name] $rise_min:$rise_max [fall_short_name] $fall_min:$fall_max" } } diff --git a/dcalc/DelayCalcBase.cc b/dcalc/DelayCalcBase.cc index bc5b77e0..f153e44c 100644 --- a/dcalc/DelayCalcBase.cc +++ b/dcalc/DelayCalcBase.cc @@ -81,10 +81,10 @@ DelayCalcBase::finishDrvrPin() void DelayCalcBase::dspfWireDelaySlew(const Pin *load_pin, const RiseFall *rf, - Slew drvr_slew, + double drvr_slew, float elmore, - ArcDelay &wire_delay, - Slew &load_slew) + double &wire_delay, + double &load_slew) { LibertyLibrary *load_library = thresholdLibrary(load_pin); @@ -107,8 +107,8 @@ void DelayCalcBase::thresholdAdjust(const Pin *load_pin, const LibertyLibrary *drvr_library, const RiseFall *rf, - ArcDelay &load_delay, - Slew &load_slew) + double &wire_delay, + double &load_slew) { LibertyLibrary *load_library = thresholdLibrary(load_pin); if (load_library @@ -118,11 +118,12 @@ DelayCalcBase::thresholdAdjust(const Pin *load_pin, float load_vth = load_library->inputThreshold(rf); float drvr_slew_delta = drvr_library->slewUpperThreshold(rf) - drvr_library->slewLowerThreshold(rf); - float load_delay_delta = + float wire_delay_delta = delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta); - load_delay += (rf == RiseFall::rise()) - ? load_delay_delta - : -load_delay_delta; + wire_delay += (rf == RiseFall::rise()) + ? wire_delay_delta + : -wire_delay_delta; + float load_slew_delta = load_library->slewUpperThreshold(rf) - load_library->slewLowerThreshold(rf); float drvr_slew_derate = drvr_library->slewDerateFromLibrary(); @@ -162,9 +163,8 @@ DelayCalcBase::checkDelay(const Pin *check_pin, float from_slew1 = delayAsFloat(from_slew); float to_slew1 = delayAsFloat(to_slew); return model->checkDelay(pinPvt(check_pin, scene, min_max), - from_slew1, to_slew1, - related_out_cap, - variables_->pocvEnabled()); + from_slew1, to_slew1, related_out_cap, + min_max, variables_->pocvMode()); } else return delay_zero; @@ -187,8 +187,8 @@ DelayCalcBase::reportCheckDelay(const Pin *check_pin, float to_slew1 = delayAsFloat(to_slew); return model->reportCheckDelay(pinPvt(check_pin, scene, min_max), from_slew1, from_slew_annotation, - to_slew1, related_out_cap, false, - digits); + to_slew1, related_out_cap, min_max, + PocvMode::scalar, digits); } return ""; } diff --git a/dcalc/DelayCalcBase.hh b/dcalc/DelayCalcBase.hh index 6d641c7e..faaa4358 100644 --- a/dcalc/DelayCalcBase.hh +++ b/dcalc/DelayCalcBase.hh @@ -72,16 +72,16 @@ protected: void thresholdAdjust(const Pin *load_pin, const LibertyLibrary *drvr_library, const RiseFall *rf, - ArcDelay &load_delay, - Slew &load_slew); + double &load_delay, + double &load_slew); // Helper function for input ports driving dspf parasitic. void dspfWireDelaySlew(const Pin *load_pin, const RiseFall *rf, - Slew drvr_slew, + double drvr_slew, float elmore, // Return values. - ArcDelay &wire_delay, - Slew &load_slew); + double &wire_delay, + double &load_slew); const Pvt *pinPvt(const Pin *pin, const Scene *scene, const MinMax *min_max); diff --git a/dcalc/DelayNormal.cc b/dcalc/DelayNormal.cc new file mode 100644 index 00000000..2c3cb059 --- /dev/null +++ b/dcalc/DelayNormal.cc @@ -0,0 +1,232 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#include "DelayNormal.hh" + +#include // sqrt + +#include "Error.hh" +#include "Fuzzy.hh" +#include "Units.hh" +#include "Format.hh" +#include "StaState.hh" +#include "Variables.hh" + +namespace sta { + +float +DelayOpsNormal::stdDev2(const Delay &delay, + const EarlyLate *) const +{ + return delay.stdDev2(); +} + +float +DelayOpsNormal::asFloat(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta) const +{ + float quantile = sta->variables()->pocvQuantile(); + if (early_late == EarlyLate::early()) + return delay.mean() - delay.stdDev() * quantile; + else // (early_late == EarlyLate::late()) + return delay.mean() + delay.stdDev() * quantile; +} + +double +DelayOpsNormal::asFloat(const DelayDbl &delay, + const EarlyLate *early_late, + const StaState *sta) const +{ + double quantile = sta->variables()->pocvQuantile(); + if (early_late == EarlyLate::early()) + return delay.mean() - delay.stdDev() * quantile; + else // (early_late == EarlyLate::late()) + return delay.mean() + delay.stdDev() * quantile; +} + +bool +DelayOpsNormal::isZero(const Delay &delay) const +{ + return fuzzyZero(delay.mean()) + && fuzzyZero(delay.stdDev2()); +} + +bool +DelayOpsNormal::isInf(const Delay &delay) const +{ + return fuzzyInf(delay.mean()); +} + +bool +DelayOpsNormal::equal(const Delay &delay1, + const Delay &delay2, + const StaState *) const +{ + return fuzzyEqual(delay1.mean(), delay2.mean()) + && fuzzyEqual(delay1.stdDev2(), delay2.stdDev2()); +} + +bool +DelayOpsNormal::less(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const +{ + return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), + delayAsFloat(delay2, EarlyLate::early(), sta)); +} + +bool +DelayOpsNormal::less(const DelayDbl &delay1, + const DelayDbl &delay2, + const StaState *sta) const +{ + return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), + delayAsFloat(delay2, EarlyLate::early(), sta)); +} + +bool +DelayOpsNormal::lessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const +{ + return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta), + delayAsFloat(delay2, EarlyLate::early(), sta)); +} + +bool +DelayOpsNormal::greater(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const +{ + return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta), + delayAsFloat(delay2, EarlyLate::late(), sta)); +} + +bool +DelayOpsNormal::greaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const +{ + return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), + delayAsFloat(delay2, EarlyLate::late(), sta)); +} + +Delay +DelayOpsNormal::sum(const Delay &delay1, + const Delay &delay2) const +{ + return Delay(delay1.mean() + delay2.mean(), + delay1.stdDev2() + delay2.stdDev2()); +} + +Delay +DelayOpsNormal::sum(const Delay &delay1, + float delay2) const +{ + return Delay(delay1.mean() + delay2, + delay1.stdDev2()); +} + +Delay +DelayOpsNormal::diff(const Delay &delay1, + const Delay &delay2) const +{ + return Delay(delay1.mean() - delay2.mean(), + delay1.stdDev2() + delay2.stdDev2()); +} + +Delay +DelayOpsNormal::diff(const Delay &delay1, + float delay2) const +{ + return Delay(delay1.mean() - delay2, + delay1.stdDev2()); +} + +Delay +DelayOpsNormal::diff(float delay1, + const Delay &delay2) const +{ + return Delay(delay1 - delay2.mean(), + delay2.stdDev2()); +} + +void +DelayOpsNormal::incr(Delay &delay1, + const Delay &delay2) const +{ + delay1.setValues(delay1.mean() + delay2.mean(), 0.0, + delay1.stdDev2() + delay2.stdDev2(), 0.0); +} + +void +DelayOpsNormal::incr(DelayDbl &delay1, + const Delay &delay2) const +{ + delay1.setValues(delay1.mean() + delay2.mean(), 0.0, + delay1.stdDev2() + delay2.stdDev2(), 0.0); +} + +void +DelayOpsNormal::decr(Delay &delay1, + const Delay &delay2) const +{ + delay1.setMean(delay1.mean() - delay2.mean()); +} + +void +DelayOpsNormal::decr(DelayDbl &delay1, + const Delay &delay2) const +{ + delay1.setMean(delay1.mean() - delay2.mean()); +} + +Delay +DelayOpsNormal::product(const Delay &delay1, + float delay2) const +{ + return Delay(delay1.mean() * delay2, + delay1.stdDev2() * square(delay2)); +} + +Delay +DelayOpsNormal::div(float delay1, + const Delay &delay2) const +{ + return Delay(delay1 / delay2.mean()); +} + +std::string +DelayOpsNormal::asStringVariance(const Delay &delay, + int digits, + const StaState *sta) const +{ + const Unit *unit = sta->units()->timeUnit(); + return sta::format("{}[{}]", + unit->asString(delay.mean(), digits), + unit->asString(delay.stdDev(), digits)); +} + +} // namespace diff --git a/dcalc/DelayScalar.cc b/dcalc/DelayScalar.cc new file mode 100644 index 00000000..6ad49178 --- /dev/null +++ b/dcalc/DelayScalar.cc @@ -0,0 +1,206 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +// Delay as floats, non-SSTA. + +#include "DelayScalar.hh" + +#include "Fuzzy.hh" +#include "Units.hh" +#include "StaState.hh" + +namespace sta { + +float +DelayOpsScalar::stdDev2(const Delay &, + const EarlyLate *) const +{ + return 0.0; +} + +float +DelayOpsScalar::asFloat(const Delay &delay, + const EarlyLate *, + const StaState *) const +{ + return delay.mean(); +} + +double +DelayOpsScalar::asFloat(const DelayDbl &delay, + const EarlyLate *, + const StaState *) const +{ + return delay.mean(); +} + +bool +DelayOpsScalar::isZero(const Delay &delay) const +{ + return fuzzyZero(delay.mean()); +} + +bool +DelayOpsScalar::isInf(const Delay &delay) const +{ + return fuzzyInf(delay.mean()); +} + +bool +DelayOpsScalar::equal(const Delay &delay1, + const Delay &delay2, + const StaState *) const +{ + return fuzzyEqual(delay1.mean(), delay2.mean()); +} + +bool +DelayOpsScalar::less(const Delay &delay1, + const Delay &delay2, + const StaState *) const +{ + return fuzzyLess(delay1.mean(), delay2.mean()); +} + +bool +DelayOpsScalar::less(const DelayDbl &delay1, + const DelayDbl &delay2, + const StaState *) const +{ + return fuzzyLess(delay1.mean(), delay2.mean()); +} + +bool +DelayOpsScalar::lessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *) const +{ + return fuzzyLessEqual(delay1.mean(), delay2.mean()); +} + +bool +DelayOpsScalar::greater(const Delay &delay1, + const Delay &delay2, + const StaState *) const +{ + return fuzzyGreater(delay1.mean(), delay2.mean()); +} + +bool +DelayOpsScalar::greaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *) const +{ + return fuzzyGreaterEqual(delay1.mean(), delay2.mean()); +} + +Delay +DelayOpsScalar::sum(const Delay &delay1, + const Delay &delay2) const +{ + return Delay(delay1.mean() + delay2.mean()); +} + +Delay +DelayOpsScalar::sum(const Delay &delay1, + float delay2) const +{ + return Delay(delay1.mean() + delay2); +} + +Delay +DelayOpsScalar::diff(const Delay &delay1, + const Delay &delay2) const +{ + return Delay(delay1.mean() - delay2.mean()); +} + +Delay +DelayOpsScalar::diff(const Delay &delay1, + float delay2) const +{ + return Delay(delay1.mean() - delay2); +} + +Delay +DelayOpsScalar::diff(float delay1, + const Delay &delay2) const +{ + return Delay(delay1 - delay2.mean()); +} + + +void +DelayOpsScalar::incr(Delay &delay1, + const Delay &delay2) const +{ + delay1.setMean(delay1.mean() + delay2.mean()); +} + +void +DelayOpsScalar::incr(DelayDbl &delay1, + const Delay &delay2) const +{ + delay1.setMean(delay1.mean() + delay2.mean()); +} + +void +DelayOpsScalar::decr(Delay &delay1, + const Delay &delay2) const +{ + delay1.setMean(delay1.mean() - delay2.mean()); +} + +void +DelayOpsScalar::decr(DelayDbl &delay1, + const Delay &delay2) const +{ + delay1.setMean(delay1.mean() - delay2.mean()); +} + +Delay +DelayOpsScalar::product(const Delay &delay1, + float delay2) const +{ + return Delay(delay1.mean() * delay2); +} + +Delay +DelayOpsScalar::div(float delay1, + const Delay &delay2) const +{ + return Delay(delay1 / delay2.mean()); +} + +std::string +DelayOpsScalar::asStringVariance(const Delay &delay, + int digits, + const StaState *sta) const +{ + const Unit *unit = sta->units()->timeUnit(); + return unit->asString(delay.mean(), digits); +} + +} // namespace + diff --git a/dcalc/DelaySkewNormal.cc b/dcalc/DelaySkewNormal.cc new file mode 100644 index 00000000..306634ba --- /dev/null +++ b/dcalc/DelaySkewNormal.cc @@ -0,0 +1,293 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#include "DelaySkewNormal.hh" + +#include // sqrt + +#include "Error.hh" +#include "Fuzzy.hh" +#include "Units.hh" +#include "Format.hh" +#include "StaState.hh" +#include "Variables.hh" + +namespace sta { + +float +DelayOpsSkewNormal::stdDev2(const Delay &delay, + const EarlyLate *) const +{ + return delay.stdDev2(); +} + +float +DelayOpsSkewNormal::asFloat(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta) const +{ + // LVF: mean + mean_shift + sigma * sigma_factor with skewness consideration. + float quantile = sta->variables()->pocvQuantile(); + if (early_late == EarlyLate::early()) + return delay.mean() + delay.meanShift() + - delay.stdDev() * (quantile + delay.skewness() * (square(quantile)-1.0) / 6.0); + else // (early_late == EarlyLate::late()) + return delay.mean() + delay.meanShift() + + delay.stdDev() * (quantile + delay.skewness() * (square(quantile)-1.0) / 6.0); +} + +double +DelayOpsSkewNormal::asFloat(const DelayDbl &delay, + const EarlyLate *early_late, + const StaState *sta) const +{ + // LVF: mean + mean_shift + sigma * sigma_factor with skewness consideration. + double quantile = sta->variables()->pocvQuantile(); + if (early_late == EarlyLate::early()) + return delay.mean() + delay.meanShift() + - delay.stdDev() * (quantile + delay.skewness() * (square(quantile)-1.0) / 6.0); + else // (early_late == EarlyLate::late()) + return delay.mean() + delay.meanShift() + + delay.stdDev() * (quantile + delay.skewness() * (square(quantile)-1.0) / 6.0); +} + +bool +DelayOpsSkewNormal::isZero(const Delay &delay) const +{ + return fuzzyZero(delay.mean()) + && fuzzyZero(delay.meanShift()) + && fuzzyZero(delay.stdDev2()) + && fuzzyZero(delay.skewness()); +} + +bool +DelayOpsSkewNormal::isInf(const Delay &delay) const +{ + return fuzzyInf(delay.mean()); +} + +bool +DelayOpsSkewNormal::equal(const Delay &delay1, + const Delay &delay2, + const StaState *) const +{ + return fuzzyEqual(delay1.mean(), delay2.mean()) + && fuzzyEqual(delay1.meanShift(), delay2.meanShift()) + && fuzzyEqual(delay1.stdDev2(), delay2.stdDev2()) + && fuzzyEqual(delay1.skewness(), delay2.skewness()); +} + +bool +DelayOpsSkewNormal::less(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const +{ + return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), + delayAsFloat(delay2, EarlyLate::early(), sta)); +} + +bool +DelayOpsSkewNormal::less(const DelayDbl &delay1, + const DelayDbl &delay2, + const StaState *sta) const +{ + return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), + delayAsFloat(delay2, EarlyLate::early(), sta)); +} + +bool +DelayOpsSkewNormal::lessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const +{ + return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta), + delayAsFloat(delay2, EarlyLate::early(), sta)); +} + +bool +DelayOpsSkewNormal::greater(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const +{ + return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta), + delayAsFloat(delay2, EarlyLate::late(), sta)); +} + +bool +DelayOpsSkewNormal::greaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const +{ + return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), + delayAsFloat(delay2, EarlyLate::late(), sta)); +} + +Delay +DelayOpsSkewNormal::sum(const Delay &delay1, + const Delay &delay2) const +{ + return Delay(delay1.mean() + delay2.mean(), + delay1.meanShift() + delay2.meanShift(), + delay1.stdDev2() + delay2.stdDev2(), + skewnessSum(delay1, delay2)); +} + +float +DelayOpsSkewNormal::skewnessSum(const Delay &delay1, + const Delay &delay2) const +{ + return skewnessSum(delay1.stdDev(), delay1.skewness(), + delay2.stdDev(), delay2.skewness()); +} + +// Helper function to compute combined skewness from std dev and skewness values. +double +DelayOpsSkewNormal::skewnessSum(double std_dev1, + double skewness1, + double std_dev2, + double skewness2) const +{ + double std_dev_sum = square(std_dev1) + square(std_dev2); + if (std_dev_sum == 0.0) + return 0.0; + else { + // Un-normalize the skews so they are third moments so they can be added. + double skew = (skewness1 * cube(std_dev1) + skewness2 * cube(std_dev2)) + // std_dev_sum^(3/2) + / (std_dev_sum * std::sqrt(std_dev_sum)); + return skew; + } +} + +Delay +DelayOpsSkewNormal::sum(const Delay &delay1, + float delay2) const +{ + return Delay(delay1.mean() + delay2, + delay1.meanShift(), + delay1.stdDev2(), + delay1.skewness()); +} + +Delay +DelayOpsSkewNormal::diff(const Delay &delay1, + const Delay &delay2) const +{ + return Delay(delay1.mean() - delay2.mean(), + delay1.meanShift() - delay2.meanShift(), + delay1.stdDev2() + delay2.stdDev2(), + skewnessSum(delay1, delay2)); +} + +Delay +DelayOpsSkewNormal::diff(const Delay &delay1, + float delay2) const +{ + return Delay(delay1.mean() - delay2, + delay1.meanShift(), + delay1.stdDev2(), + delay1.skewness()); +} + +Delay +DelayOpsSkewNormal::diff(float delay1, + const Delay &delay2) const +{ + return Delay(delay1 - delay2.mean(), + delay2.meanShift(), + delay2.stdDev2(), + delay2.skewness()); +} + +void +DelayOpsSkewNormal::incr(Delay &delay1, + const Delay &delay2) const +{ + delay1.setValues(delay1.mean() + delay2.mean(), + delay1.meanShift() + delay2.meanShift(), + delay1.stdDev2() + delay2.stdDev2(), + skewnessSum(delay1, delay2)); +} + +void +DelayOpsSkewNormal::incr(DelayDbl &delay1, + const Delay &delay2) const +{ + delay1.setValues(delay1.mean() + delay2.mean(), + delay1.meanShift() + delay2.meanShift(), + delay1.stdDev2() + delay2.stdDev2(), + skewnessSum(delay1.stdDev(), delay1.skewness())); +} + +void +DelayOpsSkewNormal::decr(Delay &delay1, + const Delay &delay2) const +{ + delay1.setValues(delay1.mean() - delay2.mean(), + delay1.meanShift() + delay2.meanShift(), + delay1.stdDev2() + delay2.stdDev2(), + skewnessSum(delay1, delay2)); +} + +void +DelayOpsSkewNormal::decr(DelayDbl &delay1, + const Delay &delay2) const +{ + delay1.setValues(delay1.mean() - delay2.mean(), + delay1.meanShift() + delay2.meanShift(), + delay1.stdDev2() + delay2.stdDev2(), + skewnessSum(delay1.stdDev(), delay1.skewness())); +} + +Delay +DelayOpsSkewNormal::product(const Delay &delay1, + float delay2) const +{ + return Delay(delay1.mean() * delay2, + delay1.meanShift() * delay2, + delay1.stdDev2() * square(delay2), + delay1.skewness() * cube(delay2)); +} + +Delay +DelayOpsSkewNormal::div(float delay1, + const Delay &delay2) const +{ + return Delay(delay1 / delay2.mean()); +} + +std::string +DelayOpsSkewNormal::asStringVariance(const Delay &delay, + int digits, + const StaState *sta) const +{ + const Unit *unit = sta->units()->timeUnit(); + return sta::format("{}[{},{},{}]", + unit->asString(delay.mean(), digits), + unit->asString(delay.meanShift(), digits), + unit->asString(delay.stdDev(), digits), + sta->units()->scalarUnit()->asString(delay.skewness(), digits)); +} + +} // namespace diff --git a/dcalc/DmpCeff.cc b/dcalc/DmpCeff.cc index 4619bc97..38c04648 100644 --- a/dcalc/DmpCeff.cc +++ b/dcalc/DmpCeff.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. // "Performance Computation for Precharacterized CMOS Gates with RC Loads", @@ -36,6 +36,7 @@ #include #include +#include "Format.hh" #include "Report.hh" #include "Debug.hh" #include "Units.hh" @@ -90,15 +91,14 @@ gateModelRd(const LibertyCell *cell, double in_slew, double c2, double c1, - const Pvt *pvt, - bool pocv_enabled); + const Pvt *pvt); static void newtonRaphson(const int max_iter, double x[], const int n, const double x_tol, // eval(state) is called to fill fvec and fjac. - std::function eval, + std::function eval, // Temporaries supplied by caller. double *fvec, double **fjac, @@ -123,7 +123,8 @@ luDecomp(double **a, class DmpAlg : public StaState { public: - DmpAlg(int nr_order, StaState *sta); + DmpAlg(int nr_order, + StaState *sta); ~DmpAlg() override = default; virtual const char *name() = 0; // Set driver model and pi model parameters for delay calculation. @@ -137,14 +138,14 @@ public: double c2, double rpi, double c1); - virtual void gateDelaySlew(// Return values. - double &delay, - double &slew) = 0; + virtual void gateDelaySlew( // Return values. + double &delay, + double &slew) = 0; virtual void loadDelaySlew(const Pin *load_pin, double elmore, // Return values. - ArcDelay &delay, - Slew &slew); + double &delay, + double &slew); double ceff() { return ceff_; } // Given x_ as a vector of input parameters, fill fvec_ with the @@ -189,9 +190,9 @@ protected: void showX(); void showFvec(); void showJacobian(); - void findDriverDelaySlew(// Return values. - double &delay, - double &slew); + void findDriverDelaySlew( // Return values. + double &delay, + double &slew); double findVoCrossing(double vth, double lower_bound, double upper_bound); @@ -261,7 +262,7 @@ protected: double fjac_storage_[max_nr_order_ * max_nr_order_]; double *fjac_[max_nr_order_]; double scale_[max_nr_order_]; - double p_[max_nr_order_ ]; + double p_[max_nr_order_]; int index_[max_nr_order_]; // Driver slew used to check load delay. @@ -275,7 +276,7 @@ protected: }; DmpAlg::DmpAlg(int nr_order, - StaState *sta): + StaState *sta) : StaState(sta), c2_(0.0), rpi_(0.0), @@ -329,14 +330,13 @@ DmpAlg::findDriverParams(double ceff) double t0 = t_vth + std::log(1.0 - vth_) * rd_ * ceff - vth_ * dt; x_[DmpParam::dt] = dt; x_[DmpParam::t0] = t0; - newtonRaphson(100, x_, nr_order_, driver_param_tol, - [this] () { evalDmpEqns(); }, - fvec_, fjac_, index_, p_, scale_); + newtonRaphson( + 100, x_, nr_order_, driver_param_tol, [this]() { evalDmpEqns(); }, fvec_, + fjac_, index_, p_, scale_); t0_ = x_[DmpParam::t0]; dt_ = x_[DmpParam::dt]; - debugPrint(debug_, "dmp_ceff", 3, " t0 = %s dt = %s ceff = %s", - units_->timeUnit()->asString(t0_), - units_->timeUnit()->asString(dt_), + debugPrint(debug_, "dmp_ceff", 3, " t0 = {} dt = {} ceff = {}", + units_->timeUnit()->asString(t0_), units_->timeUnit()->asString(dt_), units_->capacitanceUnit()->asString(x_[DmpParam::ceff])); if (debug_->check("dmp_ceff", 4)) showVo(); @@ -348,13 +348,10 @@ DmpAlg::gateCapDelaySlew(double ceff, double &delay, double &slew) { - ArcDelay model_delay; - Slew model_slew; - gate_model_->gateDelay(pvt_, in_slew_, ceff, - variables_->pocvEnabled(), - model_delay, model_slew); - delay = delayAsFloat(model_delay); - slew = delayAsFloat(model_slew); + float model_delay, model_slew; + gate_model_->gateDelay(pvt_, in_slew_, ceff, model_delay, model_slew); + delay = model_delay; + slew = model_slew; } void @@ -413,8 +410,7 @@ DmpAlg::dy(double t, } else { dydt0 = -(y0dt(t1, cl) - y0dt(t1 - dt, cl)) / dt; - dyddt = -(y0(t1, cl) + y0(t1 - dt, cl)) / (dt * dt) - + y0dt(t1 - dt, cl) / dt; + dyddt = -(y0(t1, cl) + y0(t1 - dt, cl)) / (dt * dt) + y0dt(t1 - dt, cl) / dt; dydcl = (y0dcl(t1, cl) - y0dcl(t1 - dt, cl)) / dt; } } @@ -437,14 +433,14 @@ void DmpAlg::showX() { for (int i = 0; i < nr_order_; i++) - report_->reportLine("%4s %12.3e", dmp_param_index_strings[i], x_[i]); + report_->report("{:4} {:12.3e}", dmp_param_index_strings[i], x_[i]); } void DmpAlg::showFvec() { for (int i = 0; i < nr_order_; i++) - report_->reportLine("%4s %12.3e", dmp_func_index_strings[i], fvec_[i]); + report_->report("{:4} {:12.3e}", dmp_func_index_strings[i], fvec_[i]); } void @@ -452,21 +448,21 @@ DmpAlg::showJacobian() { std::string line = " "; for (int j = 0; j < nr_order_; j++) - line += stdstrPrint("%12s", dmp_param_index_strings[j]); - report_->reportLineString(line); + line += sta::format("{:12}", dmp_param_index_strings[j]); + report_->reportLine(line); line.clear(); for (int i = 0; i < nr_order_; i++) { - line += stdstrPrint("%4s ", dmp_func_index_strings[i]); + line += sta::format("{:4} ", dmp_func_index_strings[i]); for (int j = 0; j < nr_order_; j++) - line += stdstrPrint("%12.3e ", fjac_[i][j]); - report_->reportLineString(line); + line += sta::format("{:12.3e} ", fjac_[i][j]); + report_->reportLine(line); } } void -DmpAlg::findDriverDelaySlew(// Return values. - double &delay, - double &slew) +DmpAlg::findDriverDelaySlew( // Return values. + double &delay, + double &slew) { double t_upper = voCrossingUpperBound(); delay = findVoCrossing(vth_, t0_, t_upper); @@ -482,17 +478,15 @@ DmpAlg::findVoCrossing(double vth, double t_lower, double t_upper) { - FindRootFunc vo_func = [&] (double t, - double &y, - double &dy) { + FindRootFunc vo_func = [&](double t, double &y, double &dy) { double vo, vo_dt; Vo(t, vo, vo_dt); y = vo - vth; dy = vo_dt; }; bool fail; - double t_vth = findRoot(vo_func, t_lower, t_upper, vth_time_tol, - find_root_max_iter, fail); + double t_vth = + findRoot(vo_func, t_lower, t_upper, vth_time_tol, find_root_max_iter, fail); if (fail) throw DmpError("find Vo crossing failed"); return t_vth; @@ -514,7 +508,7 @@ DmpAlg::Vo(double t, V0(t1, v0, dv0_dt); vo = v0 / dt_; - dvo_dt = dv0_dt / dt_; + dvo_dt = dv0_dt / dt_; } else { double v0, dv0_dt; @@ -531,20 +525,20 @@ DmpAlg::Vo(double t, void DmpAlg::showVo() { - report_->reportLine(" t vo(t)"); + report_->report(" t vo(t)"); double ub = voCrossingUpperBound(); for (double t = t0_; t < t0_ + ub; t += dt_ / 10.0) { double vo, dvo_dt; Vo(t, vo, dvo_dt); - report_->reportLine(" %g %g", t, vo); + report_->report(" {:g} {:g}", t, vo); } } void DmpAlg::loadDelaySlew(const Pin *, double elmore, - ArcDelay &delay, - Slew &slew) + double &delay, + double &slew) { if (!driver_valid_ || elmore == 0.0 @@ -585,8 +579,7 @@ DmpAlg::loadDelaySlew(const Pin *, } delay = delay1; slew = slew1; - } - catch (DmpError &error) { + } catch (DmpError &error) { fail(error.what()); delay = elmore_; slew = drvr_slew_; @@ -600,17 +593,15 @@ DmpAlg::findVlCrossing(double vth, double t_lower, double t_upper) { - FindRootFunc vl_func = [&] (double t, - double &y, - double &dy) { + FindRootFunc vl_func = [&](double t, double &y, double &dy) { double vl, vl_dt; Vl(t, vl, vl_dt); y = vl - vth; dy = vl_dt; }; bool fail; - double t_vth = findRoot(vl_func, t_lower, t_upper, vth_time_tol, - find_root_max_iter, fail); + double t_vth = + findRoot(vl_func, t_lower, t_upper, vth_time_tol, find_root_max_iter, fail); if (fail) throw DmpError("find Vl crossing failed"); return t_vth; @@ -654,12 +645,12 @@ DmpAlg::Vl(double t, void DmpAlg::showVl() { - report_->reportLine(" t vl(t)"); + report_->report(" t vl(t)"); double ub = vlCrossingUpperBound(); for (double t = t0_; t < t0_ + ub * 2.0; t += ub / 10.0) { double vl, dvl_dt; Vl(t, vl, dvl_dt); - report_->reportLine(" %g %g", t, vl); + report_->report(" {:g} {:g}", t, vl); } } @@ -668,12 +659,11 @@ DmpAlg::fail(const char *reason) { // Report failures with a unique debug flag. if (debug_->check("dmp_ceff", 1) || debug_->check("dcalc_error", 1)) - report_->reportLine("delay_calc: DMP failed - %s c2=%s rpi=%s c1=%s rd=%s", - reason, - units_->capacitanceUnit()->asString(c2_), - units_->resistanceUnit()->asString(rpi_), - units_->capacitanceUnit()->asString(c1_), - units_->resistanceUnit()->asString(rd_)); + report_->report("delay_calc: DMP failed - {} c2={} rpi={} c1={} rd={}", reason, + units_->capacitanceUnit()->asString(c2_), + units_->resistanceUnit()->asString(rpi_), + units_->capacitanceUnit()->asString(c1_), + units_->resistanceUnit()->asString(rd_)); } //////////////////////////////////////////////////////////////// @@ -694,14 +684,14 @@ public: double c2, double rpi, double c1) override; - void gateDelaySlew(// Return values. - double &delay, - double &slew) override; + void gateDelaySlew( // Return values. + double &delay, + double &slew) override; void loadDelaySlew(const Pin *, double elmore, // Return values. - ArcDelay &delay, - Slew &slew) override; + double &delay, + double &slew) override; void evalDmpEqns() override; double voCrossingUpperBound() override; @@ -716,8 +706,9 @@ private: double &dvl_dt) override; }; -DmpCap::DmpCap(StaState *sta): - DmpAlg(1, sta) +DmpCap::DmpCap(StaState *sta) : + DmpAlg(1, + sta) { } @@ -734,17 +725,17 @@ DmpCap::init(const LibertyLibrary *drvr_library, double c1) { debugPrint(debug_, "dmp_ceff", 3, "Using DMP cap"); - DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, - rd, in_slew, c2, rpi, c1); + DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, in_slew, c2, rpi, + c1); ceff_ = c1 + c2; } void -DmpCap::gateDelaySlew(// Return values. - double &delay, - double &slew) +DmpCap::gateDelaySlew( // Return values. + double &delay, + double &slew) { - debugPrint(debug_, "dmp_ceff", 3, " ceff = %s", + debugPrint(debug_, "dmp_ceff", 3, " ceff = {}", units_->capacitanceUnit()->asString(ceff_)); gateCapDelaySlew(ceff_, delay, slew); drvr_slew_ = slew; @@ -753,8 +744,8 @@ DmpCap::gateDelaySlew(// Return values. void DmpCap::loadDelaySlew(const Pin *, double elmore, - ArcDelay &delay, - Slew &slew) + double &delay, + double &slew) { delay = elmore; slew = drvr_slew_; @@ -782,7 +773,7 @@ DmpCap::voCrossingUpperBound() } void -DmpCap::Vl0(double , +DmpCap::Vl0(double, // Return values. double &vl, double &dvl_dt) @@ -809,9 +800,9 @@ public: double c2, double rpi, double c1) override; - void gateDelaySlew(// Return values. - double &delay, - double &slew) override; + void gateDelaySlew( // Return values. + double &delay, + double &slew) override; void evalDmpEqns() override; double voCrossingUpperBound() override; @@ -847,7 +838,8 @@ private: }; DmpPi::DmpPi(StaState *sta) : - DmpAlg(3, sta), + DmpAlg(3, + sta), p1_(0.0), p2_(0.0), z1_(0.0), @@ -875,8 +867,8 @@ DmpPi::init(const LibertyLibrary *drvr_library, double c1) { debugPrint(debug_, "dmp_ceff", 3, "Using DMP Pi"); - DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, - in_slew, c2, rpi, c1); + DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, in_slew, c2, rpi, + c1); // Find poles/zeros. z1_ = 1.0 / (rpi_ * c1_); @@ -900,9 +892,9 @@ DmpPi::init(const LibertyLibrary *drvr_library, } void -DmpPi::gateDelaySlew(// Return values. - double &delay, - double &slew) +DmpPi::gateDelaySlew( // Return values. + double &delay, + double &slew) { driver_valid_ = false; try { @@ -911,23 +903,21 @@ DmpPi::gateDelaySlew(// Return values. double table_delay, table_slew; gateCapDelaySlew(ceff_, table_delay, table_slew); delay = table_delay; - //slew = table_slew; + // slew = table_slew; try { double vo_delay, vo_slew; findDriverDelaySlew(vo_delay, vo_slew); driver_valid_ = true; // Save Vo delay to measure load wire delay waveform. vo_delay_ = vo_delay; - //delay = vo_delay; + // delay = vo_delay; slew = vo_slew; - } - catch (DmpError &error) { + } catch (DmpError &error) { fail(error.what()); // Fall back to table slew. slew = table_slew; } - } - catch (DmpError &error) { + } catch (DmpError &error) { fail(error.what()); // Driver calculation failed - use Ceff=c1+c2. ceff_ = c1_ + c2_; @@ -941,8 +931,7 @@ DmpPi::findDriverParamsPi() { try { findDriverParams(c2_ + c1_); - } - catch (DmpError &) { + } catch (DmpError &) { findDriverParams(c2_); } } @@ -985,36 +974,33 @@ DmpPi::evalDmpEqns() fvec_[DmpFunc::y20] = y20 - vl_; fjac_[DmpFunc::ipi][DmpParam::t0] = 0.0; fjac_[DmpFunc::ipi][DmpParam::dt] = - (-A_ * dt + B_ * dt * exp_p1_dt - (2 * B_ / p1_) * (1.0 - exp_p1_dt) - + D_ * dt * exp_p2_dt - (2 * D_ / p2_) * (1.0 - exp_p2_dt) - + rd_ * ceff * (dt + dt * exp_dt_rd_ceff - - 2 * rd_ * ceff * (1.0 - exp_dt_rd_ceff))) - / (rd_ * dt * dt * dt); + (-A_ * dt + B_ * dt * exp_p1_dt - (2 * B_ / p1_) * (1.0 - exp_p1_dt) + + D_ * dt * exp_p2_dt - (2 * D_ / p2_) * (1.0 - exp_p2_dt) + + rd_ * ceff + * (dt + dt * exp_dt_rd_ceff - 2 * rd_ * ceff * (1.0 - exp_dt_rd_ceff))) + / (rd_ * dt * dt * dt); fjac_[DmpFunc::ipi][DmpParam::ceff] = - (2 * rd_ * ceff - dt - (2 * rd_ * ceff + dt) * exp2(-dt / (rd_ * ceff))) - / (dt * dt); + (2 * rd_ * ceff - dt - (2 * rd_ * ceff + dt) * exp2(-dt / (rd_ * ceff))) + / (dt * dt); - dy(t_vl, t0, dt, ceff, - fjac_[DmpFunc::y20][DmpParam::t0], - fjac_[DmpFunc::y20][DmpParam::dt], - fjac_[DmpFunc::y20][DmpParam::ceff]); + dy(t_vl, t0, dt, ceff, fjac_[DmpFunc::y20][DmpParam::t0], + fjac_[DmpFunc::y20][DmpParam::dt], fjac_[DmpFunc::y20][DmpParam::ceff]); - dy(t_vth, t0, dt, ceff, - fjac_[DmpFunc::y50][DmpParam::t0], - fjac_[DmpFunc::y50][DmpParam::dt], - fjac_[DmpFunc::y50][DmpParam::ceff]); + dy(t_vth, t0, dt, ceff, fjac_[DmpFunc::y50][DmpParam::t0], + fjac_[DmpFunc::y50][DmpParam::dt], fjac_[DmpFunc::y50][DmpParam::ceff]); if (debug_->check("dmp_ceff", 4)) { showX(); showFvec(); showJacobian(); - report_->reportLine("................."); + report_->report("................."); } } // Eqn 13, Eqn 14. double -DmpPi::ipiIceff(double, double dt, +DmpPi::ipiIceff(double, + double dt, double ceff_time, double ceff) { @@ -1022,11 +1008,11 @@ DmpPi::ipiIceff(double, double dt, double exp_p2_dt = exp2(-p2_ * ceff_time); double exp_dt_rd_ceff = exp2(-ceff_time / (rd_ * ceff)); double ipi = (A_ * ceff_time + (B_ / p1_) * (1.0 - exp_p1_dt) - + (D_ / p2_) * (1.0 - exp_p2_dt)) - / (rd_ * ceff_time * dt); - double iceff = (rd_ * ceff * ceff_time - (rd_ * ceff) * (rd_ * ceff) - * (1.0 - exp_dt_rd_ceff)) - / (rd_ * ceff_time * dt); + + (D_ / p2_) * (1.0 - exp_p2_dt)) + / (rd_ * ceff_time * dt); + double iceff = + (rd_ * ceff * ceff_time - (rd_ * ceff) * (rd_ * ceff) * (1.0 - exp_dt_rd_ceff)) + / (rd_ * ceff_time * dt); return ipi - iceff; } @@ -1051,14 +1037,13 @@ DmpPi::Vl0(double t, double D1 = k0_ * (k1_ - k2_ / p3_); double D3 = -p3_ * k0_ * k3_ / (p1_ - p3_); double D4 = -p3_ * k0_ * k4_ / (p2_ - p3_); - double D5 = k0_ * (k2_ / p3_ - k1_ + p3_ * k3_ / (p1_ - p3_) - + p3_ * k4_ / (p2_ - p3_)); + double D5 = + k0_ * (k2_ / p3_ - k1_ + p3_ * k3_ / (p1_ - p3_) + p3_ * k4_ / (p2_ - p3_)); double exp_p1 = exp2(-p1_ * t); double exp_p2 = exp2(-p2_ * t); double exp_p3 = exp2(-p3_ * t); vl = D1 + t + D3 * exp_p1 + D4 * exp_p2 + D5 * exp_p3; - dvl_dt = 1.0 - D3 * p1_ * exp_p1 - D4 * p2_ * exp_p2 - - D5 * p3_ * exp_p3; + dvl_dt = 1.0 - D3 * p1_ * exp_p1 - D4 * p2_ * exp_p2 - D5 * p3_ * exp_p3; } double @@ -1080,7 +1065,8 @@ public: }; DmpOnePole::DmpOnePole(StaState *sta) : - DmpAlg(2, sta) + DmpAlg(2, + sta) { } @@ -1104,19 +1090,15 @@ DmpOnePole::evalDmpEqns() showFvec(); } - dy(t_vl, t0, dt, ceff_, - fjac_[DmpFunc::y20][DmpParam::t0], - fjac_[DmpFunc::y20][DmpParam::dt], - ignore2); + dy(t_vl, t0, dt, ceff_, fjac_[DmpFunc::y20][DmpParam::t0], + fjac_[DmpFunc::y20][DmpParam::dt], ignore2); - dy(t_vth, t0, dt, ceff_, - fjac_[DmpFunc::y50][DmpParam::t0], - fjac_[DmpFunc::y50][DmpParam::dt], - ignore2); + dy(t_vth, t0, dt, ceff_, fjac_[DmpFunc::y50][DmpParam::t0], + fjac_[DmpFunc::y50][DmpParam::dt], ignore2); if (debug_->check("dmp_ceff", 4)) { showJacobian(); - report_->reportLine("................."); + report_->report("................."); } } @@ -1144,19 +1126,19 @@ public: double c2, double rpi, double c1) override; - void gateDelaySlew(// Return values. - double &delay, - double &slew) override; + void gateDelaySlew( // Return values. + double &delay, + double &slew) override; private: void V0(double t, // Return values. double &vo, double &dvo_dt) override; - void Vl0(double t, - // Return values. - double &vl, - double &dvl_dt) override; + void Vl0(double t, + // Return values. + double &vl, + double &dvl_dt) override; double voCrossingUpperBound() override; // Pole/zero. @@ -1193,8 +1175,8 @@ DmpZeroC2::init(const LibertyLibrary *drvr_library, double c1) { debugPrint(debug_, "dmp_ceff", 3, "Using DMP C2=0"); - DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, - in_slew, c2, rpi, c1); + DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, in_slew, c2, rpi, + c1); ceff_ = c1; z1_ = 1.0 / (rpi_ * c1_); @@ -1207,9 +1189,9 @@ DmpZeroC2::init(const LibertyLibrary *drvr_library, } void -DmpZeroC2::gateDelaySlew(// Return values. - double &delay, - double &slew) +DmpZeroC2::gateDelaySlew( // Return values. + double &delay, + double &slew) { try { findDriverParams(c1_); @@ -1217,8 +1199,7 @@ DmpZeroC2::gateDelaySlew(// Return values. findDriverDelaySlew(delay, slew); driver_valid_ = true; vo_delay_ = delay; - } - catch (DmpError &error) { + } catch (DmpError &error) { fail(error.what()); // Fall back to table slew. driver_valid_ = false; @@ -1241,9 +1222,9 @@ DmpZeroC2::V0(double t, void DmpZeroC2::Vl0(double t, - // Return values. - double &vl, - double &dvl_dt) + // Return values. + double &vl, + double &dvl_dt) { double D1 = k0_ * (k1_ - k2_ / p3_); double D3 = -p3_ * k0_ * k3_ / (p1_ - p3_); @@ -1271,7 +1252,7 @@ newtonRaphson(const int max_iter, double x[], const int size, const double x_tol, - std::function eval, + std::function eval, // Temporaries supplied by caller. double *fvec, double **fjac, @@ -1498,32 +1479,48 @@ DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin, parasitics_->piModel(parasitic, c2, rpi, c1); if (std::isnan(c2) || std::isnan(c1) || std::isnan(rpi)) report_->error(1040, "parasitic Pi model has NaNs."); - setCeffAlgorithm(drvr_library, drvr_cell, pinPvt(drvr_pin, scene, min_max), + const Pvt *pvt = pinPvt(drvr_pin, scene, min_max); + setCeffAlgorithm(drvr_library, drvr_cell, pvt, table_model, rf, in_slew1, c2, rpi, c1); double gate_delay, drvr_slew; gateDelaySlew(gate_delay, drvr_slew); + + // Fill in pocv parameters. + double ceff = dmp_alg_->ceff(); + ArcDelay gate_delay2(gate_delay); + Slew drvr_slew2(drvr_slew); + if (variables_->pocvEnabled()) + table_model->gateDelayPocv(pvt, in_slew1, ceff, min_max, + variables_->pocvMode(), + gate_delay2, drvr_slew2); ArcDcalcResult dcalc_result(load_pin_index_map.size()); - dcalc_result.setGateDelay(gate_delay); - dcalc_result.setDrvrSlew(drvr_slew); + dcalc_result.setGateDelay(gate_delay2); + dcalc_result.setDrvrSlew(drvr_slew2); for (const auto &[load_pin, load_idx] : load_pin_index_map) { - ArcDelay wire_delay; - Slew load_slew; + double wire_delay; + double load_slew; loadDelaySlew(load_pin, drvr_slew, rf, drvr_library, parasitic, wire_delay, load_slew); - dcalc_result.setWireDelay(load_idx, wire_delay); - dcalc_result.setLoadSlew(load_idx, load_slew); + // Copy pocv params from driver. + ArcDelay wire_delay2(gate_delay2); + Slew load_slew2(drvr_slew2); + delaySetMean(wire_delay2, wire_delay); + delaySetMean(load_slew2, load_slew); + dcalc_result.setWireDelay(load_idx, wire_delay2); + dcalc_result.setLoadSlew(load_idx, load_slew2); } return dcalc_result; } else { ArcDcalcResult dcalc_result = - LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, - load_pin_index_map, scene, min_max); - if (parasitic - && !unsuppored_model_warned_) { + LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, + load_pin_index_map, scene, min_max); + if (parasitic && !unsuppored_model_warned_) { unsuppored_model_warned_ = true; - report_->warn(1041, "cell %s delay model not supported on SPF parasitics by DMP delay calculator", + report_->warn(1041, + "cell {} delay model not supported on SPF parasitics by DMP " + "delay calculator", drvr_cell->name()); } return dcalc_result; @@ -1543,8 +1540,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, { double rd = 0.0; if (gate_model) { - rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1, - pvt, variables_->pocvEnabled()); + rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1, pvt); // Zero Rd means the table is constant and thus independent of load cap. if (rd < 1e-2 // Rpi is small compared to Rd, which makes the load capacitive. @@ -1560,16 +1556,15 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, } else dmp_alg_ = dmp_cap_; - dmp_alg_->init(drvr_library, drvr_cell, pvt, gate_model, - rf, rd, in_slew, c2, rpi, c1); + dmp_alg_->init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, in_slew, c2, rpi, + c1); debugPrint(debug_, "dmp_ceff", 3, - " DMP in_slew = %s c2 = %s rpi = %s c1 = %s Rd = %s (%s alg)", + " DMP in_slew = {} c2 = {} rpi = {} c1 = {} Rd = {} ({} alg)", units_->timeUnit()->asString(in_slew), units_->capacitanceUnit()->asString(c2), units_->resistanceUnit()->asString(rpi), units_->capacitanceUnit()->asString(c1), - units_->resistanceUnit()->asString(rd), - dmp_alg_->name()); + units_->resistanceUnit()->asString(rd), dmp_alg_->name()); } std::string @@ -1583,8 +1578,9 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin, const MinMax *min_max, int digits) { - ArcDcalcResult dcalc_result = gateDelay(drvr_pin, arc, in_slew, load_cap, - parasitic, load_pin_index_map, scene, min_max); + ArcDcalcResult dcalc_result = + gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, load_pin_index_map, + scene, min_max); GateTableModel *model = arc->gateTableModel(scene, min_max); float c_eff = 0.0; std::string result; @@ -1612,14 +1608,12 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin, else c_eff = load_cap; if (model) { - const Unit *time_unit = units->timeUnit(); float in_slew1 = delayAsFloat(in_slew); result += model->reportGateDelay(pinPvt(drvr_pin, scene, min_max), - in_slew1, c_eff, - variables_->pocvEnabled(), digits); + in_slew1, c_eff, min_max, + variables_->pocvMode(), digits); result += "Driver waveform slew = "; - float drvr_slew = delayAsFloat(dcalc_result.drvrSlew()); - result += time_unit->asString(drvr_slew, digits); + result += delayAsString(dcalc_result.drvrSlew(), min_max, digits, this); result += '\n'; } return result; @@ -1632,25 +1626,22 @@ gateModelRd(const LibertyCell *cell, double in_slew, double c2, double c1, - const Pvt *pvt, - bool pocv_enabled) + const Pvt *pvt) { float cap1 = c1 + c2; float cap2 = cap1 + 1e-15; - ArcDelay d1, d2; - Slew s1, s2; - gate_model->gateDelay(pvt, in_slew, cap1, pocv_enabled, d1, s1); - gate_model->gateDelay(pvt, in_slew, cap2, pocv_enabled, d2, s2); + float d1, d2, s1, s2; + gate_model->gateDelay(pvt, in_slew, cap1, d1, s1); + gate_model->gateDelay(pvt, in_slew, cap2, d2, s2); double vth = cell->libertyLibrary()->outputThreshold(rf); - float rd = -std::log(vth) * std::abs(delayAsFloat(d1) - delayAsFloat(d2)) - / (cap2 - cap1); + float rd = -std::log(vth) * std::abs(d1 - d2) / (cap2 - cap1); return rd; } void -DmpCeffDelayCalc::gateDelaySlew(// Return values. - double &delay, - double &slew) +DmpCeffDelayCalc::gateDelaySlew( // Return values. + double &delay, + double &slew) { dmp_alg_->gateDelaySlew(delay, slew); } @@ -1658,8 +1649,8 @@ DmpCeffDelayCalc::gateDelaySlew(// Return values. void DmpCeffDelayCalc::loadDelaySlewElmore(const Pin *load_pin, double elmore, - ArcDelay &delay, - Slew &slew) + double &delay, + double &slew) { if (dmp_alg_) dmp_alg_->loadDelaySlew(load_pin, elmore, delay, slew); @@ -1678,7 +1669,7 @@ DmpCeffDelayCalc::copyState(const StaState *sta) DmpError::DmpError(const char *what) : what_(what) { - //printf("DmpError %s\n", what); + // printf("DmpError %s\n", what); } // This saves about 2.5% in overall run time on designs with SPEF. @@ -1707,4 +1698,4 @@ exp2(double x) } } -} // namespace +} // namespace sta diff --git a/dcalc/DmpCeff.hh b/dcalc/DmpCeff.hh index d1931517..4d3b7fd5 100644 --- a/dcalc/DmpCeff.hh +++ b/dcalc/DmpCeff.hh @@ -69,15 +69,15 @@ protected: const LibertyLibrary *drvr_library, const Parasitic *parasitic, // Return values. - ArcDelay &wire_delay, - Slew &load_slew) = 0; + double &wire_delay, + double &load_slew) = 0; void gateDelaySlew(// Return values. double &delay, double &slew); void loadDelaySlewElmore(const Pin *load_pin, double elmore, - ArcDelay &delay, - Slew &slew); + double &delay, + double &slew); // Select the appropriate special case Dartu/Menezes/Pileggi algorithm. void setCeffAlgorithm(const LibertyLibrary *library, const LibertyCell *cell, diff --git a/dcalc/DmpDelayCalc.cc b/dcalc/DmpDelayCalc.cc index e0a350d2..aece357e 100644 --- a/dcalc/DmpDelayCalc.cc +++ b/dcalc/DmpDelayCalc.cc @@ -59,8 +59,8 @@ protected: const LibertyLibrary *drvr_library, const Parasitic *parasitic, // Return values. - ArcDelay &wire_delay, - Slew &load_slew) override; + double &wire_delay, + double &load_slew) override; }; ArcDelayCalc * @@ -93,8 +93,8 @@ DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *, ArcDcalcResult dcalc_result(load_pin_index_map.size()); LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); for (auto [load_pin, load_idx] : load_pin_index_map) { - ArcDelay wire_delay = 0.0; - Slew load_slew = in_slew; + double wire_delay = 0.0; + double load_slew = in_slew; bool elmore_exists = false; float elmore = 0.0; if (parasitic) @@ -116,8 +116,8 @@ DmpCeffElmoreDelayCalc::loadDelaySlew(const Pin *load_pin, const LibertyLibrary *drvr_library, const Parasitic *parasitic, // Return values. - ArcDelay &wire_delay, - Slew &load_slew) + double &wire_delay, + double &load_slew) { wire_delay = 0.0; load_slew = drvr_slew; @@ -143,14 +143,14 @@ public: Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const Scene *scene, - const MinMax *min_max) override; + const MinMax *min_max) override; ArcDcalcResult inputPortDelay(const Pin *port_pin, float in_slew, const RiseFall *rf, const Parasitic *parasitic, const LoadPinIndexMap &load_pin_index_map, const Scene *scene, - const MinMax *min_max) override; + const MinMax *min_max) override; ArcDcalcResult gateDelay(const Pin *drvr_pin, const TimingArc *arc, const Slew &in_slew, @@ -158,7 +158,7 @@ public: const Parasitic *parasitic, const LoadPinIndexMap &load_pin_index_map, const Scene *scene, - const MinMax *min_max) override; + const MinMax *min_max) override; private: void loadDelaySlew(const Pin *load_pin, @@ -167,14 +167,14 @@ private: const LibertyLibrary *drvr_library, const Parasitic *parasitic, // Return values. - ArcDelay &wire_delay, - Slew &load_slew) override; + double &wire_delay, + double &load_slew) override; void loadDelay(double drvr_slew, Parasitic *pole_residue, double p1, double k1, - ArcDelay &wire_delay, - Slew &load_slew); + double &wire_delay, + double &load_slew); float loadDelay(double vth, double p1, double p2, @@ -267,8 +267,8 @@ DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *, { const Parasitics *parasitics = scene->parasitics(min_max); ArcDcalcResult dcalc_result(load_pin_index_map.size()); - ArcDelay wire_delay = 0.0; - Slew load_slew = in_slew; + double wire_delay = 0.0; + double load_slew = in_slew; LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); for (const auto [load_pin, load_idx] : load_pin_index_map) { if (parasitics->isPiPoleResidue(parasitic)) { @@ -323,8 +323,8 @@ DmpCeffTwoPoleDelayCalc::loadDelaySlew(const Pin *load_pin, const LibertyLibrary *drvr_library, const Parasitic *parasitic, // Return values. - ArcDelay &wire_delay, - Slew &load_slew) + double &wire_delay, + double &load_slew) { parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic); // Should handle PiElmore parasitic. @@ -362,12 +362,12 @@ DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew, double p1, double k1, // Return values. - ArcDelay &wire_delay, - Slew &load_slew) + double &wire_delay, + double &load_slew) { ComplexFloat pole2, residue2; parasitics_->poleResidue(pole_residue, 1, pole2, residue2); - if (!delayZero(drvr_slew) + if (!delayZero(drvr_slew, this) && pole2.imag() == 0.0 && residue2.imag() == 0.0) { double p2 = pole2.real(); diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index e33067d2..8c12cdf1 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -251,8 +251,8 @@ GraphDelayCalc::delayInvalid(const Pin *pin) void GraphDelayCalc::delayInvalid(Vertex *vertex) { - debugPrint(debug_, "delay_calc", 2, "delay invalid %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "delay_calc", 2, "delay invalid {}", + vertex->to_string(this)); if (graph_ && incremental_) { invalid_delays_.insert(vertex); // Invalidate driver that triggers dcalc for multi-driver nets. @@ -340,7 +340,7 @@ GraphDelayCalc::findDelays(Level level) if (arc_delay_calc_) { Stats stats(debug_, report_); int dcalc_count = 0; - debugPrint(debug_, "delay_calc", 1, "find delays to level %d", level); + debugPrint(debug_, "delay_calc", 1, "find delays to level {}", level); if (!delays_seeded_) { iter_->clear(); seedRootSlews(); @@ -368,7 +368,7 @@ GraphDelayCalc::findDelays(Level level) delays_exist_ = true; incremental_ = true; - debugPrint(debug_, "delay_calc", 1, "found %d delays", dcalc_count); + debugPrint(debug_, "delay_calc", 1, "found {} delays", dcalc_count); stats.report("Delay calc"); } } @@ -404,8 +404,8 @@ GraphDelayCalc::seedDrvrSlew(Vertex *drvr_vertex, ArcDelayCalc *arc_delay_calc) { const Pin *drvr_pin = drvr_vertex->pin(); - debugPrint(debug_, "delay_calc", 2, "seed driver slew %s", - drvr_vertex->to_string(this).c_str()); + debugPrint(debug_, "delay_calc", 2, "seed driver slew {}", + drvr_vertex->to_string(this)); for (const Scene *scene : scenes_) { const Sdc *sdc = scene->sdc(); for (const MinMax *min_max : MinMax::range()) { @@ -504,7 +504,7 @@ GraphDelayCalc::seedNoDrvrSlew(Vertex *drvr_vertex, ArcDelayCalc *arc_delay_calc) { DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); - Slew slew(default_slew); + Slew slew = default_slew; // Top level bidirect driver uses load slew unless // bidirect instance paths are disabled. if (bidirectDrvrSlewFromLoad(drvr_pin)) { @@ -527,30 +527,30 @@ void GraphDelayCalc::seedLoadSlew(Vertex *vertex) { const Pin *pin = vertex->pin(); - debugPrint(debug_, "delay_calc", 2, "seed load slew %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "delay_calc", 2, "seed load slew {}", + vertex->to_string(this)); initSlew(vertex); for (const Scene *scene : scenes_) { const Sdc *sdc = scene->sdc(); for (const MinMax *min_max : MinMax::range()) { DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); - for (const RiseFall *rf : RiseFall::range()) { + for (const RiseFall *rf : RiseFall::range()) { ClockSet *clks = sdc->findLeafPinClocks(pin); if (!vertex->slewAnnotated(rf, min_max)) { - float slew = 0.0; - if (clks) { + float slew = 0.0; + if (clks) { slew = min_max->initValue(); for (Clock *clk : *clks) { float clk_slew = clk->slew(rf, min_max); if (min_max->compare(clk_slew, slew)) - slew = clk_slew; - } - } - graph_->setSlew(vertex, rf, ap_index, slew); + slew = clk_slew; + } + } + graph_->setSlew(vertex, rf, ap_index, slew); + } } } } - } } // If a driving cell does not specify a -from_pin, the first port @@ -602,7 +602,7 @@ GraphDelayCalc::findInputDriverDelay(const LibertyCell *drvr_cell, const Scene *scene, const MinMax *min_max) { - debugPrint(debug_, "delay_calc", 2, " driver cell %s %s", + debugPrint(debug_, "delay_calc", 2, " driver cell {} {}", drvr_cell->name(), rf->shortName()); for (TimingArcSet *arc_set : drvr_cell->timingArcSets(from_port, to_port)) { @@ -627,12 +627,12 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin, const Scene *scene, const MinMax *min_max) { - debugPrint(debug_, "delay_calc", 3, " %s %s -> %s %s (%s)", + debugPrint(debug_, "delay_calc", 3, " {} {} -> {} {} ({})", arc->from()->name(), - arc->fromEdge()->to_string().c_str(), + arc->fromEdge()->to_string(), arc->to()->name(), - arc->toEdge()->to_string().c_str(), - arc->role()->to_string().c_str()); + arc->toEdge()->to_string(), + arc->role()->to_string()); const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); if (drvr_rf) { DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); @@ -646,19 +646,19 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin, ArcDcalcResult intrinsic_result = arc_delay_calc_->gateDelay(drvr_pin, arc, Slew(from_slew), 0.0, nullptr, load_pin_index_map, scene, min_max); - ArcDelay intrinsic_delay = intrinsic_result.gateDelay(); + const ArcDelay &intrinsic_delay = intrinsic_result.gateDelay(); ArcDcalcResult gate_result = arc_delay_calc_->gateDelay(drvr_pin, arc, Slew(from_slew), load_cap, parasitic, load_pin_index_map, scene, min_max); - ArcDelay gate_delay = gate_result.gateDelay(); - Slew gate_slew = gate_result.drvrSlew(); + const ArcDelay &gate_delay = gate_result.gateDelay(); + const Slew &gate_slew = gate_result.drvrSlew(); - ArcDelay load_delay = gate_delay - intrinsic_delay; + const ArcDelay load_delay = delayDiff(gate_delay, intrinsic_delay, this); debugPrint(debug_, "delay_calc", 3, - " gate delay = %s intrinsic = %s slew = %s", + " gate delay = {} intrinsic = {} slew = {}", delayAsString(gate_delay, this), delayAsString(intrinsic_delay, this), delayAsString(gate_slew, this)); @@ -681,8 +681,8 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex, bool propagate) { const Pin *pin = vertex->pin(); - debugPrint(debug_, "delay_calc", 2, "find delays %s (%s)", - vertex->to_string(this).c_str(), + debugPrint(debug_, "delay_calc", 2, "find delays {} ({})", + vertex->to_string(this), network_->cellName(network_->instance(pin))); if (vertex->isRoot()) seedRootSlew(vertex, arc_delay_calc); @@ -729,9 +729,8 @@ GraphDelayCalc::loadSlews(LoadPinIndexMap &load_pin_index_map) Vertex *load_vertex = graph_->pinLoadVertex(pin); SlewSeq &slews = load_slews[index];; slews.resize(slew_count); - Slew *vertex_slews = load_vertex->slews(); for (size_t i = 0; i < slew_count; i++) - slews[i] = vertex_slews[i]; + slews[i] = graph_->slew(load_vertex, i); } return load_slews; } @@ -744,9 +743,9 @@ GraphDelayCalc::loadSlewsChanged(DrvrLoadSlews &load_slews_prev, for (auto const [pin, index] : load_pin_index_map) { Vertex *load_vertex = graph_->pinLoadVertex(pin); SlewSeq &slews_prev = load_slews_prev[index];; - const Slew *slews = load_vertex->slews(); for (size_t i = 0; i < slew_count; i++) { - if (!delayEqual(slews[i], slews_prev[i])) + const Slew slew = graph_->slew(load_vertex, i); + if (!delayEqual(slew, slews_prev[i], this)) return true; } } @@ -886,7 +885,7 @@ GraphDelayCalc::makeMultiDrvrNet(Vertex *drvr_vertex) Vertex *drvr = edge->from(graph_); const Pin *drvr_pin = drvr->pin(); if (isLeafDriver(drvr_pin, network_)) { - debugPrint(debug_, "delay_calc", 3, " %s", + debugPrint(debug_, "delay_calc", 3, " {}", network_->pathName(drvr_pin)); multi_drvr_net_map_[drvr] = multi_drvr; drvr_vertices.push_back(drvr); @@ -915,19 +914,18 @@ GraphDelayCalc::initLoadSlews(Vertex *drvr_vertex) Edge *wire_edge = edge_iter.next(); if (wire_edge->isWire()) { Vertex *load_vertex = wire_edge->to(graph_); - for (Scene *scene : scenes_) { for (const MinMax *min_max : MinMax::range()) { DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); Slew slew_init_value(min_max->initValue()); - for (const RiseFall *rf : RiseFall::range()) { + for (const RiseFall *rf : RiseFall::range()) { if (!load_vertex->slewAnnotated(rf, min_max)) - graph_->setSlew(load_vertex, rf, ap_index, slew_init_value); + graph_->setSlew(load_vertex, rf, ap_index, slew_init_value); + } } } } } - } } bool @@ -965,12 +963,12 @@ GraphDelayCalc::initRootSlews(Vertex *vertex) for (Scene *scene : scenes_) { for (const MinMax *min_max : MinMax::range()) { DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); - for (const RiseFall *rf : RiseFall::range()) { + for (const RiseFall *rf : RiseFall::range()) { if (!vertex->slewAnnotated(rf, min_max)) - graph_->setSlew(vertex, rf, ap_index, default_slew); + graph_->setSlew(vertex, rf, ap_index, default_slew); + } } } - } } void @@ -979,7 +977,7 @@ GraphDelayCalc::findLatchEdgeDelays(Edge *edge) Vertex *drvr_vertex = edge->to(graph_); const Pin *drvr_pin = drvr_vertex->pin(); Instance *drvr_inst = network_->instance(drvr_pin); - debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s", + debugPrint(debug_, "delay_calc", 2, "find latch D->Q {}", sdc_network_->pathName(drvr_inst)); std::array delay_exists = {false, false}; LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); @@ -1195,36 +1193,36 @@ GraphDelayCalc::annotateDelaysSlews(Edge *edge, bool GraphDelayCalc::annotateDelaySlew(Edge *edge, const TimingArc *arc, - ArcDelay &gate_delay, - Slew &gate_slew, + const ArcDelay &gate_delay, + const Slew &gate_slew, const Scene *scene, const MinMax *min_max) { DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); debugPrint(debug_, "delay_calc", 3, - " %s %s -> %s %s (%s) scene:%s/%s", + " {} {} -> {} {} ({}) scene:{}/{}", arc->from()->name(), - arc->fromEdge()->to_string().c_str(), + arc->fromEdge()->to_string(), arc->to()->name(), - arc->toEdge()->to_string().c_str(), - arc->role()->to_string().c_str(), - scene->name().c_str(), - min_max->to_string().c_str()); + arc->toEdge()->to_string(), + arc->role()->to_string(), + scene->name(), + min_max->to_string()); debugPrint(debug_, "delay_calc", 3, - " gate delay = %s slew = %s", + " gate delay = {} slew = {}", delayAsString(gate_delay, this), delayAsString(gate_slew, this)); bool delay_changed = false; Vertex *drvr_vertex = edge->to(graph_); const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); // Merge slews. - const Slew &drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index); + const Slew drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index); if (delayGreater(gate_slew, drvr_slew, min_max, this) && !drvr_vertex->slewAnnotated(drvr_rf, min_max) && !edge->role()->isLatchDtoQ()) graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew); if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) { - const ArcDelay &prev_gate_delay = graph_->arcDelay(edge,arc,ap_index); + const ArcDelay prev_gate_delay = graph_->arcDelay(edge,arc,ap_index); float gate_delay1 = delayAsFloat(gate_delay); float prev_gate_delay1 = delayAsFloat(prev_gate_delay); if (prev_gate_delay1 == 0.0 @@ -1258,23 +1256,23 @@ GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex, Vertex *load_vertex = wire_edge->to(graph_); Pin *load_pin = load_vertex->pin(); size_t load_idx = load_pin_index_map[load_pin]; - ArcDelay wire_delay = dcalc_result.wireDelay(load_idx); - Slew load_slew = dcalc_result.loadSlew(load_idx); + const ArcDelay &wire_delay = dcalc_result.wireDelay(load_idx); + const Slew &load_slew = dcalc_result.loadSlew(load_idx); debugPrint(debug_, "delay_calc", 3, - " %s load delay = %s slew = %s", - load_vertex->to_string(this).c_str(), + " {} load delay = {} slew = {}", + load_vertex->to_string(this), delayAsString(wire_delay, this), delayAsString(load_slew, this)); bool load_changed = false; if (!load_vertex->slewAnnotated(drvr_rf, min_max)) { if (drvr_vertex->slewAnnotated(drvr_rf, min_max)) { // Copy the driver slew to the load if it is annotated. - const Slew &drvr_slew = graph_->slew(drvr_vertex,drvr_rf,ap_index); + const Slew drvr_slew = graph_->slew(drvr_vertex,drvr_rf,ap_index); graph_->setSlew(load_vertex, drvr_rf, ap_index, drvr_slew); load_changed = true; } else { - const Slew &slew = graph_->slew(load_vertex, drvr_rf, ap_index); + const Slew slew = graph_->slew(load_vertex, drvr_rf, ap_index); if (!merge || delayGreater(load_slew, slew, min_max, this)) { graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew); @@ -1287,7 +1285,7 @@ GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex, // annotate the same wire edges so they must be combined // rather than set. const ArcDelay &delay = graph_->wireArcDelay(wire_edge, drvr_rf, ap_index); - Delay wire_delay_extra = extra_delay + wire_delay; + Delay wire_delay_extra = delaySum(extra_delay, wire_delay, this); if (!merge || delayGreater(wire_delay_extra, delay, min_max, this)) { graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, wire_delay_extra); @@ -1582,7 +1580,7 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge, TimingArcSet *arc_set = edge->timingArcSet(); const Pin *to_pin = to_vertex->pin(); Instance *inst = network_->instance(to_pin); - debugPrint(debug_, "delay_calc", 2, "find check %s %s -> %s", + debugPrint(debug_, "delay_calc", 2, "find check {} {} -> {}", sdc_network_->pathName(inst), network_->portName(from_vertex->pin()), network_->portName(to_pin)); @@ -1602,18 +1600,18 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge, if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) { const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, scene, min_max); - const Slew &to_slew = graph_->slew(to_vertex, to_rf, ap_index); + const Slew to_slew = graph_->slew(to_vertex, to_rf, ap_index); debugPrint(debug_, "delay_calc", 3, - " %s %s -> %s %s (%s) scene:%s/%s", + " {} {} -> {} {} ({}) scene:{}/{}", arc_set->from()->name(), - arc->fromEdge()->to_string().c_str(), + arc->fromEdge()->to_string(), arc_set->to()->name(), - arc->toEdge()->to_string().c_str(), - arc_set->role()->to_string().c_str(), - scene->name().c_str(), - min_max->to_string().c_str()); + arc->toEdge()->to_string(), + arc_set->role()->to_string(), + scene->name(), + min_max->to_string()); debugPrint(debug_, "delay_calc", 3, - " from_slew = %s to_slew = %s", + " from_slew = {} to_slew = {}", delayAsString(from_slew, this), delayAsString(to_slew, this)); float related_out_cap = 0.0; @@ -1624,7 +1622,7 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge, to_slew, related_out_cap, scene, min_max); debugPrint(debug_, "delay_calc", 3, - " check_delay = %s", + " check_delay = {}", delayAsString(check_delay, this)); graph_->setArcDelay(edge, arc, ap_index, check_delay); delay_changed = true; @@ -1684,7 +1682,7 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge, if (role->isTimingCheck()) { const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, scene, min_max); DcalcAPIndex slew_index = scene->dcalcAnalysisPtIndex(min_max); - const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index); + const Slew to_slew = graph_->slew(to_vertex, to_rf, slew_index); const ClkNetwork *clk_network = scene->mode()->clkNetwork(); bool from_ideal_clk = clk_network->isIdealClock(from_vertex); const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr; diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc index 4c4a1251..692c01f0 100644 --- a/dcalc/LumpedCapDelayCalc.cc +++ b/dcalc/LumpedCapDelayCalc.cc @@ -118,7 +118,7 @@ LumpedCapDelayCalc::inputPortDelay(const Pin *, const MinMax *) { const LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); - return makeResult(drvr_library,rf, 0.0, in_slew, load_pin_index_map); + return makeResult(drvr_library,rf, delay_zero, in_slew, load_pin_index_map); } ArcDcalcResult @@ -133,22 +133,28 @@ LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin, { GateTimingModel *model = arc->gateModel(scene, min_max); debugPrint(debug_, "delay_calc", 3, - " in_slew = %s load_cap = %s lumped", + " in_slew = {} load_cap = {} lumped", delayAsString(in_slew, this), units()->capacitanceUnit()->asString(load_cap)); const RiseFall *rf = arc->toEdge()->asRiseFall(); const LibertyLibrary *drvr_library = arc->to()->libertyLibrary(); if (model) { - ArcDelay gate_delay; - Slew drvr_slew; + float gate_delay, drvr_slew; float in_slew1 = delayAsFloat(in_slew); // NaNs cause seg faults during table lookup. - if (std::isnan(load_cap) || std::isnan(delayAsFloat(in_slew))) + if (std::isnan(load_cap) || std::isnan(in_slew.mean())) report_->error(1350, "gate delay input variable is NaN"); - model->gateDelay(pinPvt(drvr_pin, scene, min_max), in_slew1, load_cap, - variables_->pocvEnabled(), - gate_delay, drvr_slew); - return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map); + const Pvt *pvt = pinPvt(drvr_pin, scene, min_max); + model->gateDelay(pvt, in_slew1, load_cap, gate_delay, drvr_slew); + + // Fill in pocv parameters. + ArcDelay gate_delay2(gate_delay); + Slew drvr_slew2(drvr_slew); + if (variables_->pocvEnabled()) + model->gateDelayPocv(pvt, in_slew1, load_cap, min_max, variables_->pocvMode(), + gate_delay2, drvr_slew2); + + return makeResult(drvr_library, rf, gate_delay2, drvr_slew2, load_pin_index_map); } else return makeResult(drvr_library, rf, delay_zero, delay_zero, load_pin_index_map); @@ -157,17 +163,18 @@ LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin, ArcDcalcResult LumpedCapDelayCalc::makeResult(const LibertyLibrary *drvr_library, const RiseFall *rf, - ArcDelay gate_delay, - Slew drvr_slew, + const ArcDelay &gate_delay, + const Slew &drvr_slew, const LoadPinIndexMap &load_pin_index_map) { ArcDcalcResult dcalc_result(load_pin_index_map.size()); dcalc_result.setGateDelay(gate_delay); dcalc_result.setDrvrSlew(drvr_slew); + double drvr_slew1 = delayAsFloat(drvr_slew); for (const auto [load_pin, load_idx] : load_pin_index_map) { - ArcDelay wire_delay = 0.0; - Slew load_slew = drvr_slew; + double wire_delay = 0.0; + double load_slew = drvr_slew1; thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); dcalc_result.setWireDelay(load_idx, wire_delay); dcalc_result.setLoadSlew(load_idx, load_slew); @@ -190,7 +197,8 @@ LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin, if (model) { float in_slew1 = delayAsFloat(in_slew); return model->reportGateDelay(pinPvt(check_pin, scene, min_max), - in_slew1, load_cap, false, digits); + in_slew1, load_cap, min_max, + PocvMode::scalar, digits); } return ""; } diff --git a/dcalc/LumpedCapDelayCalc.hh b/dcalc/LumpedCapDelayCalc.hh index ac631f3a..752edea9 100644 --- a/dcalc/LumpedCapDelayCalc.hh +++ b/dcalc/LumpedCapDelayCalc.hh @@ -74,8 +74,8 @@ public: protected: ArcDcalcResult makeResult(const LibertyLibrary *drvr_library, const RiseFall *rf, - ArcDelay gate_delay, - Slew drvr_slew, + const ArcDelay &gate_delay, + const Slew &drvr_slew, const LoadPinIndexMap &load_pin_index_map); using ArcDelayCalc::reduceParasitic; diff --git a/dcalc/ParallelDelayCalc.cc b/dcalc/ParallelDelayCalc.cc index 512ea9f5..38b71c32 100644 --- a/dcalc/ParallelDelayCalc.cc +++ b/dcalc/ParallelDelayCalc.cc @@ -88,13 +88,13 @@ ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args, load_pin_index_map, scene, min_max); ArcDelay gate_delay = gate_result.gateDelay(); Slew drvr_slew = gate_result.drvrSlew(); - ArcDelay load_delay = gate_delay - intrinsic_delay; + ArcDelay load_delay = delayDiff(gate_delay, intrinsic_delay, this); load_delays[drvr_idx] = load_delay; - if (!delayZero(load_delay)) - load_delay_sum += 1.0 / load_delay; - if (!delayZero(drvr_slew)) - slew_sum += 1.0 / drvr_slew; + if (!delayZero(load_delay, this)) + delayIncr(load_delay_sum, delayDiv(1.0, load_delay, this), this); + if (!delayZero(drvr_slew, this)) + delayIncr(slew_sum, delayDiv(1.0, drvr_slew, this), this); dcalc_result.setLoadCount(load_pin_index_map.size()); for (const auto &[load_pin, load_idx] : load_pin_index_map) { @@ -103,14 +103,16 @@ ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args, } } - ArcDelay gate_load_delay = delayZero(load_delay_sum) + ArcDelay gate_load_delay = delayZero(load_delay_sum, this) ? delay_zero - : 1.0 / load_delay_sum; - ArcDelay drvr_slew = delayZero(slew_sum) ? delay_zero : 1.0 / slew_sum; + : delayDiv(1.0, load_delay_sum, this); + ArcDelay drvr_slew = delayZero(slew_sum, this) + ? delay_zero + : delayDiv(1.0, slew_sum, this); for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) { ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx]; - dcalc_result.setGateDelay(intrinsic_delays[drvr_idx] + gate_load_delay); + dcalc_result.setGateDelay(delaySum(intrinsic_delays[drvr_idx], gate_load_delay, this)); dcalc_result.setDrvrSlew(drvr_slew); } return dcalc_results; diff --git a/dcalc/PrimaDelayCalc.cc b/dcalc/PrimaDelayCalc.cc index b8b5c85c..fc1b0208 100644 --- a/dcalc/PrimaDelayCalc.cc +++ b/dcalc/PrimaDelayCalc.cc @@ -1,30 +1,30 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "PrimaDelayCalc.hh" -#include // abs +#include // abs #include "Debug.hh" #include "Units.hh" @@ -38,15 +38,16 @@ #include "Parasitics.hh" #include "GraphDelayCalc.hh" #include "DmpDelayCalc.hh" +#include "Format.hh" #include #include namespace sta { -using Eigen::SparseLU; -using Eigen::HouseholderQR; using Eigen::ColPivHouseholderQR; +using Eigen::HouseholderQR; +using Eigen::SparseLU; // Lawrence Pillage - “Electronic Circuit & System Simulation Methods” 1998 // McGraw-Hill, Inc. New York, NY. @@ -90,10 +91,7 @@ PrimaDelayCalc::PrimaDelayCalc(const PrimaDelayCalc &dcalc) : { } -PrimaDelayCalc::~PrimaDelayCalc() -{ - delete table_dcalc_; -} +PrimaDelayCalc::~PrimaDelayCalc() { delete table_dcalc_; } ArcDelayCalc * PrimaDelayCalc::copy() @@ -130,8 +128,8 @@ PrimaDelayCalc::findParasitic(const Pin *drvr_pin, bool has_wire_cap; graph_delay_calc_->netCaps(drvr_pin, rf, scene, min_max, pin_cap, wire_cap, fanout, has_wire_cap); - parasitic = parasitics->makeWireloadNetwork(drvr_pin, wireload, - fanout, scene, min_max); + parasitic = + parasitics->makeWireloadNetwork(drvr_pin, wireload, fanout, scene, min_max); } return parasitic; } @@ -160,14 +158,14 @@ PrimaDelayCalc::inputPortDelay(const Pin *drvr_pin, LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); const Parasitic *pi_elmore = nullptr; if (parasitic && parasitics->isParasiticNetwork(parasitic)) - pi_elmore = parasitics->reduceToPiElmore(parasitic, drvr_pin, rf, - scene, min_max); + pi_elmore = + parasitics->reduceToPiElmore(parasitic, drvr_pin, rf, scene, min_max); for (auto load_pin_index : load_pin_index_map) { const Pin *load_pin = load_pin_index.first; size_t load_idx = load_pin_index.second; - ArcDelay wire_delay = 0.0; - Slew load_slew = in_slew; + double wire_delay = 0.0; + double load_slew = in_slew; bool elmore_exists = false; float elmore = 0.0; if (pi_elmore) @@ -190,12 +188,13 @@ PrimaDelayCalc::gateDelay(const Pin *drvr_pin, const Parasitic *parasitic, const LoadPinIndexMap &load_pin_index_map, const Scene *scene, - const MinMax *min_max) + const MinMax *min_max) { ArcDcalcArgSeq dcalc_args; - dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, load_cap, parasitic); - ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_pin_index_map, - scene, min_max); + dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, load_cap, + parasitic); + ArcDcalcResultSeq dcalc_results = + gateDelays(dcalc_args, load_pin_index_map, scene, min_max); return dcalc_results[0]; } @@ -229,15 +228,15 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, && output_waveforms->slewAxis()->inBounds(in_slew) && output_waveforms->capAxis()->inBounds(dcalc_arg.loadCap())) { output_waveforms_[drvr_idx] = output_waveforms; - debugPrint(debug_, "ccs_dcalc", 1, "%s %s", - dcalc_arg.drvrCell()->name(), + debugPrint(debug_, "ccs_dcalc", 1, "{} {}", dcalc_arg.drvrCell()->name(), drvr_rf_->shortName()); LibertyCell *drvr_cell = dcalc_arg.drvrCell(); const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); bool vdd_exists; drvr_library->supplyVoltage("VDD", vdd_, vdd_exists); if (!vdd_exists) - report_->error(1720, "VDD not defined in library %s", drvr_library->name()); + report_->error(1720, "VDD not defined in library {}", + drvr_library->name()); drvr_cell->ensureVoltageWaveforms(scenes_); if (drvr_idx == 0) { vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_; @@ -268,13 +267,13 @@ PrimaDelayCalc::tableDcalcResults() const Pin *drvr_pin = dcalc_arg.drvrPin(); if (drvr_pin) { const RiseFall *rf = dcalc_arg.drvrEdge(); - const Parasitic *parasitic = table_dcalc_->findParasitic(drvr_pin, rf, - scene_, min_max_); + const Parasitic *parasitic = + table_dcalc_->findParasitic(drvr_pin, rf, scene_, min_max_); dcalc_arg.setParasitic(parasitic); } } - return table_dcalc_->gateDelays(*dcalc_args_, *load_pin_index_map_, - scene_, min_max_); + return table_dcalc_->gateDelays(*dcalc_args_, *load_pin_index_map_, scene_, + min_max_); } void @@ -284,8 +283,7 @@ PrimaDelayCalc::simulate() stampEqns(); setXinit(); - if (prima_order_ > 0 - && node_count_ > prima_order_) { + if (prima_order_ > 0 && node_count_ > prima_order_) { primaReduce(); simulate1(Gq_, Cq_, Bq_, xq_init_, Vq_, prima_order_); } @@ -297,11 +295,11 @@ PrimaDelayCalc::simulate() void PrimaDelayCalc::simulate1(const MatrixSd &G, - const MatrixSd &C, - const Eigen::MatrixXd &B, - const Eigen::VectorXd &x_init, - const Eigen::MatrixXd &x_to_v, - const size_t order) + const MatrixSd &C, + const Eigen::MatrixXd &B, + const Eigen::VectorXd &x_init, + const Eigen::MatrixXd &x_to_v, + const size_t order) { Eigen::VectorXd x(order); Eigen::VectorXd x_prev(order); @@ -315,7 +313,8 @@ PrimaDelayCalc::simulate1(const MatrixSd &G, v_ = v_prev_ = x_to_v * x_init; time_step_ = time_step_prev_ = timeStep(); - debugPrint(debug_, "ccs_dcalc", 1, "time step %s", delayAsString(time_step_, this)); + debugPrint(debug_, "ccs_dcalc", 1, "time step {}", + delayAsString(time_step_, this)); MatrixSd A(order, order); A = G + (2.0 / time_step_) * C; @@ -336,8 +335,8 @@ PrimaDelayCalc::simulate1(const MatrixSd &G, v_ = v_prev_ = x_to_v * x_init; // voltageTime is always for a rising waveform so 0.0v is initial voltage. - double time_begin = output_waveforms_[0]->voltageTime((*dcalc_args_)[0].inSlewFlt(), - ceff_[0], 0.0); + double time_begin = output_waveforms_[0]->voltageTime( + (*dcalc_args_)[0].inSlewFlt(), ceff_[0], 0.0); // Limit in case load voltage waveforms don't get to final value. double time_end = time_begin + maxTime(); @@ -349,9 +348,9 @@ PrimaDelayCalc::simulate1(const MatrixSd &G, rhs = B * u_ + (1.0 / time_step_) * C * (3.0 * x_prev - x_prev2); x = A_solver.solve(rhs); v_ = x_to_v * x; - + const ArcDcalcArg &dcalc_arg = (*dcalc_args_)[0]; - debugPrint(debug_, "ccs_dcalc", 3, "%s ceff %s VDrvr %.4f Idrvr %s", + debugPrint(debug_, "ccs_dcalc", 3, "{} ceff {} VDrvr {:.4f} Idrvr {}", delayAsString(time, this), units_->capacitanceUnit()->asString(ceff_[0]), voltage(dcalc_arg.drvrPin()), @@ -384,7 +383,7 @@ double PrimaDelayCalc::maxTime() { return (*dcalc_args_)[0].inSlewFlt() - + (driverResistance() + resistance_sum_) * load_cap_ * 4; + + (driverResistance() + resistance_sum_) * load_cap_ * 4; } float @@ -429,9 +428,8 @@ PrimaDelayCalc::findNodeCount() const Pin *pin = parasitics_->pin(node); if (pin) { pin_node_map_[pin] = node_idx; - debugPrint(debug_, "ccs_dcalc", 1, "pin %s node %lu", - network_->pathName(pin), - node_idx); + debugPrint(debug_, "ccs_dcalc", 1, "pin {} node {}", + network_->pathName(pin), node_idx); } double cap = parasitics_->nodeGndCap(node) + pinCapacitance(node); node_capacitances_.push_back(cap); @@ -441,14 +439,12 @@ PrimaDelayCalc::findNodeCount() for (ParasiticCapacitor *capacitor : parasitics_->capacitors(parasitic_network_)) { float cap = parasitics_->value(capacitor) * coupling_cap_multiplier_; ParasiticNode *node1 = parasitics_->node1(capacitor); - if (node1 - && !parasitics_->isExternal(node1)) { + if (node1 && !parasitics_->isExternal(node1)) { size_t node_idx = node_index_map_[node1]; node_capacitances_[node_idx] += cap; } ParasiticNode *node2 = parasitics_->node2(capacitor); - if (node2 - && !parasitics_->isExternal(node2)) { + if (node2 && !parasitics_->isExternal(node2)) { size_t node_idx = node_index_map_[node2]; node_capacitances_[node_idx] += cap; } @@ -496,9 +492,8 @@ PrimaDelayCalc::initCeffIdrvr() const ArcDcalcArg &dcalc_arg = (*dcalc_args_)[drvr_idx]; ceff_[drvr_idx] = load_cap_; // voltageTime is always for a rising waveform so 0.0v is initial voltage. - drvr_current_[drvr_idx] = - output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(), - ceff_[drvr_idx], 0.0); + drvr_current_[drvr_idx] = output_waveforms_[drvr_idx]->voltageCurrent( + dcalc_arg.inSlewFlt(), ceff_[drvr_idx], 0.0); } } @@ -617,8 +612,7 @@ PrimaDelayCalc::updateCeffIdrvr() double v2 = voltagePrev(node_idx); double dv = v1 - v2; if (drvr_rf_ == RiseFall::rise()) { - if (drvr_current != 0.0 - && dv > 0.0) { + if (drvr_current != 0.0 && dv > 0.0) { double ceff = drvr_current * time_step_ / dv; if (output_waveforms_[drvr_idx]->capAxis()->inBounds(ceff)) ceff_[drvr_idx] = ceff; @@ -627,13 +621,11 @@ PrimaDelayCalc::updateCeffIdrvr() // Whoa partner. Head'n for the weeds. drvr_current_[drvr_idx] = 0.0; else - drvr_current_[drvr_idx] = - output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(), - ceff_[drvr_idx], v1); + drvr_current_[drvr_idx] = output_waveforms_[drvr_idx]->voltageCurrent( + dcalc_arg.inSlewFlt(), ceff_[drvr_idx], v1); } else { - if (drvr_current != 0.0 - && dv < 0.0) { + if (drvr_current != 0.0 && dv < 0.0) { double ceff = drvr_current * time_step_ / dv; if (output_waveforms_[drvr_idx]->capAxis()->inBounds(ceff)) ceff_[drvr_idx] = ceff; @@ -643,10 +635,8 @@ PrimaDelayCalc::updateCeffIdrvr() drvr_current_[drvr_idx] = 0.0; } else - drvr_current_[drvr_idx] = - output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(), - ceff_[drvr_idx], - vdd_ - v1); + drvr_current_[drvr_idx] = output_waveforms_[drvr_idx]->voltageCurrent( + dcalc_arg.inSlewFlt(), ceff_[drvr_idx], vdd_ - v1); } } } @@ -657,10 +647,8 @@ PrimaDelayCalc::loadWaveformsFinished() for (auto pin_node : pin_node_map_) { size_t node_idx = pin_node.second; double v = voltage(node_idx); - if ((drvr_rf_ == RiseFall::rise() - && v < vh_ + (vdd_ - vh_) * .5) - || (drvr_rf_ == RiseFall::fall() - && (v > vl_ * .5))) { + if ((drvr_rf_ == RiseFall::rise() && v < vh_ + (vdd_ - vh_) * .5) + || (drvr_rf_ == RiseFall::fall() && (v > vl_ * .5))) { return false; } } @@ -678,12 +666,10 @@ PrimaDelayCalc::measureThresholds(double time) double v_prev = voltagePrev(node_idx); for (size_t m = 0; m < measure_threshold_count_; m++) { double th = measure_thresholds_[m]; - if ((v_prev < th && th <= v) - || (v_prev > th && th >= v)) { - double t_cross = time - time_step_ + (th - v_prev) * time_step_ / (v - v_prev); - debugPrint(debug_, "ccs_measure", 1, "node %lu cross %.2f %s", - node_idx, - th, + if ((v_prev < th && th <= v) || (v_prev > th && th >= v)) { + double t_cross = + time - time_step_ + (th - v_prev) * time_step_ / (v - v_prev); + debugPrint(debug_, "ccs_measure", 1, "node {} cross {:.2f} {}", node_idx, th, delayAsString(t_cross, this)); threshold_times_[node_idx][m] = t_cross; } @@ -722,14 +708,12 @@ PrimaDelayCalc::dcalcResults() size_t drvr_node = pin_node_map_[drvr_pin]; ThresholdTimes &drvr_times = threshold_times_[drvr_node]; float ref_time = output_waveforms_[drvr_idx]->referenceTime(dcalc_arg.inSlewFlt()); - ArcDelay gate_delay = drvr_times[threshold_vth] - ref_time; - Slew drvr_slew = std::abs(drvr_times[threshold_vh] - drvr_times[threshold_vl]); + double gate_delay = drvr_times[threshold_vth] - ref_time; + double drvr_slew = std::abs(drvr_times[threshold_vh] - drvr_times[threshold_vl]); dcalc_result.setGateDelay(gate_delay); dcalc_result.setDrvrSlew(drvr_slew); - debugPrint(debug_, "ccs_dcalc", 2, - "%s gate delay %s slew %s", - network_->pathName(drvr_pin), - delayAsString(gate_delay, this), + debugPrint(debug_, "ccs_dcalc", 2, "{} gate delay {} slew {}", + network_->pathName(drvr_pin), delayAsString(gate_delay, this), delayAsString(drvr_slew, this)); dcalc_result.setLoadCount(load_pin_index_map_->size()); @@ -739,10 +723,9 @@ PrimaDelayCalc::dcalcResults() size_t load_node = pin_node_map_[load_pin]; ThresholdTimes &wire_times = threshold_times_[load_node]; ThresholdTimes &drvr_times = threshold_times_[drvr_node]; - ArcDelay wire_delay = wire_times[threshold_vth] - drvr_times[threshold_vth]; - Slew load_slew = std::abs(wire_times[threshold_vh] - wire_times[threshold_vl]); - debugPrint(debug_, "ccs_dcalc", 2, - "load %s %s delay %s slew %s", + double wire_delay = wire_times[threshold_vth] - drvr_times[threshold_vth]; + double load_slew = std::abs(wire_times[threshold_vh] - wire_times[threshold_vl]); + debugPrint(debug_, "ccs_dcalc", 2, "load {} {} delay {} slew {}", network_->pathName(load_pin), drvr_rf_->shortName(), delayAsString(wire_delay, this), @@ -849,16 +832,18 @@ PrimaDelayCalc::primaReduce2() // Modified Gram-Schmidt orthonormalization for (size_t j = 0; j < k; j++) { - Eigen::MatrixXd H = Vq.block(0, j * port_count_, order_, port_count_).transpose() - * Vq.block(0, k * port_count_, order_, port_count_); + Eigen::MatrixXd H = + Vq.block(0, j * port_count_, order_, port_count_).transpose() + * Vq.block(0, k * port_count_, order_, port_count_); Vq.block(0, k * port_count_, order_, port_count_) = - Vq.block(0, k * port_count_, order_, port_count_) - Vq.block(0, j * port_count_, order_, port_count_) * H; + Vq.block(0, k * port_count_, order_, port_count_) + - Vq.block(0, j * port_count_, order_, port_count_) * H; } Eigen::MatrixXd Vq_k = Vq.block(0, k * port_count_, order_, port_count_); Eigen::HouseholderQR Vq_k_solver(Vq_k); Eigen::MatrixXd VqQ = Vq_k_solver.householderQ(); - Vq.block(0, k * port_count_, order_, port_count_) = - VqQ.block(0, 0, order_, port_count_); + Vq.block(0, k * port_count_, order_, port_count_) = + VqQ.block(0, 0, order_, port_count_); } Vq_.resize(order_, prima_order_); Vq_ = Vq.block(0, 0, order_, prima_order_); @@ -920,7 +905,8 @@ PrimaDelayCalc::reportGateDelay(const Pin *drvr_pin, if (model) { float in_slew1 = delayAsFloat(in_slew); return model->reportGateDelay(pinPvt(drvr_pin, scene, min_max), - in_slew1, load_cap, false, digits); + in_slew1, load_cap, min_max, + PocvMode::scalar, digits); } return ""; } @@ -956,8 +942,8 @@ Waveform PrimaDelayCalc::watchWaveform(const Pin *pin) { FloatSeq &voltages = watch_pin_values_[pin]; - TableAxisPtr time_axis = std::make_shared(TableAxisVariable::time, - FloatSeq(times_)); + TableAxisPtr time_axis = + std::make_shared(TableAxisVariable::time, FloatSeq(times_)); Table waveform(new FloatSeq(voltages), time_axis); return waveform; } @@ -968,7 +954,7 @@ void PrimaDelayCalc::reportMatrix(const char *name, MatrixSd &matrix) { - report_->reportLine("%s", name); + report_->report("{}", name); reportMatrix(matrix); } @@ -976,7 +962,7 @@ void PrimaDelayCalc::reportMatrix(const char *name, Eigen::MatrixXd &matrix) { - report_->reportLine("%s", name); + report_->report("{}", name); reportMatrix(matrix); } @@ -984,7 +970,7 @@ void PrimaDelayCalc::reportMatrix(const char *name, Eigen::VectorXd &matrix) { - report_->reportLine("%s", name); + report_->report("{}", name); reportMatrix(matrix); } @@ -992,22 +978,19 @@ void PrimaDelayCalc::reportVector(const char *name, std::vector &matrix) { - report_->reportLine("%s", name); + report_->report("{}", name); reportVector(matrix); } - + void PrimaDelayCalc::reportMatrix(MatrixSd &matrix) { for (Eigen::Index i = 0; i < matrix.rows(); i++) { std::string line = "| "; - for (Eigen::Index j = 0; j < matrix.cols(); j++) { - std::string entry = stdstrPrint("%10.3e", matrix.coeff(i, j)); - line += entry; - line += " "; - } + for (Eigen::Index j = 0; j < matrix.cols(); j++) + line += sta::format("{:10.3e}", matrix.coeff(i, j)) + " "; line += "|"; - report_->reportLineString(line); + report_->reportLine(line); } } @@ -1016,13 +999,10 @@ PrimaDelayCalc::reportMatrix(Eigen::MatrixXd &matrix) { for (Eigen::Index i = 0; i < matrix.rows(); i++) { std::string line = "| "; - for (Eigen::Index j = 0; j < matrix.cols(); j++) { - std::string entry = stdstrPrint("%10.3e", matrix.coeff(i, j)); - line += entry; - line += " "; - } + for (Eigen::Index j = 0; j < matrix.cols(); j++) + line += sta::format("{:10.3e}", matrix.coeff(i, j)) + " "; line += "|"; - report_->reportLineString(line); + report_->reportLine(line); } } @@ -1031,25 +1011,21 @@ PrimaDelayCalc::reportMatrix(Eigen::VectorXd &matrix) { std::string line = "| "; for (Eigen::Index i = 0; i < matrix.rows(); i++) { - std::string entry = stdstrPrint("%10.3e", matrix.coeff(i)); - line += entry; - line += " "; + std::string entry = + line += sta::format("{:10.3e}", matrix.coeff(i)) + " "; } line += "|"; - report_->reportLineString(line); + report_->reportLine(line); } void PrimaDelayCalc::reportVector(std::vector &matrix) { std::string line = "| "; - for (size_t i = 0; i < matrix.size(); i++) { - std::string entry = stdstrPrint("%10.3e", matrix[i]); - line += entry; - line += " "; - } + for (size_t i = 0; i < matrix.size(); i++) + line += sta::format("{:10.3e}", matrix[i]) + " "; line += "|"; - report_->reportLineString(line); + report_->reportLine(line); } -} // namespace +} // namespace sta diff --git a/doc/ApiChanges.txt b/doc/ApiChanges.txt index 23c9e11f..83759119 100644 --- a/doc/ApiChanges.txt +++ b/doc/ApiChanges.txt @@ -24,6 +24,19 @@ This file summarizes STA API changes for each release. +2026/03/12 +---------- + +The Report class used for reporting and error messages now uses std::format +instead of printf. + +sta::format is a wrapper for std::format that will compile on gcc8, which +centos7 uses and does not support std::format. + +stdstrPrint, strintPrint, stringAppend have been removed. Use sta::format. + +reportLineString is now reportLine + Release 3.0.0 2025/01/03 ------------------------ @@ -62,6 +75,8 @@ The Vector/Map/Set/UnorderedSet classes have been removed and replaced by the std containers. The member functions are now templated functions found in ContainerHelpers.hh. +The Graph slew_rf_count option is no longer supported. + Release 2.6.2 2025/03/30 ------------------------ diff --git a/doc/ChangeLog.txt b/doc/ChangeLog.txt index 8d695f63..bebf05b6 100644 --- a/doc/ChangeLog.txt +++ b/doc/ChangeLog.txt @@ -2,6 +2,135 @@ OpenSTA Timing Analyzer Release Notes ------------------------------------- This file summarizes user visible changes for each release. +See ApiChangeLog.txt for changes to the STA api. + +Release 3.0.1 2026/03/12 +------------------------ + +Statistical timing (SSTA) with Liberty LVF (Liberty Variation Format) +models is now supported. Statistical timing uses a probaility +distribution to represent a delay or slew ranther than a single +number. + +Normal and skew normal probability distributions are supported. + +SSTA is enabled with the sta_pocv_mode variaable. + + set sta_pocv_mode scalar|normal|skew_normal + +scalar mode is for non-SSTA analysis +normal mode uses gaussian normal distributions +skew_normal'mode is for skew normal LVF moment based distributions + +The target quantile of a delay probability distribution (confidence level) is +set with the sta_pocv_quantile variable. + + sta_pocv_quantile + +The default value is 3 standard deviations, or sigma. + +Use the variance field with report_checks or report_check_types to see +distribution parameters in timing reports. + +A command file for analyzing a design with statisical timing with an +LVF library is shown below. + +read_liberty lvf_library.lib.gz +read_verilog design.v +link_design top +create_clock -period 50 clk +set_input_delay -clock clk 1 {in1 in2} +set sta_pocv_mode skew_normal +report_checks -fields {slew variation input_pin variation} -digits 3 + +Startpoint: r2 (rising edge-triggered flip-flop clocked by clk) +Endpoint: r3 (rising edge-triggered flip-flop clocked by clk) +Path Group: clk +Path Type: max + + Slew Delay Variation Time Description +--------------------------------------------------------------------------- + 0.000 0.000 0.000 clock clk (rise edge) + 0.000 0.000 clock network delay (ideal) + 0.000 0.000 0.000 ^ r2/CK (FDPQ1) + 12.026 mean + 0.017 mean_shift + 0.366 std_dev + 0.000 skewness + 4.648 12.409 12.409 v r2/Q (FFQ1) + 4.648 0.000 12.409 v u1/A (BUF1) + 6.084 mean + 0.007 mean_shift + 0.188 std_dev + 0.000 skewness + 2.513 6.137 18.546 v u1/X (BUF1) + 2.513 0.000 18.546 v u2/A2 (AN21) + 6.447 mean + 0.008 mean_shift + 0.191 std_dev + 0.000 skewness + 2.565 6.497 25.043 v u2/X (AN21) + 2.565 0.000 25.043 v r3/D (FFQ1) + 25.043 data arrival time + + 0.000 50.000 50.000 clock clk (rise edge) + 0.000 50.000 clock network delay (ideal) + 0.000 50.000 clock reconvergence pessimism + 50.000 ^ r3/CK (FFQ1) + -9.376 40.624 library setup time + 40.624 data required time +--------------------------------------------------------------------------- + 40.624 data required time + -25.043 data arrival time +--------------------------------------------------------------------------- + 15.581 slack (MET) + + +The following commands now support a -report_variance arggument. + + report_arrival [-report_variance] + report_required [-report_variance] + report_slack [-report_variance] + report_slews [-report_variance] + report_edges [-report_variance] + +The following commands now support a -digits option. + + report_edges [-digits digits] + report_slews [-digits digits] + +The standard deviation for normal distributions is specified with the +following liberty timing groups. + + ocv_sigma_cell_rise + ocv_sigma_cell_fall + ocv_sigma_rise_transition + ocv_sigma_fall_transition + ocv_sigma_rise_constraint + ocv_sigma_fall_constraint + +LVF skew normal distributions are specified with liberty groups below. + + ocv_std_dev_cell_rise + ocv_std_dev_cell_fall + ocv_mean_shift_cell_rise + ocv_mean_shift_cell_fall + ocv_skewness_cell_rise + ocv_skewness_cell_fall + + ocv_std_dev_rise_transition + ocv_std_dev_fall_transition + ocv_skewness_rise_transition + ocv_skewness_fall_transition + ocv_mean_shift_rise_transition + ocv_mean_shift_fall_transition + + ocv_std_dev_rise_constraint + ocv_std_dev_fall_constraint + ocv_skewness_rise_constraint + ocv_skewness_fall_constraint + ocv_mean_shift_rise_constraint + ocv_mean_shift_fall_constraint 2026/02/24 ---------- diff --git a/doc/OpenSTA.fodt b/doc/OpenSTA.fodt index fb9ea3b6..56bfdfc2 100644 --- a/doc/OpenSTA.fodt +++ b/doc/OpenSTA.fodt @@ -1,24 +1,24 @@ - Parallax STA documentationJames Cherry5192025-03-17T12:59:52.4638705382010-07-31T21:07:002026-03-07T17:12:46.349252000P123DT1H24M11SLibreOffice/25.8.1.1$MacOSX_AARCH64 LibreOffice_project/54047653041915e595ad4e45cccea684809c77b5PDF files: James CherryJames Cherry12.00000falsefalsefalsefalse + Parallax STA documentationJames Cherry5272025-03-17T12:59:52.4638705382010-07-31T21:07:002026-03-13T08:23:12.816774000P123DT2H11M52SLibreOffice/25.8.1.1$MacOSX_AARCH64 LibreOffice_project/54047653041915e595ad4e45cccea684809c77b5PDF files: James CherryJames Cherry12.00000falsefalsefalsefalse - 1488348 - 1956 - 19290 - 17736 + 138335 + 12 + 21890 + 20512 true false view2 - 17619 - 1497110 - 1956 - 1488348 - 21244 - 1506082 + 5793 + 99330 + 12 + 138335 + 21900 + 158845 0 1 false @@ -89,7 +89,7 @@ false true false - 26953533 + 27526206 0 false @@ -198,7 +198,7 @@ - + @@ -4029,6 +4029,21 @@ + + + + + + + + + + + + + + + @@ -4175,267 +4190,289 @@ - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + - - + + + - - + + + - + - + - - + - - + + - - + - - + + - - + + - - + + - - + + - + - - + + - + - - + + - - + - - + + - + + - - + + - + - + - - + - + - + - + - + - + + - + - + + - - + + + - + - - + - + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + @@ -4444,864 +4481,883 @@ - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - + + - - + + + - - + - + - + - - - + + - + - - + + + - - + + - - + + - + - + - + - - - - - - - - + + + + + + + + - + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - + - - - + + + - - + + + - - + - + - - - + + - - + + - - + + - - - + + - - - + + - - + + - - + + - + + - + - - + + + - - + + - - + + + - + - + - - + + - - + + + - - + - - - - + - + + + + - - + + - - + + - - + + - + - - - - - + - - + + - + - + + + + - - + + - - + + + - - + - - + + - + - - + + + - + - - - - - + - - + + + + + + - - + + - - + + - + - - + + + - + - - - + + - - + + - + - - + + + - - - + + - - + + - - + - - + - - + + + - + - - + + - + - + - - + + - + - - + + + - - + + + - - + + + - + - - - + + - - - + + - - + + - + - + - - - - + - - + + - - - + + - - - + + + + + - + - + - + - + - - + + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + - + - - + + - - + + - - - + + - - - + + - - + + - - + - - - + + + - + - - + + + - + - - + + - + - - + - + - + - + - - + + + - - + + + - - + + + - + - - - + + - + - - - + + - + - + - - - - - - - + - + - + - + - - - + + - - + + + + + + + + + - + - + - - + + - + - - - - + - - + + + + + - + - - - - - - - + - + - + + + + + + + + - + + + + + - + - - + + + - - - - - + + - + + - - + + - + - + - - - + + - + + - - - - + - - - + + + - - - + + - - - + + + + + - - + - - - + + - - + + - + - - + + + - - + + - - + - + - - + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + - + - + - + @@ -5345,1044 +5401,1077 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -6518,85 +6607,101 @@ Variables85 - Command Line Arguments + Command Line Arguments The command line arguments for sta are shown below. sta -help show help and exit -version show version and exit -no_init do not read ~/.sta -no_splash do not print the splash message -threads count|max use count threads -exit exit after reading cmd_file cmd_file source cmd_file When OpenSTA starts up, commands are first read from the user initialization file ~/.sta if it exists. If a TCL command file cmd_file is specified on the command line, commands are read from the file and executed before entering an interactive TCL command interpreter. If -exit is specified the application exits after reading cmd_file. Use the TCL exit command to exit the application. The –threads option specifies how many parallel threads to use. Use –threads max to use one thread per processor. - Example Command Scripts + Example Command Scripts To read a design into OpenSTA use the read_liberty command to read Liberty library files. Next, read hierarchical structural Verilog files with the read_verilog command. The link_design command links the Verilog to the Liberty timing cells. Any number of Liberty and Verilog files can be read before linking the design. Delays used for timing analysis are calculated using the Liberty timing models. If no parasitics are read only the pin capacitances of the timing models are used in delay calculation. Use the read_spef command to read parasitics from an extractor, or read_sdf to use delays calculated by an external delay calculator. Timing constraints can be entered as TCL commands or read using the read_sdc command. The units used by OpenSTA for all command arguments and reports are taken from the first Liberty file that is read. Use the set_cmd_units command to override the default units. Use the report_units command to see the ccmmand units. - Timing Analysis using SDF + Timing Analysis using SDF A sample command file that reads a library and a Verilog netlist and reports timing checks is shown below. read_liberty example1_slow.libread_verilog example1.vlink_design topread_sdf example1.sdfcreate_clock -name clk -period 10 {clk1 clk2 clk3}set_input_delay -clock clk 0 {in1 in2}report_checks This example can be found in examples/sdf_delays.tcl. - Timing Analysis with Multiple Process Corners + Timing Analysis with Multiple Process Corners An example command script using three process corners and +/-10% min/max derating is shown below. read_liberty nangate45_slow.lib.gzread_liberty nangate45_typ.lib.gzread_liberty nangate45_fast.lib.gzread_verilog example1.link_design topset_timing_derate -early 0.9set_timing_derate -late 1.1create_clock -name clk -period 10 {clk1 clk2 clk3}set_input_delay -clock clk 0 {in1 in2}define_scene ss -liberty nangate45_slowdefine_scene tt -liberty nangate45_typdefine_scene ff -liberty nangate45_fast# report all scenesreport_checks -path_delay min_max# report typical scenereport_checks -scene tt This example can be found in examples/multi_corner.tcl. Other examples can be found in the examples directory. - Timing Analysis with Multiple Corners and Modes + Timing Analysis with Multiple Corners and Modes OpenSTA supports multi-corner, multi-mode analysis. Each corner/mode combination is called a “scene”. The SDC constraints in each mode describe a different operating mode, such as mission mode or scan mode. Each corner has min/max Liberty libraries and SPEF parasitics. A mode named “default” is initially created for SDC commands. It is deleted when a mode is defined with set_mode or read_sdc -mode. Similartly, a named “default” is initially created that is deleted when define_scene is used to define a scene. An example command script using two process corners two modes is shown below. read_liberty asap7_small_ff.lib.gzread_liberty asap7_small_ss.lib.gzread_verilog reg1_asap7.vlink_design topread_sdc -mode mode1 mcmm2_mode1.sdcread_sdc -mode mode2 mcmm2_mode2.sdcread_spef -name reg1_ff reg1_asap7.spefread_spef -name reg1_ss reg1_asap7_ss.spefdefine_scene scene1 -mode mode1 -liberty asap7_small_ff -spef reg1_ffdefine_scene scene2 -mode mode2 -liberty asap7_small_ss -spef reg1_ssreport_checks -scenes scene1report_checks -scenes scene2report_checks -group_path_count 4 This example can be found in examples/mcmm3.tcl.In the example show above the SDC for the modes is in separate files. Alternatively, the SDC can be defined in the command file using the set_mode command between SDC command groups. set_mode mode1create_clock -name m1_clk -period 1000 {clk1 clk2 clk3}set_input_delay -clock m1_clk 100 {in1 in2}set_mode mode2create_clock -name m2_clk -period 500 {clk1 clk3}set_output_delay -clock m2_clk 100 out - Power Analysis - OpenSTA also supports static power analysis with the report_power command. Probabalistic switching activities are propagated from the input ports to determine switching activities for internal pins. - read_liberty sky130hd_tt.libread_verilog gcd_sky130hd.vlink_design gcdread_sdc gcd_sky130hd.sdcread_spef gcd_sky130hd.spefset_power_activity -input -activity 0.1set_power_activity -input_port reset -activity 0report_power - In this example the activity for all inputs is set to 0.1, and then the activity for the reset signal is set to zero because it does not switch during steady state operation. - Group Internal Switching Leakage Total Power Power Power Power (Watts)----------------------------------------------------------------Sequential 3.27e-04 7.87e-05 2.96e-10 4.06e-04 36.4%Combinational 2.34e-04 3.10e-04 6.95e-10 5.43e-04 48.7%Clock 4.68e-05 1.20e-04 2.30e-11 1.67e-04 15.0%Macro 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0%Pad 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0%----------------------------------------------------------------Total 6.07e-04 5.09e-04 1.01e-09 1.12e-03 100.0% 54.4% 45.6% 0.0% - This example can be found in examples/power.tcl. - Gate level simulation results can be used to get a more accurate power estimate. For example, the Icarus verilog simulator can be used to run the the test bench examples/gcd_tb.v for the gcd design in the previous example. + Statistical Timing Analysis + OpenSTA also supports statistical timing .anallysis with Liberty Variation Format (LVF) libraries. Statistical timing uses a probaility distribution to represent a delay or slew ranther than a single number. + Normal and skew normal probability distributions are supported. SSTA is enabled with the sta_pocv_mode variaable. + set sta_pocv_mode scalar|normal|skew_normalscalar mode is for non-SSTA analysisnormal mode uses gaussian normal distributionsskew_normal mode is for skew normal LVF moment based distributions + The target quantile of a delay probability distribution (confidence level) is set with the sta_pocv_quantile variable. + set sta_pocv_quantile <float> + The default value is 3 standard deviations, or sigma. + Use the variance field with the report_checks and report_check_types commands to see distribution parameters in timing reports. + A command file for analyzing a design with statisical timing is shown below. + read_liberty lvf_library.lib.gzread_verilog design.vlink_design topcreate_clock -period 50 clkset_input_delay -clock clk 1 {in1 in2}set sta_pocv_mode skew_normalreport_checks -fields {slew variation input_pin variation} -digits 3 + Startpoint: r2 (rising edge-triggered flip-flop clocked by clk)Endpoint: r3 (rising edge-triggered flip-flop clocked by clk)Path Group: clkPath Type: max Slew Delay Variation Time Description--------------------------------------------------------------------------- 0.000 0.000 0.000 clock clk (rise edge) 0.000 0.000 clock network delay (ideal) 0.000 0.000 0.000 ^ r2/CK (FDPQ1) 12.026 mean 0.017 mean_shift 0.366 std_dev 0.000 skewness 4.648 12.409 12.409 v r2/Q (FFQ1) 4.648 0.000 12.409 v u1/A (BUF1) 6.084 mean 0.007 mean_shift 0.188 std_dev 0.000 skewness 2.513 6.137 18.546 v u1/X (BUF1) 2.513 0.000 18.546 v u2/A2 (AN21) 6.447 mean 0.008 mean_shift 0.191 std_dev 0.000 skewness 2.565 6.497 25.043 v u2/X (AN21) 2.565 0.000 25.043 v r3/D (FFQ1) 25.043 data arrival time 0.000 50.000 50.000 clock clk (rise edge) 0.000 50.000 clock network delay (ideal) 0.000 50.000 clock reconvergence pessimism 50.000 ^ r3/CK (FFQ1) -9.376 40.624 library setup time 40.624 data required time--------------------------------------------------------------------------- 40.624 data required time -25.043 data arrival time--------------------------------------------------------------------------- 15.581 slack (MET) + The standard deviation for normal distributions is specified with the following liberty timing groups. + ocv_sigma_cell_riseocv_sigma_cell_fallocv_sigma_rise_transitionocv_sigma_fall_transitionocv_sigma_rise_constraintocv_sigma_fall_constraint + LVF skew normal distributions are specified with liberty groups below. + ocv_std_dev_cell_riseocv_std_dev_cell_fallocv_mean_shift_cell_riseocv_mean_shift_cell_fallocv_skewness_cell_riseocv_skewness_cell_fallocv_std_dev_rise_transitionocv_std_dev_fall_transitionocv_skewness_rise_transitionocv_skewness_fall_transitionocv_mean_shift_rise_transitionocv_mean_shift_fall_transitionocv_std_dev_rise_constraintocv_std_dev_fall_constraintocv_skewness_rise_constraintocv_skewness_fall_constraintocv_mean_shift_rise_constraintocv_mean_shift_fall_constraint + + Power Analysis + OpenSTA also supports static power analysis with the report_power command. Probabalistic switching activities are propagated from the input ports to determine switching activities for internal pins. + read_liberty sky130hd_tt.libread_verilog gcd_sky130hd.vlink_design gcdread_sdc gcd_sky130hd.sdcread_spef gcd_sky130hd.spefset_power_activity -input -activity 0.1set_power_activity -input_port reset -activity 0report_power + In this example the activity for all inputs is set to 0.1, and then the activity for the reset signal is set to zero because it does not switch during steady state operation. + Group Internal Switching Leakage Total Power Power Power Power (Watts)----------------------------------------------------------------Sequential 3.27e-04 7.87e-05 2.96e-10 4.06e-04 36.4%Combinational 2.34e-04 3.10e-04 6.95e-10 5.43e-04 48.7%Clock 4.68e-05 1.20e-04 2.30e-11 1.67e-04 15.0%Macro 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0%Pad 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0%----------------------------------------------------------------Total 6.07e-04 5.09e-04 1.01e-09 1.12e-03 100.0% 54.4% 45.6% 0.0% + This example can be found in examples/power.tcl. + Gate level simulation results can be used to get a more accurate power estimate. For example, the Icarus verilog simulator can be used to run the the test bench examples/gcd_tb.v for the gcd design in the previous example. iverilog -o gcd_tb gcd_tb.vvvp gcd_tb - The test bench writes the VCD (Value Change Data) file gcd_sky130hd.vcd which can then be read with the read_vcd command. - read_liberty sky130hd_tt.libread_verilog gcd_sky130hd.vlink_design gcdread_sdc gcd_sky130hd.sdcread_spef gcd_sky130hd.spefread_vcd -scope gcd_tb/gcd1 gcd_sky130hd.vcd.gzreport_power - This example can be found in examples/power_vcd.tcl. - Note that in this simple example design simulation based activities does not significantly change the results. - TCL Interpreter + The test bench writes the VCD (Value Change Data) file gcd_sky130hd.vcd which can then be read with the read_vcd command. + read_liberty sky130hd_tt.libread_verilog gcd_sky130hd.vlink_design gcdread_sdc gcd_sky130hd.sdcread_spef gcd_sky130hd.spefread_vcd -scope gcd_tb/gcd1 gcd_sky130hd.vcd.gzreport_power + This example can be found in examples/power_vcd.tcl. + Note that in this simple example design simulation based activities does not significantly change the results. + TCL Interpreter Keyword arguments to commands may be abbreviated. For example, report_checks -unique is equivalent to the following command. - report_checks -unique_paths_to_endpoint - The help command lists matching commands and their arguments. - > help report*report_annotated_check [-setup] [-hold] [-recovery] [-removal] [-nochange] [-width] [-period] [-max_skew] [-max_lines liness] [-list_annotated]group_path_count [-list_not_annotated] [-constant_arcs]report_annotated_delay [-cell] [-net] [-from_in_ports] [-to_out_ports] [-max_lines liness] [-list_annotated] [-list_not_annotated] [-constant_arcs]report_arrival pinreport_check_types [-violators] [-verbose] [-scene scene] [-format slack_only|end] [-max_delay] [-min_delay] [-recovery] [-removal] [-clock_gating_setup] [-clock_gating_hold] [-max_slew] [-min_slew] [-max_fanout] [-min_fanout] [-max_capacitance] [-min_capacitance [-min_pulse_width] [-min_period] [-max_skew] [-net net] [-digits digits [-no_line_splits] [> filename] [>> filename]report_checks [-from from_list|-rise_from from_list|-fall_from from_list] [-through through_list|-rise_through through_list|-fall_through through_list] [-to to_list|-rise_to to_list|-fall_to to_list] [-unconstrained] [-path_delay min|min_rise|min_fall|max|max_rise|max_fall|min_max] [-scene scene] [-group_path_count path_count] [-endpoint_path_count path_count] [-unique_paths_to_endpoint] [-slack_max slack_max] [-slack_min slack_min] [-sort_by_slack] [-path_group group_name] [-format full|full_clock|full_clock_expanded|short|end|summary]... - Many reporting commands support redirection of the output to a file much like a Unix shell. - report_checks -to out1 > path.logreport_checks -to out2 >> path.log - Debugging Timing - Here are some guidelines for debugging your design if static timing does not report any paths, or does not report the expected paths. - Debugging timing problems generally involves using the following commands to follow the propagation of arrival times from a known arrival downstream to understand why the arrival times are not propagating: - report_edgesreport_arrivalsreport_net - report_edges -from can be used to walk forward and report_edges -to to walk backward in the netlist/timing graph. report_arrivals shows the min/max rise/fall arrival times with respect to each clock that has a path to the pin. report_net shows connections to a net across hierarchy levels. + report_checks -unique_paths_to_endpoint + The help command lists matching commands and their arguments. + > help report*report_annotated_check [-setup] [-hold] [-recovery] [-removal] [-nochange] [-width] [-period] [-max_skew] [-max_lines liness] [-list_annotated]group_path_count [-list_not_annotated] [-constant_arcs]report_annotated_delay [-cell] [-net] [-from_in_ports] [-to_out_ports] [-max_lines liness] [-list_annotated] [-list_not_annotated] [-constant_arcs]report_arrival pinreport_check_types [-violators] [-verbose] [-scene scene] [-format slack_only|end] [-max_delay] [-min_delay] [-recovery] [-removal] [-clock_gating_setup] [-clock_gating_hold] [-max_slew] [-min_slew] [-max_fanout] [-min_fanout] [-max_capacitance] [-min_capacitance [-min_pulse_width] [-min_period] [-max_skew] [-net net] [-digits digits [-no_line_splits] [> filename] [>> filename]report_checks [-from from_list|-rise_from from_list|-fall_from from_list] [-through through_list|-rise_through through_list|-fall_through through_list] [-to to_list|-rise_to to_list|-fall_to to_list] [-unconstrained] [-path_delay min|min_rise|min_fall|max|max_rise|max_fall|min_max] [-scene scene] [-group_path_count path_count] [-endpoint_path_count path_count] [-unique_paths_to_endpoint] [-slack_max slack_max] [-slack_min slack_min] [-sort_by_slack] [-path_group group_name] [-format full|full_clock|full_clock_expanded|short|end|summary]... + Many reporting commands support redirection of the output to a file much like a Unix shell. + report_checks -to out1 > path.logreport_checks -to out2 >> path.log + Debugging Timing + Here are some guidelines for debugging your design if static timing does not report any paths, or does not report the expected paths. + Debugging timing problems generally involves using the following commands to follow the propagation of arrival times from a known arrival downstream to understand why the arrival times are not propagating: + report_edgesreport_arrivalsreport_net + report_edges -from can be used to walk forward and report_edges -to to walk backward in the netlist/timing graph. report_arrivals shows the min/max rise/fall arrival times with respect to each clock that has a path to the pin. report_net shows connections to a net across hierarchy levels. No paths found - The report_checks command only reports paths that are constrained by timing checks or SDC commands such as set_output_delay. If the design has only combinational logic (no registers or latches), there are no timing checks, so no paths are reported. Use the -unconstrained option to report_checks to see unconstrained paths. + The report_checks command only reports paths that are constrained by timing checks or SDC commands such as set_output_delay. If the design has only combinational logic (no registers or latches), there are no timing checks, so no paths are reported. Use the -unconstrained option to report_checks to see unconstrained paths. % report_checks -unconstrained - If the design is sequential (has registers or latches) and no paths are reported, it is likely that there is a problem with the clock propagation. Check the timing at an register in the design with the report_arrivals command. - % report_arrivals r1/CP (clk ^) r 0.00:0.00 f INF:-INF (clk v) r INF:-INF f 5.00:5.00 - In this example the rising edge of the clock "clk" causes the rising arrival min:max time at 0.00, and the falling edge arrives at 5.00. Since the rising edge of the clock causes the rising edge of the register clock pin, the clock path is positive unate. - The clock path should be positive or negative unate. Something is probably wrong with the clock network if it is non-unate. A non-unate clock path will report arrivals similar to the foillowing: + If the design is sequential (has registers or latches) and no paths are reported, it is likely that there is a problem with the clock propagation. Check the timing at an register in the design with the report_arrivals command. + % report_arrivals r1/CP (clk ^) r 0.00:0.00 f INF:-INF (clk v) r INF:-INF f 5.00:5.00 + In this example the rising edge of the clock "clk" causes the rising arrival min:max time at 0.00, and the falling edge arrives at 5.00. Since the rising edge of the clock causes the rising edge of the register clock pin, the clock path is positive unate. + The clock path should be positive or negative unate. Something is probably wrong with the clock network if it is non-unate. A non-unate clock path will report arrivals similar to the foillowing: % report_arrivals r1/CP (clk ^) r 0.00:0.00 f 0.00:0.00 (clk v) r 5.00:5.00 f 5.00:5.00 - Notice that each clock edge causes both rise and fall arrivals at the register clock pin. - If there are no paths to the register clock pin, nothing is printed. Use the report_edges -to command to find the gate driving the clock pin. - % report_edges -to r1/CPi1/ZN -> CP wire ^ -> ^ 0.00:0.00 v -> v 0.00:0.00 - This shows that the gate/pin i1/ZN is driving the clock pin. The report_edges -to commond can be used to walk backward or forward through the netlist one gate/net at a time. By checking the arrivals with the report_arrival command you can determine where the path is broken. - No path reported an endpoint - In order for a timing check to be reported, there must be an arrival time at the data pin (the constrained pin) as well as the timing check clock pin. If report_checks -to a register input does not report any paths, check that the input is constrained by a timing check with report_edges -to. + Notice that each clock edge causes both rise and fall arrivals at the register clock pin. + If there are no paths to the register clock pin, nothing is printed. Use the report_edges -to command to find the gate driving the clock pin. + % report_edges -to r1/CPi1/ZN -> CP wire ^ -> ^ 0.00:0.00 v -> v 0.00:0.00 + This shows that the gate/pin i1/ZN is driving the clock pin. The report_edges -to commond can be used to walk backward or forward through the netlist one gate/net at a time. By checking the arrivals with the report_arrival command you can determine where the path is broken. + No path reported an endpoint + In order for a timing check to be reported, there must be an arrival time at the data pin (the constrained pin) as well as the timing check clock pin. If report_checks -to a register input does not report any paths, check that the input is constrained by a timing check with report_edges -to. % report_edges -to r1/DCP -> D hold ^ -> ^ -0.04:-0.04 ^ -> v -0.03:-0.03CP -> D setup ^ -> ^ 0.09:0.0 ^ -> v 0.08:0.08in1 -> D wire ^ -> ^ 0.00:0.00 v -> v 0.00:0.00 - This reports the setup and hold checks for the D pin of r1. - Next, check the arrival times at the D and CP pins of the register with report_arrivals. + This reports the setup and hold checks for the D pin of r1. + Next, check the arrival times at the D and CP pins of the register with report_arrivals. % report_arrivals r1/D (clk1 ^) r 1.00:1.00 f 1.00:1.00% report_arrivals r1/CP (clk1 ^) r 0.00:0.00 f INF:-INF (clk1 v) r INF:-INF f 5.00:5.00 - If there are no arrivals on an input port of the design, use the set_input_delay command to specify the arrival times on the port. - Commands + If there are no arrivals on an input port of the design, use the set_input_delay command to specify the arrival times on the port. + Commands - all_clocks + all_clocks - + @@ -6606,16 +6711,15 @@ - all_inputs + all_inputs - [-no_clocks] + [-no_clocks] - - -no_clocks + -no_clocks Exclude inputs defined as clock sources. @@ -6628,10 +6732,10 @@ - all_outputs + all_outputs - + @@ -6639,95 +6743,95 @@ + - all_registers + all_registers - [-clock clock_names][-cells | -data_pins | -clock_pins | -async_pins | ‑output_pins][-level_sensitive][-edge_triggered] + [-clock clock_names][-cells | -data_pins | -clock_pins | -async_pins | ‑output_pins][-level_sensitive][-edge_triggered] - -clock clock_names + -clock clock_names - A list of clock names. Only registers clocked by these clocks are returned. + A list of clock names. Only registers clocked by these clocks are returned. - -cells + -cells - Return a list of register instances. + Return a list of register instances. - -data_pins + -data_pins - Return the register data pins. + Return the register data pins. - -clock_pins + -clock_pins - Return the register clock pins. + Return the register clock pins. - -async_pins + -async_pins - Return the register set/clear pins. + Return the register set/clear pins. - -output_pins + -output_pins - Return the register output pins. + Return the register output pins. - -level_sensitive + -level_sensitive - Return level-sensitive latches. + Return level-sensitive latches. - -edge_triggered + -edge_triggered - Return edge-triggered registers. + Return edge-triggered registers. - The all_registers command returns a list of register instances or register pins in the design. Options allow the list of registers to be restricted in various ways. The -clock keyword restrcts the registers to those that are clocked by a set of clocks. The -cells option returns the list of registers or latches (the default). The -‑data_pins, -clock_pins, -async_pins and -output_pins options cause all_registers to return a list of register pins rather than instances. + The all_registers command returns a list of register instances or register pins in the design. Options allow the list of registers to be restricted in various ways. The -clock keyword restrcts the registers to those that are clocked by a set of clocks. The -cells option returns the list of registers or latches (the default). The -‑data_pins, -clock_pins, -async_pins and -output_pins options cause all_registers to return a list of register pins rather than instances. - - check_setup + check_setup - [-verbose][-unconstrained_endpoints][-multiple_clock][-no_clock][-no_input_delay][-loops][-generated_clocks][> filename][>> filename] + [-verbose][-unconstrained_endpoints][-multiple_clock][-no_clock][-no_input_delay][-loops][-generated_clocks][> filename][>> filename] - -verbose + -verbose Show offending objects rather than just error counts. @@ -6735,7 +6839,7 @@ - -unconstrained_endpoints + -unconstrained_endpoints Check path endpoints for timing constraints (timing check or set_output_delay). @@ -6743,15 +6847,16 @@ - -multiple_clock + -multiple_clock Check register/latch clock pins for multiple clocks. + - -no_clock + -no_clock Check register/latch clock pins for a clock. @@ -6759,7 +6864,7 @@ - -no_input_delay + -no_input_delay Check for inputs that do not have a set_input_delay command. @@ -6767,7 +6872,7 @@ - -loops + -loops Check for combinational logic loops. @@ -6775,28 +6880,28 @@ - -generated_clocks + -generated_clocks Check that generated clock source pins have been defined as clocks. - The check_setup command performs sanity checks on the design. Individual checks can be performed with the keywords. If no check keywords are specified all checks are performed. Checks that fail are reported as warnings. If no checks fail nothing is reported. The command returns 1 if there are no warnings for use in scripts. + The check_setup command performs sanity checks on the design. Individual checks can be performed with the keywords. If no check keywords are specified all checks are performed. Checks that fail are reported as warnings. If no checks fail nothing is reported. The command returns 1 if there are no warnings for use in scripts. - connect_pin + connect_pin - netport|pin + netport|pin - net + net A net to add connections to. @@ -6804,7 +6909,7 @@ - port + port A port to connect to net. @@ -6812,29 +6917,28 @@ - Pin + Pin A pin to connect to net. - The connect_pin command connects a port or instance pin to a net. + The connect_pin command connects a port or instance pin to a net. - - create_clock + create_clock - -period period[-name clock_name][-waveform edge_list][-add][pin_list] + -period period[-name clock_name][-waveform edge_list][-add][pin_list] - -period period + -period period The clock period. @@ -6842,7 +6946,7 @@ - -name clock_name + -name clock_name The name of the clock. @@ -6850,7 +6954,7 @@ - -waveform edge_list + -waveform edge_list A list of edge rise and fall time. @@ -6858,15 +6962,15 @@ - -add + -add - Add this clock to the clocks on pin_list. + Add this clock to the clocks on pin_list. - pin_list + pin_list A list of pins driven by the clock. @@ -6874,28 +6978,28 @@ The create_clock command defines the waveform of a clock used by the design. - If no pin_list is specified the clock is virtual. A virtual clock can be refered to by name in input arrival and departure time commands but is not attached to any pins in the design. - If no clock name is specified the name of the first pin is used as the clock name. + If no pin_list is specified the clock is virtual. A virtual clock can be refered to by name in input arrival and departure time commands but is not attached to any pins in the design. + If no clock name is specified the name of the first pin is used as the clock name. If a wavform is not specified the clock rises at zero and falls at half the clock period. The waveform is a list with time the clock rises as the first element and the time it falls as the second element. If a clock is already defined on a pin the clock is redefined using the new clock parameters. If multiple clocks drive the same pin, use the -add option to prevent the existing definition from being overwritten. The following command creates a clock with a period of 10 time units that rises at time 0 and falls at 5 time units on the pin named clk1. create_clock -period 10 clk1 The following command creates a clock with a period of 10 time units that is high at time zero, falls at time 2 and rises at time 8. The clock drives three pins named clk1, clk2, and clk3. - create_clock -period 10 -waveform {8 2} -name clk {clk1 clk2 clk3} + create_clock -period 10 -waveform {8 2} -name clk {clk1 clk2 clk3} - create_generated_clock + create_generated_clock - [-name clock_name]-source master_pin[-master_clock master_clock][-divide_by divisor][-multiply_by multiplier][-duty_cycle duty_cycle][-invert][-edges edge_list][-edge_shift shift_list][-add]pin_list + [-name clock_name]-source master_pin[-master_clock master_clock][-divide_by divisor][-multiply_by multiplier][-duty_cycle duty_cycle][-invert][-edges edge_list][-edge_shift shift_list][-add]pin_list - -name clock_name + -name clock_name The name of the generated clock. @@ -6903,39 +7007,39 @@ - -source master_pin + -source master_pin - A pin or port in the fanout of the master clock that is the source of the generated clock. + A pin or port in the fanout of the master clock that is the source of the generated clock. - -master_clock master_clock + -master_clock master_clock - Use -master_clock to specify which source clock to use when multiple clocks are present on master_pin. + Use -master_clock to specify which source clock to use when multiple clocks are present on master_pin. - -divide_by divisor + -divide_by divisor - Divide the master clock period by divisor. + Divide the master clock period by divisor. - -multiply_by multiplier + -multiply_by multiplier - Multiply the master clock period by multiplier. + Multiply the master clock period by multiplier. - -duty_cycle duty_cycle + -duty_cycle duty_cycle The percent of the period that the generated clock is high (between 0 and 100). @@ -6943,23 +7047,24 @@ - -invert + -invert Invert the master clock. + - -edges edge_list + -edges edge_list - List of master clock edges to use in the generated clock. Edges are numbered from 1. edge_list must be 3 edges long. + List of master clock edges to use in the generated clock. Edges are numbered from 1. edge_list must be 3 edges long. - -edge_shift shift_list + -edge_shift shift_list Not supported. @@ -6967,46 +7072,46 @@ - -add + -add - Add this clock to the existing clocks on pin_list. + Add this clock to the existing clocks on pin_list. - pin_list + pin_list - A list of pins driven by the generated clock. + A list of pins driven by the generated clock. The create_generated_clock command is used to generate a clock from an existing clock definition. It is used to model clock generation circuits such as clock dividers and phase locked loops. The -divide_by, -multiply_by and -edges arguments are mutually exclusive. - The -multiply_by option is used to generate a higher frequency clock from the source clock. The period of the generated clock is divided by multiplier. The clock multiplier must be a positive integer. If a duty cycle is specified the generated clock rises at zero and falls at period * duty_cycle / 100. If no duty cycle is specified the source clock edge times are divided by multiplier. + The -multiply_by option is used to generate a higher frequency clock from the source clock. The period of the generated clock is divided by multiplier. The clock multiplier must be a positive integer. If a duty cycle is specified the generated clock rises at zero and falls at period * duty_cycle / 100. If no duty cycle is specified the source clock edge times are divided by multiplier. The -divide_by option is used to generate a lower frequency clock from the source clock. The clock divisor must be a positive integer. If the clock divisor is a power of two the source clock period is multiplied by divisor, the clock rise time is the same as the source clock, and the clock fall edge is one half period later. If the clock divisor is not a power of two the source clock waveform edge times are multiplied by divisor. The -edges option forms the generated clock waveform by selecting edges from the source clock waveform. If the -invert option is specified the waveform derived above is inverted. If a clock is already defined on a pin the clock is redefined using the new clock parameters. If multiple clocks drive the same pin, use the -add option to prevent the existing definition from being overwritten. - In the example show below generates a clock named gclk1 on register output pin r1/Q by dividing it by four. + In the example show below generates a clock named gclk1 on register output pin r1/Q by dividing it by four. create_clock -period 10 -waveform {1 8} clk1create_generated_clock -name gclk1 -source clk1 -divide_by 4 r1/Q The generated clock has a period of 40, rises at time 1 and falls at time 21. In the example shown below the duty cycle is used to define the derived clock waveform. create_generated_clock -name gclk1 -source clk1 -duty_cycle 50 \ -multiply_by 2 r1/Q The generated clock has a period of 5, rises at time .5 and falls at time 3. In the example shown below the first, third and fifth source clock edges are used to define the derived clock waveform. - create_generated_clock -name gclk1 -source clk1 -edges {1 3 5} r1/Q + create_generated_clock -name gclk1 -source clk1 -edges {1 3 5} r1/Q The generated clock has a period of 20, rises at time 1 and falls at time 11. - create_voltage_area + create_voltage_area - [-name name][-coordinate coordinates][-guard_band_x guard_x][-guard_band_y guard_y]cells + [-name name][-coordinate coordinates][-guard_band_x guard_x][-guard_band_y guard_y]cells @@ -7016,90 +7121,91 @@ - current_design + current_design - [design] + [design] - + - current_instance + current_instance - [instance] + [instance] - instance + instance - Not supported. + Not supported. - + - define_scene + define_scene - -mode mode_name -liberty liberty_files|-liberty_min liberty_min_files -liberty_max liberty_max_files-spef spef_file| -spef_min spef_min_file -spef_max spef_max_file + -mode mode_name -liberty liberty_files|-liberty_min liberty_min_files -liberty_max liberty_max_files-spef spef_file| -spef_min spef_min_file -spef_max spef_max_file - mode_name + mode_name - The SDC mode to use. + The SDC mode to use. - liberty_files + liberty_files - List of Liberty files to use. + List of Liberty files to use. - spef_file + spef_file - The SPEF parasitics file to use. + The SPEF parasitics file to use. - The define_scene command defines a scene for a mode (SDC), liberty files and spef parasitics. Define scenes after reading Liberty libraries and SPEF parasitics.Liberty files are specifiec with the name of the liberty library or the filename of the liberty file. If a filename is used, it must be the same as the filename used to read the library with read_liberty.. - Use get_scenes to find defined scenes. + The define_scene command defines a scene for a mode (SDC), liberty files and spef parasitics. Define scenes after reading Liberty libraries and SPEF parasitics.Liberty files are specifiec with the name of the liberty library or the filename of the liberty file. If a filename is used, it must be the same as the filename used to read the library with read_liberty.. + Use get_scenes to find defined scenes. + - delete_clock + delete_clock - [-all] clocks + [-all] clocks - clocks + clocks - A list of clocks to remove. + A list of clocks to remove. @@ -7109,26 +7215,26 @@ - delete_from_list + delete_from_list - list objects + list objects - list + list - A list of objects. + A list of objects. - objects + objects - A list of objects to delete from list. + A list of objects to delete from list. @@ -7136,21 +7242,20 @@ - - delete_generated_clock + delete_generated_clock - [-all] clocks + [-all] clocks - clocks + clocks - A list of generated clocks to remove. + A list of generated clocks to remove. @@ -7160,18 +7265,18 @@ - delete_instance + delete_instance - instance + instance - instance + instance - Instance to delete. + Instance to delete. @@ -7181,18 +7286,18 @@ - delete_net + delete_net - net + net - net + net - Net to delete. + Net to delete. @@ -7202,23 +7307,23 @@ - disconnect_pin + disconnect_pin - netport | pin | -all + netport | pin | -all - net + net - The net to disconnect pins from. + The net to disconnect pins from. - port + port A port to connect to net. @@ -7226,18 +7331,19 @@ - pin + pin A pin to connect to net. + - -all + -all - Disconnect all pins from the net. + Disconnect all pins from the net. @@ -7247,10 +7353,10 @@ - elapsed_run_time + elapsed_run_time - + @@ -7258,99 +7364,98 @@ - - find_timing_paths + find_timing_paths - [-from from_list |-rise_from from_list |-fall_from from_list][-through through_list |-rise_through through_list |-fall_through through_list][-to to_list |-rise_to to_list |-fall_to to_list][-unconstrained][-path_delay min|min_rise|min_fall |max|max_rise|max_fall |min_max][-group_path_count path_count][-endpoint_path_count endpoint_path_count][-unique_paths_to_endpoint][-scene scene][-slack_max max_slack][-slack_min min_slack][-sort_by_slack][-path_group groups] + [-from from_list |-rise_from from_list |-fall_from from_list][-through through_list |-rise_through through_list |-fall_through through_list][-to to_list |-rise_to to_list |-fall_to to_list][-unconstrained][-path_delay min|min_rise|min_fall |max|max_rise|max_fall |min_max][-group_path_count path_count][-endpoint_path_count endpoint_path_count][-unique_paths_to_endpoint][-scene scene][-slack_max max_slack][-slack_min min_slack][-sort_by_slack][-path_group groups] - -from from_list + -from from_list - Return paths from a list of clocks, instances, ports, register clock pins, or latch data pins. + Return paths from a list of clocks, instances, ports, register clock pins, or latch data pins. - -rise_from from_list + -rise_from from_list - Return paths from the rising edge of clocks, instances, ports, register clock pins, or latch data pins. + Return paths from the rising edge of clocks, instances, ports, register clock pins, or latch data pins. - -fall_from from_list + -fall_from from_list - Return paths from the falling edge of clocks, instances, ports, register clock pins, or latch data pins. + Return paths from the falling edge of clocks, instances, ports, register clock pins, or latch data pins. - -through through_list + -through through_list - Return paths through a list of instances, pins or nets. + Return paths through a list of instances, pins or nets. - -rise_through through_list + -rise_through through_list - Return rising paths through a list of instances, pins or nets. - - - - - -fall_through through_list - - - Return falling paths through a list of instances, pins or nets. - - - - - -to to_list - - - Return paths to a list of clocks, instances, ports or pins. - - - - - -rise_to to_list - - - Return rising paths to a list of clocks, instances, ports or pins. - - - - - -fall_to to_list - - - Return falling paths to a list of clocks, instances, ports or pins. - - - - - -unconstrained - - - Report unconstrained paths also. + Return rising paths through a list of instances, pins or nets. - -path_delay min + -fall_through through_list + + + Return falling paths through a list of instances, pins or nets. + + + + + -to to_list + + + Return paths to a list of clocks, instances, ports or pins. + + + + + -rise_to to_list + + + Return rising paths to a list of clocks, instances, ports or pins. + + + + + -fall_to to_list + + + Return falling paths to a list of clocks, instances, ports or pins. + + + + + -unconstrained + + + Report unconstrained paths also. + + + + + -path_delay min Return min path (hold) checks. @@ -7358,7 +7463,7 @@ - -path_delay min_rise + -path_delay min_rise Return min path (hold) checks for rising endpoints. @@ -7366,7 +7471,7 @@ - -path_delay min_fall + -path_delay min_fall Return min path (hold) checks for falling endpoints. @@ -7374,7 +7479,7 @@ - -path_delay max + -path_delay max Return max path (setup) checks. @@ -7382,7 +7487,7 @@ - -path_delay max_rise + -path_delay max_rise Return max path (setup) checks for rising endpoints. @@ -7390,7 +7495,7 @@ - -path_delay max_fall + -path_delay max_fall Return max path (setup) checks for falling endpoints. @@ -7398,7 +7503,7 @@ - -path_delay min_max + -path_delay min_max Return max and max path (setup and hold) checks. @@ -7406,23 +7511,23 @@ - -group_path_count path_count + -group_path_count path_count - The number of paths to return in each path group. + The number of paths to return in each path group. - -endpoint_path_count endpoint_path_count + -endpoint_path_count endpoint_path_count - The number of paths to return for each endpoint. + The number of paths to return for each endpoint. - ‑unique_paths_to_endpoint + ‑unique_paths_to_endpoint Return multiple paths to an endpoint that traverse different pins without showing multiple paths with different rise/fall transitions. @@ -7430,7 +7535,7 @@ - -scene scene + -scene scene Return paths for one process corner. @@ -7438,109 +7543,108 @@ - -slack_max max_slack + -slack_max max_slack - Return paths with slack less than max_slack. + Return paths with slack less than max_slack. - -slack_min min_slack + -slack_min min_slack - Return paths with slack greater than min_slack. + Return paths with slack greater than min_slack. - -sort_by_slack + -sort_by_slack - Sort paths by slack rather than slack within path groups. + Sort paths by slack rather than slack within path groups. - -path_group groups + -path_group groups - Return paths in path groups. Paths in all groups are returned if this option is not specified. + Return paths in path groups. Paths in all groups are returned if this option is not specified. - The find_timing_paths command returns a list of path objects for scripting. Use the get_property function to access properties of the paths. + The find_timing_paths command returns a list of path objects for scripting. Use the get_property function to access properties of the paths. - - get_cells + get_cells - [-hierarchical][-hsc separator][-filter expr][-regexp][-nocase][-quiet][-of_objects objects][patterns] + [-hierarchical][-hsc separator][-filter expr][-regexp][-nocase][-quiet][-of_objects objects][patterns] - -hierarchical + -hierarchical - Searches hierarchy levels below the current instance for matches. + Searches hierarchy levels below the current instance for matches. - -hsc separator + -hsc separator - Character to use to separate hierarchical instance names in patterns. + Character to use to separate hierarchical instance names in patterns. - -filter expr + -filter expr - A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. + A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. - -regexp + -regexp - Use regular expression matching instead of glob pattern matching. + Use regular expression matching instead of glob pattern matching. - -nocase + -nocase - Ignore case when matching. Only valid with –regexp. + Ignore case when matching. Only valid with –regexp. - -quiet + -quiet - Do not warn if no matches are found. + Do not warn if no matches are found. - -of_objects objects + -of_objects objects - The name of a pin or net, a list of pins returned by get_pins, or a list of nets returned by get_nets. The –hierarchical option cannot be used with ‑of_objects. + The name of a pin or net, a list of pins returned by get_pins, or a list of nets returned by get_nets. The –hierarchical option cannot be used with ‑of_objects. - patterns + patterns A list of instance name patterns. @@ -7553,48 +7657,48 @@ - get_clocks + get_clocks - [-regexp][-nocase][-filter expr][-quiet]patterns + [-regexp][-nocase][-filter expr][-quiet]patterns - -regexp + -regexp - Use regular expression matching instead of glob pattern matching. + Use regular expression matching instead of glob pattern matching. - -nocase + -nocase - Ignore case when matching. Only valid with –regexp. + Ignore case when matching. Only valid with –regexp. - -filter expr + -filter expr - A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. + A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. - -quiet + -quiet - Do not warn if no matches are found. + Do not warn if no matches are found. - patterns + patterns A list of clock name patterns. @@ -7607,15 +7711,15 @@ - get_fanin + get_fanin - -to sink_list[-flat][-only_cells][-startpoints_only][-levels level_count][-pin_levels pin_count][-trace_arcs timing|enabled|all] + -to sink_list[-flat][-only_cells][-startpoints_only][-levels level_count][-pin_levels pin_count][-trace_arcs timing|enabled|all] - -to sink_list + -to sink_list List of pins, ports, or nets to find the fanin of. For nets, the fanin of driver pins on the nets are returned. @@ -7623,15 +7727,15 @@ - -flat + -flat - With –flat pins in the fanin at any hierarchy level are returned. Without ‑flat only pins at the same hierarchy level as the sinks are returned. + With –flat pins in the fanin at any hierarchy level are returned. Without ‑flat only pins at the same hierarchy level as the sinks are returned. - -only_cells + -only_cells Return the instances connected to the pins in the fanin. @@ -7639,7 +7743,7 @@ - -startpoints_only + -startpoints_only Only return pins that are startpoints. @@ -7647,7 +7751,7 @@ - -level level_count + -level level_count Only return pins within level_count instance traversals. @@ -7655,7 +7759,7 @@ - -pin_levels pin_count + -pin_levels pin_count Only return pins within pin_count pin traversals. @@ -7663,26 +7767,26 @@ - -trace_arcs timing + -trace_arcs timing - Only trace through timing arcs that are not disabled. + Only trace through timing arcs that are not disabled. - -trace_arcs enabled + -trace_arcs enabled - Only trace through timing arcs that are not disabled. + Only trace through timing arcs that are not disabled. - -trace_arcs all + -trace_arcs all - Trace through all arcs, including disabled ones. + Trace through all arcs, including disabled ones. @@ -7693,15 +7797,15 @@ - get_fanout + get_fanout - -from source_list[-flat][-only_cells][-endpoints_only][-levels level_count][-pin_levels pin_count][-trace_arcs timing|enabled|all] + -from source_list[-flat][-only_cells][-endpoints_only][-levels level_count][-pin_levels pin_count][-trace_arcs timing|enabled|all] - -from source_list + -from source_list List of pins, ports, or nets to find the fanout of. For nets, the fanout of load pins on the nets are returned. @@ -7709,15 +7813,15 @@ - -flat + -flat - With –flat pins in the fanin at any hierarchy level are returned. Without ‑flat only pins at the same hierarchy level as the sinks are returned. + With –flat pins in the fanin at any hierarchy level are returned. Without ‑flat only pins at the same hierarchy level as the sinks are returned. - -only_cells + -only_cells Return the instances connected to the pins in the fanout. @@ -7725,7 +7829,7 @@ - -endpoints_only + -endpoints_only Only return pins that are endpoints. @@ -7733,7 +7837,7 @@ - -level level_count + -level level_count Only return pins within level_count instance traversals. @@ -7741,7 +7845,7 @@ - -pin_levels pin_count + -pin_levels pin_count Only return pins within pin_count pin traversals. @@ -7749,26 +7853,26 @@ - -trace_arcs timing + -trace_arcs timing - Only trace through timing arcs that are not disabled. + Only trace through timing arcs that are not disabled. - -trace_arcs enabled + -trace_arcs enabled - Only trace through timing arcs that are not disabled. + Only trace through timing arcs that are not disabled. - -trace_arcs all + -trace_arcs all - Trace through all arcs, including disabled ones. + Trace through all arcs, including disabled ones. @@ -7778,85 +7882,85 @@ - get_full_name + get_full_name - object + object - object + object - A library, cell, port, instance, pin or timing arc object. + A library, cell, port, instance, pin or timing arc object. - Return the name of object. Equivalent to [get_property object full_name]. + Return the name of object. Equivalent to [get_property object full_name]. - get_lib_cells + get_lib_cells - [-of_objects objects][-hsc separator][-filter expr][-regexp][-nocase][-quiet]patterns + [-of_objects objects][-hsc separator][-filter expr][-regexp][-nocase][-quiet]patterns - -of_objects objects + -of_objects objects - A list of instance objects. + A list of instance objects. - -hsc separator + -hsc separator - Character that separates the library name and cell name in patterns. Defaults to ‘/’. + Character that separates the library name and cell name in patterns. Defaults to ‘/’. - -filter expr + -filter expr - A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. + A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. - -regexp + -regexp - Use regular expression matching instead of glob pattern matching. + Use regular expression matching instead of glob pattern matching. - -nocase + -nocase - Ignore case when matching. Only valid with –regexp. + Ignore case when matching. Only valid with –regexp. - -quiet + -quiet - Do not warn if no matches are found. + Do not warn if no matches are found. - patterns + patterns A list of library cell name patterns of the form library_name/cell_name. @@ -7869,64 +7973,64 @@ - get_lib_pins + get_lib_pins - [-of_objects objects][-hsc separator][-filter expr][-regexp][-nocase][-quiet]patterns + [-of_objects objects][-hsc separator][-filter expr][-regexp][-nocase][-quiet]patterns - -of_objects objects + -of_objects objects - A list of library cell objects. + A list of library cell objects. - -hsc separator + -hsc separator - Character that separates the library name, cell name and port name in pattern. Defaults to ‘/’. + Character that separates the library name, cell name and port name in pattern. Defaults to ‘/’. - -filter expr + -filter expr - A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. + A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. - -regexp + -regexp - Use regular expression matching instead of glob pattern matching. + Use regular expression matching instead of glob pattern matching. - -nocase + -nocase - Ignore case when matching. Only valid with –regexp. + Ignore case when matching. Only valid with –regexp. - -quiet + -quiet - Do not warn if no matches are found. + Do not warn if no matches are found. - patterns + patterns A list of library port name patterns of the form library_name/cell_name/port_name. @@ -7939,117 +8043,117 @@ - get_libs + get_libs - [-filter expr][-regexp][-nocase][-quiet]patterns + [-filter expr][-regexp][-nocase][-quiet]patterns - -filter expr + -filter expr - A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. + A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. - -regexp + -regexp - Use regular expression matching instead of glob pattern matching. + Use regular expression matching instead of glob pattern matching. - -nocase + -nocase - Ignore case when matching. Only valid with –regexp. + Ignore case when matching. Only valid with –regexp. - -quiet + -quiet - Do not warn if no matches are found. + Do not warn if no matches are found. - patterns + patterns A list of library name patterns. - The get_libs command returns a list of clocks that match patterns. + The get_libs command returns a list of clocks that match patterns. - get_nets + get_nets - [-hierarchical][-hsc separator][-filter expr][-regexp][-nocase][-quiet][-of_objects objects][patterns] + [-hierarchical][-hsc separator][-filter expr][-regexp][-nocase][-quiet][-of_objects objects][patterns] - -hierarchical + -hierarchical - Searches hierarchy levels below the current instance for matches. + Searches hierarchy levels below the current instance for matches. - -hsc separator + -hsc separator - Character that separates the library name, cell name and port name in pattern. Defaults to ‘/’. + Character that separates the library name, cell name and port name in pattern. Defaults to ‘/’. - -filter expr + -filter expr - A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. + A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. - -regexp + -regexp - Use regular expression matching instead of glob pattern matching. + Use regular expression matching instead of glob pattern matching. - -nocase + -nocase - Ignore case when matching. Only valid with –regexp. + Ignore case when matching. Only valid with –regexp. - -quiet + -quiet - Do not warn if no matches are found. + Do not warn if no matches are found. - -of_objects objects + -of_objects objects The name of a pin or instance, a list of pins returned by get_pins, or a list of instances returned by get_cells. The –hierarchical option cannot be used with –of_objects. @@ -8057,7 +8161,7 @@ - patterns + patterns A list of net name patterns. @@ -8070,15 +8174,15 @@ - get_name + get_name - object + object - object + object A library, cell, port, instance, pin or timing arc object. @@ -8092,63 +8196,63 @@ - get_pins + get_pins - [-hierarchical][-hsc separator][-filter expr][-regexp][-nocase][-quiet][-of_objects objects][patterns] + [-hierarchical][-hsc separator][-filter expr][-regexp][-nocase][-quiet][-of_objects objects][patterns] - -hierarchical + -hierarchical - Searches hierarchy levels below the current instance for matches. + Searches hierarchy levels below the current instance for matches. - -hsc separator + -hsc separator - Character that separates the library name, cell name and port name in pattern. Defaults to ‘/’. + Character that separates the library name, cell name and port name in pattern. Defaults to ‘/’. - -filter expr + -filter expr - A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. + A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. - -nocase + -nocase - Ignore case when matching. Only valid with –regexp. + Ignore case when matching. Only valid with –regexp. - -quiet + -quiet - Do not warn if no matches are found. + Do not warn if no matches are found. - -of_objects objects + -of_objects objects - The name of a net or instance, a list of nets returned by get_nets, or a list of instances returned by get_cells. The –hierarchical option cannot be used with –of_objects. + The name of a net or instance, a list of nets returned by get_nets, or a list of instances returned by get_cells. The –hierarchical option cannot be used with –of_objects. - patterns + patterns A list of pin name patterns. @@ -8156,63 +8260,63 @@ The get_pins command returns a list of all instance pins that match patterns. - A useful idiom to find the driver pin for a net is the following. - get_pins -of_objects [get_net net_name] -filter “direction==output” + A useful idiom to find the driver pin for a net is the following. + get_pins -of_objects [get_net net_name] -filter “direction==output” - get_ports + get_ports - [-filter expr][-regexp][-nocase][-quiet][-of_objects objects][patterns] + [-filter expr][-regexp][-nocase][-quiet][-of_objects objects][patterns] - -filter expr + -filter expr - A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. + A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. - -regexp + -regexp - Use regular expression matching instead of glob pattern matching. + Use regular expression matching instead of glob pattern matching. - -nocase + -nocase - Ignore case when matching. Only valid with –regexp. + Ignore case when matching. Only valid with –regexp. - -quiet + -quiet - Do not warn if no matches are found. + Do not warn if no matches are found. - -of_objects objects + -of_objects objects - The name of net or a list of nets returned by get_nets. + The name of net or a list of nets returned by get_nets. - patterns + patterns A list of port name patterns. @@ -8225,31 +8329,31 @@ - get_property + get_property - [-object_type object_type]objectproperty + [-object_type object_type]objectproperty - -object_type object_type + -object_type object_type - The type of object when it is specified as a name.cell|pin|net|port|clock|library|library_cell|library_pin|timing_arc + The type of object when it is specified as a name.cell|pin|net|port|clock|library|library_cell|library_pin|timing_arc - object + object - An object returned by get_cells, get_pins, get_nets, get_ports, get_clocks, get_libs, get_lib_cells, get_lib_pins, or get_timing_arcs, or object name. ‑object_type is required if object is a name. + An object returned by get_cells, get_pins, get_nets, get_ports, get_clocks, get_libs, get_lib_cells, get_lib_pins, or get_timing_arcs, or object name. ‑object_type is required if object is a name. - property + property A property name. @@ -8257,120 +8361,120 @@ The properties for different objects types are shown below. - cell (SDC lib_cell) - base_namefilenamefull_namelibraryname - clock - full_nameis_generatedis_propagatedis_virtualnameperiodsources - edge - delay_max_falldelay_min_falldelay_max_risedelay_min_risefull_namefrom_pinsenseto_pin - instance (SDC cell) - cellfull_nameis_bufferis_clock_gateis_hierarchicalis_inverteris_macrois_memoryliberty_cellnameref_name - liberty_cell (SDC lib_cell) - areabase_namedont_usefilenamefull_nameis_bufferis_inverteris_memorylibraryname - liberty_port (SDC lib_pin) - capacitancedirectiondrive_resistancedrive_resistance_max_falldrive_resistance_max_risedrive_resistance_min_falldrive_resistance_min_risefull_nameintrinsic_delayintrinsic_delay_max_fallintrinsic_delay_max_riseintrinsic_delay_min_fallintrinsic_delay_min_riseis_register_clocklib_cellname - library - filename (Liberty library only)namefull_name - net - full_namename - path (PathEnd) + cell (SDC lib_cell) + base_namefilenamefull_namelibraryname + clock + full_nameis_generatedis_propagatedis_virtualnameperiodsources + edge + delay_max_falldelay_min_falldelay_max_risedelay_min_risefull_namefrom_pinsenseto_pin + instance (SDC cell) + cellfull_nameis_bufferis_clock_gateis_hierarchicalis_inverteris_macrois_memoryliberty_cellnameref_name + liberty_cell (SDC lib_cell) + areabase_namedont_usefilenamefull_nameis_bufferis_inverteris_memorylibraryname + liberty_port (SDC lib_pin) + capacitancedirectiondrive_resistancedrive_resistance_max_falldrive_resistance_max_risedrive_resistance_min_falldrive_resistance_min_risefull_nameintrinsic_delayintrinsic_delay_max_fallintrinsic_delay_max_riseintrinsic_delay_min_fallintrinsic_delay_min_riseis_register_clocklib_cellname + library + filename (Liberty library only)namefull_name + net + full_namename + path (PathEnd) endpointendpoint_clockendpoint_clock_pinslackstartpointstartpoint_clockpoints - pin - activity (activity in transitions per second, duty cycle, origin)origin is one ofglobalset_power_activity -globalinputset_power_activity -inputuserset_power_activity -input_ports -pinsvcdread_vcdsaifread_saifpropagatedpropagated from upstream activitiesclockSDC create_clock or create_generated_clockconstantconstant pins propagated from verilog tie high/low, set_case_analysis, set_logic_one/zero/dc - slew_max_fallslew_max_riseslew_min_fallslew_min_riseclocksclock_domainsdirectionfull_nameis_hierarchicalis_portis_register_clocklib_pin_namenameslack_maxslack_max_fallslack_max_riseslack_minslack_min_fallslack_min_rise - port - activityslew_max_fallslew_max_riseslew_min_fallslew_min_risedirectionfull_nameliberty_portnameslack_maxslack_max_fallslack_max_riseslack_minslack_min_fallslack_min_rise - point (PathRef) - arrivalpinrequiredslack + pin + activity (activity in transitions per second, duty cycle, origin)origin is one ofglobalset_power_activity -globalinputset_power_activity -inputuserset_power_activity -input_ports -pinsvcdread_vcdsaifread_saifpropagatedpropagated from upstream activitiesclockSDC create_clock or create_generated_clockconstantconstant pins propagated from verilog tie high/low, set_case_analysis, set_logic_one/zero/dc + slew_max_fallslew_max_riseslew_min_fallslew_min_riseclocksclock_domainsdirectionfull_nameis_hierarchicalis_portis_register_clocklib_pin_namenameslack_maxslack_max_fallslack_max_riseslack_minslack_min_fallslack_min_rise + port + activityslew_max_fallslew_max_riseslew_min_fallslew_min_risedirectionfull_nameliberty_portnameslack_maxslack_max_fallslack_max_riseslack_minslack_min_fallslack_min_rise + point (PathRef) + arrivalpinrequiredslack - get_scenes + get_scenes - [-mode mode_name]scene_name + [-mode mode_name]scene_name - mode_name + mode_name - Get the scenes for mode_name. + Get the scenes for mode_name. - scene_name + scene_name - A scene name pattern. + A scene name pattern. - The get_scenes command is used to find the scenes matching a pattern or that use an SDC mode. + The get_scenes command is used to find the scenes matching a pattern or that use an SDC mode. - get_timing_edges + get_timing_edges - [-from from_pins][-to to_pins][-of_objects objects][-filter expr][patterns] + [-from from_pins][-to to_pins][-of_objects objects][-filter expr][patterns] - -from from_pin + -from from_pin - A list of pins. + A list of pins. - -to to_pin + -to to_pin - A list of pins. + A list of pins. - -of_objects objects + -of_objects objects - A list of instances or library cells. The –from and -to options cannot be used with –of_objects. + A list of instances or library cells. The –from and -to options cannot be used with –of_objects. - -filter expr + -filter expr - A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. + A filter expression of the form property==value”where property is a property supported by the get_property command. See the section “Filter Expressions” for additional forms. - The get_timing_edges command returns a list of timing edges (arcs) to, from or between pins. The result can be passed to get_property or set_disable_timing. + The get_timing_edges command returns a list of timing edges (arcs) to, from or between pins. The result can be passed to get_property or set_disable_timing. - group_path + group_path - -name group_name[-weight weight][-critical_range range][-from from_list |-rise_from from_list |-fall_from from_list][-through through_list][-rise_through through_list][-fall_through through_list][-to to_list |-rise_to to_list |-fall_to to_list][-default] + -name group_name[-weight weight][-critical_range range][-from from_list |-rise_from from_list |-fall_from from_list][-through through_list][-rise_through through_list][-fall_through through_list][-to to_list |-rise_to to_list |-fall_to to_list][-default] - -name group_name + -name group_name The name of the path group. @@ -8378,7 +8482,7 @@ - -weight weight + -weight weight Not supported. @@ -8386,7 +8490,7 @@ - -critical_range range + -critical_range range Not supported. @@ -8394,82 +8498,82 @@ - -from from_list + -from from_list - Group paths from a list of clocks, instances, ports, register clock pins, or latch data pins. + Group paths from a list of clocks, instances, ports, register clock pins, or latch data pins. - -rise_from from_list + -rise_from from_list - Group paths from the rising edge of clocks, instances, ports, register clock pins, or latch data pins. + Group paths from the rising edge of clocks, instances, ports, register clock pins, or latch data pins. - -fall_from from_list + -fall_from from_list - Group paths from the falling edge of clocks, instances, ports, register clock pins, or latch data pins. + Group paths from the falling edge of clocks, instances, ports, register clock pins, or latch data pins. - -through through_list + -through through_list - Group paths through a list of instances, pins or nets. + Group paths through a list of instances, pins or nets. - -rise_through through_list + -rise_through through_list - Group rising paths through a list of instances, pins or nets. + Group rising paths through a list of instances, pins or nets. - -fall_through through_list + -fall_through through_list - Group falling paths through a list of instances, pins or nets. + Group falling paths through a list of instances, pins or nets. - -to to_list + -to to_list - Group paths to a list of clocks, instances, ports or pins. + Group paths to a list of clocks, instances, ports or pins. - -rise_to to_list + -rise_to to_list - Group rising paths to a list of clocks, instances, ports or pins. + Group rising paths to a list of clocks, instances, ports or pins. - -fall_to to_list + -fall_to to_list - Group falling paths to a list of clocks, instances, port-s or pins. + Group falling paths to a list of clocks, instances, port-s or pins. - -default + -default - Restore the paths in the path group -from/-to/-through/-to to their default path group. + Restore the paths in the path group -from/-to/-through/-to to their default path group. @@ -8479,84 +8583,84 @@ - include + include - [-echo|-e][-verbose|-v]filename[> log_filename][>> log_filename] + [-echo|-e][-verbose|-v]filename[> log_filename][>> log_filename] - -echo|-e + -echo|-e - Print each command before evaluating it. + Print each command before evaluating it. - -verbose|-v + -verbose|-v - Print each command before evaluating it as well as the result it returns. + Print each command before evaluating it as well as the result it returns. - filename + filename - The name of the file containing commands to read. + The name of the file containing commands to read. - > log_filename + > log_filename - Redirect command output to log_filename. + Redirect command output to log_filename. - >> log_filename + >> log_filename - Redirect command output and append log_filename. + Redirect command output and append log_filename. - Read STA/SDC/Tcl commands from filename. - The include command stops and reports any errors encountered while reading a file unless sta_continue_on_error is 1. + Read STA/SDC/Tcl commands from filename. + The include command stops and reports any errors encountered while reading a file unless sta_continue_on_error is 1. - link_design + link_design - [-no_black_boxes][cell_name] + [-no_black_boxes][cell_name] - -no_black_boxes + -no_black_boxes - Do not make empty “black box” cells for instances that reference undefined cells. + Do not make empty “black box” cells for instances that reference undefined cells. - cell_name + cell_name - The top level module/cell name of the design hierarchy to link. + The top level module/cell name of the design hierarchy to link. - Link (elaborate, flatten) the the top level cell cell_name. The design must be linked after reading netlist and library files. The default value of cell_name is the current design. + Link (elaborate, flatten) the the top level cell cell_name. The design must be linked after reading netlist and library files. The default value of cell_name is the current design. The linker creates empty "block box" cells for instances the reference undefined cells when the variable link_create_black_boxes is true. When link_create_black_boxes is false an error is reported and the link fails. The link_design command returns 1 if the link succeeds and 0 if it fails. @@ -8564,15 +8668,15 @@ - make_instance + make_instance - inst_pathlib_cell + inst_pathlib_cell - inst_path + inst_path A hierarchical instance name. @@ -8581,28 +8685,28 @@ - lib_cell + lib_cell The library cell of the new instance. - The make_instance command makes an instance of library cell lib_cell. + The make_instance command makes an instance of library cell lib_cell. - make_net + make_net - net_name_list + net_name_list - net_name_list + net_name_list A list of net names. @@ -8615,47 +8719,47 @@ - read_liberty + read_liberty - [-corner corner][-min][-max][-infer_latches]filename + [-corner corner][-min][-max][-infer_latches]filename - -corner corner + -corner corner - Use the library for process corner corner delay calculation. + Use the library for process corner corner delay calculation. - -min + -min - Use library for min delay calculation. + Use library for min delay calculation. - -max + -max - Use library for max delay calculation. + Use library for max delay calculation. - filename + filename - The liberty file name to read. + The liberty file name to read. The read_liberty command reads a Liberty format library file. The first library that is read sets the units used by SDC/TCL commands and reporting. The include_file attribute is supported. - Some Liberty libraries do not include latch groups for cells that are describe transparent latches. In that situation the -infer_latches command flag can be used to infer the latches. The timing arcs required for a latch to be inferred should look like the following: + Some Liberty libraries do not include latch groups for cells that are describe transparent latches. In that situation the -infer_latches command flag can be used to infer the latches. The timing arcs required for a latch to be inferred should look like the following: cell (infered_latch) { pin(D) { direction : input ; timing () { related_pin : "E" ; timing_type : setup_falling ; } timing () { related_pin : "E" ; timing_type : hold_falling ; } } pin(E) { direction : input; } pin(Q) { direction : output ; timing () { related_pin : "D" ; } timing () { related_pin : "E" ; timing_type : rising_edge ; } }} In this example a positive level-sensitive latch is inferred. Files compressed with gzip are automatically uncompressed. @@ -8664,69 +8768,69 @@ - read_saif + read_saif - [-scope scope]filename + [-scope scope]filename - scope + scope - The SAIF scope of the current design to extract simulation data. Typically the test bench name and design under test instance name. Scope levels are separated with ‘/’. + The SAIF scope of the current design to extract simulation data. Typically the test bench name and design under test instance name. Scope levels are separated with ‘/’. - filename + filename - The name of the SAIF file to read. + The name of the SAIF file to read. - The read_saif command reads a SAIF (Switching Activity Interchange Format) file from a Verilog simulation and extracts pin activities and duty cycles for use in power estimation. Files compressed with gzip are supported. Annotated activities are propagated to the fanout of the annotated pins. + The read_saif command reads a SAIF (Switching Activity Interchange Format) file from a Verilog simulation and extracts pin activities and duty cycles for use in power estimation. Files compressed with gzip are supported. Annotated activities are propagated to the fanout of the annotated pins. - read_sdc + read_sdc - [-mode mode_name][-echo]filename + [-mode mode_name][-echo]filename - mode_name + mode_name - Mode for the SDC commands in the file. + Mode for the SDC commands in the file. - -echo + -echo - Print each command before evaluating it. + Print each command before evaluating it. - filename + filename - SDC command file. + SDC command file. - Read SDC commands from filename. - If the mode does not exist it is created. Multiple SDC files can append commands to a mode by using the -mode_name argument for each one. If no -mode arguement is is used the commands are added to the current mode. + Read SDC commands from filename. + If the mode does not exist it is created. Multiple SDC files can append commands to a mode by using the -mode_name argument for each one. If no -mode arguement is is used the commands are added to the current mode. The read_sdc command stops and reports any errors encountered while reading a file unless sta_continue_on_error is 1. Files compressed with gzip are automatically uncompressed. @@ -8734,23 +8838,23 @@ - read_sdf + read_sdf - [-scene scene][-unescaped_dividers]filename + [-scene scene][-unescaped_dividers]filename - scene + scene - Scene delays to annotate. + Scene delays to annotate. - -unescaped_dividers + -unescaped_dividers With this option path names in the SDF do not have to escape hierarchy dividers when the path name is escaped. For example, the escaped Verilog name "\inst1/inst2 " can be referenced as "inst1/inst2". The correct SDF name is "inst1\/inst2", since the divider does not represent a change in hierarchy in this case. @@ -8758,138 +8862,138 @@ - filename + filename - The name of the SDF file to read. + The name of the SDF file to read. - Read SDF delays from a file. The min and max values in the SDF tuples are used to annotate the delays for corner. The typical values in the SDF tuples are ignored. If multiple scenes are defined -scene must be specified. SDC annotation for mcmm analysis must follow the scene definitions. + Read SDF delays from a file. The min and max values in the SDF tuples are used to annotate the delays for corner. The typical values in the SDF tuples are ignored. If multiple scenes are defined -scene must be specified. SDC annotation for mcmm analysis must follow the scene definitions. Files compressed with gzip are automatically uncompressed. INCREMENT is supported as an alias for INCREMENTAL. - The following SDF statements are not supported. + The following SDF statements are not supported. PORTINSTANCE wildcards - read_spef + read_spef - [-name name][-keep_capacitive_coupling][-coupling_reduction_factor factor][-reduce][-path path]filename + [-name name][-keep_capacitive_coupling][-coupling_reduction_factor factor][-reduce][-path path]filename - name + name - The name of the SPEF parasitics to use for defining scenes. The default is the base name of filename. + The name of the SPEF parasitics to use for defining scenes. The default is the base name of filename. - path + path - Hierarchical block instance path to annotate with parasitics. + Hierarchical block instance path to annotate with parasitics. - ‑keep_capacitive_coupling + ‑keep_capacitive_coupling - Keep coupling capacitors in parasitic networks rather than converting them to grounded capacitors. + Keep coupling capacitors in parasitic networks rather than converting them to grounded capacitors. - ‑coupling_reduction_factorfactor + ‑coupling_reduction_factorfactor - Factor to multiply coupling capacitance by when reducing parasitic networks. The default value is 1.0. + Factor to multiply coupling capacitance by when reducing parasitic networks. The default value is 1.0. - filename + filename - The name of the parasitics file to read. + The name of the parasitics file to read. - The read_spef command reads a file of net parasitics in SPEF format. Use the report_parasitic_annotation command to check for nets that are not annotated. + The read_spef command reads a file of net parasitics in SPEF format. Use the report_parasitic_annotation command to check for nets that are not annotated. Files compressed with gzip are automatically uncompressed. - Separate min/max parasitics can be annotated for each scene mode/corner. - read_spef -name min spef1read_spef -name max spef2define_scene -mode mode1 -spef_min min -spef_max max - Coupling capacitors are multiplied by the –coupling_reduction_factor when a parasitic network is reduced. + Separate min/max parasitics can be annotated for each scene mode/corner. + read_spef -name min spef1read_spef -name max spef2define_scene -mode mode1 -spef_min min -spef_max max + Coupling capacitors are multiplied by the –coupling_reduction_factor when a parasitic network is reduced. The following SPEF constructs are ignored. *DESIGN_FLOW (all values are ignored)*S slews*D driving cell*I pin capacitances (library cell capacitances are used instead)*Q r_net load poles*K r_net load residues - If the SPEF file contains triplet values the first value is used. - Parasitic networks (DSPEF) can be annotated on hierarchical blocks using the -path argument to specify the instance path to the block. Parasitic networks in the higher level netlist are stitched together at the hierarchical pins of the blocks. + If the SPEF file contains triplet values the first value is used. + Parasitic networks (DSPEF) can be annotated on hierarchical blocks using the -path argument to specify the instance path to the block. Parasitic networks in the higher level netlist are stitched together at the hierarchical pins of the blocks. - read_vcd + read_vcd - [-scope scope][-mode mode_name]filename + [-scope scope][-mode mode_name]filename - scope + scope - The VCD scope of the current design to extract simulation data. Typically the test bench name and design under test instance name. Scope levels are separated with ‘/’. + The VCD scope of the current design to extract simulation data. Typically the test bench name and design under test instance name. Scope levels are separated with ‘/’. - mode_name + mode_name - Mode to annotate activities. + Mode to annotate activities. - filename + filename - The name of the VCD file to read. + The name of the VCD file to read. - The read_vcd command reads a VCD (Value Change Dump) file from a Verilog simulation and extracts pin activities and duty cycles for use in power estimation. Files compressed with gzip are supported. Annotated activities are propagated to the fanout of the annotated pins. + The read_vcd command reads a VCD (Value Change Dump) file from a Verilog simulation and extracts pin activities and duty cycles for use in power estimation. Files compressed with gzip are supported. Annotated activities are propagated to the fanout of the annotated pins. - read_verilog + read_verilog - filename + filename - filename + filename - The name of the verilog file to read. + The name of the verilog file to read. - The read_verilog command reads a gate level verilog netlist. After all verilog netlist and Liberty libraries are read the design must be linked with the link_design command. - Verilog 2001 module port declaratations are supported. An example is shown below. + The read_verilog command reads a gate level verilog netlist. After all verilog netlist and Liberty libraries are read the design must be linked with the link_design command. + Verilog 2001 module port declaratations are supported. An example is shown below. module top (input in1, in2, clk1, clk2, clk3, output out); Files compressed with gzip are automatically uncompressed. @@ -8897,707 +9001,715 @@ - replace_cell + replace_cell - instance_listreplacement_cell + instance_listreplacement_cell - instance_list + instance_list - A list of instances to swap the cell. + A list of instances to swap the cell. - replacement_cell + replacement_cell - The replacement lib cell. + The replacement lib cell. - The replace_cell command changes the cell of an instance. The replacement cell must have the same port list (number, name, and order) as the instance's existing cell for the replacement to be successful. + The replace_cell command changes the cell of an instance. The replacement cell must have the same port list (number, name, and order) as the instance's existing cell for the replacement to be successful. - replace_activity_annotation + replace_activity_annotation - [-report_unannotated][-report_annotated] + [-report_unannotated][-report_annotated] - -report_unannotated + -report_unannotated - Report unannotated pins. + Report unannotated pins. - -report_unannotated + -report_unannotated - Report annotated pins. + Report annotated pins. - Report a summary of pins that are annotated by read_vcd, read_saif or set_power_activity. Sequential internal pins and hierarchical pins are ignored. + Report a summary of pins that are annotated by read_vcd, read_saif or set_power_activity. Sequential internal pins and hierarchical pins are ignored. - report_annotated_check + report_annotated_check - [-setup][-hold][-recovery][-removal][-nochange][-width][-period][-max_skew][-max_line lines][-report_annotated][-report_unannotated][-constant_arcs] + [-setup][-hold][-recovery][-removal][-nochange][-width][-period][-max_skew][-max_line lines][-report_annotated][-report_unannotated][-constant_arcs] - -setup + -setup - Report annotated setup checks. + Report annotated setup checks. - -hold + -hold - Report annotated hold checks. + Report annotated hold checks. - -recovery + -recovery - Report annotated recovery checks. + Report annotated recovery checks. - -removal + -removal - Report annotated removal checks. + Report annotated removal checks. - -nochange + -nochange - Report annotated nochange checks. + Report annotated nochange checks. - -width + -width - Report annotated width checks. + Report annotated width checks. - -period + -period - Report annotated period checks. + Report annotated period checks. - -max_skew + -max_skew - Report annotated max skew checks. + Report annotated max skew checks. - -max_line lines + -max_line lines - Maximum number of lines listed by the report_annotated and ‑report_unannotated options. + Maximum number of lines listed by the report_annotated and ‑report_unannotated options. - -report_annotated + -report_annotated - Report annotated timing arcs. + Report annotated timing arcs. - -report_unannotated + -report_unannotated - Report unannotated timing arcs. + Report unannotated timing arcs. - -constant_arcs + -constant_arcs - Report separate annotation counts for arcs disabled by logic constants (set_logic_one, set_logic_zero). + Report separate annotation counts for arcs disabled by logic constants (set_logic_one, set_logic_zero). - The report_annotated_check command reports a summary of SDF timing check annotation. The -report_annotated and report_annotated options can be used to list arcs that are annotated or not annotated. + The report_annotated_check command reports a summary of SDF timing check annotation. The -report_annotated and report_annotated options can be used to list arcs that are annotated or not annotated. - report_annotated_delay + report_annotated_delay - [-cell][-net][-from_in_ports][-to_out_ports][-max_lines lines][-report_annotated][-report_unannotated][-constant_arcs] + [-cell][-net][-from_in_ports][-to_out_ports][-max_lines lines][-report_annotated][-report_unannotated][-constant_arcs] - -cell + -cell - Report annotated cell delays. + Report annotated cell delays. - -net + -net - Report annotated internal net delays. + Report annotated internal net delays. - -from_in_ports + -from_in_ports - Report annotated delays from input ports. + Report annotated delays from input ports. - -to_out_ports + -to_out_ports - Report annotated delays to output ports. + Report annotated delays to output ports. - -max_lines lines + -max_lines lines - Maximum number of lines listed by the report_annotated and ‑report_unannotated options. + Maximum number of lines listed by the report_annotated and ‑report_unannotated options. - -report_annotated + -report_annotated - Report annotated timing arcs. + Report annotated timing arcs. - -report_unannotated + -report_unannotated - Report unannotated timing arcs. + Report unannotated timing arcs. - -constant_arcs + -constant_arcs Report separate annotation counts for arcs disabled by logic constants (set_logic_one, set_logic_zero). - The report_annotated_delay command reports a summary of SDF delay annotation. Without the ‑from_in_ports and –to_out_ports options arcs to and from top level ports are not reported. The ‑report_annotated and report_unannotated options can be used to list arcs that are annotated or not annotated. + The report_annotated_delay command reports a summary of SDF delay annotation. Without the ‑from_in_ports and –to_out_ports options arcs to and from top level ports are not reported. The ‑report_annotated and report_unannotated options can be used to list arcs that are annotated or not annotated. - report_checks + report_checks - [-from from_list |-rise_from from_list |-fall_from from_list][-through through_list |-rise_through through_list |-fall_through through_list][-to to_list |-rise_to to_list |-fall_to to_list][-unconstrained][-path_delay min|min_rise|min_fall |max|max_rise|max_fall |min_max][-group_path_count path_count][-endpoint_path_count endpoint_path_count][-unique_paths_to_endpoint][-unique_edges_to_endpoint][-scenes scenes][-slack_max max_slack][-slack_min min_slack][-sort_by_slack][-path_group groups][-format end|full|short|summary |full_clock|full_clock_expanded |json][-fields fields][-digits digits][-no_line_split][> filename][>> filename] + [-from from_list |-rise_from from_list |-fall_from from_list][-through through_list |-rise_through through_list |-fall_through through_list][-to to_list |-rise_to to_list |-fall_to to_list][-unconstrained][-path_delay min|min_rise|min_fall |max|max_rise|max_fall |min_max][-group_path_count path_count][-endpoint_path_count endpoint_path_count][-unique_paths_to_endpoint][-unique_edges_to_endpoint][-scenes scenes][-slack_max max_slack][-slack_min min_slack][-sort_by_slack][-path_group groups][-format end|full|short|summary |full_clock|full_clock_expanded |json][-fields fields][-digits digits][-no_line_split][> filename][>> filename] - -from from_list + -from from_list - Report paths from a list of clocks, instances, ports, register clock pins, or latch data pins. + Report paths from a list of clocks, instances, ports, register clock pins, or latch data pins. - -rise_from from_list + -rise_from from_list - Report paths from the rising edge of clocks, instances, ports, register clock pins, or latch data pins. + Report paths from the rising edge of clocks, instances, ports, register clock pins, or latch data pins. - -fall_from from_list + -fall_from from_list - Report paths from the falling edge of clocks, instances, ports, register clock pins, or latch data pins. + Report paths from the falling edge of clocks, instances, ports, register clock pins, or latch data pins. - -through through_list + -through through_list - Report paths through a list of instances, pins or nets. + Report paths through a list of instances, pins or nets. - -rise_through through_list + -rise_through through_list - Report rising paths through a list of instances, pins or nets. + Report rising paths through a list of instances, pins or nets. - -fall_through through_list + -fall_through through_list - Report falling paths through a list of instances, pins or nets. + Report falling paths through a list of instances, pins or nets. - -to to_list + -to to_list - Report paths to a list of clocks, instances, ports or pins. + Report paths to a list of clocks, instances, ports or pins. - -rise_to to_list + -rise_to to_list - Report rising paths to a list of clocks, instances, ports or pins. + Report rising paths to a list of clocks, instances, ports or pins. - -fall_to to_list + -fall_to to_list - Report falling paths to a list of clocks, instances, ports or pins. + Report falling paths to a list of clocks, instances, ports or pins. - -unconstrained + -unconstrained - Report unconstrained paths also. The unconstrained path group is not reported without this option. + Report unconstrained paths also. The unconstrained path group is not reported without this option. - -path_delay min + -path_delay min - Report min path (hold) checks. + Report min path (hold) checks. - -path_delay min_rise + -path_delay min_rise - Report min path (hold) checks for rising endpoints. + Report min path (hold) checks for rising endpoints. - -path_delay min_fall + -path_delay min_fall - Report min path (hold) checks for falling endpoints. + Report min path (hold) checks for falling endpoints. - -path_delay max + -path_delay max - Report max path (setup) checks. + Report max path (setup) checks. - -path_delay max_rise + -path_delay max_rise - Report max path (setup) checks for rising endpoints. + Report max path (setup) checks for rising endpoints. - -path_delay max_fall + -path_delay max_fall - Report max path (setup) checks for falling endpoints. + Report max path (setup) checks for falling endpoints. - -path_delay min_max + -path_delay min_max - Report max and max path (setup and hold) checks. + Report max and max path (setup and hold) checks. - -group_path_count path_count + -group_path_count path_count - The number of paths to report in each path group. The default is 1. + The number of paths to report in each path group. The default is 1. - -endpoint_path_count endpoint_path_count + -endpoint_path_count endpoint_path_count - The number of paths to report for each endpoint. The default is 1. + The number of paths to report for each endpoint. The default is 1. - ‑unique_paths_to_endpoint + ‑unique_paths_to_endpoint - When multiple paths to an endpoint are specified with ‑endpoint_path_count, many of the paths may differ only in the rise/fall edges of the pins in the paths. With this option only the worst path through the set of pins is reported. + When multiple paths to an endpoint are specified with ‑endpoint_path_count, many of the paths may differ only in the rise/fall edges of the pins in the paths. With this option only the worst path through the set of pins is reported. - ‑unique_edges_to_endpoint + ‑unique_edges_to_endpoint - When multiple paths to an endpoint are specified with ‑endpoint_path_count, conditional timing arcs result in paths that through the same pins and rise/fall edges. With this option only the worst path through the set of pins and rise/fall edges is reported. + When multiple paths to an endpoint are specified with ‑endpoint_path_count, conditional timing arcs result in paths that through the same pins and rise/fall edges. With this option only the worst path through the set of pins and rise/fall edges is reported. - scenes + scenes - Report paths for one process corner. The default is to report paths for all process corners. + Report paths for one process corner. The default is to report paths for all process corners. - max_slack + max_slack - Only report paths with less slack than max_slack. + Only report paths with less slack than max_slack. - min_slack + min_slack - Only report paths with more slack than min_slack. + Only report paths with more slack than min_slack. - -sort_by_slack + -sort_by_slack - Sort paths by slack rather than slack grouped by path group. + Sort paths by slack rather than slack grouped by path group. - groups + groups - List of path groups to report. The default is to report all path groups. + List of path groups to report. The default is to report all path groups. - -format end + -format end - Report path ends in one line with delay, required time and slack. + Report path ends in one line with delay, required time and slack. - -format full + -format full - Report path start and end points and the path. This is the default path type. + Report path start and end points and the path. This is the default path type. - -format full_clock + -format full_clock - Report path start and end points, the path, and the source and and target clock paths. + Report path start and end points, the path, and the source and and target clock paths. - -format full_clock_expanded + -format full_clock_expanded - Report path start and end points, the path, and the source and and target clock paths. If the clock is generated and propagated, the path from the clock source pin is also reported. + Report path start and end points, the path, and the source and and target clock paths. If the clock is generated and propagated, the path from the clock source pin is also reported. - -format short + -format short - Report only path start and end points. + Report only path start and end points. - -format summary + -format summary - Report only path ends with delay. + Report only path ends with delay. - -format json + -format json - Report in json format. -fields is ignored. + Report in json format. -fields is ignored. - fields + fields - List of capacitance|slew|input_pins|hierarchical_pins|nets|fanout|src_attr + List of capacitance|slew|input_pins|hierarchical_pins|nets|fanout|src_attr|variance - digits + digits - The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. + The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. - -no_line_splits + -no_line_splits - Do not split long lines into multiple lines. + Do not split long lines into multiple lines. - The report_checks command reports paths in the design. Paths are reported in groups by capture clock, unclocked path delays, gated clocks and unconstrained. - See set_false_path for a description of allowed from_list, through_list and to_list objects. + The report_checks command reports paths in the design. Paths are reported in groups by capture clock, unclocked path delays, gated clocks and unconstrained. + See set_false_path for a description of allowed from_list, through_list and to_list objects. - report_check_types + report_check_types - [-scenes scenes][-violators][-verbose][-format slack_only|end][-max_delay][-min_delay][-recovery][-removal][-clock_gating_setup][-clock_gating_hold][-max_slew][-min_slew][-min_pulse_width][-min_period][-digits digits][-no_split_lines][> filename][>> filename] + [-scenes scenes][-violators][-verbose][-fields fields][-format slack_only|end][-max_delay][-min_delay][-recovery][-removal][-clock_gating_setup][-clock_gating_hold][-max_slew][-min_slew][-min_pulse_width][-min_period][-digits digits][-no_split_lines][> filename][>> filename] - scenes + scenes - Report checks for some scens. The default value is all scenes. + Report checks for some scenes. The default value is all scenes. - -violators + -violators - Report all violated timing and design rule constraints. + Report all violated timing and design rule constraints. - -verbose + -verbose - Use a verbose output format. + Use a verbose output format. - -format slack_only + -format slack_only - Report the minimum slack for each timing check. + Report the minimum slack for each timing check. - -format end + -format end - Report the endpoint for each check. + Report the endpoint for each check. - -max_delay + fields - Report setup and max delay path delay constraints. + List of capacitance|slew|input_pins|hierarchical_pins|nets|fanout|src_attr|variance - -min_delay + -max_delay - Report hold and min delay path delay constraints. + Report setup and max delay path delay constraints. - -recovery + -min_delay - Report asynchronous recovery checks. + Report hold and min delay path delay constraints. - -removal + -recovery - Report asynchronous removal checks. + Report asynchronous recovery checks. - -clock_gating_setup + -removal - Report gated clock enable setup checks. + Report asynchronous removal checks. - -clock_gating_hold + -clock_gating_setup - Report gated clock hold setup checks. + Report gated clock enable setup checks. - -max_slew + -clock_gating_hold - Report max transition design rule checks. + Report gated clock hold setup checks. - -max_skew + -max_slew - Report max skew design rule checks. + Report max transition design rule checks. - -min_pulse_width + -max_skew - Report min pulse width design rule checks. + Report max skew design rule checks. - -min_period + -min_pulse_width - Report min period design rule checks. + Report min pulse width design rule checks. - -min_slew + -min_period - Report min slew design rule checks. + Report min period design rule checks. - -digits digits + -min_slew - The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. + Report min slew design rule checks. - -no_split_lines + -digits digits - Do not split long lines into multiple lines. + The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. + + + + + -no_split_lines + + + Do not split long lines into multiple lines. @@ -9607,93 +9719,92 @@ - report_clock_latency + report_clock_latency - [-clocks clocks][-scenes scenes][-include_internal_latency][-digits digits] + [-clocks clocks][-scenes scenes][-include_internal_latency][-digits digits] - clocks + clocks - The clocks to report. The default value is all c + The clocks to report. The default value is all c - scenes + scenes - Report clocks for scenes. The default value is all clocks in scenes modes. + Report clocks for scenes. The default value is all clocks in scenes modes. - -include_internal_latency + -include_internal_latency - Include internal clock latency from liberty min/max_clock_tree_path timing groups. + Include internal clock latency from liberty min/max_clock_tree_path timing groups. - digits + digits - The number of digits to report for delays. + The number of digits to report for delays. - Report the clock network latency. + Report the clock network latency. - report_clock_min_period + report_clock_min_period - [-clocks clocks][-scenes scenes][-include_port_paths] + [-clocks clocks][-scenes scenes][-include_port_paths] - clocks + clocks - The clocks to report. + The clocks to report. - -include_port_paths + -include_port_paths - Include paths from input port and to output ports. + Include paths from input port and to output ports. - Report the minimum period and maximum frequency for clocks. If the -clocks argument is not specified all clocks are reported. The minimum period is determined by examining the smallest slack paths between registers the rising edges of the clock or between falling edges of the clock. Paths between different clocks, different clock edges of the same clock, level sensitive latches, or paths constrained by set_multicycle_path, set_max_path are not considered. + Report the minimum period and maximum frequency for clocks. If the -clocks argument is not specified all clocks are reported. The minimum period is determined by examining the smallest slack paths between registers the rising edges of the clock or between falling edges of the clock. Paths between different clocks, different clock edges of the same clock, level sensitive latches, or paths constrained by set_multicycle_path, set_max_path are not considered. - - report_clock_properties + report_clock_properties - [clock_names] + [clock_names] - clock_names + clock_names - List of clock names to report. + List of clock names to report. @@ -9703,120 +9814,120 @@ - report_clock_skew + report_clock_skew - [-setup|-hold][-clocks clocks][-scenes scenes][-include_internal_latency][-digits digits] + [-setup|-hold][-clocks clocks][-scenes scenes][-include_internal_latency][-digits digits] - -setup + -setup - Report skew for setup checks. + Report skew for setup checks. - -hold + -hold - Report skew for hold checks. + Report skew for hold checks. - clocks + clocks - The clocks to report. The default value is all clocks in scenes modes. + The clocks to report. The default value is all clocks in scenes modes. - scenes + scenes - Report clocks for scenes. The default value is all scenes. + Report clocks for scenes. The default value is all scenes. - -include_internal_latency + -include_internal_latency - Include internal clock latency from liberty min/max_clock_tree_path timing groups. + Include internal clock latency from liberty min/max_clock_tree_path timing groups. - -digits digits + -digits digits - The number of digits to report for delays. + The number of digits to report for delays. - Report the maximum difference in clock arrival between every source and target register that has a path between the source and target registers. + Report the maximum difference in clock arrival between every source and target register that has a path between the source and target registers. - report_dcalc + report_dcalc - [-from from_pin][-to to_pin][-scene scene][-min][-max][-digits digits][> filename][>> filename] + [-from from_pin][-to to_pin][-scene scene][-min][-max][-digits digits][> filename][>> filename] - from_pin + from_pin - Report delay calculations for timing arcs from instance input pin from_pin. + Report delay calculations for timing arcs from instance input pin from_pin. - to_pin + to_pin - Report delay calculations for timing arcs to instance output pin to_pin. - - - - - scene - - - Report paths for process scene. The -scene keyword is required if more than one process corner is defined. + Report delay calculations for timing arcs to instance output pin to_pin. - -min + scene - Report delay calculation for min delays. + Report paths for process scene. The -scene keyword is required if more than one process corner is defined. - -max + -min - Report delay calculation for max delays. + Report delay calculation for min delays. - -digits digits + -max - The number of digits after the decimal point to report. The default is sta_report_default_digits. + Report delay calculation for max delays. + + + + + -digits digits + + + The number of digits after the decimal point to report. The default is sta_report_default_digits. @@ -9826,61 +9937,78 @@ - report_disabled_edges + report_disabled_edges - + The report_disabled_edges command reports disabled timing arcs along with the reason they are disabled. Each disabled timing arc is reported as the instance name along with the from and to ports of the arc. The disable reason is shown next. Arcs that are disabled with set_disable_timing are reported with constraint as the reason. Arcs that are disabled by constants are reported with constant as the reason along with the constant instance pin and value. Arcs that are disabled to break combinational feedback loops are reported with loop as the reason. - > report_disabled_edgesu1 A B constant B=0 + > report_disabled_edgesu1 A B constant B=0 - report_edges + report_edges - [-from from_pin][-to to_pin] + [-from from_pin][-to to_pin][-report_variation][-digits digits] - -from from_pin + from_pin - Report edges/timing arcs from pin from_pin. + Report edges/timing arcs from pin from_pin. - -to to_pin + to_pin - Report edges/timing arcs to pin to_pin. + Report edges/timing arcs to pin to_pin. + + + + + -report_variation + + + + + + + + digits + + + The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. - Report the edges/timing arcs and their delays in the timing graph from/to/between pins. + Report the edges/timing arcs and their delays in the timing graph from/to/between pins. + - report_instance + report_instance - instance_path[> filename][>> filename] + instance_path[> filename][>> filename] - instance_path + instance_path - Hierarchical path to an instance. + Hierarchical path to an instance. @@ -9890,262 +10018,280 @@ - report_lib_cell + report_lib_cell - cell_name[> filename][>> filename] + cell_name[> filename][>> filename] - - cell_name + cell_name - The name of a library cell. + The name of a library cell. - Describe the liberty library cell cell_name. + Describe the liberty library cell cell_name. - report_net + report_net - [-digits digits]net_path[> filename][>> filename] + [-digits digits]net_path[> filename][>> filename] - -digits digits + digits - The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. + The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. - net_path + net_path - Hierarchical path to a net. + Hierarchical path to a net. - Report the connections and capacitance of a net. + Report the connections and capacitance of a net. - report_parasitic_annotation + report_parasitic_annotation - [-report_unannotated][> filename][>> filename] + [-report_unannotated][> filename][>> filename] - -report_unannotated + -report_unannotated - Report unannotated and partially annotated nets. + Report unannotated and partially annotated nets. - Report SPEF parasitic annotation completeness. + Report SPEF parasitic annotation completeness. - report_power + report_power - [-instances instances][-highest_power_instances count][-digits digits][> filename][>> filename] + [-instances instances][-highest_power_instances count][-digits digits][> filename][>> filename] + + + + + + -instances instances + + + Report the power for each instance of instances. If the instance is hierarchical the total power for the instances inside the hierarchical instance is reported. - -instances instances + -highest_power_instances count - Report the power for each instance of instances. If the instance is hierarchical the total power for the instances inside the hierarchical instance is reported. + Report the power for the count highest power instances. - -highest_power_instances count + -digits digits - Report the power for the count highest power instances. - - - - - -digits digits - - - The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. + The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. - The report_power command uses static power analysis based on propagated or annotated pin activities in the circuit using Liberty power models. The internal, switching, leakage and total power are reported. Design power is reported separately for combinational, sequential, macro and pad groups. Power values are reported in watts. - The read_vcd or read_saif commands can be used to read activities from a file based on simulation. If no simulation activities are available, the set_power_activity command should be used to set the activity of input ports or pins in the design. The default input activity and duty for inputs are 0.1 and 0.5 respectively. The activities are propagated from annotated input ports or pins through gates and used in the power calculations. + The report_power command uses static power analysis based on propagated or annotated pin activities in the circuit using Liberty power models. The internal, switching, leakage and total power are reported. Design power is reported separately for combinational, sequential, macro and pad groups. Power values are reported in watts. + The read_vcd or read_saif commands can be used to read activities from a file based on simulation. If no simulation activities are available, the set_power_activity command should be used to set the activity of input ports or pins in the design. The default input activity and duty for inputs are 0.1 and 0.5 respectively. The activities are propagated from annotated input ports or pins through gates and used in the power calculations. Group Internal Switching Leakage Total Power Power Power Power----------------------------------------------------------------Sequential 3.29e-06 3.41e-08 2.37e-07 3.56e-06 92.4%Combinational 1.86e-07 3.31e-08 7.51e-08 2.94e-07 7.6%Macro 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0%Pad 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0%---------------------------------------------------------------Total 3.48e-06 6.72e-08 3.12e-07 3.86e-06 100.0% 90.2% 1.7% 8.1% - report_slews + report_slews - [-scenes scenes]pin + [-scenes scenes][-report_variation][-digits digits]pin - scenes + scenes - Report slews for process for scenes process corners.. + Report slews for process for scenes process corners. - pin + -report_variation - + Report SSTA distribution parameters. + + + + + -digits digits + + + The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. + + + + + pin + + + - Report the slews at pin + Report the slews at pin + - report_tns + report_tns - [-min][-max][-digits digits] + [-min][-max][-digits digits] - -max + -max - Report the total max/setup slack. + Report the total max/setup slack. - -min + -min - Report the total min/hold slack. + Report the total min/hold slack. - -digits digits + -digits digits - The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. + The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. - Report the total negative slack. + Report the total negative slack. - report_units + report_units - + - Report the units used for command arguments and reporting. - report_units time 1ns capacitance 1pF resistance 1kohm voltage 1v current 1A power 1pW distance 1um + Report the units used for command arguments and reporting. + report_units time 1ns capacitance 1pF resistance 1kohm voltage 1v current 1A power 1pW distance 1um - report_wns + report_wns - [-min][-max][-digits digits] + [-min][-max][-digits digits] - -max + -max - Report the worst max/setup slack. + Report the worst max/setup slack. - -min + -min - Report the worst min/hold slack. + Report the worst min/hold slack. - -digits digits + -digits digits - The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. + The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. - Report the worst negative slack. If the worst slack is positive, zero is reported. + Report the worst negative slack. If the worst slack is positive, zero is reported. - report_worst_slack + report_worst_slack - [-min][-max][-digits digits] + [-min][-max][-digits digits] + + + + + + -max + + + Report the worst max/setup slack. - -max + -min - Report the worst max/setup slack. + Report the worst min/hold slack. - -min + -digits digits - Report the worst min/hold slack. - - - - - -digits digits - - - The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. + The number of digits after the decimal point to report. The default value is the variable sta_report_default_digits. @@ -10153,117 +10299,117 @@ + + + set_assigned_check + + + -setup|-hold|-recovery|-removal[-rise][-fall][-scene scene][-min][-max][-from from_pins][-to to_pins][-clock rise|fall][-cond sdf_cond][-worst]margin + + + + + -setup + + + Annotate setup timing checks. + + + + + -hold + + + Annotate hold timing checks. + + + + + -recovery + + + Annotate recovery timing checks. + + + + + -removal + + + Annotate removal timing checks. + + + + + -rise + + + Annotate rising delays. + + + + + -fall + + + Annotate falling delays. + + + + + scene + + + The name of a scene. The -scene keyword is required if more than one scene is defined. + + + + + -min + + + Annotate the minimum value of the process corner. + + + + + -max + + + Annotate the maximum value of the process corner. + + + + + from_pins + + + A list of pins for the clock. + + + + + to_pins + + + A list of pins for the data. + + - - set_assigned_check + + -clock rise|fall - - -setup|-hold|-recovery|-removal[-rise][-fall][-scene scene][-min][-max][-from from_pins][-to to_pins][-clock rise|fall][-cond sdf_cond][-worst]margin + + The timing check clock pin transition. - -setup + margin - Annotate setup timing checks. - - - - - -hold - - - Annotate hold timing checks. - - - - - -recovery - - - Annotate recovery timing checks. - - - - - -removal - - - Annotate removal timing checks. - - - - - -rise - - - Annotate rising delays. - - - - - -fall - - - Annotate falling delays. - - - - - scene - - - The name of a scene. The -scene keyword is required if more than one scene is defined. - - - - - -min - - - Annotate the minimum value of the process corner. - - - - - -max - - - Annotate the maximum value of the process corner. - - - - - from_pins - - - A list of pins for the clock. - - - - - to_pins - - - A list of pins for the data. - - - - - -clock rise|fall - - - The timing check clock pin transition. - - - - - margin - - - The timing check margin. + The timing check margin. @@ -10271,93 +10417,92 @@ - - set_assigned_delay + set_assigned_delay - -cell|-net[-rise][-fall][-scene scene][-min][-max][-from from_pins][-to to_pins]delay + -cell|-net[-rise][-fall][-scene scene][-min][-max][-from from_pins][-to to_pins]delay - -cell + -cell - Annotate the delays between two pins on an instance. + Annotate the delays between two pins on an instance. - -net + -net - Annotate the delays between two pins on a net. + Annotate the delays between two pins on a net. - -rise + -rise - Annotate the rising delays. + Annotate the rising delays. - -fall + -fall - Annotate the falling delays. + Annotate the falling delays. - scene + scene - The name of a scene. The -scene keyword is required if more than one scene is defined. + The name of a scene. The -scene keyword is required if more than one scene is defined. - -min + -min - Annotate the minimum delays. + Annotate the minimum delays. - -max + -max - Annotate the maximum delays. + Annotate the maximum delays. - from_pins + from_pins - A list of pins. + A list of pins. - to_pins + to_pins - A list of pins. + A list of pins. - delay + delay - The delay between from_pins and to_pins. + The delay between from_pins and to_pins. @@ -10365,69 +10510,69 @@ - - - set_assigned_transition - - - [-rise][-fall][-scene scene][-min][-max]slewpin_list - - - - - -rise - - - Annotate the rising transition. - - - - -fall + + set_assigned_transition - - Annotate the falling transition. + + [-rise][-fall][-scene scene][-min][-max]slewpin_list - scene + -rise - Annotate delays for scene. + Annotate the rising transition. - -min + -fall - Annotate the minimum transition time. + Annotate the falling transition. - -max + scene - Annotate the maximum transition time. + Annotate delays for scene. - slew + -min - The pin transition time. + Annotate the minimum transition time. - pin_list + -max - A list of pins. + Annotate the maximum transition time. + + + + + slew + + + The pin transition time. + + + + + pin_list + + + A list of pins. @@ -10437,89 +10582,89 @@ - set_case_analysis + set_case_analysis - 0|1|zero|one|rise|rising|fall|fallingport_or_pin_list + 0|1|zero|one|rise|rising|fall|fallingport_or_pin_list - port_or_pin_list + port_or_pin_list - A list of ports or pins. + A list of ports or pins. The set_case_analysis command sets the signal on a port or pin to a constant logic value. No paths are propagated from constant pins. Constant values set with the set_case_analysis command are propagated through downstream gates. - Conditional timing arcs with mode groups are controlled by logic values on the instance pins. + Conditional timing arcs with mode groups are controlled by logic values on the instance pins. - set_clock_gating_check + set_clock_gating_check - [-setup setup_time][-hold hold_time][-rise][-fall][-high][-low][objects] - - - - - -setup setup_time - - - Clock enable setup margin. - - - - - -hold hold_time - - - Clock enable hold margin. - - - - - -rise - - - The setup/hold margin is for the rising edge of the clock enable. - - - - - -fall - - - The setup/hold margin is for the falling edge of the clock enable. - - - - - -high - - - The gating clock is active high (pin and instance objects only). + [-setup setup_time][-hold hold_time][-rise][-fall][-high][-low][objects] - -low + -setup setup_time - The gating clock is active low (pin and instance objects only). + Clock enable setup margin. - objects + -hold hold_time - A list of clocks, instances, pins or ports. + Clock enable hold margin. + + + + + -rise + + + The setup/hold margin is for the rising edge of the clock enable. + + + + + -fall + + + The setup/hold margin is for the falling edge of the clock enable. + + + + + -high + + + The gating clock is active high (pin and instance objects only). + + + + + -low + + + The gating clock is active low (pin and instance objects only). + + + + + objects + + + A list of clocks, instances, pins or ports. @@ -10533,197 +10678,197 @@ - set_clock_groups + set_clock_groups - [-name name][-logically_exclusive][-physically_exclusive][-asynchronous][-allow_paths]-group clocks + [-name name][-logically_exclusive][-physically_exclusive][-asynchronous][-allow_paths]-group clocks - -name name + -name name - The clock group name. + The clock group name. - -logically_exclusive + -logically_exclusive - The clocks in different groups do not interact logically but can be physically present on the same chip. Paths between clock groups are considered for noise analysis. + The clocks in different groups do not interact logically but can be physically present on the same chip. Paths between clock groups are considered for noise analysis. + + + + + + -physically_exclusive + + + The clocks in different groups cannot be present at the same time on a chip. Paths between clock groups are not considered for noise analysis. - -physically_exclusive + -asynchronous - The clocks in different groups cannot be present at the same time on a chip. Paths between clock groups are not considered for noise analysis. + The clock groups are asynchronous. Paths between clock groups are considered for noise analysis. - -asynchronous + -allow_paths - The clock groups are asynchronous. Paths between clock groups are considered for noise analysis. - - - - - -allow_paths - - - + - clocks + clocks - A list of clocks in the group. + A list of clocks in the group. - The set_clock_groups command is used to define groups of clocks that interact with each other. Clocks in different groups do not interact and paths between them are not reported. Use a –group argument for each clock group. + The set_clock_groups command is used to define groups of clocks that interact with each other. Clocks in different groups do not interact and paths between them are not reported. Use a –group argument for each clock group. - set_clock_latency + set_clock_latency - [-source][-clock clock][-rise][-fall][-min][-max]delayobjects + [-source][-clock clock][-rise][-fall][-min][-max]delayobjects - -source + -source - The latency is at the clock source. + The latency is at the clock source. - -clock clock + -clock clock - If multiple clocks are defined at a pin this use this option to specify the latency for a specific clock. + If multiple clocks are defined at a pin this use this option to specify the latency for a specific clock. - -rise + -rise - The latency is for the rising edge of the clock. + The latency is for the rising edge of the clock. - -fall + -fall - The latency is for the falling edge of the clock. + The latency is for the falling edge of the clock. - -min + -min - delay is the minimum latency. + delay is the minimum latency. - -max + -max - delay is the maximum latency. + delay is the maximum latency. - delay + delay - Clock source or insertion delay. + Clock source or insertion delay. - objects + objects - A list of clocks, pins or ports. + A list of clocks, pins or ports. - The set_clock_latency command describes expected delays of the clock tree when anxsalyzing a design using ideal clocks. Use the -source option to specify latency at the clock source, also known as insertion delay. Source latency is delay in the clock tree that is external to the design or a clock tree internal to an instance that implements a complex logic function.set_clock_latency removes propagated clock properties for the clocks and pins objects. + The set_clock_latency command describes expected delays of the clock tree when anxsalyzing a design using ideal clocks. Use the -source option to specify latency at the clock source, also known as insertion delay. Source latency is delay in the clock tree that is external to the design or a clock tree internal to an instance that implements a complex logic function.set_clock_latency removes propagated clock properties for the clocks and pins objects. - set_clock_transition + set_clock_transition - [-rise][-fall][-min][-max]transitionclocks + [-rise][-fall][-min][-max]transitionclocks - -rise + -rise - Set the transition time for the rising edge of the clock. - - - - - - -fall - - - Set the transition time for the falling edge of the clock. + Set the transition time for the rising edge of the clock. - -min + -fall - Set the min transition time. + Set the transition time for the falling edge of the clock. - -max + -min - Set the min transition time. + Set the min transition time. - transition + -max - Clock transition time (slew). + Set the min transition time. - clocks + transition - A list of clocks. + Clock transition time (slew). + + + + + clocks + + + A list of clocks. @@ -10733,154 +10878,155 @@ - set_clock_uncertainty + set_clock_uncertainty - [-from|-rise_from|-fall_from from_clock][-to|-rise_to|-fall_to to_clock][-rise][-fall][-setup][-hold]uncertainty[objects] + [-from|-rise_from|-fall_from from_clock][-to|-rise_to|-fall_to to_clock][-rise][-fall][-setup][-hold]uncertainty[objects] - -from from_clock + -from from_clock - Inter-clock uncertainty source clock. + Inter-clock uncertainty source clock. - -to to_clock + -to to_clock - Inter-clock uncertainty target clock. + Inter-clock uncertainty target clock. - -rise + -rise - Inter-clock target clock rise edge, alternative to ‑rise_to.Inter-clock target clock rise edge, alternative to ‑rise_to. + Inter-clock target clock rise edge, alternative to ‑rise_to.Inter-clock target clock rise edge, alternative to ‑rise_to. - -fall + -fall - Inter-clock target clock rise edge, alternative to ‑fall_to. + Inter-clock target clock rise edge, alternative to ‑fall_to. - -setup + -setup - uncertainty is for setup checks. + uncertainty is for setup checks. + + + + + + -hold + + + uncertainty is for hold checks. - -hold + uncertainty - uncertainty is for hold checks. + Clock uncertainty. - uncertainty + objects - Clock uncertainty. - - - - - objects - - - A list of clocks, ports or pins. + A list of clocks, ports or pins. - The set_clock_uncertainty command specifies the uncertainty or jitter in a clock. The uncertainty for a clock can be specified on its source pin or port, or the clock itself. - set_clock_uncertainty .1 [get_clock clk1] - Inter-clock uncertainty between the source and target clocks of timing checks is specified with the ‑from|‑rise_from|-fall_from andto|‑rise_to|-fall_to arguments . - set_clock_uncertainty -from [get_clock clk1] -to [get_clocks clk2] .1 - The following commands are equivalent. - set_clock_uncertainty -from [get_clock clk1] -rise_to [get_clocks clk2] .1set_clock_uncertainty -from [get_clock clk1] -to [get_clocks clk2] -rise .1 + The set_clock_uncertainty command specifies the uncertainty or jitter in a clock. The uncertainty for a clock can be specified on its source pin or port, or the clock itself. + set_clock_uncertainty .1 [get_clock clk1] + Inter-clock uncertainty between the source and target clocks of timing checks is specified with the ‑from|‑rise_from|-fall_from andto|‑rise_to|-fall_to arguments . + set_clock_uncertainty -from [get_clock clk1] -to [get_clocks clk2] .1 + The following commands are equivalent. + set_clock_uncertainty -from [get_clock clk1] -rise_to [get_clocks clk2] .1set_clock_uncertainty -from [get_clock clk1] -to [get_clocks clk2] -rise .1 - set_cmd_units + set_cmd_units - [-capacitance cap_unit][-resistance res_unit][-time time_unit][-voltage voltage_unit][-current current_unit][-power power_unit][-distance distance_unit] + [-capacitance cap_unit][-resistance res_unit][-time time_unit][-voltage voltage_unit][-current current_unit][-power power_unit][-distance distance_unit] - -capacitance cap_unit + -capacitance cap_unit - The capacitance scale factor followed by 'f'. + The capacitance scale factor followed by 'f'. - -resistance res_unit + -resistance res_unit - The resistance scale factor followed by 'ohm'. + The resistance scale factor followed by 'ohm'. - -time time_unit + -time time_unit - The time scale factor followed by 's'. + The time scale factor followed by 's'. - -voltage voltage_unit + -voltage voltage_unit - The voltage scale factor followed by 'v'. + The voltage scale factor followed by 'v'. - -current current_unit + -current current_unit - The current scale factor followed by 'A'. + The current scale factor followed by 'A'. - -power power_unit + -power power_unit - The power scale factor followed by 'w'. + The power scale factor followed by 'w'. - -distance distance_unit + -distance distance_unit - The distance scale factor followed by 'm'. + The distance scale factor followed by 'm'. - The set_cmd_units command is used to change the units used by the STA command interpreter when parsing commands and reporting results. The default units are the units specified in the first Liberty library file that is read. + The set_cmd_units command is used to change the units used by the STA command interpreter when parsing commands and reporting results. The default units are the units specified in the first Liberty library file that is read. Units are specified as a scale factor followed by a unit name. The scale factors are as follows. - M 1E+6k 1E+3m 1E-3u 1E-6n 1E-9p 1E-12f 1E-15 + M 1E+6k 1E+3m 1E-3u 1E-6n 1E-9p 1E-12f 1E-15 An example of the set_units command is shown below. set_cmd_units -time ns -capacitance pF -current mA -voltage V -resistance kOhm -distance um @@ -10888,58 +11034,58 @@ - set_data_check + set_data_check - [-from|-rise_from|-fall_from from_pin][-to|-rise_to|-fall_to to_pin][-setup][-hold][-clock clock]margin + [-from|-rise_from|-fall_from from_pin][-to|-rise_to|-fall_to to_pin][-setup][-hold][-clock clock]margin - -from from_pin + -from from_pin - A pin used as the timing check reference. + A pin used as the timing check reference. - -to to_pin + -to to_pin - A pin that the setup/hold check is applied to. + A pin that the setup/hold check is applied to. - -setup + -setup - Add a setup timing check. + Add a setup timing check. - -hold + -hold - Add a hold timing check. + Add a hold timing check. - -clock clock + -clock clock - The setup/hold check clock. + The setup/hold check clock. - margin + margin - The setup or hold time margin. + The setup or hold time margin. @@ -10949,123 +11095,121 @@ - set_disable_inferred_clock_gating + set_disable_inferred_clock_gating - objects + objects - objects + objects - A list of clock gating instances, clock gating pins, or clock enable pins. + A list of clock gating instances, clock gating pins, or clock enable pins. - The set_disable_inferred_clock_gating command disables clock gating checks on a clock gating instance, clock gating pin, or clock gating enable pin. + The set_disable_inferred_clock_gating command disables clock gating checks on a clock gating instance, clock gating pin, or clock gating enable pin. - - set_disable_timing + set_disable_timing - [-from from_port][-to to_port]objects + [-from from_port][-to to_port]objects - -from from_port + -from from_port - + - -to to_port + -to to_port - + - objects + objects - A list of instances, ports, pins, cells, cell/port, or library/cell/port. + A list of instances, ports, pins, cells, cell/port, or library/cell/port. The set_disable_timing command is used to disable paths though pins in the design. There are many different forms of the command depending on the objects specified in objects. - All timing paths though an instance are disabled when objects contains an instance. Timing checks in the instance are not disabled. + All timing paths though an instance are disabled when objects contains an instance. Timing checks in the instance are not disabled. set_disable_timing u2 The -from and -to options can be used to restrict the disabled path to those from, to or between specific pins on the instance. set_disable_timing -from A u2set_disable_timing -to Z u2set_disable_timing -from A -to Z u2 A list of top level ports or instance pins can also be disabled. set_disable_timing u2/Zset_disable_timing in1 Timing paths though all instances of a library cell in the design can be disabled by naming the cell using a hierarchy separator between the library and cell name. Paths from or to a cell port can be disabled with the -from and -to options or a port name after library and cell names. - set_disable_timing liberty1/snl_bufx2set_disable_timing -from A liberty1/snl_bufxset_disable_timing -to Z liberty1/snl_bufxset_disable_timing liberty1/snl_bufx2/A + set_disable_timing liberty1/snl_bufx2set_disable_timing -from A liberty1/snl_bufxset_disable_timing -to Z liberty1/snl_bufxset_disable_timing liberty1/snl_bufx2/A - set_drive + set_drive - [-rise][-fall][-max][-min]resistanceports - - - - - - -rise - - - Set the drive rise resistance. + [-rise][-fall][-max][-min]resistanceports - -fall + -rise - Set the drive fall resistance. + Set the drive rise resistance. - -max + -fall - Set the maximum resistance. + Set the drive fall resistance. - -min + -max - Set the minimum resistance. + Set the maximum resistance. - resistance + -min - The external drive resistance. + Set the minimum resistance. - ports + resistance + + + The external drive resistance. + + + + + ports A list of ports. @@ -11078,96 +11222,96 @@ - set_driving_cell + set_driving_cell - [-lib_cell cell_name][-library library][-rise][-fall][-min][-max][-pin pin][-from_pin from_pin][-input_transition_rise trans_rise][-input_transition_fall trans_fall]ports + [-lib_cell cell_name][-library library][-rise][-fall][-min][-max][-pin pin][-from_pin from_pin][-input_transition_rise trans_rise][-input_transition_fall trans_fall]ports - -lib_cell cell_name + -lib_cell cell_name - The driving cell. + The driving cell. - -library library + -library library - The driving cell library. + The driving cell library. - -rise + -rise - Set the driving cell for a rising edge. - - - - - -fall - - - Set the driving cell for a falling edge. - - - - - -max - - - Set the driving cell for max delays. - - - - - -min - - - Set the driving cell for min delays. - - - - - -pin pin - - - The output port of the driving cell. - - - - - -from_pin from_pin - - - Use timing arcs from from_pin to the output pin. + Set the driving cell for a rising edge. - -input_transition_rise trans_rise + -fall - The transition time for a rising input at from_pin. + Set the driving cell for a falling edge. - -input_transition_fall trans_fall + -max - The transition time for a falling input at from_pin. + Set the driving cell for max delays. - ports + -min + + + Set the driving cell for min delays. + + + + + -pin pin + + + The output port of the driving cell. + + + + + -from_pin from_pin + + + Use timing arcs from from_pin to the output pin. + + + + + -input_transition_rise trans_rise + + + The transition time for a rising input at from_pin. + + + + + -input_transition_fall trans_fall + + + The transition time for a falling input at from_pin. + + + + + ports A list of ports. @@ -11180,47 +11324,48 @@ - set_false_path + set_false_path - [-setup][-hold][-rise][-fall][-from from_list][-rise_from from_list][-fall_from from_list][-through through_list][-rise_through through_list][-fall_through through_list][-to to_list][-rise_to to_list][-fall_to to_list][-reset_path] + [-setup][-hold][-rise][-fall][-from from_list][-rise_from from_list][-fall_from from_list][-through through_list][-rise_through through_list][-fall_through through_list][-to to_list][-rise_to to_list][-fall_to to_list][-reset_path] - -setup + -setup - Apply to setup checks. + Apply to setup checks. - -hold + -hold - Apply to hold checks. + Apply to hold checks. - -rise + -rise - Apply to rising path edges. + Apply to rising path edges. - -fall + -fall - Apply to falling path edges. + Apply to falling path edges. + - -reset_path + -reset_path Remove any matching set_false_path, set_multicycle_path, set_max_delay, set_min_delay exceptions first. @@ -11228,7 +11373,7 @@ - -from from_list + -from from_list A list of clocks, instances, ports or pins. @@ -11236,7 +11381,7 @@ - -through through_list + -through through_list A list of instances, pins or nets. @@ -11244,7 +11389,7 @@ - -to to_list + -to to_list A list of clocks, instances, ports or pins. @@ -11252,7 +11397,7 @@ The set_false_path command disables timing along a path from, through and to a group of design objects. - Objects in from_list can be clocks, register/latch instances, or register/latch clock pins. The -rise_from and -fall_from keywords restrict the false paths to a specific clock edge. + Objects in from_list can be clocks, register/latch instances, or register/latch clock pins. The -rise_from and -fall_from keywords restrict the false paths to a specific clock edge. Objects in through_list can be nets, instances, instance pins, or hierarchical pins,. The -rise_through and -fall_through keywords restrict the false paths to a specific path edge that traverses through the object. Objects in to_list can be clocks, register/latch instances, or register/latch clock pins. The -rise_to and -fall_to keywords restrict the false paths to a specific transition at the path end. @@ -11260,10 +11405,10 @@ - set_fanout_load + set_fanout_load - fanoutport_list + fanoutport_list @@ -11273,18 +11418,18 @@ - set_hierarchy_separator + set_hierarchy_separator - separator + separator - separator + separator - Character used to separate hierarchical names. + Character used to separate hierarchical names. @@ -11294,10 +11439,10 @@ - set_ideal_latency + set_ideal_latency - [-rise] [-fall] [-min] [-max] delay objects + [-rise] [-fall] [-min] [-max] delay objects @@ -11307,10 +11452,10 @@ - set_ideal_network + set_ideal_network - [-no_propagation] objects + [-no_propagation] objects @@ -11320,187 +11465,186 @@ - set_ideal_transition + set_ideal_transition - [-rise] [-fall] [-min] [-max] transition_time objects + [-rise] [-fall] [-min] [-max] transition_time objects - The set_ideal_transition command is parsed but ignored. + The set_ideal_transition command is parsed but ignored. - - set_input_delay + set_input_delay - [-rise][-fall][-max][-min][-clock clock][-clock_fall][-reference_pin ref_pin][-source_latency_included][-network_latency_included][-add_delay]delayport_pin_list + [-rise][-fall][-max][-min][-clock clock][-clock_fall][-reference_pin ref_pin][-source_latency_included][-network_latency_included][-add_delay]delayport_pin_list - -rise + -rise - Set the arrival time for the rising edge of the input. + Set the arrival time for the rising edge of the input. - -fall + -fall - Set the arrival time for the falling edge of the input. + Set the arrival time for the falling edge of the input. - -max + -max - Set the maximum arrival time. + Set the maximum arrival time. - -min + -min - Set the minimum arrival time. + Set the minimum arrival time. - -clock clock + -clock clock - The arrival time is from clock. + The arrival time is from clock. - -clock_fall + -clock_fall - The arrival time is from the falling edge of clock. + The arrival time is from the falling edge of clock. - -reference_pin ref_pin + -reference_pin ref_pin - The arrival time is with respect to the clock that arrives at ref_pin. + The arrival time is with respect to the clock that arrives at ref_pin. - -source_latency_included + -source_latency_included - D no add the clock source latency (insertion delay) to the delay value. + D no add the clock source latency (insertion delay) to the delay value. - -network_latency_included + -network_latency_included - Do not add the clock latency to the delay value when the clock is ideal. + Do not add the clock latency to the delay value when the clock is ideal. - -add_delay + -add_delay - Add this arrival to any existing arrivals. + Add this arrival to any existing arrivals. - delay + delay - The arrival time after clock. + The arrival time after clock. - pin_port_list + pin_port_list - A list of pins or ports. + A list of pins or ports. - The set_input_delay command is used to specify the arrival time of an input signal. - The following command sets the min, max, rise and fall times on the in1 input port 1.0 time units after the rising edge of clk1. - set_input_delay -clock clk1 1.0 [get_ports in1] - Use multiple commands with the -add_delay option to specify separate arrival times for min, max, rise and fall times or multiple clocks. For example, the following specifies separate arrival times with respect to clocks clk1 and clk2. - set_input_delay -clock clk1 1.0 [get_ports in1]set_input_delay -add_delay -clock clk2 2.0 [get_ports in1] - The –reference_pin option is used to specify an arrival time with respect to the arrival on a pin in the clock network. For propagated clocks, the input arrival time is relative to the clock arrival time at the reference pin (the clock source latency and network latency from the clock source to the reference pin). For ideal clocks, input arrival time is relative to the reference pin clock source latency. With the -clock_fall flag the arrival time is relative to the falling transition at the reference pin. If no clocks arrive at the reference pin the set_input_delay command is ignored. If no -clock is specified the arrival time is with respect to all clocks that arrive at the reference pin. The -source_latency_included and -network_latency_included options cannot be used with -reference_pin. - Paths from inputs that do not have an arrival time defined by set_input_delay are not reported. Set the sta_input_port_default_clock variable to 1 to report paths from inputs without a set_input_delay. + The set_input_delay command is used to specify the arrival time of an input signal. + The following command sets the min, max, rise and fall times on the in1 input port 1.0 time units after the rising edge of clk1. + set_input_delay -clock clk1 1.0 [get_ports in1] + Use multiple commands with the -add_delay option to specify separate arrival times for min, max, rise and fall times or multiple clocks. For example, the following specifies separate arrival times with respect to clocks clk1 and clk2. + set_input_delay -clock clk1 1.0 [get_ports in1]set_input_delay -add_delay -clock clk2 2.0 [get_ports in1] + The –reference_pin option is used to specify an arrival time with respect to the arrival on a pin in the clock network. For propagated clocks, the input arrival time is relative to the clock arrival time at the reference pin (the clock source latency and network latency from the clock source to the reference pin). For ideal clocks, input arrival time is relative to the reference pin clock source latency. With the -clock_fall flag the arrival time is relative to the falling transition at the reference pin. If no clocks arrive at the reference pin the set_input_delay command is ignored. If no -clock is specified the arrival time is with respect to all clocks that arrive at the reference pin. The -source_latency_included and -network_latency_included options cannot be used with -reference_pin. + Paths from inputs that do not have an arrival time defined by set_input_delay are not reported. Set the sta_input_port_default_clock variable to 1 to report paths from inputs without a set_input_delay. - set_input_transition + set_input_transition - [-rise][-fall][-max][-min]transitionport_list + [-rise][-fall][-max][-min]transitionport_list - -rise + -rise - Set the rising edge transition. + Set the rising edge transition. - -fall + -fall - Set the falling edge transition. + Set the falling edge transition. - -max + -max - Set the minimum transition time. + Set the minimum transition time. - -min + -min - Set the maximum transition time. + Set the maximum transition time. - transition + transition - The transition time (slew). + The transition time (slew). - port_list + port_list - A list of ports. + A list of ports. @@ -11510,10 +11654,10 @@ - set_level_shifter_strategy + set_level_shifter_strategy - [-rule rule_type] + [-rule rule_type] @@ -11524,10 +11668,10 @@ - set_level_shifter_threshold + set_level_shifter_threshold - [-voltage voltage] + [-voltage voltage] @@ -11537,55 +11681,55 @@ - set_load + set_load - [-rise][-fall][-max][-min][-subtract_pin_load][-pin_load][-wire_load]capacitanceobjects + [-rise][-fall][-max][-min][-subtract_pin_load][-pin_load][-wire_load]capacitanceobjects - -rise + -rise - Set the external port rising capacitance (ports only). + Set the external port rising capacitance (ports only). - -fall + -fall - Set the external port falling capacitance (ports only). + Set the external port falling capacitance (ports only). - -max + -max - Set the max capacitance. + Set the max capacitance. - -min + -min - Set the min capacitance. + Set the min capacitance. - -subtract_pin_load + -subtract_pin_load - Subtract the capacitance of all instance pins connected to the net from capacitance (nets only). If the resulting capacitance is negative, zero is used. Pin capacitances are ignored by delay calculation when this option is used. + Subtract the capacitance of all instance pins connected to the net from capacitance (nets only). If the resulting capacitance is negative, zero is used. Pin capacitances are ignored by delay calculation when this option is used. - -pin_load + -pin_load capacitance is external instance pin capacitance (ports only). @@ -11593,7 +11737,7 @@ - -wire_load + -wire_load capacitance is external wire capacitance (ports only). @@ -11601,7 +11745,7 @@ - capacitance + capacitance The capacitance, in library capacitance units. @@ -11609,34 +11753,34 @@ - objects + objects A list of nets or ports. - The set_load command annotates wire capacitance on a net or external capacitance on a port. There are four different uses for the set_load commanc: - set_load -wire_load port external port wire capacitanceset_load -pin_load port external port pin capacitanceset_load port same as -pin_loadset_load net net wire capacitance - External port capacitance can be annotated separately with the -pin_load and ‑wire_load options. Without the -pin_load and -wire_load options pin capacitance is annotated. - When annotating net wire capacitance with the -subtract_pin_load option the capacitance of all instance pins connected to the net is subtracted from capacitance. Setting the capacitance on a net overrides SPEF parasitics for delay calculation. + The set_load command annotates wire capacitance on a net or external capacitance on a port. There are four different uses for the set_load commanc: + set_load -wire_load port external port wire capacitanceset_load -pin_load port external port pin capacitanceset_load port same as -pin_loadset_load net net wire capacitance + External port capacitance can be annotated separately with the -pin_load and ‑wire_load options. Without the -pin_load and -wire_load options pin capacitance is annotated. + When annotating net wire capacitance with the -subtract_pin_load option the capacitance of all instance pins connected to the net is subtracted from capacitance. Setting the capacitance on a net overrides SPEF parasitics for delay calculation. - set_logic_dc + set_logic_dc - port_list + port_list - port_pin_list + port_pin_list - List of ports or pins. + List of ports or pins. @@ -11646,60 +11790,60 @@ - set_logic_one + set_logic_one - port_list + port_list - port_pin_list + port_pin_list - List of ports or pins. + List of ports or pins. - Set a port or pin to a constant logic one value. No paths are propagated from constant pins. Constant values set with the set_logic_one command are not propagated through downstream gates. + Set a port or pin to a constant logic one value. No paths are propagated from constant pins. Constant values set with the set_logic_one command are not propagated through downstream gates. - set_logic_zero + set_logic_zero - port_list + port_list - port_pin_list + port_pin_list - List of ports or pins. + List of ports or pins. - Set a port or pin to a constant logic zero value. No paths are propagated from constant pins. Constant values set with the set_logic_zero command are not propagated through downstream gates. + Set a port or pin to a constant logic zero value. No paths are propagated from constant pins. Constant values set with the set_logic_zero command are not propagated through downstream gates. - set_max_area + set_max_area - area + area - area + area - + @@ -11709,27 +11853,27 @@ - set_max_capacitance + set_max_capacitance - capacitanceobjects + capacitanceobjects - capacitance + capacitance - + - objects + objects - List of ports or cells. + List of ports or cells. @@ -11739,31 +11883,31 @@ - set_max_delay + set_max_delay - [-rise][-fall][-from from_list][-rise_from from_list][-fall_from from_list][-through through_list][-rise_through through_list][-fall_through through_list][-to to_list][-rise_to to_list][-fall_to to_list][-ignore_clock_latency][-probe][-reset_path]delay + [-rise][-fall][-from from_list][-rise_from from_list][-fall_from from_list][-through through_list][-rise_through through_list][-fall_through through_list][-to to_list][-rise_to to_list][-fall_to to_list][-ignore_clock_latency][-probe][-reset_path]delay - -rise + -rise - Set max delay for rising paths. + Set max delay for rising paths. - -fall + -fall - Set max delay for falling paths. + Set max delay for falling paths. - -from from_list + -from from_list A list of clocks, instances, ports or pins. @@ -11771,7 +11915,7 @@ - -through through_list + -through through_list A list of instances, pins or nets. @@ -11779,7 +11923,7 @@ - -to to_list + -to to_list A list of clocks, instances, ports or pins. @@ -11787,7 +11931,7 @@ - -ignore_clock_latency + -ignore_clock_latency Ignore clock latency at the source and target registers. @@ -11795,15 +11939,15 @@ - -probe + -probe - Do not break paths at internal pins (non startpoints). + Do not break paths at internal pins (non startpoints). - -reset_path + -reset_path Remove any matching set_false_path, set_multicycle_path, set_max_delay, set_min_delay exceptions first. @@ -11811,7 +11955,7 @@ - delay + delay The maximum delay. @@ -11825,10 +11969,10 @@ - set_max_dynamic_power + set_max_dynamic_power - power [unit] + power [unit] @@ -11838,26 +11982,26 @@ - set_max_fanout + set_max_fanout - fanoutobjects + fanoutobjects - fanout + fanout - + - objects + objects - List of ports or cells. + List of ports or cells. @@ -11867,10 +12011,10 @@ - set_max_leakage_power + set_max_leakage_power - power [unit] + power [unit] @@ -11880,92 +12024,92 @@ - set_max_time_borrow + set_max_time_borrow - delayobjects + delayobjects - delay + delay - The maximum time the latches can borrow. + The maximum time the latches can borrow. - objects + objects - List of clocks, instances or pins. + List of clocks, instances or pins. - The set_max_time_borrow command specifies the maximum amount of time that latches can borrow. Time borrowing is the time that a data input to a transparent latch arrives after the latch opens. + The set_max_time_borrow command specifies the maximum amount of time that latches can borrow. Time borrowing is the time that a data input to a transparent latch arrives after the latch opens. - set_max_transition + set_max_transition - [-data_path][-clock_path][-rise][-fall]transitionobjects + [-data_path][-clock_path][-rise][-fall]transitionobjects - -data_path + -data_path - Set the max slew for data paths. + Set the max slew for data paths. - -clock_path + -clock_path - Set the max slew for clock paths. + Set the max slew for clock paths. - -rise + -rise - Set the max slew for rising paths. + Set the max slew for rising paths. - -fall + -fall - Set the max slew for falling paths. + Set the max slew for falling paths. - transition + transition - The maximum slew/transition time. + The maximum slew/transition time. - objects + objects - List of clocks, ports or designs. + List of clocks, ports or designs. - The set_max_transition command is specifies the maximum transition time (slew) design rule checked by the report_check_types –max_transition command. + The set_max_transition command is specifies the maximum transition time (slew) design rule checked by the report_check_types –max_transition command. If specified for a design, the default maximum transition is set for the design. If specified for a clock, the maximum transition is applied to all pins in the clock domain. The –clock_path option restricts the maximum transition to clocks in clock paths. The -data_path option restricts the maximum transition to clocks data paths. The –clock_path, -data_path, -rise and –fall options only apply to clock objects. @@ -11973,26 +12117,26 @@ - set_min_capacitance + set_min_capacitance - capacitanceobjects + capacitanceobjects - capacitance + capacitance - Minimum capacitance. + Minimum capacitance. - objects + objects - List of ports or cells. + List of ports or cells. @@ -12002,32 +12146,32 @@ - set_min_delay + set_min_delay - [-rise][-fall][-from from_list][-rise_from from_list][-fall_from from_list][-through through_list][-rise_through through_list][-fall_through through_list][-to to_list][-rise_to to_list][-fall_to to_list][-ignore_clock_latency][-probe][-reset_path]delay + [-rise][-fall][-from from_list][-rise_from from_list][-fall_from from_list][-through through_list][-rise_through through_list][-fall_through through_list][-to to_list][-rise_to to_list][-fall_to to_list][-ignore_clock_latency][-probe][-reset_path]delay - -rise + -rise - Set min delay for rising paths. + Set min delay for rising paths. - -fall + -fall - Set min delay for falling paths. + Set min delay for falling paths. - -from from_list + -from from_list A list of clocks, instances, ports or pins. @@ -12035,7 +12179,7 @@ - -through through_list + -through through_list A list of instances, pins or nets. @@ -12043,7 +12187,7 @@ - -to to_list + -to to_list A list of clocks, instances, ports or pins. @@ -12051,7 +12195,7 @@ - -ignore_clock_latency + -ignore_clock_latency Ignore clock latency at the source and target registers. @@ -12059,15 +12203,15 @@ - -probe + -probe - Do not break paths at internal pins (non startpoints). + Do not break paths at internal pins (non startpoints). - -reset_path + -reset_path Remove any matching set_false_path, set_multicycle_path, set_max_delay, set_min_delay exceptions first. @@ -12075,10 +12219,10 @@ - delay + delay - The minimum delay. + The minimum delay. @@ -12089,42 +12233,42 @@ - set_min_pulse_width + set_min_pulse_width - [-high][-low]min_widthobjects + [-high][-low]min_widthobjects - -high + -high - Set the minimum high pulse width. + Set the minimum high pulse width. - -low + -low - Set the minimum low pulse width. + Set the minimum low pulse width. - min_width + min_width - + - objects + objects - List of pins, instances or clocks. + List of pins, instances or clocks. @@ -12134,61 +12278,61 @@ - set_mode + set_mode - mode_name + mode_name - The the mode for SDC c ommands in the TCL interpreter. If mode mode_name does not exist, it is created. When modes are created the default mode is deleted. + The the mode for SDC c ommands in the TCL interpreter. If mode mode_name does not exist, it is created. When modes are created the default mode is deleted. - set_multicycle_path + set_multicycle_path - [-setup][-hold][-rise][-fall][-start][-end][-from from_list][-rise_from from_list][-fall_from from_list][-through through_list][-rise_through through_list][-fall_through through_list][-to to_list][-rise_to to_list][-fall_to to_list][-reset_path]path_multiplier + [-setup][-hold][-rise][-fall][-start][-end][-from from_list][-rise_from from_list][-fall_from from_list][-through through_list][-rise_through through_list][-fall_through through_list][-to to_list][-rise_to to_list][-fall_to to_list][-reset_path]path_multiplier - -setup + -setup - Set cycle count for setup checks. + Set cycle count for setup checks. - -hold + -hold - Set cycle count for hold checks. + Set cycle count for hold checks. - -rise + -rise - Set cycle count for rising path edges. + Set cycle count for rising path edges. - -fall + -fall - Set cycle count for falling path edges. + Set cycle count for falling path edges. - -start + -start Multiply the source clock period by period_multiplier. @@ -12196,7 +12340,7 @@ - -end + -end Multiply the target clock period by period_multiplier. @@ -12204,7 +12348,7 @@ - -from from_list + -from from_list A list of clocks, instances, ports or pins. @@ -12212,7 +12356,7 @@ - -through through_list + -through through_list A list of instances, pins or nets. @@ -12220,7 +12364,7 @@ - -to to_list + -to to_list A list of clocks, instances, ports or pins. @@ -12228,7 +12372,7 @@ - -reset_path + -reset_path Remove any matching set_false_path, set_multicycle_path, set_max_delay, set_min_delay exceptions first. @@ -12236,7 +12380,7 @@ - path_multiplier + path_multiplier The number of clock periods to add to the path required time. @@ -12250,82 +12394,82 @@ - set_operating_conditions + set_operating_conditions - [-analysis_type single|bc_wc|on_chip_variation][-library lib][condition][-min min_condition][-max max_condition][-min_library min_lib][-max_library max_lib] + [-analysis_type single|bc_wc|on_chip_variation][-library lib][condition][-min min_condition][-max max_condition][-min_library min_lib][-max_library max_lib] - -analysis_type single + -analysis_type single - Use one operating condition for min and max paths. + Use one operating condition for min and max paths. - -analysis_type bc_wc + -analysis_type bc_wc - Best case, worst case analysis. Setup checks use max_condition for clock and data paths. Hold checks use the min_condition for clock and data paths. + Best case, worst case analysis. Setup checks use max_condition for clock and data paths. Hold checks use the min_condition for clock and data paths. - ‑analysis_type on_chip_variation + ‑analysis_type on_chip_variation - The min and max operating conditions represent variations on the chip that can occur simultaneously. Setup checks use max_condition for data paths and min_condition for clock paths. Hold checks use min_condition for data paths and max_condition for clock paths. This is the default analysis type. + The min and max operating conditions represent variations on the chip that can occur simultaneously. Setup checks use max_condition for data paths and min_condition for clock paths. Hold checks use min_condition for data paths and max_condition for clock paths. This is the default analysis type. - -library lib + -library lib - The name of the library that contains condition. + The name of the library that contains condition. - condition + condition - The operating condition for analysis type single. + The operating condition for analysis type single. - -min min_condition + -min min_condition - The operating condition to use for min paths and hold checks. + The operating condition to use for min paths and hold checks. - -max max_condition + -max max_condition - The operating condition to use for max paths and setup checks. + The operating condition to use for max paths and setup checks. - -min_library min_lib + -min_library min_lib - The name of the library that contains min_condition. + The name of the library that contains min_condition. - -max_library max_lib + -max_library max_lib - The name of the library that contains max_condition. + The name of the library that contains max_condition. @@ -12335,237 +12479,237 @@ - set_output_delay + set_output_delay - [-rise][-fall][-max][-min][-clock clock][-clock_fall][-reference_pin ref_pin][-source_latency_included][-network_latency_included][-add_delay]delayport_pin_list + [-rise][-fall][-max][-min][-clock clock][-clock_fall][-reference_pin ref_pin][-source_latency_included][-network_latency_included][-add_delay]delayport_pin_list - -rise + -rise - Set the output delay for the rising edge of the input. + Set the output delay for the rising edge of the input. - -fall + -fall - Set the output delay for the falling edge of the input. + Set the output delay for the falling edge of the input. - -max + -max - Set the maximum output delay. + Set the maximum output delay. - -min + -min - Set the minimum output delay. + Set the minimum output delay. - -clock clock + -clock clock - The external check is to clock. The default clock edge is rising. + The external check is to clock. The default clock edge is rising. - -clock_fall + -clock_fall - The external check is to the falling edge of clock. + The external check is to the falling edge of clock. - -reference_pin ref_pin + -reference_pin ref_pin - The external check is clocked by the clock that arrives at ref_pin. + The external check is clocked by the clock that arrives at ref_pin. - -add_delay + -add_delay - Add this output delay to any existing output delays. + Add this output delay to any existing output delays. - delay + delay - The external delay to the check clocked by clock. + The external delay to the check clocked by clock. - pin_port_list + pin_port_list - A list of pins or ports. + A list of pins or ports. - The set_output_delay command is used to specify the external delay to a setup/hold check on an output port or internal pin that is clocked by clock. Unless the -add_delay option is specified any existing output delays are replaced. - The –reference_pin option is used to specify a timing check with respect to the arrival on a pin in the clock network. For propagated clocks, the timing check is relative to the clock arrival time at the reference pin (the clock source latency and network latency from the clock source to the reference pin). For ideal clocks, the timing check is relative to the reference pin clock source latency. With the -clock_fall flag the timing check is relative to the falling edge of the reference pin. If no clocks arrive at the reference pin the set_output_delay command is ignored. If no -clock is specified the timing check is with respect to all clocks that arrive at the reference pin. The -source_latency_included and -network_latency_included options cannot be used with -reference_pin. + The set_output_delay command is used to specify the external delay to a setup/hold check on an output port or internal pin that is clocked by clock. Unless the -add_delay option is specified any existing output delays are replaced. + The –reference_pin option is used to specify a timing check with respect to the arrival on a pin in the clock network. For propagated clocks, the timing check is relative to the clock arrival time at the reference pin (the clock source latency and network latency from the clock source to the reference pin). For ideal clocks, the timing check is relative to the reference pin clock source latency. With the -clock_fall flag the timing check is relative to the falling edge of the reference pin. If no clocks arrive at the reference pin the set_output_delay command is ignored. If no -clock is specified the timing check is with respect to all clocks that arrive at the reference pin. The -source_latency_included and -network_latency_included options cannot be used with -reference_pin. - set_port_fanout_number + set_port_fanout_number - [-min][-max]fanoutports + [-min][-max]fanoutports - -min + -min - Set the min fanout. + Set the min fanout. - -max + -max - Set the max fanout. + Set the max fanout. - fanout + fanout - The external fanout of the ports. + The external fanout of the ports. - port_list + port_list - A list of ports. + A list of ports. - Set the external fanout for ports. + Set the external fanout for ports. - set_power_activity + set_power_activity - [-global][-input][-input_ports ports][-pins pins][-activity activity | -density density][-duty duty][-clock clock] + [-global][-input][-input_ports ports][-pins pins][-activity activity | -density density][-duty duty][-clock clock] - -global + -global - Set the activity/duty for all non-clock pins. + Set the activity/duty for all non-clock pins. - -input + -input - Set the default input port activity/duty. + Set the default input port activity/duty. - -input_ports input_ports + -input_ports input_ports - Set the input port activity/duty. + Set the input port activity/duty. - -pins pins + -pins pins - Set the pin activity/duty. + Set the pin activity/duty. - -activity activity + -activity activity - The activity, or number of transitions per clock cycle. If clock is not specified the clock with the minimum period is used. If no clocks are defined an error is reported. + The activity, or number of transitions per clock cycle. If clock is not specified the clock with the minimum period is used. If no clocks are defined an error is reported. - -density density + -density density - Transitions per library time unit. + Transitions per library time unit. - -duty duty + -duty duty - The duty, or probability the signal is high (0 <= duty <= 1.0). Defaults to 0.5. + The duty, or probability the signal is high (0 <= duty <= 1.0). Defaults to 0.5. - -clock clock + -clock clock - The clock to use for the period with -activity. This option is ignored if -density is used. + The clock to use for the period with -activity. This option is ignored if -density is used. - The set_power_activity command is used to set the activity and duty used for power analysis globally or for input ports or pins in the design. - The default input activity for inputs is 0.1 transitions per minimum clock period if a clock is defined or 0.0 if there are no clocks defined. The default input duty is 0.5. This is equivalent to the following command: - set_power_activity -input -activity 0.1 -duty 0.5 + The set_power_activity command is used to set the activity and duty used for power analysis globally or for input ports or pins in the design. + The default input activity for inputs is 0.1 transitions per minimum clock period if a clock is defined or 0.0 if there are no clocks defined. The default input duty is 0.5. This is equivalent to the following command: + set_power_activity -input -activity 0.1 -duty 0.5 - set_propagated_clock + set_propagated_clock - objects + objects - objects + objects - A list of clocks, ports or pins. + A list of clocks, ports or pins. @@ -12576,59 +12720,59 @@ - set_pvt + set_pvt - [-min][-max][-process process][-voltage voltage] - [-temperature temperature]instances + [-min][-max][-process process][-voltage voltage] + [-temperature temperature]instances - -min + -min - Set the PVT values for max delays. + Set the PVT values for max delays. - -max + -max - Set the PVT values for min delays. + Set the PVT values for min delays. - -process process + -process process - A process value (float). + A process value (float). - -voltage voltage + -voltage voltage - A voltage value (float). + A voltage value (float). - -temperature temperature + -temperature temperature - A temperature value (float). + A temperature value (float). - instances + instances - A list instances. + A list instances. @@ -12638,177 +12782,177 @@ - set_sense + set_sense - [-type clock|data][-positive][-negative][-pulse pulse_type][-stop_propagation][-clock clocks]pins + [-type clock|data][-positive][-negative][-pulse pulse_type][-stop_propagation][-clock clocks]pins - -type clock + -type clock - Set the sense for clock paths. + Set the sense for clock paths. - -type data + -type data - Set the sense for data paths (not supported). + Set the sense for data paths (not supported). - -positive + -positive - The clock sense is positive unate. + The clock sense is positive unate. - -negative + -negative - The clock sense is negative unate. + The clock sense is negative unate. - -pulse pulse_type + -pulse pulse_type - rise_triggered_high_pulserise_triggered_low_pulsefall_triggered_high_pulsefall_triggered_low_pulseNot supported. + rise_triggered_high_pulserise_triggered_low_pulsefall_triggered_high_pulsefall_triggered_low_pulseNot supported. - -stop_propagation + -stop_propagation - Stop propagating clocks at pins. + Stop propagating clocks at pins. - clocks + clocks - A list of clocks to apply the sense. + A list of clocks to apply the sense. - pins + pins - A list of pins. + A list of pins. - The set_sense command is used to modify the propagation of a clock signal. The clock sense is set with the ‑positive and –negative flags. Use the –stop_propagation flag to stop the clock from propagating beyond a pin. The –positive, -negative, -stop_propagation, and –pulse options are mutually exclusive. If the –clock option is not used the command applies to all clocks that traverse pins. The –pulse option is currently not supported. + The set_sense command is used to modify the propagation of a clock signal. The clock sense is set with the ‑positive and –negative flags. Use the –stop_propagation flag to stop the clock from propagating beyond a pin. The –positive, -negative, -stop_propagation, and –pulse options are mutually exclusive. If the –clock option is not used the command applies to all clocks that traverse pins. The –pulse option is currently not supported. - set_timing_derate + set_timing_derate - [-rise][-fall][-early][-late][-clock][-data][-net_delay][-cell_delay][-cell_check]derate[objects] + [-rise][-fall][-early][-late][-clock][-data][-net_delay][-cell_delay][-cell_check]derate[objects] - -rise + -rise - Set the derating for rising delays. + Set the derating for rising delays. - -fall + -fall - Set the derating for falling delays. + Set the derating for falling delays. - -early + -early - Derate early (min) paths. + Derate early (min) paths. - -late + -late - Derate late (max) paths. + Derate late (max) paths. - -clock + -clock - Derate paths in the clock network. + Derate paths in the clock network. - -data + -data - Derate data paths. + Derate data paths. - -net_delay + -net_delay - Derate net (interconnect) delays. + Derate net (interconnect) delays. - -cell_delay + -cell_delay - Derate cell delays. + Derate cell delays. - -cell_check + -cell_check - Derate cell timing check margins. + Derate cell timing check margins. - derate + derate - The derating factor to apply to delays. + The derating factor to apply to delays. - objects + objects - A list of instances, library cells, or nets. + A list of instances, library cells, or nets. @@ -12819,42 +12963,42 @@ - set_resistance + set_resistance - [-max][-min]resistancenets + [-max][-min]resistancenets - -min + -min - The resistance for minimum path delay calculation. + The resistance for minimum path delay calculation. - -max + -max - The resistance for maximum path delay calculation. + The resistance for maximum path delay calculation. - resistance + resistance - The net resistance. + The net resistance. - nets + nets - A list of nets. + A list of nets. @@ -12864,76 +13008,76 @@ - set_units + set_units - [-capacitance cap_unit][-resistance res_unit][-time time_unit][-voltage voltage_unit][-current current_unit][-power power_unit][-distance distance_unit] + [-capacitance cap_unit][-resistance res_unit][-time time_unit][-voltage voltage_unit][-current current_unit][-power power_unit][-distance distance_unit] - -capacitance cap_unit + -capacitance cap_unit - The capacitance scale factor followed by 'f'. + The capacitance scale factor followed by 'f'. - -resistance res_unit + -resistance res_unit - The resistance scale factor followed by 'ohm'. + The resistance scale factor followed by 'ohm'. - -time time_unit + -time time_unit - The time scale factor followed by 's'. + The time scale factor followed by 's'. - -voltage voltage_unit + -voltage voltage_unit - The voltage scale factor followed by 'v'. + The voltage scale factor followed by 'v'. - -current current_unit + -current current_unit - The current scale factor followed by 'A'. + The current scale factor followed by 'A'. - -power power_unit + -power power_unit - The power scale factor followed by 'w'. + The power scale factor followed by 'w'. - The set_units command is used to check the units used by the STA command interpreter when parsing commands and reporting results. If the current units differ from the set_unit value a warning is printed. Use the set_cmd_units command to change the command units. + The set_units command is used to check the units used by the STA command interpreter when parsing commands and reporting results. If the current units differ from the set_unit value a warning is printed. Use the set_cmd_units command to change the command units. Units are specified as a scale factor followed by a unit name. The scale factors are as follows. - M 1E+6k 1E+3m 1E-3u 1E-6n 1E-9p 1E-12f 1E-15 + M 1E+6k 1E+3m 1E-3u 1E-6n 1E-9p 1E-12f 1E-15 An example of the set_units command is shown below. - set_units -time ns -capacitance pF -current mA -voltage V -resistance kOhm + set_units -time ns -capacitance pF -current mA -voltage V -resistance kOhm - set_wire_load_min_block_size + set_wire_load_min_block_size - size + size @@ -12943,34 +13087,34 @@ - set_wire_load_mode + set_wire_load_mode - top|enclosed|segmented + top|enclosed|segmented - top + top - + - enclosed + enclosed - + - segmented + segmented - + @@ -12980,51 +13124,51 @@ - set_wire_load_model + set_wire_load_model - -name model_name[-library library][-max][-min][objects] + -name model_name[-library library][-max][-min][objects] - -name model_name + -name model_name - The name of a wire load model. + The name of a wire load model. - -library library + -library library - Library to look for model_name. + Library to look for model_name. - -max + -max - The wire load model is for maximum path delays. + The wire load model is for maximum path delays. - -min + -min - The wire load model is for minimum path delays. + The wire load model is for minimum path delays. - objects + objects - Not supported. + Not supported. @@ -13034,50 +13178,50 @@ - set_wire_load_selection_group + set_wire_load_selection_group - [-library library][-max][-min]group_name[objects] + [-library library][-max][-min]group_name[objects] - library + library - Library to look for group_name. + Library to look for group_name. - -max + -max - The wire load selection is for maximum path delays. + The wire load selection is for maximum path delays. - -min + -min - The wire load selection is for minimum path delays. + The wire load selection is for minimum path delays. - group_name + group_name - A wire load selection group name. + A wire load selection group name. - objects + objects - Not supported. + Not supported. @@ -13087,39 +13231,39 @@ - suppress_msg + suppress_msg - msg_ids + msg_ids - msg_ids + msg_ids - A list of error/warning message IDs to suppress. + A list of error/warning message IDs to suppress. - The suppress_msg command suppresses specified error/warning messages by ID. The list of message IDs can be found in doc/messages.txt. + The suppress_msg command suppresses specified error/warning messages by ID. The list of message IDs can be found in doc/messages.txt. - unset_case_analysis + unset_case_analysis - port_or_pin_list + port_or_pin_list - port_or_pin_list + port_or_pin_list - A list of ports or pins. + A list of ports or pins. @@ -13129,26 +13273,26 @@ - unset_clock_latency + unset_clock_latency - [-source]objects + [-source]objects - -source + -source - Specifies source clock latency (clock insertion delay). + Specifies source clock latency (clock insertion delay). - objects + objects - A list of clocks, pins or ports. + A list of clocks, pins or ports. @@ -13158,18 +13302,18 @@ - unset_clock_transition + unset_clock_transition - clocks + clocks - clocks + clocks - A list of clocks. + A list of clocks. @@ -13179,74 +13323,74 @@ - unset_clock_uncertainty + unset_clock_uncertainty - [-from|-rise_from|-fall_from from_clock][-to|-rise_to|-fall_to to_clock][-rise][-fall][-setup][-hold][objects] + [-from|-rise_from|-fall_from from_clock][-to|-rise_to|-fall_to to_clock][-rise][-fall][-setup][-hold][objects] - -from from_clock + -from from_clock - + - -to to_clock + -to to_clock - + - -rise + -rise - The uncertainty is for the rising edge of the clock. + The uncertainty is for the rising edge of the clock. - -fall + -fall - The uncertainty is for the falling edge of the clock. + The uncertainty is for the falling edge of the clock. - -setup + -setup - uncertainty is the setup check uncertainty. + uncertainty is the setup check uncertainty. - -hold + -hold - uncertainty is the hold uncertainty. + uncertainty is the hold uncertainty. - uncertainty + uncertainty - Clock uncertainty. + Clock uncertainty. - objects + objects - A list of clocks, ports or pins. + A list of clocks, ports or pins. @@ -13256,50 +13400,50 @@ - unset_data_check + unset_data_check - [-from|-rise_from|-fall_from from_object][-to|-rise_to|-fall_to to_object][-setup][-hold][-clock clock] + [-from|-rise_from|-fall_from from_object][-to|-rise_to|-fall_to to_object][-setup][-hold][-clock clock] - -from from_object + -from from_object - A pin used as the timing check reference. + A pin used as the timing check reference. - -to to_object + -to to_object - A pin that the setup/hold check is applied to. + A pin that the setup/hold check is applied to. - -setup + -setup - Add a setup timing check. + Add a setup timing check. - -hold + -hold - Add a hold timing check. + Add a hold timing check. - clock + clock - The setup/hold check clock. + The setup/hold check clock. @@ -13309,52 +13453,52 @@ - unset_disable_inferred_clock_gating + unset_disable_inferred_clock_gating - objects + objects - objects + objects - A list of clock gating instances, clock gating pins, or clock enable pins. + A list of clock gating instances, clock gating pins, or clock enable pins. - The unset_disable_inferred_clock_gating command removes a previous set_disable_inferred_clock_gating command. + The unset_disable_inferred_clock_gating command removes a previous set_disable_inferred_clock_gating command. - unset_disable_timing + unset_disable_timing - [-from from_port][-to to_port]objects + [-from from_port][-to to_port]objects - from_port + from_port - + - to_port + to_port - + - objects + objects A list of instances, ports, pins, cells or [library/]cell/port. @@ -13368,66 +13512,66 @@ - unset_input_delay + unset_input_delay - [-rise][-fall][-max][-min][-clock clock][-clock_fall]port_pin_list + [-rise][-fall][-max][-min][-clock clock][-clock_fall]port_pin_list - -rise + -rise - Unset the arrival time for the rising edge of the input. + Unset the arrival time for the rising edge of the input. - -fall + -fall - Unset the arrival time for the falling edge of the input. + Unset the arrival time for the falling edge of the input. - -max + -max - Unset the minimum arrival time. + Unset the minimum arrival time. - -min + -min - Unset the maximum arrival time. + Unset the maximum arrival time. - clock + clock - Unset the arrival time from clock. + Unset the arrival time from clock. - -clock_fall + -clock_fall - Unset the arrival time from the falling edge of clock + Unset the arrival time from the falling edge of clock - pin_port_list + pin_port_list - A list of pins or ports. + A list of pins or ports. @@ -13437,67 +13581,67 @@ - unset_output_delay + unset_output_delay - [-rise][-fall][-max][-min][-clock clock][-clock_fall]port_pin_list + [-rise][-fall][-max][-min][-clock clock][-clock_fall]port_pin_list - -rise + -rise - This is the arrival time for the rising edge of the input. + This is the arrival time for the rising edge of the input. - -fall + -fall - This is the arrival time for the falling edge of the input. + This is the arrival time for the falling edge of the input. - -max + -max - This is the minimum arrival time. + This is the minimum arrival time. - -min + -min - This is the maximum arrival time. + This is the maximum arrival time. - clock + clock - The arrival time is from this clock. + The arrival time is from this clock. - -clock_fall + -clock_fall - The arrival time is from the falling edge of clock + The arrival time is from the falling edge of clock - pin_port_list + pin_port_list - A list of pins or ports. + A list of pins or ports. @@ -13507,47 +13651,47 @@ - unset_path_exceptions + unset_path_exceptions - [-setup][-hold][-rise][-fall][-from|-rise_from|-fall_from from][-through|-rise_through|-fall_through through][-to|-rise_to|-fall_to to] + [-setup][-hold][-rise][-fall][-from|-rise_from|-fall_from from][-through|-rise_through|-fall_through through][-to|-rise_to|-fall_to to] - -setup + -setup - Unset path exceptions for setup checks. + Unset path exceptions for setup checks. - -hold + -hold - Unset path exceptions for hold checks. + Unset path exceptions for hold checks. - -rise + -rise - Unset path exceptions for rising path edges. + Unset path exceptions for rising path edges. - -fall + -fall - Unset path exceptions for falling path edges. + Unset path exceptions for falling path edges. - -from from + -from from A list of clocks, instances, ports or pins. @@ -13555,7 +13699,7 @@ - -through through + -through through A list of instances, pins or nets. @@ -13563,7 +13707,7 @@ - -to to + -to to A list of clocks, instances, ports or pins. @@ -13571,75 +13715,75 @@ The unset_path_exceptions command removes any matching set_false_path, set_multicycle_path, set_max_delay, and set_min_delay exceptions. - + - unset_power_activity + unset_power_activity - [-global][-input][-input_ports ports][-pins pins] + [-global][-input][-input_ports ports][-pins pins] - -global + -global - Set the activity/duty for all non-clock pins. + Set the activity/duty for all non-clock pins. - -input + -input - Set the default input port activity/duty. + Set the default input port activity/duty. - -input_ports input_ports + -input_ports input_ports - Set the input port activity/duty. + Set the input port activity/duty. - -pins pins + -pins pins - Set the pin activity/duty. + Set the pin activity/duty. - -activity activity + -activity activity - The activity, or number of transitions per clock cycle. If clock is not specified the clock with the minimum period is used. If no clocks are defined an error is reported. + The activity, or number of transitions per clock cycle. If clock is not specified the clock with the minimum period is used. If no clocks are defined an error is reported. - The unset_power_activity_command is used to undo the effects of the set_power_activity command. + The unset_power_activity_command is used to undo the effects of the set_power_activity command. - unset_propagated_clock + unset_propagated_clock - objects + objects - objects + objects A list of clocks, ports or pins. @@ -13652,44 +13796,44 @@ - unset_timing_derate + unset_timing_derate - + - Remove all derating factors set with the set_timing_derate command. + Remove all derating factors set with the set_timing_derate command. - unsuppress_msg + unsuppress_msg - msg_ids + msg_ids - msg_ids + msg_ids - A list of error/warning message IDs to unsuppress. + A list of error/warning message IDs to unsuppress. - The unsuppress_msg command removes suppressions for the specified error/warning messages by ID. The list of message IDs can be found in doc/messages.txt. + The unsuppress_msg command removes suppressions for the specified error/warning messages by ID. The list of message IDs can be found in doc/messages.txt. - user_run_time + user_run_time - + @@ -13699,147 +13843,147 @@ - with_output_to_variable + with_output_to_variable - var { commands } + var { commands } - var + var - The name of a variable to save the output of commands to. + The name of a variable to save the output of commands to. - commands + commands - TCL commands that the output will be redirected from. + TCL commands that the output will be redirected from. - The with_output_to_variable command redirects the output of TCL commands to a variable. + The with_output_to_variable command redirects the output of TCL commands to a variable. - write_path_spice + write_path_spice - -path_args path_args-spice_directory spice_directory-lib_subckt_file lib_subckts_file-model_file model_file-power power-ground ground[-simulator hspice|ngspice|xyce] + -path_args path_args-spice_directory spice_directory-lib_subckt_file lib_subckts_file-model_file model_file-power power-ground ground[-simulator hspice|ngspice|xyce] - path_args + path_args - -from|-through|-to arguments as in report_checks. + -from|-through|-to arguments as in report_checks. - spice_directory + spice_directory - Directory for spice to write output files. + Directory for spice to write output files. - lib_subckts_file + lib_subckts_file - Cell transistor level subckts. + Cell transistor level subckts. - model_file + model_file - Transistor model definitions .included by spice_file. + Transistor model definitions .included by spice_file. - power + power - Voltage supply name in voltage_map of the default liberty library. + Voltage supply name in voltage_map of the default liberty library. - ground + ground - Ground supply name in voltage_map of the default liberty library. + Ground supply name in voltage_map of the default liberty library. - -simulator + -simulator - Simulator that will read the spice netlist. + Simulator that will read the spice netlist. The write_path_spice command writes a spice netlist for timing paths. Use path_args to specify -from/-through/-to as arguments to the find_timing_paths command. For each path, a spice netlist and the subckts referenced by the path are written in spice_directory. The spice netlist is written in path_<id>.sp and subckt file is path_<id>.subckt. The spice netlists used by the path are written to subckt_file, which spice_file .includes. The device models used by the spice subckt netlists in model_file are also .included in spice_file. Power and ground names are specified with the -power and -ground arguments. The spice netlist includes a piecewise linear voltage source at the input and .measure statement for each gate delay and pin slew. - Example command: - write_path_spice -path_args {-from "in0" -to "out1" -unconstrained} \ -spice_directory $result_dir \ -lib_subckt_file "write_spice1.subckt" \ -model_file "write_spice1.models" \ -power VDD -ground VSS - When the simulator is hspice, .measure statements will be added to the spice netlist. - When the simulator is Xyce, the .print statement selects the CSV format and writes the waveform data to a file name path_<id>.csv so the results can be used by gnuplot. + Example command: + write_path_spice -path_args {-from "in0" -to "out1" -unconstrained} \ -spice_directory $result_dir \ -lib_subckt_file "write_spice1.subckt" \ -model_file "write_spice1.models" \ -power VDD -ground VSS + When the simulator is hspice, .measure statements will be added to the spice netlist. + When the simulator is Xyce, the .print statement selects the CSV format and writes the waveform data to a file name path_<id>.csv so the results can be used by gnuplot. - write_sdc + write_sdc - [-digits digits][-gzip][-no_timestamp]filename + [-digits digits][-gzip][-no_timestamp]filename - digits + digits - The number of digits after the decimal point to report. The default is 4. + The number of digits after the decimal point to report. The default is 4. - -gzip + -gzip - Compress the SDC with gzip. + Compress the SDC with gzip. - -no_timestamp + -no_timestamp - Do not include a time and date in the SDC file. + Do not include a time and date in the SDC file. - filename + filename - The name of the file to write the constraints to. + The name of the file to write the constraints to. @@ -13849,242 +13993,242 @@ - write_sdf + write_sdf - [-scene scene][-divider /|.][-include_typ][-digits digits][-gzip][-no_timestamp][-no_version]filename + [-scene scene][-divider /|.][-include_typ][-digits digits][-gzip][-no_timestamp][-no_version]filename - scene + scene - Write delays for scene. + Write delays for scene. - -divider + -divider - Divider to use between hierarchy levels in pin and instance names. + Divider to use between hierarchy levels in pin and instance names. - -include_typ + -include_typ - Include a 'typ' value in the SDF triple that is the average of min and max delays to satisfy some Verilog simulators that require three values in the delay triples. + Include a 'typ' value in the SDF triple that is the average of min and max delays to satisfy some Verilog simulators that require three values in the delay triples. - -digits digits + -digits digits - The number of digits after the decimal point to report. The default is 4. + The number of digits after the decimal point to report. The default is 4. - -gzip + -gzip - Compress the SDF using gzip. + Compress the SDF using gzip. - -no_timestamp + -no_timestamp - Do not write a DATE statement. + Do not write a DATE statement. - -no_version + -no_version - Do not write a VERSION statement. + Do not write a VERSION statement. - filename + filename - The SDF filename to write. + The SDF filename to write. - Write the delay calculation delays for the design in SDF format to filename. If -corner is not specified the min/max delays are across all corners. With -corner the min/max delays for corner are written. The SDF TIMESCALE is same as the time_unit in the first liberty file read. + Write the delay calculation delays for the design in SDF format to filename. If -corner is not specified the min/max delays are across all corners. With -corner the min/max delays for corner are written. The SDF TIMESCALE is same as the time_unit in the first liberty file read. - write_timing_model + write_timing_model - [-library_name lib_name][-cell_name cell_name] - [-scene scene]filename + [-library_name lib_name][-cell_name cell_name] + [-scene scene]filename - lib_name + lib_name - The name to use for the liberty library. Defaults to cell_name. + The name to use for the liberty library. Defaults to cell_name. - cell_name + cell_name - The name to use for the liberty cell. Defaults to the top level module name. + The name to use for the liberty cell. Defaults to the top level module name. - scene + scene - The scene to use for extracting the model. + The scene to use for extracting the model. - filename + filename - Filename for the liberty timing model. + Filename for the liberty timing model. - The write_timing_model command constructs a liberty timing model for the current design and writes it to filename. cell_name defaults to the cell name of the top level block in the design. - The SDC used to extract the block should include the clock definitions. If the block contains a clock network set_propagated_clock should be used so the clock delays are included in the timing model. The following SDC commands are ignored when building the timing model. - set_input_delayset_output_delayset_loadset_timing_derate - Using set_input_transition with the slew from the block context will be used will improve the match between the timing model and the block netlist. Paths defined on clocks that are defined on internal pins are ignored because the model has no way to include the clock definition. + The write_timing_model command constructs a liberty timing model for the current design and writes it to filename. cell_name defaults to the cell name of the top level block in the design. + The SDC used to extract the block should include the clock definitions. If the block contains a clock network set_propagated_clock should be used so the clock delays are included in the timing model. The following SDC commands are ignored when building the timing model. + set_input_delayset_output_delayset_loadset_timing_derate + Using set_input_transition with the slew from the block context will be used will improve the match between the timing model and the block netlist. Paths defined on clocks that are defined on internal pins are ignored because the model has no way to include the clock definition. The resulting timing model can be used in a hierarchical timing flow as a replacement for the block to speed up timing analysis. This hierarchical timing methodology does not handle timing exceptions that originate or terminate inside the block. The timing model includes: - combinational paths between inputs and outputssetup and hold timing constraints on inputsclock to output timing paths - Resistance of long wires on inputs and outputs of the block cannot be modeled in Liberty. To reduce inaccuracies from wire resistance in technologies with resistive wires place buffers on inputs and ouputs. + combinational paths between inputs and outputssetup and hold timing constraints on inputsclock to output timing paths + Resistance of long wires on inputs and outputs of the block cannot be modeled in Liberty. To reduce inaccuracies from wire resistance in technologies with resistive wires place buffers on inputs and ouputs. The extracted timing model setup/hold checks are scalar (no input slew dependence). Delay timing arcs are load dependent but do not include input slew dependency. - write_verilog + write_verilog - [-include_pwr_gnd][-remove_cells lib_cells]filename + [-include_pwr_gnd][-remove_cells lib_cells]filename - -include_pwr_gnd + -include_pwr_gnd - Include power and ground pins on instances. + Include power and ground pins on instances. - -remove_cells lib_cells + -remove_cells lib_cells - Liberty cells to remove from the Verilog netlist. Use get_lib_cells, a list of cells names, or a cell name with wildcards. + Liberty cells to remove from the Verilog netlist. Use get_lib_cells, a list of cells names, or a cell name with wildcards. - filename + filename - Filename for the liberty library. + Filename for the liberty library. - The write_verilog command writes a Verilog netlist to filename. Use -sort to sort the instances so the results are reproducible across operating systems. Use -remove_cells to remove instances of lib_cells from the netlist. - Filter Expressions - The get_cells, get_pins, get_ports and get_timing_edges functions support filtering the returned objects by property values. Supported filter expressions are shown below. + The write_verilog command writes a Verilog netlist to filename. Use -sort to sort the instances so the results are reproducible across operating systems. Use -remove_cells to remove instances of lib_cells from the netlist. + Filter Expressions + The get_cells, get_pins, get_ports and get_timing_edges functions support filtering the returned objects by property values. Supported filter expressions are shown below. - property + property - Return objects with property value equal to 1. + Return objects with property value equal to 1. - property==value + property==value - Return objects with property value equal to value. + Return objects with property value equal to value. - property=~pattern + property=~pattern - Return objects with property value that matches pattern. + Return objects with property value that matches pattern. - property!=value + property!=value - Return objects with property value not equal to value. + Return objects with property value not equal to value. - property!~value + property!~value - Return objects with property value that does not match pattern. + Return objects with property value that does not match pattern. - expr1&&expr2 + expr1&&expr2 - Return objects with expr1 and expr2. expr1 and expr2 are one of the first three property value forms shown above. + Return objects with expr1 and expr2. expr1 and expr2 are one of the first three property value forms shown above. - expr1||expr2 + expr1||expr2 - Return objects with expr1 or expr2. expr1 and expr2 are one of the first three property value forms shown above. + Return objects with expr1 or expr2. expr1 and expr2 are one of the first three property value forms shown above. - Where property is a property supported by the get_property command. Note that if there are spaces in the expression it must be enclosed in quotes so that it is a single argument. - Variables + Where property is a property supported by the get_property command. Note that if there are spaces in the expression it must be enclosed in quotes so that it is a single argument. + Variables - hierarchy_separator + hierarchy_separator - Any character. + Any character. @@ -14094,37 +14238,37 @@ - sta_continue_on_error + sta_continue_on_error - 0|1 + 0|1 - The include and read_sdc commands stop and report any errors encountered while reading a file unless sta_continue_on_error is 1. The default value is 0. + The include and read_sdc commands stop and report any errors encountered while reading a file unless sta_continue_on_error is 1. The default value is 0. - sta_crpr_mode + sta_crpr_mode - same_pin|same_transition + same_pin|same_transition - When the data and clock paths of a timing check overlap (see sta_crpr_enabled), pessimism is removed independent of whether of the path rise/fall transitions. When sta_crpr_mode is same_transition, the pessimism is only removed if the path rise/fall transitions are the same. The default value is same_pin. + When the data and clock paths of a timing check overlap (see sta_crpr_enabled), pessimism is removed independent of whether of the path rise/fall transitions. When sta_crpr_mode is same_transition, the pessimism is only removed if the path rise/fall transitions are the same. The default value is same_pin. - sta_cond_default_arcs_enabled + sta_cond_default_arcs_enabled - 0|1 + 0|1 @@ -14134,10 +14278,10 @@ - sta_crpr_enabled + sta_crpr_enabled - 0|1 + 0|1 @@ -14147,10 +14291,10 @@ - sta_dynamic_loop_breaking + sta_dynamic_loop_breaking - 0|1 + 0|1 @@ -14160,23 +14304,23 @@ - sta_gated_clock_checks_enabled + sta_gated_clock_checks_enabled - 0|1 + 0|1 - When sta_gated_clock_checks_enabled is 1, clock gating setup and hold timing checks are checked. The default value is 1. + When sta_gated_clock_checks_enabled is 1, clock gating setup and hold timing checks are checked. The default value is 1. - sta_input_port_default_clock + sta_input_port_default_clock - 0|1 + 0|1 @@ -14186,10 +14330,10 @@ - sta_internal_bidirect_instance_paths_enabled + sta_internal_bidirect_instance_paths_enabled - 0|1 + 0|1 @@ -14199,27 +14343,40 @@ - sta_pocv_enabled + sta_pocv_mode - 0|1 + scalar|normal|skew_normal - Enable parametric on chip variation using statistical timing analysis. The default value is 0. + Enable parametric on chip variation using statistical timing analysis. The default value is scalar. + + + + + + sta_pocv_quartile + + + quartile + + + + The target quantile of a delay probability distribution (confidence level).The default value is 3 standard deviations, or sigma. - sta_propagate_all_clocks + sta_propagate_all_clocks - 0|1 + 0|1 - All clocks defined after sta_propagate_all_clocks is set to 1 are propagated. If it is set before any clocks are defined it has the same effect as + All clocks defined after sta_propagate_all_clocks is set to 1 are propagated. If it is set before any clocks are defined it has the same effect as set_propagated_clock [all_clocks] After all clocks have been defined. The default value is 0. @@ -14227,36 +14384,36 @@ - sta_propagate_gated_clock_enable + sta_propagate_gated_clock_enable - 0|1 + 0|1 - When set to 1, paths of gated clock enables are propagated through the clock gating instances. If the gated clock controls sequential elements setting sta_propagate_gated_clock_enable to 0 prevents spurious paths from the clock enable. The default value is 1. + When set to 1, paths of gated clock enables are propagated through the clock gating instances. If the gated clock controls sequential elements setting sta_propagate_gated_clock_enable to 0 prevents spurious paths from the clock enable. The default value is 1. - sta_recovery_removal_checks_enabled + sta_recovery_removal_checks_enabled - 0|1 + 0|1 - When sta_recovery_removal_checks_enabled is 0, recovery and removal timing checks are disabled. The default value is 1. + When sta_recovery_removal_checks_enabled is 0, recovery and removal timing checks are disabled. The default value is 1. - sta_report_default_digits + sta_report_default_digits - integer + integer @@ -14266,10 +14423,10 @@ - sta_preset_clear_arcs_enabled + sta_preset_clear_arcs_enabled - 0|1 + 0|1 @@ -14299,186 +14456,186 @@ - Alphabetical Index + Alphabetical Index - all_clocks7 - all_inputs7 - all_outputs8 - all_registers8 - check_setup9 - Command Line Arguments1 - Commands7 - connect_pin9 - create_generated_clock11 - create_voltage_area12 - current_design12 - current_instance13 - define_scene13 - delete_clock13 - delete_from_list13 - delete_generated_clock14 - delete_instance14 - delete_net14 - disconnect_pin14 - elapsed_run_time14 - Example Command Scripts1 - Filter Expressions84 - find_timing_paths15 - get_cells17 - get_clocks17 - get_fanin18 - get_fanout19 - get_full_name19 - get_lib_pins20 - get_libs21 - get_name22 - get_nets22 - get_pins23 - get_ports23 - get_property24 - get_scenes28 - get_timing_edges28 - group_path29 - hierarchy_separator85 - include30 - link_design30 - make_instance30 - make_net31 - Power Analysis3 - read_liberty31 - read_saif32 - read_sdc33 - read_sdf33 - read_spef34 - read_vcd35 - read_verilog35 - redirection5 - replace_activity_annotation36 - replace_cell35 - report_annotated_check36 - report_annotated_delay37 - report_check_types41 - report_checks38 - report_clock_latency42 - report_clock_min_period42 - report_clock_properties43 - report_clock_skew43 - report_dcalc43 - report_disabled_edges44 - report_edges44 - report_instance44 - report_lib_cell44 - report_net45 - report_parasitic_annotation45 - report_power45 - report_slews46 - report_tns46 - report_units46 - report_wns47 - report_worst_slack47 - set_assigned_check48 - set_assigned_delay49 - set_assigned_transition49 - set_case_analysis50 - set_clock_gating_check50 - set_clock_groups51 - set_clock_latency52 - set_clock_transition52 - set_clock_uncertainty53 - set_cmd_units54 - set_data_check55 - set_disable_inferred_clock_gating55 - set_disable_timing55 - set_drive56 - set_driving_cell57 - set_false_path58 - set_fanout_load59 - set_hierarchy_separator59 - set_ideal_latency59 - set_ideal_network59 - set_ideal_transition59 - set_input_delay59 - set_input_transition61 - set_level_shifter_strategy61 - set_level_shifter_threshold61 - set_load61 - set_logic_dc62 - set_logic_one62 - set_logic_zero63 - set_max_area63 - set_max_capacitance63 - set_max_delay63 - set_max_dynamic_power64 - set_max_fanout64 - set_max_leakage_power64 - set_max_time_borrow64 - set_max_transition65 - set_min_capacitance65 - set_min_delay66 - set_min_pulse_width67 - set_mode67 - set_multicycle_path67 - set_operating_conditions68 - set_output_delay69 - set_port_fanout_number70 - set_power_activity70 - set_propagated_clock71 - set_pvt71 - set_resistance73 - set_sense72 - set_timing_derate73 - set_units74 - set_wire_load_min_block_size75 - set_wire_load_mode75 - set_wire_load_model75 - set_wire_load_selection_group75 - SPEF34 - sta_cond_default_arcs_enabled85 - sta_continue_on_error85 - sta_crpr_enabled85 - sta_crpr_mode85 - sta_dynamic_loop_breaking85 - sta_gated_clock_checks_enabled85 - sta_input_port_default_clock86 - sta_internal_bidirect_instance_paths_enabled86 - sta_pocv_enabled86 - sta_preset_clear_arcs_enabled87 - sta_propagate_all_clocks86 - sta_propagate_gated_clock_enable86 - sta_recovery_removal_checks_enabled86 - sta_report_default_digits86 - suppress_msg76 - TCL Interpreter5 - Timing Analysis using SDF2 - Timing Analysis with Multiple Corners and Modes3 - Timing Analysis with Multiple Process Corners2 - unset_case_analysis76 - unset_clock_latency76 - unset_clock_transition76 - unset_clock_uncertainty77 - unset_data_check77 - unset_disable_inferred_clock_gating78 - unset_disable_timing78 - unset_input_delay78 - unset_output_delay79 - unset_path_exceptions79 - unset_power_activity80 - unset_propagated_clock80 - unset_timing_derate80 - unsuppress_msg81 - user_run_time81 - Variables85 - verilog netlist35 - with_output_to_variable81 - write_path_spice81 - write_sdc82 - write_sdf82 - write_timing_model83 - write_verilog84 + all_clocks7 + all_inputs7 + all_outputs8 + all_registers8 + check_setup9 + Command Line Arguments1 + Commands7 + connect_pin9 + create_generated_clock11 + create_voltage_area12 + current_design12 + current_instance13 + define_scene13 + delete_clock13 + delete_from_list13 + delete_generated_clock14 + delete_instance14 + delete_net14 + disconnect_pin14 + elapsed_run_time14 + Example Command Scripts1 + Filter Expressions84 + find_timing_paths15 + get_cells17 + get_clocks17 + get_fanin18 + get_fanout19 + get_full_name19 + get_lib_pins20 + get_libs21 + get_name22 + get_nets22 + get_pins23 + get_ports23 + get_property24 + get_scenes28 + get_timing_edges28 + group_path29 + hierarchy_separator85 + include30 + link_design30 + make_instance30 + make_net31 + Power Analysis3 + read_liberty31 + read_saif32 + read_sdc33 + read_sdf33 + read_spef34 + read_vcd35 + read_verilog35 + redirection5 + replace_activity_annotation36 + replace_cell35 + report_annotated_check36 + report_annotated_delay37 + report_check_types41 + report_checks38 + report_clock_latency42 + report_clock_min_period42 + report_clock_properties43 + report_clock_skew43 + report_dcalc43 + report_disabled_edges44 + report_edges44 + report_instance44 + report_lib_cell44 + report_net45 + report_parasitic_annotation45 + report_power45 + report_slews46 + report_tns46 + report_units46 + report_wns47 + report_worst_slack47 + set_assigned_check48 + set_assigned_delay49 + set_assigned_transition49 + set_case_analysis50 + set_clock_gating_check50 + set_clock_groups51 + set_clock_latency52 + set_clock_transition52 + set_clock_uncertainty53 + set_cmd_units54 + set_data_check55 + set_disable_inferred_clock_gating55 + set_disable_timing55 + set_drive56 + set_driving_cell57 + set_false_path58 + set_fanout_load59 + set_hierarchy_separator59 + set_ideal_latency59 + set_ideal_network59 + set_ideal_transition59 + set_input_delay59 + set_input_transition61 + set_level_shifter_strategy61 + set_level_shifter_threshold61 + set_load61 + set_logic_dc62 + set_logic_one62 + set_logic_zero63 + set_max_area63 + set_max_capacitance63 + set_max_delay63 + set_max_dynamic_power64 + set_max_fanout64 + set_max_leakage_power64 + set_max_time_borrow64 + set_max_transition65 + set_min_capacitance65 + set_min_delay66 + set_min_pulse_width67 + set_mode67 + set_multicycle_path67 + set_operating_conditions68 + set_output_delay69 + set_port_fanout_number70 + set_power_activity70 + set_propagated_clock71 + set_pvt71 + set_resistance73 + set_sense72 + set_timing_derate73 + set_units74 + set_wire_load_min_block_size75 + set_wire_load_mode75 + set_wire_load_model75 + set_wire_load_selection_group75 + SPEF34 + sta_cond_default_arcs_enabled85 + sta_continue_on_error85 + sta_crpr_enabled85 + sta_crpr_mode85 + sta_dynamic_loop_breaking85 + sta_gated_clock_checks_enabled85 + sta_input_port_default_clock86 + sta_internal_bidirect_instance_paths_enabled86 + sta_pocv_enabled86 + sta_preset_clear_arcs_enabled87 + sta_propagate_all_clocks86 + sta_propagate_gated_clock_enable86 + sta_recovery_removal_checks_enabled86 + sta_report_default_digits86 + suppress_msg76 + TCL Interpreter5 + Timing Analysis using SDF2 + Timing Analysis with Multiple Corners and Modes3 + Timing Analysis with Multiple Process Corners2 + unset_case_analysis76 + unset_clock_latency76 + unset_clock_transition76 + unset_clock_uncertainty77 + unset_data_check77 + unset_disable_inferred_clock_gating78 + unset_disable_timing78 + unset_input_delay78 + unset_output_delay79 + unset_path_exceptions79 + unset_power_activity80 + unset_propagated_clock80 + unset_timing_derate80 + unsuppress_msg81 + user_run_time81 + Variables85 + verilog netlist35 + with_output_to_variable81 + write_path_spice81 + write_sdc82 + write_sdf82 + write_timing_model83 + write_verilog84 - - Version 3.0.0, Mar 7, 2026Copyright (c) 2026, Parallax Software, Inc. + + Version 3.0.0, Mar 7, 2026Copyright (c) 2026, Parallax Software, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. diff --git a/doc/OpenSTA.pdf b/doc/OpenSTA.pdf index 77ebd937..5cfe2789 100644 Binary files a/doc/OpenSTA.pdf and b/doc/OpenSTA.pdf differ diff --git a/doc/StaApi.txt b/doc/StaApi.txt index 30a16a9c..ecf7d35a 100644 --- a/doc/StaApi.txt +++ b/doc/StaApi.txt @@ -323,28 +323,6 @@ net have wire edges between the pin vertices. Timing arc sets in the leaf instance timing models have corresponding edges in the graph between pins on the instance. -The Graph class constructor option slew_tr_count is used to prevent -the grpah from reserving memory to store slews. Similarly, if the -have_arc_delays option is false no memory is reserved for storing arc -delay values. This is useful if an external delay calculator is used -to annotate delays on the graph. In this case the Graph functions -arcDelay and wireDelay should be overloaded to return delay values -stored outside of the STA. - -A graph with no slews or delays is constructed using: - - Graph(this, 0, false, ap_count); - -A graph with one slew for rising and falling edges is constructed using: - - Graph(this, 1, true, ap_count); - -A graph with separate rising and falling slews (the default) is -constructed using: - - Graph(this, 2, true, ap_count); - - SDC --- diff --git a/etc/FindMessages.tcl b/etc/FindMessages.tcl index c5fad936..40f00d29 100755 --- a/etc/FindMessages.tcl +++ b/etc/FindMessages.tcl @@ -61,7 +61,7 @@ foreach subdir $subdirs { set files [glob -nocomplain [file join $subdir "*.{cc,hh,yy,ll,i}"]] set files_c [concat $files_c $files] } -set warn_regexp_c {(?:(?:->critical|->warn|->fileWarn|->error|->fileError|criticalError|libWarn|libError)\(|tclArgError\(interp,\s*)([0-9]+),.*(".+")} +set warn_regexp_c {(?:(?:->critical|->warn|->fileWarn|->error|->fileError|criticalError|warn|error)\(|tclArgError\(interp,\s*)([0-9]+),.*(".+")} set files_tcl {} foreach subdir $subdirs { diff --git a/graph/DelayFloat.cc b/graph/DelayFloat.cc deleted file mode 100644 index cdb19f9c..00000000 --- a/graph/DelayFloat.cc +++ /dev/null @@ -1,199 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2026, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. -// -// Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// This notice may not be removed or altered from any source distribution. - -#include "Delay.hh" - -#include "StaConfig.hh" -#include "Fuzzy.hh" -#include "Units.hh" -#include "StaState.hh" - -// Non-SSTA compilation. -#if !SSTA - -namespace sta { - -static Delay delay_init_values[MinMax::index_count]; - -void -initDelayConstants() -{ - delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue(); - delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue(); -} - -const char * -delayAsString(const Delay &delay, - const StaState *sta) -{ - return delayAsString(delay, sta, sta->units()->timeUnit()->digits()); -} - -const char * -delayAsString(const Delay &delay, - const StaState *sta, - int digits) -{ - return sta->units()->timeUnit()->asString(delay, digits); -} - -const char * -delayAsString(const Delay &delay, - const EarlyLate *, - const StaState *sta, - int digits) -{ - const Unit *unit = sta->units()->timeUnit(); - return unit->asString(delay, digits); -} - -const Delay & -delayInitValue(const MinMax *min_max) -{ - return delay_init_values[min_max->index()]; -} - -bool -delayIsInitValue(const Delay &delay, - const MinMax *min_max) -{ - return fuzzyEqual(delay, min_max->initValue()); -} - -bool -delayZero(const Delay &delay) -{ - return fuzzyZero(delay); -} - -bool -delayInf(const Delay &delay) -{ - return fuzzyInf(delay); -} - -bool -delayEqual(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyEqual(delay1, delay2); -} - -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const StaState *) -{ - return fuzzyLess(delay1, delay2); -} - -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *) -{ - if (min_max == MinMax::max()) - return fuzzyLess(delay1, delay2); - else - return fuzzyGreater(delay1, delay2); -} - -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const StaState *) -{ - return fuzzyLessEqual(delay1, delay2); -} - -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *) -{ - if (min_max == MinMax::max()) - return fuzzyLessEqual(delay1, delay2); - else - return fuzzyGreaterEqual(delay1, delay2); -} - -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const StaState *) -{ - return fuzzyGreater(delay1, delay2); -} - -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *) -{ - if (min_max == MinMax::max()) - return fuzzyGreater(delay1, delay2); - else - return fuzzyLess(delay1, delay2); -} - -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const StaState *) -{ - return fuzzyGreaterEqual(delay1, delay2); -} - -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *) -{ - if (min_max == MinMax::max()) - return fuzzyGreaterEqual(delay1, delay2); - else - return fuzzyLessEqual(delay1, delay2); -} - -Delay -delayRemove(const Delay &delay1, - const Delay &delay2) -{ - return delay1 - delay2; -} - -float -delayRatio(const Delay &delay1, - const Delay &delay2) -{ - return delay1 / delay2; -} - -} // namespace - -#endif // !SSTA diff --git a/graph/DelayNormal1.cc b/graph/DelayNormal1.cc deleted file mode 100644 index f13518e0..00000000 --- a/graph/DelayNormal1.cc +++ /dev/null @@ -1,483 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2026, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. -// -// Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// This notice may not be removed or altered from any source distribution. - -#include "Delay.hh" - -#include // sqrt - -#include "StaConfig.hh" -#include "Error.hh" -#include "StringUtil.hh" -#include "Fuzzy.hh" -#include "Units.hh" -#include "StaState.hh" -#include "Variables.hh" - -// SSTA compilation. -#if (SSTA == 1) - -namespace sta { - -inline float -square(float x) -{ - return x * x; -} - -static Delay delay_init_values[MinMax::index_count]; - -void -initDelayConstants() -{ - delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue(); - delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue(); -} - -const Delay & -delayInitValue(const MinMax *min_max) -{ - return delay_init_values[min_max->index()]; -} - -Delay::Delay() : - mean_(0.0), - sigma2_(0.0) -{ -} - -Delay::Delay(const Delay &delay) : - mean_(delay.mean_), - sigma2_(delay.sigma2_) -{ -} - -Delay::Delay(const DelayDbl &delay) : - mean_(delay.mean_), - sigma2_(delay.sigma2_) -{ -} - -Delay::Delay(float mean) : - mean_(mean), - sigma2_(0.0) -{ -} - -Delay::Delay(float mean, - float sigma2) : - mean_(mean), - sigma2_(sigma2) -{ -} - -float -Delay::sigma() const -{ - if (sigma2_ < 0.0) - // Sigma is negative for crpr to offset sigmas in the common - // clock path. - return -sqrt(-sigma2_); - else - return sqrt(sigma2_); -} - -float -Delay::sigma2() const -{ - return sigma2_; -} - -void -Delay::operator=(const Delay &delay) -{ - mean_ = delay.mean_; - sigma2_ = delay.sigma2_; -} - -void -Delay::operator=(float delay) -{ - mean_ = delay; - sigma2_ = 0.0; -} - -void -Delay::operator+=(const Delay &delay) -{ - mean_ += delay.mean_; - sigma2_ += delay.sigma2_; -} - -void -Delay::operator+=(float delay) -{ - mean_ += delay; -} - -Delay -Delay::operator+(const Delay &delay) const -{ - return Delay(mean_ + delay.mean_, - sigma2_ + delay.sigma2_); -} - -Delay -Delay::operator+(float delay) const -{ - return Delay(mean_ + delay, sigma2_); -} - -Delay -Delay::operator-(const Delay &delay) const -{ - return Delay(mean_ - delay.mean_, - sigma2_ + delay.sigma2_); -} - -Delay -Delay::operator-(float delay) const -{ - return Delay(mean_ - delay, sigma2_); -} - -Delay -Delay::operator-() const -{ - return Delay(-mean_, sigma2_); -} - -void -Delay::operator-=(float delay) -{ - mean_ -= delay; -} - -void -Delay::operator-=(const Delay &delay) -{ - mean_ -= delay.mean_; - sigma2_ += delay.sigma2_; -} - -bool -Delay::operator==(const Delay &delay) const -{ - return delayEqual(*this, delay); -} - -//////////////////////////////////////////////////////////////// - -DelayDbl::DelayDbl() : - mean_(0.0), - sigma2_(0.0) -{ -} - -void -DelayDbl::operator=(float delay) -{ - mean_ = delay; - sigma2_ = 0.0; -} - -void -DelayDbl::operator+=(const Delay &delay) -{ - mean_ += delay.mean_; - sigma2_ += delay.sigma2_; -} - -void -DelayDbl::operator-=(const Delay &delay) -{ - mean_ -= delay.mean_; - sigma2_ += delay.sigma2_; -} - -//////////////////////////////////////////////////////////////// - -Delay -makeDelay(float delay, - float sigma, - float) -{ - return Delay(delay, square(sigma)); -} - -Delay -makeDelay2(float delay, - float sigma2, - float ) -{ - return Delay(delay, sigma2); -} - -float -delayAsFloat(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta) -{ - if (sta->variables()->pocvEnabled()) { - if (early_late == EarlyLate::early()) - return delay.mean() - delay.sigma() * sta->sigmaFactor(); - else if (early_late == EarlyLate::late()) - return delay.mean() + delay.sigma() * sta->sigmaFactor(); - else - sta->report()->critical(1020, "unknown early/late value."); - } - return delay.mean(); -} - -float -delaySigma2(const Delay &delay, - const EarlyLate *) -{ - return delay.sigma2(); -} - -const char * -delayAsString(const Delay &delay, - const StaState *sta) -{ - return delayAsString(delay, sta, sta->units()->timeUnit()->digits()); -} - -const char * -delayAsString(const Delay &delay, - const StaState *sta, - int digits) -{ - const Unit *unit = sta->units()->timeUnit(); - if (sta->variables()->pocvEnabled()) { - float sigma = delay.sigma(); - return stringPrintTmp("%s[%s]", - unit->asString(delay.mean(), digits), - unit->asString(sigma, digits)); - } - else - return unit->asString(delay.mean(), digits); -} - -const char * -delayAsString(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta, - int digits) -{ - float mean_sigma = delayAsFloat(delay, early_late, sta); - return sta->units()->timeUnit()->asString(mean_sigma, digits); -} - -bool -delayIsInitValue(const Delay &delay, - const MinMax *min_max) -{ - return fuzzyEqual(delay.mean(), min_max->initValue()) - && delay.sigma2() == 0.0; -} - -bool -delayZero(const Delay &delay) -{ - return fuzzyZero(delay.mean()) - && fuzzyZero(delay.sigma2()); -} - -bool -delayInf(const Delay &delay) -{ - return fuzzyInf(delay.mean()); -} - -bool -delayEqual(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyEqual(delay1.mean(), delay2.mean()) - && fuzzyEqual(delay1.sigma2(), delay2.sigma2()); -} - -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const StaState *sta) -{ - return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), - delayAsFloat(delay2, EarlyLate::early(), sta)); -} - -bool -delayLess(const Delay &delay1, - float delay2, - const StaState *sta) -{ - return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), - delay2); -} - -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta) -{ - if (min_max == MinMax::max()) - return delayLess(delay1, delay2, sta); - else - return delayGreater(delay1, delay2, sta); -} - -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const StaState *sta) -{ - return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta), - delayAsFloat(delay2, EarlyLate::early(), sta)); -} - -bool -delayLessEqual(const Delay &delay1, - float delay2, - const StaState *sta) -{ - return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta), - delay2); -} - -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta) -{ - if (min_max == MinMax::max()) - return delayLessEqual(delay1, delay2, sta); - else - return delayGreaterEqual(delay1, delay2, sta); -} - -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const StaState *sta) - -{ - return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta), - delayAsFloat(delay2, EarlyLate::late(), sta)); -} - -bool -delayGreater(const Delay &delay1, - float delay2, - const StaState *sta) -{ - return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta), - delay2); -} - -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const StaState *sta) -{ - return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), - delayAsFloat(delay2, EarlyLate::late(), sta)); -} - -bool -delayGreaterEqual(const Delay &delay1, - float delay2, - const StaState *sta) -{ - return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), - delay2); -} - -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta) -{ - if (min_max == MinMax::max()) - return delayGreater(delay1, delay2, sta); - else - return delayLess(delay1, delay2, sta); -} - -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta) -{ - if (min_max == MinMax::max()) - return delayGreaterEqual(delay1, delay2, sta); - else - return delayLessEqual(delay1, delay2, sta); -} - -Delay -delayRemove(const Delay &delay1, - const Delay &delay2) -{ - return Delay(delay1.mean() - delay2.mean(), - delay1.sigma2() - delay2.sigma2()); -} - -float -delayRatio(const Delay &delay1, - const Delay &delay2) -{ - return delay1.mean() / delay2.mean(); -} - -Delay -operator+(float delay1, - const Delay &delay2) -{ - return Delay(delay1 + delay2.mean(), - delay2.sigma2()); -} - -Delay -operator/(float delay1, - const Delay &delay2) -{ - return Delay(delay1 / delay2.mean(), - delay2.sigma2()); -} - -Delay -operator*(const Delay &delay1, - float delay2) -{ - return Delay(delay1.mean() * delay2, - delay1.sigma2() * delay2 * delay2); -} - -} // namespace - -#endif // (SSTA == 1) diff --git a/graph/DelayNormal2.cc b/graph/DelayNormal2.cc deleted file mode 100644 index be8936a0..00000000 --- a/graph/DelayNormal2.cc +++ /dev/null @@ -1,517 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2026, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. -// -// Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// This notice may not be removed or altered from any source distribution. - -#include "Delay.hh" - -#include // sqrt - -#include "StaConfig.hh" -#include "Error.hh" -#include "StringUtil.hh" -#include "Fuzzy.hh" -#include "Units.hh" -#include "StaState.hh" - -// SSTA compilation. -#if (SSTA == 2) - -namespace sta { - -inline float -square(float x) -{ - return x * x; -} - -static Delay delay_init_values[MinMax::index_count]; - -void -initDelayConstants() -{ - delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue(); - delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue(); -} - -const Delay & -delayInitValue(const MinMax *min_max) -{ - return delay_init_values[min_max->index()]; -} - -Delay::Delay() : - mean_(0.0), - sigma2_{0.0, 0.0} -{ -} - -Delay::Delay(const Delay &delay) : - mean_(delay.mean_) -{ - sigma2_[EarlyLate::earlyIndex()] = delay.sigma2_[EarlyLate::earlyIndex()]; - sigma2_[EarlyLate::lateIndex()] = delay.sigma2_[EarlyLate::lateIndex()]; -} - -Delay::Delay(const DelayDbl &delay) : - mean_(delay.mean_) -{ - sigma2_[EarlyLate::earlyIndex()] = delay.sigma2_[EarlyLate::earlyIndex()]; - sigma2_[EarlyLate::lateIndex()] = delay.sigma2_[EarlyLate::lateIndex()]; -} - -Delay::Delay(float mean) : - mean_(mean), - sigma2_{0.0, 0.0} -{ -} - -Delay::Delay(float mean, - float sigma2_early, - float sigma2_late) : - mean_(mean), - sigma2_{sigma2_early, sigma2_late} -{ -} - -float -Delay::sigma(const EarlyLate *early_late) const -{ - float sigma = sigma2_[early_late->index()]; - if (sigma < 0.0) - // Sigma is negative for crpr to offset sigmas in the common - // clock path. - return -sqrt(-sigma); - else - return sqrt(sigma); -} - -float -Delay::sigma2(const EarlyLate *early_late) const -{ - return sigma2_[early_late->index()]; -} - -float -Delay::sigma2Early() const -{ - return sigma2_[early_index]; -} - -float -Delay::sigma2Late() const -{ - return sigma2_[late_index]; -} - -void -Delay::operator=(const Delay &delay) -{ - mean_ = delay.mean_; - sigma2_[early_index] = delay.sigma2_[early_index]; - sigma2_[late_index] = delay.sigma2_[late_index]; -} - -void -Delay::operator=(float delay) -{ - mean_ = delay; - sigma2_[early_index] = 0.0; - sigma2_[late_index] = 0.0; -} - -void -Delay::operator+=(const Delay &delay) -{ - mean_ += delay.mean_; - sigma2_[early_index] += delay.sigma2_[early_index]; - sigma2_[late_index] += delay.sigma2_[late_index]; -} - -void -Delay::operator+=(float delay) -{ - mean_ += delay; -} - -Delay -Delay::operator+(const Delay &delay) const -{ - return Delay(mean_ + delay.mean_, - sigma2_[early_index] + delay.sigma2_[early_index], - sigma2_[late_index] + delay.sigma2_[late_index]); -} - -Delay -Delay::operator+(float delay) const -{ - return Delay(mean_ + delay, sigma2_[early_index], sigma2_[late_index]); -} - -Delay -Delay::operator-(const Delay &delay) const -{ - return Delay(mean_ - delay.mean_, - sigma2_[early_index] + delay.sigma2_[late_index], - sigma2_[late_index] + delay.sigma2_[early_index]); -} - -Delay -Delay::operator-(float delay) const -{ - return Delay(mean_ - delay, sigma2_[early_index], sigma2_[late_index]); -} - -Delay -Delay::operator-() const -{ - return Delay(-mean_, sigma2_[late_index], sigma2_[early_index]); -} - -void -Delay::operator-=(float delay) -{ - mean_ -= delay; -} - -void -Delay::operator-=(const Delay &delay) -{ - mean_ -= delay.mean_; - sigma2_[early_index] += delay.sigma2_[early_index]; - sigma2_[late_index] += delay.sigma2_[late_index]; -} - -bool -Delay::operator==(const Delay &delay) const -{ - return mean_ == delay.mean_ - && sigma2_[early_index] == delay.sigma2_[late_index] - && sigma2_[late_index] == delay.sigma2_[early_index]; -} - -//////////////////////////////////////////////////////////////// - -DelayDbl::DelayDbl() : - mean_(0.0), - sigma2_{0.0, 0.0} -{ -} - -void -DelayDbl::operator=(float delay) -{ - mean_ = delay; - sigma2_[early_index] = 0.0; - sigma2_[late_index] = 0.0; -} - -void -DelayDbl::operator+=(const Delay &delay) -{ - mean_ += delay.mean_; - sigma2_[early_index] += delay.sigma2_[early_index]; - sigma2_[late_index] += delay.sigma2_[late_index]; -} - -void -DelayDbl::operator-=(const Delay &delay) -{ - mean_ -= delay.mean_; - sigma2_[early_index] += delay.sigma2_[early_index]; - sigma2_[late_index] += delay.sigma2_[late_index]; -} - -//////////////////////////////////////////////////////////////// - -Delay -makeDelay(float delay, - float sigma_early, - float sigma_late) -{ - return Delay(delay, square(sigma_early), square(sigma_late)); -} - -Delay -makeDelay2(float delay, - float sigma2_early, - float sigma2_late) -{ - return Delay(delay, sigma2_early, sigma2_late); -} - -bool -delayIsInitValue(const Delay &delay, - const MinMax *min_max) -{ - return fuzzyEqual(delay.mean(), min_max->initValue()) - && fuzzyZero(delay.sigma2Early()) - && fuzzyZero(delay.sigma2Late()); -} - -bool -delayZero(const Delay &delay) -{ - return fuzzyZero(delay.mean()) - && fuzzyZero(delay.sigma2Early()) - && fuzzyZero(delay.sigma2Late()); -} - -bool -delayInf(const Delay &delay) -{ - return fuzzyInf(delay.mean()); -} - -bool -delayEqual(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyEqual(delay1.mean(), delay2.mean()) - && fuzzyEqual(delay1.sigma2Early(), delay2.sigma2Early()) - && fuzzyEqual(delay1.sigma2Late(), delay2.sigma2Late()); -} - -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const StaState *sta) -{ - return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), - delayAsFloat(delay2, EarlyLate::early(), sta)); -} - -bool -delayLess(const Delay &delay1, - float delay2, - const StaState *sta) -{ - return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), - delay2); -} - -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta) -{ - if (min_max == MinMax::max()) - return delayLess(delay1, delay2, sta); - else - return delayGreater(delay1, delay2, sta); -} - -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const StaState *sta) -{ - return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta), - delayAsFloat(delay2, EarlyLate::early(), sta)); -} - -bool -delayLessEqual(const Delay &delay1, - float delay2, - const StaState *sta) -{ - return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta), - delay2); -} - -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta) -{ - if (min_max == MinMax::max()) - return delayLessEqual(delay1, delay2, sta); - else - return delayGreaterEqual(delay1, delay2, sta); -} - -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const StaState *sta) -{ - return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta), - delayAsFloat(delay2, EarlyLate::late(), sta)); -} - -bool -delayGreater(const Delay &delay1, - float delay2, - const StaState *sta) -{ - return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), - delayAsFloat(delay2, EarlyLate::late(), sta)); -} - -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const StaState *sta) -{ - return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), - delayAsFloat(delay2, EarlyLate::late(), sta)); -} - -bool -delayGreaterEqual(const Delay &delay1, - float delay2, - const StaState *sta) -{ - return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), - delay2); -} - -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta) -{ - if (min_max == MinMax::max()) - return delayGreater(delay1, delay2, sta); - else - return delayLess(delay1, delay2, sta); -} - -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta) -{ - if (min_max == MinMax::max()) - return delayGreaterEqual(delay1, delay2, sta); - else - return delayLessEqual(delay1, delay2, sta); -} - -float -delayAsFloat(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta) -{ - if (sta->pocvEnabled()) { - if (early_late == EarlyLate::early()) - return delay.mean() - delay.sigma(early_late) * sta->sigmaFactor(); - else if (early_late == EarlyLate::late()) - return delay.mean() + delay.sigma(early_late) * sta->sigmaFactor(); - else - sta->report()->critical(1030, "unknown early/late value."); - } - return delay.mean(); -} - -float -delaySigma2(const Delay &delay, - const EarlyLate *early_late) -{ - return delay.sigma2(early_late); -} - -const char * -delayAsString(const Delay &delay, - const StaState *sta) -{ - return delayAsString(delay, sta, sta->units()->timeUnit()->digits()); -} - -const char * -delayAsString(const Delay &delay, - const StaState *sta, - int digits) -{ - const Unit *unit = sta->units()->timeUnit(); - if (sta->pocvEnabled()) { - float sigma_early = delay.sigma(EarlyLate::early()); - float sigma_late = delay.sigma(EarlyLate::late()); - return stringPrintTmp("%s[%s:%s]", - unit->asString(delay.mean(), digits), - unit->asString(sigma_early, digits), - unit->asString(sigma_late, digits)); - } - else - return unit->asString(delay.mean(), digits); -} - -const char * -delayAsString(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta, - int digits) -{ - float mean_sigma = delayAsFloat(delay, early_late, sta); - return sta->units()->timeUnit()->asString(mean_sigma, digits); -} - -Delay -delayRemove(const Delay &delay1, - const Delay &delay2) -{ - return Delay(delay1.mean() - delay2.mean(), - delay1.sigma2Early() - delay2.sigma2Early(), - delay1.sigma2Late() - delay2.sigma2Late()); -} - -float -delayRatio(const Delay &delay1, - const Delay &delay2) -{ - return delay1.mean() / delay2.mean(); -} - -Delay -operator+(float delay1, - const Delay &delay2) -{ - return Delay(delay1 + delay2.mean(), - delay2.sigma2Early(), - delay2.sigma2Late()); -} - -Delay -operator/(float delay1, - const Delay &delay2) -{ - return Delay(delay1 / delay2.mean(), - delay2.sigma2Early(), - delay2.sigma2Late()); -} - -Delay -operator*(const Delay &delay1, - float delay2) -{ - return Delay(delay1.mean() * delay2, - delay1.sigma2Early() * delay2 * delay2, - delay1.sigma2Late() * delay2 * delay2); -} - -} // namespace - -#endif // (SSTA == 2) diff --git a/graph/Graph.cc b/graph/Graph.cc index b397b7b2..022504ca 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -36,6 +36,7 @@ #include "PortDirection.hh" #include "Network.hh" #include "FuncExpr.hh" +#include "Variables.hh" namespace sta { @@ -46,12 +47,10 @@ namespace sta { //////////////////////////////////////////////////////////////// Graph::Graph(StaState *sta, - int slew_rf_count, DcalcAPIndex ap_count) : StaState(sta), vertices_(nullptr), edges_(nullptr), - slew_rf_count_(slew_rf_count), ap_count_(ap_count), period_check_annotations_(nullptr), reg_clk_vertices_(makeVertexSet(this)) @@ -284,7 +283,7 @@ Graph::makeWireEdgesFromPin(const Pin *drvr_pin, if (isIsolatedNet(drvrs, loads)) { for (auto drvr_pin : drvrs) { visited_drvrs.insert(drvr_pin); - debugPrint(debug_, "graph", 1, "ignoring isolated driver %s", + debugPrint(debug_, "graph", 1, "ignoring isolated driver {}", network_->pathName(drvr_pin)); } return; @@ -578,22 +577,32 @@ Graph::gateEdgeArc(const Pin *in_pin, //////////////////////////////////////////////////////////////// -const Slew & +Slew Graph::slew(const Vertex *vertex, const RiseFall *rf, DcalcAPIndex ap_index) { - if (slew_rf_count_) { - const Slew *slews = vertex->slews(); - size_t slew_index = (slew_rf_count_ == 1) - ? ap_index - : ap_index*slew_rf_count_+rf->index(); + size_t slew_index = ap_index * RiseFall::index_count + rf->index(); + const float *slews_flt = vertex->slewsFloat(); + if (variables_->pocvEnabled()) { + const Slew *slews = std::bit_cast(slews_flt); return slews[slew_index]; } - else { - static Slew slew(0.0); - return slew; + else + return slews_flt[slew_index]; +} + +Slew +Graph::slew(const Vertex *vertex, + size_t index) +{ + const float *slews_flt = vertex->slewsFloat(); + if (variables_->pocvEnabled()) { + const Slew *slews = std::bit_cast(slews_flt); + return slews[index]; } + else + return slews_flt[index]; } void @@ -602,18 +611,15 @@ Graph::setSlew(Vertex *vertex, DcalcAPIndex ap_index, const Slew &slew) { - if (slew_rf_count_) { + size_t slew_index = ap_index * RiseFall::index_count + rf->index(); + if (variables_->pocvEnabled()) { Slew *slews = vertex->slews(); - if (slews == nullptr) { - int slew_count = slew_rf_count_ * ap_count_; - slews = new Slew[slew_count]; - vertex->setSlews(slews); - } - size_t slew_index = (slew_rf_count_ == 1) - ? ap_index - : ap_index*slew_rf_count_+rf->index(); slews[slew_index] = slew; } + else { + float *slews_flt = vertex->slewsFloat(); + slews_flt[slew_index] = slew.mean(); + } } //////////////////////////////////////////////////////////////// @@ -670,30 +676,48 @@ Graph::arcDelay(const Edge *edge, const TimingArc *arc, DcalcAPIndex ap_index) const { - ArcDelay *delays = edge->arcDelays(); size_t index = arc->index() * ap_count_ + ap_index; - return delays[index]; + if (variables_->pocvEnabled()) { + ArcDelay *delays = std::bit_cast(edge->arcDelays()); + return delays[index]; + } + else { + const float *delays = edge->arcDelays(); + return delays[index]; + } } void Graph::setArcDelay(Edge *edge, const TimingArc *arc, DcalcAPIndex ap_index, - ArcDelay delay) + const ArcDelay &delay) { - ArcDelay *arc_delays = edge->arcDelays(); size_t index = arc->index() * ap_count_ + ap_index; - arc_delays[index] = delay; + if (variables_->pocvEnabled()) { + ArcDelay *delays = std::bit_cast(edge->arcDelays()); + delays[index] = delay; + } + else { + float *delays = edge->arcDelays(); + delays[index] = delay.mean(); + } } -const ArcDelay & +ArcDelay Graph::wireArcDelay(const Edge *edge, const RiseFall *rf, DcalcAPIndex ap_index) { - ArcDelay *delays = edge->arcDelays(); size_t index = rf->index() * ap_count_ + ap_index; - return delays[index]; + if (variables_->pocvEnabled()) { + ArcDelay *delays = std::bit_cast(edge->arcDelays()); + return delays[index]; + } + else { + const float *delays = edge->arcDelays(); + return delays[index]; + } } void @@ -702,9 +726,15 @@ Graph::setWireArcDelay(Edge *edge, DcalcAPIndex ap_index, const ArcDelay &delay) { - ArcDelay *delays = edge->arcDelays(); size_t index = rf->index() * ap_count_ + ap_index; - delays[index] = delay; + if (variables_->pocvEnabled()) { + ArcDelay *delays = std::bit_cast(edge->arcDelays()); + delays[index] = delay; + } + else { + float *delays = edge->arcDelays(); + delays[index] = delay.mean(); + } } //////////////////////////////////////////////////////////////// @@ -788,16 +818,20 @@ void Graph::initSlews(Vertex *vertex) { size_t slew_count = slewCount(); - Slew *slews = new Slew[slew_count]; - vertex->setSlews(slews); - for (size_t i = 0; i < slew_count; i++) - slews[i] = 0.0; + if (variables_->pocvEnabled()) { + float *slews = std::bit_cast(new Slew[slew_count]{}); + vertex->setSlews(slews); + } + else { + float *slews = new float[slew_count]{}; + vertex->setSlews(slews); + } } size_t Graph::slewCount() { - return slew_rf_count_ * ap_count_; + return RiseFall::index_count * ap_count_; } void @@ -805,10 +839,14 @@ Graph::initArcDelays(Edge *edge) { size_t arc_count = edge->timingArcSet()->arcCount(); size_t delay_count = arc_count * ap_count_; - ArcDelay *arc_delays = new ArcDelay[delay_count]; - edge->setArcDelays(arc_delays); - for (size_t i = 0; i < delay_count; i++) - arc_delays[i] = 0.0; + if (variables_->pocvEnabled()) { + float *delays = std::bit_cast(new ArcDelay[delay_count]{}); + edge->setArcDelays(delays); + } + else { + float *delays = new float[delay_count]{}; + edge->setArcDelays(delays); + } } //////////////////////////////////////////////////////////////// @@ -1040,7 +1078,7 @@ Vertex::setVisited2(bool visited) } void -Vertex::setSlews(Slew *slews) +Vertex::setSlews(float *slews) { delete [] slews_; slews_ = slews; @@ -1251,10 +1289,10 @@ Edge::setTimingArcSet(TimingArcSet *set) } void -Edge::setArcDelays(ArcDelay *arc_delays) +Edge::setArcDelays(float *delays) { delete [] arc_delays_; - arc_delays_ = arc_delays; + arc_delays_ = delays; } bool diff --git a/graph/Graph.i b/graph/Graph.i index 5c16e5f8..85cb5124 100644 --- a/graph/Graph.i +++ b/graph/Graph.i @@ -132,21 +132,24 @@ bool is_bidirect_driver() { return self->isBidirectDriver(); } int level() { return Sta::sta()->vertexLevel(self); } int tag_group_index() { return self->tagGroupIndex(); } -Slew +float slew(const RiseFallBoth *rf, const MinMax *min_max) { Sta *sta = Sta::sta(); - return sta->slew(self, rf, sta->scenes(), min_max); + return delayAsFloat(sta->slew(self, rf, sta->scenes(), min_max), min_max, sta); } -Slew -slew_scenes(const RiseFallBoth *rf, - const SceneSeq scenes, - const MinMax *min_max) +std::string +slew_scenes_string(const RiseFallBoth *rf, + const SceneSeq scenes, + const MinMax *min_max, + bool report_variance, + int digits) { Sta *sta = Sta::sta(); - return sta->slew(self, rf, scenes, min_max); + Slew slew = sta->slew(self, rf, scenes, min_max); + return delayAsString(slew, min_max, report_variance, digits, sta); } VertexOutEdgeIterator * @@ -223,22 +226,29 @@ arc_delays(TimingArc *arc) { Sta *sta = Sta::sta(); FloatSeq delays; - DcalcAPIndex ap_count = sta->dcalcAnalysisPtCount(); - for (DcalcAPIndex ap_index = 0; ap_index < ap_count; ap_index++) - delays.push_back(delayAsFloat(sta->arcDelay(self, arc, ap_index))); + for (Scene *scene : sta->scenes()) { + for (const MinMax *min_max : MinMax::range()) { + DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); + delays.push_back(delayAsFloat(sta->arcDelay(self, arc, ap_index), min_max, sta)); + } + } return delays; } StringSeq arc_delay_strings(TimingArc *arc, + bool report_variance, int digits) { Sta *sta = Sta::sta(); StringSeq delays; - DcalcAPIndex ap_count = sta->dcalcAnalysisPtCount(); - for (DcalcAPIndex ap_index = 0; ap_index < ap_count; ap_index++) - delays.push_back(delayAsString(sta->arcDelay(self, arc, ap_index), - sta, digits)); + for (Scene *scene : sta->scenes()) { + for (const MinMax *min_max : MinMax::range()) { + DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); + delays.push_back(delayAsString(sta->arcDelay(self, arc, ap_index), + min_max, report_variance, digits, sta)); + } + } return delays; } @@ -255,8 +265,9 @@ arc_delay(TimingArc *arc, const Scene *scene, const MinMax *min_max) { + Sta *sta = Sta::sta(); DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); - return delayAsFloat(Sta::sta()->arcDelay(self, arc, ap_index)); + return delayAsFloat(Sta::sta()->arcDelay(self, arc, ap_index), min_max, sta); } std::string @@ -281,7 +292,7 @@ mode_value() return self->timingArcSet()->modeValue().c_str(); } -const char * +std::string latch_d_to_q_en() { if (self->role() == TimingRole::latchDtoQ()) { @@ -297,9 +308,7 @@ latch_d_to_q_en() const RiseFall *enable_rf; lib_cell->latchEnable(d_q_set, enable_port, enable_func, enable_rf); if (enable_port) - return stringPrintTmp("%s %s", - enable_port->name(), - enable_rf->shortName()); + return sta::format("{} {}", enable_port->name(), enable_rf->shortName()); } return ""; } diff --git a/graph/Graph.tcl b/graph/Graph.tcl index 27ea5f19..3d04bf68 100644 --- a/graph/Graph.tcl +++ b/graph/Graph.tcl @@ -26,51 +26,64 @@ namespace eval sta { -define_cmd_args "report_edges" {[-from from_pin] [-to to_pin]} +define_cmd_args "report_edges" {[-from from_pin] [-to to_pin]\ + [-digits digits] [-report_variance]} proc report_edges { args } { - parse_key_args "report_edges" args keys {-from -to} flags {} + global sta_report_default_digits + + parse_key_args "report_edges" args keys {-from -to -digits} flags {-report_variance} check_argc_eq0 "report_edges" $args + if [info exists keys(-digits)] { + set digits $keys(-digits) + check_positive_integer "-digits" $digits + } else { + set digits $sta_report_default_digits + } + + set report_variance [info exists flags(-report_variance)] + if { [info exists keys(-from)] && [info exists keys(-to)] } { set from_pin [get_port_pin_error "from_pin" $keys(-from)] set to_pin [get_port_pin_error "to_pin" $keys(-to)] foreach from_vertex [$from_pin vertices] { foreach to_vertex [$to_pin vertices] { - report_edges_between_ $from_vertex $to_vertex + report_edges_between_ $from_vertex $to_vertex $digits $report_variance } } } elseif [info exists keys(-from)] { set from_pin [get_port_pin_error "from_pin" $keys(-from)] foreach from_vertex [$from_pin vertices] { report_edges_ $from_vertex out_edge_iterator \ - vertex_port_name vertex_path_name + vertex_port_name vertex_path_name $digits $report_variance } } elseif [info exists keys(-to)] { set to_pin [get_port_pin_error "to_pin" $keys(-to)] foreach to_vertex [$to_pin vertices] { report_edges_ $to_vertex in_edge_iterator \ - vertex_path_name vertex_port_name + vertex_path_name vertex_port_name $digits $report_variance } } } -proc report_edges_between_ { from_vertex to_vertex } { +proc report_edges_between_ { from_vertex to_vertex digits report_variance } { set iter [$from_vertex out_edge_iterator] while {[$iter has_next]} { set edge [$iter next] if { [$edge to] == $to_vertex } { if { [$edge role] == "wire" } { - report_edge_ $edge vertex_path_name vertex_path_name + report_edge_ $edge vertex_path_name vertex_path_name $digits $report_variance } else { - report_edge_ $edge vertex_port_name vertex_port_name + report_edge_ $edge vertex_port_name vertex_port_name $digits $report_variance } } } $iter finish } -proc report_edges_ { vertex iter_proc wire_from_name_proc wire_to_name_proc } { +proc report_edges_ { vertex iter_proc wire_from_name_proc wire_to_name_proc \ + digits report_variance } { # First report edges internal to the device. set device_header 0 set iter [$vertex $iter_proc] @@ -84,7 +97,7 @@ proc report_edges_ { vertex iter_proc wire_from_name_proc wire_to_name_proc } { } set device_header 1 } - report_edge_ $edge vertex_port_name vertex_port_name + report_edge_ $edge vertex_port_name vertex_port_name $digits $report_variance } } $iter finish @@ -94,15 +107,14 @@ proc report_edges_ { vertex iter_proc wire_from_name_proc wire_to_name_proc } { while {[$iter has_next]} { set edge [$iter next] if { [$edge role] == "wire" } { - report_edge_ $edge $wire_from_name_proc $wire_to_name_proc + report_edge_ $edge $wire_from_name_proc $wire_to_name_proc $digits $report_variance } } $iter finish } -proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc } { - global sta_report_default_digits - +proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc \ + digits report_variance } { set latch_enable [$edge latch_d_to_q_en] if { $latch_enable != "" } { set latch_enable " enable $latch_enable" @@ -125,7 +137,7 @@ proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc } { } foreach arc [$edge timing_arcs] { - set delays [$edge arc_delay_strings $arc $sta_report_default_digits] + set delays [$edge arc_delay_strings $arc $report_variance $digits] set delays_fmt [format_delays $delays] set disable_reason "" if { [timing_arc_disabled $edge $arc] } { @@ -135,18 +147,6 @@ proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc } { } } -# Separate list elements with colons. -proc format_times { values digits } { - set result "" - foreach value $values { - if { $result != "" } { - append result ":" - } - append result [format_time $value $digits] - } - return $result -} - # Separate delay list elements with colons. proc format_delays { values } { set result "" diff --git a/include/sta/ArcDelayCalc.hh b/include/sta/ArcDelayCalc.hh index d2b99012..45dcbae3 100644 --- a/include/sta/ArcDelayCalc.hh +++ b/include/sta/ArcDelayCalc.hh @@ -119,15 +119,15 @@ public: ArcDcalcResult(size_t load_count); void setLoadCount(size_t load_count); ArcDelay &gateDelay() { return gate_delay_; } - void setGateDelay(ArcDelay gate_delay); + void setGateDelay(const ArcDelay &gate_delay); Slew &drvrSlew() { return drvr_slew_; } - void setDrvrSlew(Slew drvr_slew); - ArcDelay wireDelay(size_t load_idx) const; + void setDrvrSlew(const Slew &drvr_slew); + const ArcDelay &wireDelay(size_t load_idx) const; void setWireDelay(size_t load_idx, - ArcDelay wire_delay); - Slew loadSlew(size_t load_idx) const; + const ArcDelay &wire_delay); + const Slew &loadSlew(size_t load_idx) const; void setLoadSlew(size_t load_idx, - Slew load_slew); + const Slew &load_slew); protected: ArcDelay gate_delay_; diff --git a/include/sta/Clock.hh b/include/sta/Clock.hh index 2b9efc5e..06215222 100644 --- a/include/sta/Clock.hh +++ b/include/sta/Clock.hh @@ -25,6 +25,7 @@ #pragma once #include +#include #include "MinMax.hh" #include "RiseFallMinMax.hh" @@ -207,7 +208,7 @@ public: ~ClockEdge(); const RiseFall *transition() const { return rf_; } float time() const { return time_; } - const char *name() const { return name_; } + const std::string &name() const { return name_; } int index() const { return index_; } ClockEdge *opposite() const; // Pulse width if this is the leading edge of the pulse. @@ -221,7 +222,7 @@ private: Clock *clock_; const RiseFall *rf_; - const char *name_; + std::string name_; float time_; int index_; }; diff --git a/include/sta/ClockGroups.hh b/include/sta/ClockGroups.hh index e09cfb91..89159a82 100644 --- a/include/sta/ClockGroups.hh +++ b/include/sta/ClockGroups.hh @@ -24,6 +24,8 @@ #pragma once +#include + #include "SdcCmdComment.hh" #include "SdcClass.hh" @@ -32,7 +34,7 @@ namespace sta { class ClockGroups : public SdcCmdComment { public: - ClockGroups(const char *name, + ClockGroups(const std::string &name, bool logically_exclusive, bool physically_exclusive, bool asynchronous, @@ -40,7 +42,7 @@ public: const char *comment); ~ClockGroups(); void makeClockGroup(ClockSet *clks); - const char *name() const { return name_; } + const std::string &name() const { return name_; } ClockGroupSet *groups() { return &groups_; } bool logicallyExclusive() const { return logically_exclusive_; } bool physicallyExclusive() const { return physically_exclusive_; } @@ -49,7 +51,7 @@ public: void removeClock(Clock *clk); private: - const char *name_; + std::string name_; bool logically_exclusive_; bool physically_exclusive_; bool asynchronous_; diff --git a/include/sta/Debug.hh b/include/sta/Debug.hh index 1c21131e..1ff45934 100644 --- a/include/sta/Debug.hh +++ b/include/sta/Debug.hh @@ -25,10 +25,12 @@ #pragma once #include -#include +#include #include #include +#include "Format.hh" +#include "Report.hh" #include "StringUtil.hh" namespace sta { @@ -48,10 +50,16 @@ public: bool check(const char *what, int level) const; int statsLevel() const { return stats_level_; } - void reportLine(const char *what, - const char *fmt, - ...) - __attribute__((format (printf, 3, 4))); + template + void report(const char *what, + std::string_view fmt, + Args &&...args) + { + std::string msg = sta::format("{}: {}", what, + sta::formatRuntime(fmt, std::forward(args)...)); + std::unique_lock lock(buffer_lock_); + report_->reportLine(msg); + } protected: Report *report_; @@ -63,9 +71,9 @@ protected: // Inlining a varargs function would eval the args, which can // be expensive, so use a macro. -#define debugPrint(debug, what, level, ...) \ +#define debugPrint(debug, what, level, fmt, ...) \ if (debug->check(what, level)) { \ - debug->reportLine(what __VA_OPT__(,) __VA_ARGS__); \ + debug->report(what, fmt __VA_OPT__(,) __VA_ARGS__); \ } } // namespace diff --git a/include/sta/Delay.hh b/include/sta/Delay.hh index 860b23da..e2547557 100644 --- a/include/sta/Delay.hh +++ b/include/sta/Delay.hh @@ -24,27 +24,336 @@ #pragma once -#include "StaConfig.hh" +#include +#include -// IWYU pragma: begin_exports -#if (SSTA == 1) - // Delays are Normal PDFs. - #include "DelayNormal1.hh" -#elif (SSTA == 2) - // Delays are Normal PDFs with early/late sigma. - #include "DelayNormal2.hh" -#else - // Delays are floats. - #include "DelayFloat.hh" -#endif -// IWYU pragma: end_exports +#include "StaConfig.hh" +#include "MinMax.hh" namespace sta { +class StaState; + +class Delay +{ +public: + Delay(); + Delay(float mean); + Delay(float mean, + // std_dev^2 + float std_dev2); + Delay(float mean, + float mean_shift, + // std_dev^2 + float std_dev2, + float skewness); + void setValues(float mean, + float mean_shift, + float std_dev2, + float skewnes); + float mean() const { return values_[0]; } + void setMean(float mean); + float meanShift() const { return values_[1]; } + void setMeanShift(float mean_shift); + float stdDev() const; + // std_dev ^ 2 + float stdDev2() const { return values_[2]; } + void setStdDev(float std_dev); + float skewness() const { return values_[3]; } + void setSkewness(float skewness); + + void operator=(float delay); + // This allows applications that do not support statistical timing + // to treat Delays as floats without explicitly converting with + // delayAsFloat. + operator float() const { return mean(); } + +private: + std::array values_; +}; + +// Delay with doubles for accumulating Delays. +// Only a subset of operations are required for DelayDbl. +class DelayDbl +{ +public: + DelayDbl(); + DelayDbl(double value); + double mean() const { return values_[0]; } + void setMean(double mean); + double meanShift() const { return values_[1]; } + // std_dev ^ 2 + double stdDev2() const { return values_[2]; } + double stdDev() const; + double skewness() const { return values_[3]; } + void setValues(double mean, + double mean_shift, + double std_dev2, + double skewnes); + + void operator=(double delay); + +private: + std::array values_; +}; + using ArcDelay = Delay; using Slew = Delay; using Arrival = Delay; using Required = Delay; using Slack = Delay; +const Delay delay_zero(0.0); + +class DelayOps +{ +public: + virtual ~DelayOps() {} + virtual float stdDev2(const Delay &delay, + const EarlyLate *early_late) const = 0; + virtual float asFloat(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta) const = 0; + virtual double asFloat(const DelayDbl &delay, + const EarlyLate *early_late, + const StaState *sta) const = 0; + virtual bool isZero(const Delay &delay) const = 0; + virtual bool isInf(const Delay &delay) const = 0; + virtual bool equal(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const = 0; + virtual bool less(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const = 0; + virtual bool less(const DelayDbl &delay1, + const DelayDbl &delay2, + const StaState *sta) const = 0; + virtual bool lessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const = 0; + virtual bool greater(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const = 0; + virtual bool greaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const = 0; + virtual Delay sum(const Delay &delay1, + const Delay &delay2) const = 0; + virtual Delay sum(const Delay &delay1, + float delay2) const = 0; + virtual Delay diff(const Delay &delay1, + const Delay &delay2) const = 0; + virtual Delay diff(const Delay &delay1, + float delay2) const = 0; + virtual Delay diff(float delay1, + const Delay &delay2) const = 0; + virtual void incr(Delay &delay1, + const Delay &delay2) const = 0; + virtual void incr(DelayDbl &delay1, + const Delay &delay2) const = 0; + virtual void decr(Delay &delay1, + const Delay &delay2) const = 0; + virtual void decr(DelayDbl &delay1, + const Delay &delay2) const = 0; + virtual Delay product(const Delay &delay1, + float delay2) const = 0; + virtual Delay div(float delay1, + const Delay &delay2) const = 0; + virtual std::string asStringVariance(const Delay &delay, + int digits, + const StaState *sta) const = 0; + +}; + +void +initDelayConstants(); + +inline float +square(float x) +{ + return x * x; +} + +inline double +square(double x) +{ + return x * x; +} + +inline float +cube(float x) +{ + return x * x * x; +} + +inline double +cube(double x) +{ + return x * x * x; +} + +Delay +makeDelay(float mean, + float mean_shift, + float std_dev, + float skewness); +Delay +makeDelay(float mean, + float std_dev); +Delay +makeDelay2(float mean, + float std_dev); +void +delaySetMean(Delay &delay, + float mean); + +// early_late == late +std::string +delayAsString(const Delay &delay, + const StaState *sta); +// early_late == late +std::string +delayAsString(const Delay &delay, + int digits, + const StaState *sta); +std::string +delayAsString(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta); +std::string +delayAsString(const Delay &delay, + const EarlyLate *early_late, + int digits, + const StaState *sta); +std::string +delayAsString(const Delay &delay, + const EarlyLate *early_late, + bool report_variance, + int digits, + const StaState *sta); + +float +delayAsFloat(const Delay &delay); +float +delayAsFloat(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta); +float +delayAsFloat(const DelayDbl &delay, + const EarlyLate *early_late, + const StaState *sta); + +Delay +delayDblAsDelay(DelayDbl &delay); + +Delay +delaySum(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +Delay +delaySum(const Delay &delay1, + float delay2, + const StaState *sta); +Delay +delayDiff(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +Delay +delayDiff(const Delay &delay1, + float delay2, + const StaState *sta); +Delay +delayDiff(float delay1, + const Delay &delay2, + const StaState *sta); +void +delayIncr(Delay &delay1, + const Delay &delay2, + const StaState *sta); +void +delayIncr(DelayDbl &delay1, + const Delay &delay2, + const StaState *sta); +void +delayIncr(Delay &delay1, + float delay2, + const StaState *sta); +void +delayDecr(Delay &delay1, + const Delay &delay2, + const StaState *sta); +void +delayDecr(DelayDbl &delay1, + const Delay &delay2, + const StaState *sta); +Delay +delayProduct(const Delay &delay1, + float delay2, + const StaState *sta); +Delay +delayDiv(float delay1, + const Delay &delay2, + const StaState *sta); + +const Delay & +delayInitValue(const MinMax *min_max); +bool +delayIsInitValue(const Delay &delay, + const MinMax *min_max); +bool +delayZero(const Delay &delay, + const StaState *sta); +bool +delayInf(const Delay &delay, + const StaState *sta); +bool +delayEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayLess(const DelayDbl &delay1, + const DelayDbl &delay2, + const StaState *sta); +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); + +// delay1-delay2 subtracting sigma instead of addiing. +Delay +delayRemove(const Delay &delay1, + const Delay &delay2); + } // namespace diff --git a/include/sta/DelayFloat.hh b/include/sta/DelayFloat.hh deleted file mode 100644 index 81f047b9..00000000 --- a/include/sta/DelayFloat.hh +++ /dev/null @@ -1,152 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2026, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. -// -// Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// This notice may not be removed or altered from any source distribution. - -#pragma once - -#include "MinMax.hh" - -// Delay values defined as floats. - -namespace sta { - -class StaState; - -using Delay = float; -// Delay double for accumulating Delays. -using DelayDbl = double; - -const Delay delay_zero = 0.0; - -void -initDelayConstants(); - -const char * -delayAsString(const Delay &delay, - const StaState *sta); -const char * -delayAsString(const Delay &delay, - const StaState *sta, - int digits); -const char * -delayAsString(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta, - int digits); - -inline Delay -makeDelay(float delay, - float, - float) -{ - return delay; -} - -inline Delay -makeDelay2(float delay, - float, - float) -{ - return delay; -} - -inline float -delayAsFloat(const Delay &delay) -{ - return delay; -} - -// mean late+/early- sigma -inline float -delayAsFloat(const Delay &delay, - const EarlyLate *, - const StaState *) -{ - return delay; -} - -inline float -delaySigma2(const Delay &, - const EarlyLate *) -{ - return 0.0; -} - -const Delay & -delayInitValue(const MinMax *min_max); -bool -delayIsInitValue(const Delay &delay, - const MinMax *min_max); -bool -delayZero(const Delay &delay); -bool -delayInf(const Delay &delay); -bool -delayEqual(const Delay &delay1, - const Delay &delay2); -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); - -// delay1-delay2 subtracting sigma instead of addiing. -Delay -delayRemove(const Delay &delay1, - const Delay &delay2); -float -delayRatio(const Delay &delay1, - const Delay &delay2); - -} // namespace diff --git a/include/sta/DelayNormal.hh b/include/sta/DelayNormal.hh new file mode 100644 index 00000000..3a25cbf7 --- /dev/null +++ b/include/sta/DelayNormal.hh @@ -0,0 +1,90 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#pragma once + +#include "Delay.hh" + +namespace sta { + +class DelayOpsNormal : public DelayOps +{ +public: + float stdDev2(const Delay &delay, + const EarlyLate *early_late) const override; + float asFloat(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta) const override; + double asFloat(const DelayDbl &delay, + const EarlyLate *early_late, + const StaState *sta) const override; + + bool isZero(const Delay &delay) const override; + bool isInf(const Delay &delay) const override; + bool equal(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + bool less(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + bool less(const DelayDbl &delay1, + const DelayDbl &delay2, + const StaState *sta) const override; + bool lessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + bool greater(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + bool greaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + Delay sum(const Delay &delay1, + const Delay &delay2) const override; + Delay sum(const Delay &delay1, + float delay2) const override; + Delay diff(const Delay &delay1, + const Delay &delay2) const override; + Delay diff(const Delay &delay1, + float delay2) const override; + Delay diff(float delay1, + const Delay &delay2) const override; + void incr(Delay &delay1, + const Delay &delay2) const override; + void incr(DelayDbl &delay1, + const Delay &delay2) const override; + void decr(Delay &delay1, + const Delay &delay2) const override; + void decr(DelayDbl &delay1, + const Delay &delay2) const override; + Delay product(const Delay &delay1, + float delay2) const override; + Delay div(float delay1, + const Delay &delay2) const override; + std::string asStringVariance(const Delay &delay, + int digits, + const StaState *sta) const override; +}; + +} // namespace diff --git a/include/sta/DelayNormal1.hh b/include/sta/DelayNormal1.hh deleted file mode 100644 index 5787797f..00000000 --- a/include/sta/DelayNormal1.hh +++ /dev/null @@ -1,203 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2026, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. -// -// Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// This notice may not be removed or altered from any source distribution. - -#pragma once - -#include "MinMax.hh" - -namespace sta { - -class Delay; -class DelayDbl; -class StaState; - -// Normal distribution with std deviation. -class Delay -{ -public: - Delay(); - Delay(const Delay &delay); - Delay(const DelayDbl &delay); - Delay(float mean); - Delay(float mean, - float sigma2); - float mean() const { return mean_; } - float sigma() const; - // sigma^2 - float sigma2() const; - void operator=(const Delay &delay); - void operator=(float delay); - void operator+=(const Delay &delay); - void operator+=(float delay); - Delay operator+(const Delay &delay) const; - Delay operator+(float delay) const; - Delay operator-(const Delay &delay) const; - Delay operator-(float delay) const; - Delay operator-() const; - void operator-=(float delay); - void operator-=(const Delay &delay); - bool operator==(const Delay &delay) const; - -private: - float mean_; - // Sigma^2 - float sigma2_; - - friend class DelayDbl; -}; - -// Dwlay with doubles for accumulating delays. -class DelayDbl -{ -public: - DelayDbl(); - float mean() const { return mean_; } - float sigma() const; - // sigma^2 - float sigma2() const; - void operator=(float delay); - void operator+=(const Delay &delay); - void operator-=(const Delay &delay); - -private: - double mean_; - // Sigma^2 - double sigma2_; - - friend class Delay; -}; - -const Delay delay_zero(0.0); - -void -initDelayConstants(); - -const char * -delayAsString(const Delay &delay, - const StaState *sta); -const char * -delayAsString(const Delay &delay, - const StaState *sta, - int digits); -const char * -delayAsString(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta, - int digits); - -Delay -makeDelay(float delay, - float sigma_early, - float sigma_late); - -Delay -makeDelay2(float delay, - // sigma^2 - float sigma_early, - float sigma_late); - -inline float -delayAsFloat(const Delay &delay) -{ - return delay.mean(); -} - -// mean late+/early- sigma -float -delayAsFloat(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta); -float -delaySigma2(const Delay &delay, - const EarlyLate *early_late); -const Delay & -delayInitValue(const MinMax *min_max); -bool -delayIsInitValue(const Delay &delay, - const MinMax *min_max); -bool -delayZero(const Delay &delay); -bool -delayInf(const Delay &delay); -bool -delayEqual(const Delay &delay1, - const Delay &delay2); -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); - -// delay1-delay2 subtracting sigma instead of addiing. -Delay delayRemove(const Delay &delay1, - const Delay &delay2); -float -delayRatio(const Delay &delay1, - const Delay &delay2); - -// Most non-operator functions on Delay are not defined as member -// functions so they can be defined on floats, where there is no class -// to define them. - -Delay operator+(float delay1, - const Delay &delay2); -// Used for parallel gate delay calc. -Delay operator/(float delay1, - const Delay &delay2); -// Used for parallel gate delay calc. -Delay operator*(const Delay &delay1, - float delay2); - -} // namespace diff --git a/include/sta/DelayNormal2.hh b/include/sta/DelayNormal2.hh deleted file mode 100644 index 7355fd77..00000000 --- a/include/sta/DelayNormal2.hh +++ /dev/null @@ -1,214 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2026, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. -// -// Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// This notice may not be removed or altered from any source distribution. - -#pragma once - -#include "MinMax.hh" - -namespace sta { - -class Delay; -class DelayDbl; -class StaState; - -// Normal distribution with early(left)/late(right) std deviations. -class Delay -{ -public: - Delay(); - Delay(const Delay &delay); - Delay(const DelayDbl &delay); - Delay(float mean); - Delay(float mean, - float sigma2_early, - float sigma2_late); - float mean() const { return mean_; } - float sigma(const EarlyLate *early_late) const; - // sigma^2 - float sigma2(const EarlyLate *early_late) const; - float sigma2Early() const; - float sigma2Late() const; - void operator=(const Delay &delay); - void operator=(float delay); - void operator+=(const Delay &delay); - void operator+=(float delay); - Delay operator+(const Delay &delay) const; - Delay operator+(float delay) const; - Delay operator-(const Delay &delay) const; - Delay operator-(float delay) const; - Delay operator-() const; - void operator-=(float delay); - void operator-=(const Delay &delay); - bool operator==(const Delay &delay) const; - -protected: - static const int early_index = 0; - static const int late_index = 1; - -private: - float mean_; - // Sigma^2 - float sigma2_[EarlyLate::index_count]; - - friend class DelayDbl; -}; - -// Dwlay with doubles for accumulating delays. -class DelayDbl -{ -public: - DelayDbl(); - float mean() const { return mean_; } - float sigma() const; - // sigma^2 - float sigma2() const; - void operator=(float delay); - void operator+=(const Delay &delay); - void operator-=(const Delay &delay); - -protected: - static const int early_index = 0; - static const int late_index = 1; - -private: - double mean_; - // Sigma^2 - double sigma2_[EarlyLate::index_count]; - - friend class Delay; -}; - -const Delay delay_zero(0.0); - -void -initDelayConstants(); - -const char * -delayAsString(const Delay &delay, - const StaState *sta); -const char * -delayAsString(const Delay &delay, - const StaState *sta, - int digits); -const char * -delayAsString(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta, - int digits); - -Delay -makeDelay(float delay, - float sigma_early, - float sigma_late); - -Delay -makeDelay2(float delay, - // sigma^2 - float sigma_early, - float sigma_late); - -inline float -delayAsFloat(const Delay &delay) -{ - return delay.mean(); -} - -// mean late+/early- sigma -float -delayAsFloat(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta); -float -delaySigma2(const Delay &delay, - const EarlyLate *early_late); -const Delay & -delayInitValue(const MinMax *min_max); -bool -delayIsInitValue(const Delay &delay, - const MinMax *min_max); -bool -delayZero(const Delay &delay); -bool -delayInf(const Delay &delay); -bool -delayEqual(const Delay &delay1, - const Delay &delay2); -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayLess(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayLessEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const StaState *sta); -bool -delayGreaterEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); -bool -delayGreater(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max, - const StaState *sta); - -// delay1-delay2 subtracting sigma instead of addiing. -Delay delayRemove(const Delay &delay1, - const Delay &delay2); -float -delayRatio(const Delay &delay1, - const Delay &delay2); - -// Most non-operator functions on Delay are not defined as member -// functions so they can be defined on floats, where there is no class -// to define them. - -Delay operator+(float delay1, - const Delay &delay2); -// Used for parallel gate delay calc. -Delay operator/(float delay1, - const Delay &delay2); -// Used for parallel gate delay calc. -Delay operator*(const Delay &delay1, - float delay2); - -} // namespace diff --git a/include/sta/DelayScalar.hh b/include/sta/DelayScalar.hh new file mode 100644 index 00000000..a413c92d --- /dev/null +++ b/include/sta/DelayScalar.hh @@ -0,0 +1,90 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#pragma once + +#include "Delay.hh" + +namespace sta { + +class DelayOpsScalar : public DelayOps +{ +public: + float stdDev2(const Delay &delay, + const EarlyLate *early_late) const override; + float asFloat(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta) const override; + double asFloat(const DelayDbl &delay, + const EarlyLate *early_late, + const StaState *sta) const override; + + bool isZero(const Delay &delay) const override; + bool isInf(const Delay &delay) const override; + bool equal(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + bool less(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + bool less(const DelayDbl &delay1, + const DelayDbl &delay2, + const StaState *sta) const override; + bool lessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + bool greater(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + bool greaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + Delay sum(const Delay &delay1, + const Delay &delay2) const override; + Delay sum(const Delay &delay1, + float delay2) const override; + Delay diff(const Delay &delay1, + const Delay &delay2) const override; + Delay diff(const Delay &delay1, + float delay2) const override; + Delay diff(float delay1, + const Delay &delay2) const override; + void incr(Delay &delay1, + const Delay &delay2) const override; + void incr(DelayDbl &delay1, + const Delay &delay2) const override; + void decr(Delay &delay1, + const Delay &delay2) const override; + void decr(DelayDbl &delay1, + const Delay &delay2) const override; + Delay product(const Delay &delay1, + float delay2) const override; + Delay div(float delay1, + const Delay &delay2) const override; + std::string asStringVariance(const Delay &delay, + int digits, + const StaState *sta) const override; +}; + +} // namespace diff --git a/include/sta/DelaySkewNormal.hh b/include/sta/DelaySkewNormal.hh new file mode 100644 index 00000000..5922e03e --- /dev/null +++ b/include/sta/DelaySkewNormal.hh @@ -0,0 +1,98 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#pragma once + +#include "Delay.hh" + +namespace sta { + +class DelayOpsSkewNormal : public DelayOps +{ +public: + float stdDev2(const Delay &delay, + const EarlyLate *early_late) const override; + float asFloat(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta) const override; + double asFloat(const DelayDbl &delay, + const EarlyLate *early_late, + const StaState *sta) const override; + + bool isZero(const Delay &delay) const override; + bool isInf(const Delay &delay) const override; + bool equal(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + bool less(const Delay &delay1, + const Delay &delay2, + const StaState *sta) const override; + bool less(const DelayDbl &delay1, + const DelayDbl &delay2, + const StaState *sta) const override; + bool lessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *) const override; + bool greater(const Delay &delay1, + const Delay &delay2, + const StaState *) const override; + bool greaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *) const override; + Delay sum(const Delay &delay1, + const Delay &delay2) const override; + Delay sum(const Delay &delay1, + float delay2) const override; + Delay diff(const Delay &delay1, + const Delay &delay2) const override; + Delay diff(const Delay &delay1, + float delay2) const override; + Delay diff(float delay1, + const Delay &delay2) const override; + void incr(Delay &delay1, + const Delay &delay2) const override; + void incr(DelayDbl &delay1, + const Delay &delay2) const override; + void decr(Delay &delay1, + const Delay &delay2) const override; + void decr(DelayDbl &delay1, + const Delay &delay2) const override; + Delay product(const Delay &delay1, + float delay2) const override; + Delay div(float delay1, + const Delay &delay2) const override; + std::string asStringVariance(const Delay &delay, + int digits, + const StaState *sta) const override; + +private: + float skewnessSum(const Delay &delay1, + const Delay &delay2) const; + double skewnessSum(double std_dev1, + double skewness1, + double std_dev2, + double skewness2) const; +}; + +} // namespace diff --git a/include/sta/Error.hh b/include/sta/Error.hh index d73775f4..a653024d 100644 --- a/include/sta/Error.hh +++ b/include/sta/Error.hh @@ -25,6 +25,7 @@ #pragma once #include +#include #include "Report.hh" @@ -42,7 +43,7 @@ public: class ExceptionMsg : public Exception { public: - ExceptionMsg(const char *msg, + ExceptionMsg(const std::string &msg, const bool suppressed); virtual const char *what() const noexcept; virtual bool suppressed() const { return suppressed_; } @@ -55,11 +56,11 @@ private: class ExceptionLine : public Exception { public: - ExceptionLine(const char *filename, + ExceptionLine(const std::string &filename, int line); protected: - const char *filename_; + std::string filename_; int line_; }; @@ -67,29 +68,31 @@ protected: class FileNotReadable : public Exception { public: - FileNotReadable(const char *filename); + FileNotReadable(std::string filename); virtual const char *what() const noexcept; protected: - const char *filename_; + std::string filename_; + std::string msg_; }; // Failure opening filename for writing. class FileNotWritable : public Exception { public: - FileNotWritable(const char *filename); + FileNotWritable(std::string filename); virtual const char *what() const noexcept; protected: - const char *filename_; + std::string filename_; + std::string msg_; }; // Report an error condition that should not be possible. // The default handler prints msg to stderr and exits. // The msg should NOT include a period or return. -// Only for use in those cases where a Report object is not available. -#define criticalError(id,msg) \ +// Only for use in those cases where a Report object is not available. +#define criticalError(id, msg) \ Report::defaultReport()->fileCritical(id, __FILE__, __LINE__, msg) } // namespace diff --git a/include/sta/ExceptionPath.hh b/include/sta/ExceptionPath.hh index b7f7e655..9e4a555c 100644 --- a/include/sta/ExceptionPath.hh +++ b/include/sta/ExceptionPath.hh @@ -24,6 +24,7 @@ #pragma once +#include #include #include "Error.hh" @@ -67,7 +68,7 @@ public: virtual bool isGroupPath() const { return false; } virtual bool isFilter() const { return false; } virtual ExceptionPathType type() const = 0; - virtual const char *asString(const Network *network) const; + virtual std::string to_string(const Network *network) const; ExceptionFrom *from() const { return from_; } ExceptionThruSeq *thrus() const { return thrus_; } ExceptionTo *to() const { return to_; } @@ -127,14 +128,14 @@ public: virtual bool useEndClk() const { return false; } virtual int pathMultiplier() const { return 0; } virtual float delay() const { return 0.0; } - virtual const char *name() const { return nullptr; } + virtual std::string name() const { return ""; } virtual bool isDefault() const { return false; } virtual bool ignoreClkLatency() const { return false; } virtual bool breakPath() const { return false; } protected: virtual const char *typeString() const = 0; - const char *fromThruToString(const Network *network) const; + std::string fromThruToString(const Network *network) const; void makeStates(); ExceptionFrom *from_; @@ -209,7 +210,7 @@ public: bool own_pts) override; bool isPathDelay() const override { return true; } ExceptionPathType type() const override { return ExceptionPathType::path_delay; } - const char *asString(const Network *network) const override; + std::string to_string(const Network *network) const override; const char *typeString() const override; bool mergeable(ExceptionPath *exception) const override; bool overrides(ExceptionPath *exception) const override; @@ -245,7 +246,7 @@ public: ExceptionPathType type() const override { return ExceptionPathType::multi_cycle; } bool matches(const MinMax *min_max, bool exactly) const override; - const char *asString(const Network *network) const override; + std::string to_string(const Network *network) const override; const char *typeString() const override; bool mergeable(ExceptionPath *exception) const override; bool overrides(ExceptionPath *exception) const override; @@ -292,7 +293,7 @@ public: class GroupPath : public ExceptionPath { public: - GroupPath(const char *name, + GroupPath(const std::string &name, bool is_default, ExceptionFrom *from, ExceptionThruSeq *thrus, @@ -311,11 +312,11 @@ public: bool overrides(ExceptionPath *exception) const override; int typePriority() const override; bool tighterThan(ExceptionPath *exception) const override; - const char *name() const override { return name_; } + std::string name() const override { return name_; } bool isDefault() const override { return is_default_; } protected: - const char *name_; + std::string name_; bool is_default_; }; @@ -343,7 +344,7 @@ public: // All pins and instance/net pins. virtual PinSet allPins(const Network *network) = 0; virtual int typePriority() const = 0; - virtual const char *asString(const Network *network) const = 0; + virtual std::string to_string(const Network *network) const = 0; virtual size_t objectCount() const = 0; virtual void addPin(const Pin *pin, const Network *network) = 0; @@ -367,8 +368,8 @@ protected: // exception merging. size_t hash_; - // Maximum number of objects for asString() to show. - static const int as_string_max_objects_; + // Maximum number of objects for to_string() to show. + static const int to_string_max_objects_; static const size_t hash_clk = 3; static const size_t hash_pin = 5; static const size_t hash_net = 7; @@ -402,7 +403,7 @@ public: const Network *network) const override; void mergeInto(ExceptionPt *pt, const Network *network) override; - const char *asString(const Network *network) const override; + std::string to_string(const Network *network) const override; size_t objectCount() const override; void deleteClock(Clock *clk); void addPin(const Pin *pin, @@ -467,7 +468,7 @@ public: const Network *network); ExceptionTo *clone(const Network *network); bool isTo() const override { return true; } - const char *asString(const Network *network) const override; + std::string to_string(const Network *network) const override; const RiseFallBoth *endTransition() { return end_rf_; } bool intersectsPts(ExceptionTo *to, const Network *network) const; @@ -512,7 +513,7 @@ public: const Network *network); ~ExceptionThru(); ExceptionThru *clone(const Network *network); - const char *asString(const Network *network) const override; + std::string to_string(const Network *network) const override; bool isThru() const override { return true; } PinSet *pins() override { return pins_; } EdgePinsSet *edges() override { return edges_; } diff --git a/include/sta/Format.hh b/include/sta/Format.hh new file mode 100644 index 00000000..1745f482 --- /dev/null +++ b/include/sta/Format.hh @@ -0,0 +1,153 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2026, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#pragma once + +#include +#include +#include +#include + +#include "StaConfig.hh" + +#ifdef ZLIB_FOUND +#include +#endif + +// std::format is not supported in GCC 11 (e.g. Ubuntu 22.04). +// Use fmt library as fallback when __cpp_lib_format is not defined. + +#if defined(__cpp_lib_format) && __cpp_lib_format >= 201907L +#include + +namespace sta { + +template +std::string format(std::format_string fmt, + Args &&...args) { + return std::format(fmt, std::forward(args)...); +} + +template +void print(std::ofstream &stream, + std::format_string fmt, + Args &&...args) { + stream << std::format(fmt, std::forward(args)...); +} + +#ifdef ZLIB_FOUND +template +void print(gzFile stream, + std::format_string fmt, + Args &&...args) { + std::string s = sta::format(fmt, std::forward(args)...); + gzwrite(stream, s.c_str(), s.size()); +} +#endif +template +void print(FILE *stream, + std::format_string fmt, + Args &&...args) { + std::string s = sta::format(fmt, std::forward(args)...); + std::fprintf(stream, "%s", s.c_str()); +} + +inline std::string vformat(std::string_view fmt, + std::format_args args) { + return std::vformat(fmt, args); +} + +template +auto make_format_args(Args &&...args) { + return std::make_format_args(std::forward(args)...); +} + +// Format with runtime format string - captures args to avoid make_format_args +// rvalue reference issues. +template +std::string formatRuntime(std::string_view fmt, + Args &&...args) { + auto args_tuple = std::make_tuple(std::forward(args)...); + return std::apply( + [fmt](auto &...a) { + return std::vformat(fmt, std::make_format_args(a...)); + }, + args_tuple); +} + +} // namespace sta + +#else +#include + +namespace sta { + +template +std::string format(fmt::format_string fmt, + Args &&...args) { + return fmt::format(fmt, std::forward(args)...); +} +template +void print(std::ofstream &stream, + fmt::format_string fmt, + Args &&...args) { + stream << fmt::format(fmt, std::forward(args)...); +} + +#ifdef ZLIB_FOUND +template +void print(gzFile stream, + fmt::format_string fmt, + Args &&...args) { + std::string s = sta::format(fmt, std::forward(args)...); + gzwrite(stream, s.c_str(), s.size()); +} +#endif +template +void print(FILE *stream, + fmt::format_string fmt, + Args &&...args) { + std::string s = sta::format(fmt, std::forward(args)...); + std::fprintf(stream, "%s", s.c_str()); +} + +inline +std::string vformat(std::string_view fmt, + fmt::format_args args) { + return fmt::vformat(fmt, args); +} + +template +auto make_format_args(Args &&...args) { + return fmt::make_format_args(std::forward(args)...); +} + +template +std::string formatRuntime(std::string_view fmt, + Args &&...args) { + return fmt::format(fmt::runtime(fmt), std::forward(args)...); +} + +} // namespace sta +#endif diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index e96a2c64..6846ae89 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -58,13 +58,7 @@ static constexpr ObjectIdx vertex_idx_null = object_idx_null; class Graph : public StaState { public: - // slew_rf_count is - // 0 no slews - // 1 one slew for rise/fall - // 2 rise/fall slews - // ap_count is the dcalc analysis point count. Graph(StaState *sta, - int slew_rf_count, DcalcAPIndex ap_count); void makeGraph(); ~Graph(); @@ -97,9 +91,11 @@ public: // Reported slew are the same as those in the liberty tables. // reported_slews = measured_slews / slew_derate_from_library // Measured slews are between slew_lower_threshold and slew_upper_threshold. - const Slew &slew(const Vertex *vertex, - const RiseFall *rf, - DcalcAPIndex ap_index); + Slew slew(const Vertex *vertex, + const RiseFall *rf, + DcalcAPIndex ap_index); + Slew slew(const Vertex *vertex, + size_t index); void setSlew(Vertex *vertex, const RiseFall *rf, DcalcAPIndex ap_index, @@ -134,11 +130,11 @@ public: void setArcDelay(Edge *edge, const TimingArc *arc, DcalcAPIndex ap_index, - ArcDelay delay); + const ArcDelay &delay); // Alias for arcDelays using library wire arcs. - const ArcDelay &wireArcDelay(const Edge *edge, - const RiseFall *rf, - DcalcAPIndex ap_index); + ArcDelay wireArcDelay(const Edge *edge, + const RiseFall *rf, + DcalcAPIndex ap_index); void setWireArcDelay(Edge *edge, const RiseFall *rf, DcalcAPIndex ap_index, @@ -222,7 +218,6 @@ protected: // driver/source (top level input, instance pin output) vertex // in pin_bidirect_drvr_vertex_map PinVertexMap pin_bidirect_drvr_vertex_map_; - int slew_rf_count_; DcalcAPIndex ap_count_; // Sdf period check annotations. PeriodCheckAnnotations *period_check_annotations_; @@ -258,8 +253,6 @@ public: [[nodiscard]] bool isRoot() const{ return level_ == 0; } [[nodiscard]] bool hasFanin() const; [[nodiscard]] bool hasFanout() const; - Slew *slews() { return slews_; } - const Slew *slews() const { return slews_; } Path *paths() const { return paths_; } Path *makePaths(uint32_t count); void setPaths(Path *paths); @@ -298,14 +291,18 @@ protected: bool is_bidirect_drvr, bool is_reg_clk); void clear(); - void setSlews(Slew *slews); + Slew *slews() { return std::bit_cast(slews_); } + const Slew *slews() const { return std::bit_cast(slews_); } + float *slewsFloat() { return slews_; } + const float *slewsFloat() const { return slews_; } + void setSlews(float *slews); Pin *pin_; EdgeId in_edges_; // Edges to this vertex. EdgeId out_edges_; // Edges from this vertex. // Delay calc - Slew *slews_; + float *slews_; // Search Path *paths_; @@ -356,8 +353,9 @@ public: TimingSense sense() const; TimingArcSet *timingArcSet() const { return arc_set_; } void setTimingArcSet(TimingArcSet *set); - ArcDelay *arcDelays() const { return arc_delays_; } - void setArcDelays(ArcDelay *arc_delays); + float *arcDelays() { return arc_delays_; } + const float *arcDelays() const { return arc_delays_; } + void setArcDelays(float *delays); bool delay_Annotation_Is_Incremental() const {return delay_annotation_is_incremental_;}; void setDelayAnnotationIsIncremental(bool is_incr); // Edge is disabled to break combinational loops. @@ -398,7 +396,7 @@ protected: EdgeId vertex_in_link_; // Vertex in edges list. EdgeId vertex_out_next_; // Vertex out edges doubly linked list. EdgeId vertex_out_prev_; - ArcDelay *arc_delays_; + float *arc_delays_; union { uintptr_t bits_; std::vector *seq_; diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh index a1f5373a..60c12d43 100644 --- a/include/sta/GraphDelayCalc.hh +++ b/include/sta/GraphDelayCalc.hh @@ -245,8 +245,8 @@ protected: bool annotateDelaySlew(Edge *edge, const TimingArc *arc, - ArcDelay &gate_delay, - Slew &gate_slew, + const ArcDelay &gate_delay, + const Slew &gate_slew, const Scene *scene, const MinMax *min_max); bool annotateLoadDelays(Vertex *drvr_vertex, diff --git a/include/sta/InternalPower.hh b/include/sta/InternalPower.hh index e37003ac..30d20ebb 100644 --- a/include/sta/InternalPower.hh +++ b/include/sta/InternalPower.hh @@ -33,44 +33,11 @@ namespace sta { -class InternalPowerModel; - -using InternalPowerModels = - std::array, RiseFall::index_count>; - -class InternalPower -{ -public: - InternalPower(LibertyPort *port, - LibertyPort *related_port, - LibertyPort *related_pg_pin, - const std::shared_ptr &when, - InternalPowerModels &models); - //InternalPower(InternalPower &&other) noexcept; - LibertyCell *libertyCell() const; - LibertyPort *port() const { return port_; } - LibertyPort *relatedPort() const { return related_port_; } - FuncExpr *when() const { return when_.get(); } - LibertyPort *relatedPgPin() const { return related_pg_pin_; } - float power(const RiseFall *rf, - const Pvt *pvt, - float in_slew, - float load_cap) const; - const InternalPowerModel *model(const RiseFall *rf) const; - -protected: - LibertyPort *port_; - LibertyPort *related_port_; - LibertyPort *related_pg_pin_; - std::shared_ptr when_; - InternalPowerModels models_; -}; - class InternalPowerModel { public: - InternalPowerModel(TableModel *model); - ~InternalPowerModel(); + InternalPowerModel(); + InternalPowerModel(std::shared_ptr model); float power(const LibertyCell *cell, const Pvt *pvt, float in_slew, @@ -80,7 +47,7 @@ public: float in_slew, float load_cap, int digits) const; - const TableModel *model() const { return model_; } + const TableModel *model() const { return model_.get(); } protected: void findAxisValues(float in_slew, @@ -95,7 +62,36 @@ protected: bool checkAxes(const TableModel *model); bool checkAxis(const TableAxis *axis); - TableModel *model_; + std::shared_ptr model_; +}; + +using InternalPowerModels = std::array; + +class InternalPower +{ +public: + InternalPower(LibertyPort *port, + LibertyPort *related_port, + LibertyPort *related_pg_pin, + const std::shared_ptr &when, + const InternalPowerModels &models); + LibertyCell *libertyCell() const; + LibertyPort *port() const { return port_; } + LibertyPort *relatedPort() const { return related_port_; } + FuncExpr *when() const { return when_.get(); } + LibertyPort *relatedPgPin() const { return related_pg_pin_; } + float power(const RiseFall *rf, + const Pvt *pvt, + float in_slew, + float load_cap) const; + const InternalPowerModel &model(const RiseFall *rf) const; + +protected: + LibertyPort *port_; + LibertyPort *related_port_; + LibertyPort *related_pg_pin_; + std::shared_ptr when_; + InternalPowerModels models_; }; } // namespace diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index 76bc763e..450f1dff 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -589,7 +589,7 @@ public: LibertyPort *related_port, LibertyPort *related_pg_pin, const std::shared_ptr &when, - InternalPowerModels &models); + const InternalPowerModels &models); void makeLeakagePower(LibertyPort *related_pg_port, FuncExpr *when, float power); diff --git a/include/sta/LinearModel.hh b/include/sta/LinearModel.hh index aa7ba59e..07251739 100644 --- a/include/sta/LinearModel.hh +++ b/include/sta/LinearModel.hh @@ -37,14 +37,22 @@ public: void gateDelay(const Pvt *pvt, float in_slew, float load_cap, - bool pocv_enabled, // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) const override; + float &gate_delay, + float &drvr_slew) const override; + void gateDelayPocv(const Pvt *pvt, + float in_slew, + float load_cap, + const MinMax *min_max, + PocvMode pocv_mode, + // Return values. + ArcDelay &gate_delay, + Slew &drvr_slew) const override; std::string reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - bool pocv_enabled, + const MinMax *min_max, + PocvMode pocv_mode, int digits) const override; float driveResistance(const Pvt *pvt) const override; @@ -64,13 +72,15 @@ public: float from_slew, float to_slew, float related_out_cap, - bool pocv_enabled) const override; + const MinMax *min_max, + PocvMode pocv_mode) const override; std::string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, float to_slew, float related_out_cap, - bool pocv_enabled, + const MinMax *min_max, + PocvMode pocv_mode, int digits) const override; protected: diff --git a/include/sta/ParseBus.hh b/include/sta/ParseBus.hh index d62bd982..9b40063a 100644 --- a/include/sta/ParseBus.hh +++ b/include/sta/ParseBus.hh @@ -25,12 +25,13 @@ #pragma once #include +#include namespace sta { // Return true if name is a bus. bool -isBusName(const char *name, +isBusName(std::string_view name, const char brkt_left, const char brkt_right, char escape); @@ -43,7 +44,7 @@ isBusName(const char *name, // index = bit // Caller must delete returned bus_name string. void -parseBusName(const char *name, +parseBusName(std::string_view name, const char brkt_left, const char brkt_right, char escape, @@ -53,9 +54,9 @@ parseBusName(const char *name, int &index); // Allow multiple different left/right bus brackets. void -parseBusName(const char *name, - const char *brkts_left, - const char *brkts_right, +parseBusName(std::string_view name, + std::string_view brkts_left, + std::string_view brkts_right, char escape, // Return values. bool &is_bus, @@ -66,7 +67,7 @@ parseBusName(const char *name, // bus_name is set to null if name is not a range. // Caller must delete returned bus_name string. void -parseBusName(const char *name, +parseBusName(std::string_view name, const char brkt_left, const char brkt_right, char escape, @@ -81,9 +82,9 @@ parseBusName(const char *name, // brkt_lefts and brkt_rights are corresponding strings of legal // bus brackets such as "[(<" and "])>". void -parseBusName(const char *name, - const char *brkts_left, - const char *brkts_right, +parseBusName(std::string_view name, + std::string_view brkts_left, + std::string_view brkts_right, const char escape, // Return values. bool &is_bus, @@ -95,7 +96,7 @@ parseBusName(const char *name, // Insert escapes before ch1 and ch2 in token. std::string -escapeChars(const char *token, +escapeChars(std::string_view token, const char ch1, const char ch2, const char escape); diff --git a/include/sta/Path.hh b/include/sta/Path.hh index 6ca1d8cc..7095a269 100644 --- a/include/sta/Path.hh +++ b/include/sta/Path.hh @@ -45,14 +45,14 @@ public: const StaState *sta); Path(Vertex *vertex, Tag *tag, - Arrival arrival, + const Arrival &arrival, Path *prev_path, Edge *prev_edge, TimingArc *prev_arc, const StaState *sta); Path(Vertex *vertex, Tag *tag, - Arrival arrival, + const Arrival &arrival, Path *prev_path, Edge *prev_edge, TimingArc *prev_arc, @@ -62,11 +62,11 @@ public: bool isNull() const; // prev_path null void init(Vertex *vertex, - Arrival arrival, + const Arrival &arrival, const StaState *sta); void init(Vertex *vertex, Tag *tag, - Arrival arrival, + const Arrival &arrival, Path *prev_path, Edge *prev_edge, TimingArc *prev_arc, @@ -76,7 +76,7 @@ public: const StaState *sta); void init(Vertex *vertex, Tag *tag, - Arrival arrival, + const Arrival &arrival, const StaState *sta); Vertex *vertex(const StaState *sta) const; @@ -98,14 +98,12 @@ public: const MinMax *minMax(const StaState *sta) const; PathAPIndex pathAnalysisPtIndex(const StaState *sta) const; DcalcAPIndex dcalcAnalysisPtIndex(const StaState *sta) const; - Arrival &arrival() { return arrival_; } const Arrival &arrival() const { return arrival_; } void setArrival(Arrival arrival); - Required &required() { return required_; } const Required &required() const {return required_; } void setRequired(const Required &required); Slack slack(const StaState *sta) const; - Slew slew(const StaState *sta) const; + const Slew slew(const StaState *sta) const; // This takes the same time as prevPath and prevArc combined. Path *prevPath() const; void setPrevPath(Path *prev_path); diff --git a/include/sta/PathEnd.hh b/include/sta/PathEnd.hh index 899c96ac..1fca8d5a 100644 --- a/include/sta/PathEnd.hh +++ b/include/sta/PathEnd.hh @@ -98,7 +98,7 @@ public: virtual const char *typeName() const = 0; virtual int exceptPathCmp(const PathEnd *path_end, const StaState *sta) const; - virtual Arrival dataArrivalTime(const StaState *sta) const; + virtual const Arrival &dataArrivalTime(const StaState *sta) const; // Arrival time with source clock offset. Arrival dataArrivalTimeOffset(const StaState *sta) const; virtual Required requiredTime(const StaState *sta) const = 0; @@ -270,11 +270,6 @@ public: protected: PathEndClkConstrained(Path *path, Path *clk_path); - PathEndClkConstrained(Path *path, - Path *clk_path, - Crpr crpr, - bool crpr_valid); - float sourceClkOffset(const ClockEdge *src_clk_edge, const ClockEdge *tgt_clk_edge, const TimingRole *check_role, @@ -300,11 +295,6 @@ protected: PathEndClkConstrainedMcp(Path *path, Path *clk_path, MultiCyclePath *mcp); - PathEndClkConstrainedMcp(Path *path, - Path *clk_path, - MultiCyclePath *mcp, - Crpr crpr, - bool crpr_valid); float checkMcpAdjustment(const Path *path, const ClockEdge *tgt_clk_edge, const StaState *sta) const; @@ -341,13 +331,6 @@ public: virtual Delay clkSkew(const StaState *sta); protected: - PathEndCheck(Path *path, - TimingArc *check_arc, - Edge *check_edge, - Path *clk_path, - MultiCyclePath *mcp, - Crpr crpr, - bool crpr_valid); Delay sourceClkDelay(const StaState *sta) const; virtual Required requiredTimeNoCrpr(const StaState *sta) const; @@ -404,18 +387,6 @@ public: virtual bool ignoreClkLatency(const StaState *sta) const; protected: - PathEndLatchCheck(Path *path, - TimingArc *check_arc, - Edge *check_edge, - Path *clk_path, - Path *disable, - MultiCyclePath *mcp, - PathDelay *path_delay, - Delay src_clk_arrival, - Crpr crpr, - bool crpr_valid); - -private: Path *disable_path_; PathDelay *path_delay_; // Source clk arrival for set_max_delay -ignore_clk_latency. @@ -450,12 +421,6 @@ public: const StaState *sta) const; protected: - PathEndOutputDelay(OutputDelay *output_delay, - Path *path, - Path *clk_path, - MultiCyclePath *mcp, - Crpr crpr, - bool crpr_valid); Arrival tgtClkDelay(const ClockEdge *tgt_clk_edge, const TimingRole *check_role, const StaState *sta) const; @@ -491,14 +456,6 @@ public: const StaState *sta) const; protected: - PathEndGatedClock(Path *gating_ref, - Path *clk_path, - const TimingRole *check_role, - MultiCyclePath *mcp, - ArcDelay margin, - Crpr crpr, - bool crpr_valid); - const TimingRole *check_role_; ArcDelay margin_; }; @@ -525,20 +482,12 @@ public: virtual const Path *dataClkPath() const { return data_clk_path_; } protected: - PathEndDataCheck(DataCheck *check, - Path *data_path, - Path *data_clk_path, - Path *clk_path, - MultiCyclePath *mcp, - Crpr crpr, - bool crpr_valid); Path *clkPath(Path *path, const StaState *sta); Arrival requiredTimeNoCrpr(const StaState *sta) const; // setup uses zero cycle default virtual int setupDefaultCycles() const { return 0; } -private: Path *data_clk_path_; DataCheck *check_; }; @@ -588,15 +537,6 @@ public: virtual bool ignoreClkLatency(const StaState *sta) const; protected: - PathEndPathDelay(PathDelay *path_delay, - Path *path, - Path *clk_path, - TimingArc *check_arc, - Edge *check_edge, - OutputDelay *output_delay, - Arrival src_clk_arrival, - Crpr crpr, - bool crpr_valid); void findSrcClkArrival(const StaState *sta); PathDelay *path_delay_; diff --git a/include/sta/PathGroup.hh b/include/sta/PathGroup.hh index 418238bf..d8ba2af6 100644 --- a/include/sta/PathGroup.hh +++ b/include/sta/PathGroup.hh @@ -29,7 +29,6 @@ #include #include -#include "BoundedHeap.hh" #include "SdcClass.hh" #include "StaState.hh" #include "SearchClass.hh" @@ -43,7 +42,7 @@ class PathEndVisitor; using PathGroupIterator = PathEndSeq::iterator; using PathGroupClkMap = std::map; -using PathGroupNamedMap = std::map; +using PathGroupNamedMap = std::map; using PathGroupSeq = std::vector; // A collection of PathEnds grouped and sorted for reporting. @@ -70,7 +69,7 @@ public: ~PathGroup(); const std::string &name() const { return name_; } const MinMax *minMax() const { return min_max_;} - PathEndSeq pathEnds() const; + PathEndSeq pathEnds() const { return path_ends_; } void insert(PathEnd *path_end); // Push group_path_count into path_ends. void pushEnds(PathEndSeq &path_ends); @@ -93,6 +92,9 @@ protected: bool cmp_slack, const MinMax *min_max, const StaState *sta); + void ensureSortedMaxPaths(); + void prune(); + void sort(); std::string name_; int group_path_count_; @@ -101,9 +103,11 @@ protected: bool unique_edges_; float slack_min_; float slack_max_; + PathEndSeq path_ends_; const MinMax *min_max_; bool cmp_slack_; - BoundedHeap heap_; + float threshold_; + std::mutex lock_; const StaState *sta_; }; @@ -136,7 +140,7 @@ public: bool unconstrained_paths, // Return value. PathEndSeq &path_ends); - PathGroup *findPathGroup(const char *name, + PathGroup *findPathGroup(const std::string &name, const MinMax *min_max) const; PathGroup *findPathGroup(const Clock *clock, const MinMax *min_max) const; @@ -187,7 +191,7 @@ protected: bool gated_clk, bool unconstrained, const MinMax *min_max); - bool reportGroup(const char *group_name, + bool reportGroup(const std::string &group_name, StringSet &group_names) const; static GroupPath *groupPathTo(const PathEnd *path_end, const StaState *sta); diff --git a/graph/Delay.cc b/include/sta/PocvMode.hh similarity index 81% rename from graph/Delay.cc rename to include/sta/PocvMode.hh index 2f538a30..29d19a63 100644 --- a/graph/Delay.cc +++ b/include/sta/PocvMode.hh @@ -22,19 +22,15 @@ // // This notice may not be removed or altered from any source distribution. -#include "Machine.hh" -#include "StringUtil.hh" -#include "Units.hh" -#include "StaState.hh" -#include "Delay.hh" +#pragma once namespace sta { +enum class PocvMode { scalar, normal, skew_normal }; + const char * -delayAsString(const Delay &delay, - const StaState *sta) -{ - return delayAsString(delay, sta, sta->units()->timeUnit()->digits()); -} +pocvModeName(PocvMode mode); +PocvMode +findPocvMode(const char *mode_name); } // namespace diff --git a/include/sta/Report.hh b/include/sta/Report.hh index 3ca8ffe0..51cde2ed 100644 --- a/include/sta/Report.hh +++ b/include/sta/Report.hh @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #pragma once @@ -27,15 +27,23 @@ #include #include #include +#include #include #include -#include "Machine.hh" // __attribute__ +#include "Machine.hh" // __attribute__ +#include "Format.hh" struct Tcl_Interp; namespace sta { +// Throws ExceptionMsg - implemented in Report.cc to avoid circular include with +// Error.hh +void +reportThrowExceptionMsg(const std::string &msg, + bool suppressed); + // Output streams used for printing. // This is a wrapper for all printing. It supports logging output to // a file and redirection of command output to a file. @@ -45,74 +53,137 @@ public: Report(); virtual ~Report(); - // Print line with return. - virtual void reportLine(const char *fmt, ...) - __attribute__((format (printf, 2, 3))); - virtual void reportLineString(const char *line); - virtual void reportLineString(const std::string &line); + virtual void reportLine(const std::string &line); virtual void reportBlankLine(); + // Print formatted line using std::format (C++20). + template + void report(std::string_view fmt, + Args &&...args) + { + reportMsg(sta::vformat(fmt, sta::make_format_args(args...))); + } + virtual void reportMsg(const std::string &formatted_msg) + { + reportLine(formatted_msg); + } + //////////////////////////////////////////////////////////////// // Report warning. - virtual void warn(int id, - const char *fmt, ...) - __attribute__((format (printf, 3, 4))); - virtual void vwarn(int id, - const char *fmt, - va_list args); + template + void warn(int id, + std::string_view fmt, + Args &&...args) + { + if (!isSuppressed(id)) + warnMsg(id, sta::vformat(fmt, sta::make_format_args(args...))); + } + virtual void warnMsg(int id, + const std::string &formatted_msg) { + reportLine(sta::format("Warning {}: {}", id, formatted_msg)); + } + // Report warning in a file. - virtual void fileWarn(int id, - const char *filename, - int line, - const char *fmt, ...) - __attribute__((format (printf, 5, 6))); - virtual void vfileWarn(int id, - const char *filename, - int line, - const char *fmt, - va_list args); + template + void fileWarn(int id, + std::string_view filename, + int line, + std::string_view fmt, + Args &&...args) + { + if (!isSuppressed(id)) { + fileWarnMsg(id, filename, line, + sta::vformat(fmt, sta::make_format_args(args...))); + } + } + virtual void + fileWarnMsg(int id, + std::string_view filename, + int line, + const std::string &formatted_msg) { + reportLine(sta::format("Warning {}: {} line {}, {}", + id, filename, line, formatted_msg)); + } - virtual void error(int id, - const char *fmt, ...) - __attribute__((format (printf, 3, 4))); - virtual void verror(int id, - const char *fmt, - va_list args); + template + void error(int id, + std::string_view fmt, + Args &&...args) + { + errorMsg(id, sta::vformat(fmt, sta::make_format_args(args...))); + } + virtual void errorMsg(int id, + const std::string &formatted_msg) + { + reportThrowExceptionMsg(sta::format("{} {}", id, formatted_msg), isSuppressed(id)); + } // Report error in a file. - virtual void fileError(int id, - const char *filename, - int line, - const char *fmt, ...) - __attribute__((format (printf, 5, 6))); - virtual void vfileError(int id, - const char *filename, - int line, - const char *fmt, - va_list args); + template + void fileError(int id, + std::string_view filename, + int line, + std::string_view fmt, + Args &&...args) + { + fileErrorMsg(id, filename, line, + sta::vformat(fmt, sta::make_format_args(args...))); + } + virtual void fileErrorMsg(int id, + std::string_view filename, + int line, + const std::string &formatted_msg) + { + reportThrowExceptionMsg(sta::format("{} {} line {}, {}", + id, filename, line, formatted_msg), + isSuppressed(id)); + } - // Critical. + // Critical. // Report error condition that should not be possible or that prevents execution. // The default handler prints msg to stderr and exits. - virtual void critical(int id, - const char *fmt, - ...) - __attribute__((format (printf, 3, 4))); - virtual void fileCritical(int id, - const char *filename, - int line, - const char *fmt, - ...) - __attribute__((format (printf, 5, 6))); + template + void critical(int id, + std::string_view fmt, + Args &&...args) + { + criticalMsg(id, sta::vformat(fmt, sta::make_format_args(args...))); + } + virtual void criticalMsg(int id, + const std::string &formatted_msg) + { + reportLine(sta::format("Critical {}: {}", id, formatted_msg)); + exit(1); + } + + template + void fileCritical(int id, + std::string_view filename, + int line, + std::string_view fmt, + Args &&...args) + { + fileCriticalMsg(id, filename, line, + sta::vformat(fmt, sta::make_format_args(args...))); + } + virtual void fileCriticalMsg(int id, + std::string_view filename, + int line, + const std::string &formatted_msg) + { + reportLine(sta::format("Critical {}: {} line {}, {}", id, filename, line, + formatted_msg)); + exit(1); + } // Log output to filename until logEnd is called. - virtual void logBegin(const char *filename); + virtual void logBegin(std::string filename); virtual void logEnd(); // Redirect output to filename until redirectFileEnd is called. - virtual void redirectFileBegin(const char *filename); + virtual void redirectFileBegin(std::string filename); // Redirect append output to filename until redirectFileEnd is called. - virtual void redirectFileAppendBegin(const char *filename); + virtual void redirectFileAppendBegin(std::string filename); virtual void redirectFileEnd(); // Redirect output to a string until redirectStringEnd is called. virtual void redirectStringBegin(); @@ -139,9 +210,7 @@ protected: // Return the number of characters written. virtual size_t printConsole(const char *buffer, size_t length); - void printToBuffer(const char *fmt, - ...) - __attribute__((format (printf, 2, 3))); + void printToBuffer(const char *fmt, ...) __attribute__((format(printf, 2, 3))); void printToBuffer(const char *fmt, va_list args); @@ -169,4 +238,4 @@ protected: friend class Debug; }; -} // namespace +} // namespace sta diff --git a/include/sta/ReportTcl.hh b/include/sta/ReportTcl.hh index 127cb23c..acdf84dc 100644 --- a/include/sta/ReportTcl.hh +++ b/include/sta/ReportTcl.hh @@ -44,20 +44,20 @@ class ReportTcl : public Report public: ReportTcl(); virtual ~ReportTcl(); - virtual void logBegin(const char *filename); - virtual void logEnd(); - virtual void redirectFileBegin(const char *filename); - virtual void redirectFileAppendBegin(const char *filename); - virtual void redirectFileEnd(); - virtual void redirectStringBegin(); - virtual const char *redirectStringEnd(); + void logBegin(std::string filename) override; + void logEnd() override; + void redirectFileBegin(std::string filename) override; + void redirectFileAppendBegin(std::string filename) override; + void redirectFileEnd() override; + void redirectStringBegin() override; + const char *redirectStringEnd() override; // This must be called after the Tcl interpreter has been constructed. // It makes the encapsulated channels. - virtual void setTclInterp(Tcl_Interp *interp); + void setTclInterp(Tcl_Interp *interp) override; protected: - virtual size_t printConsole(const char *buffer, - size_t length); + size_t printConsole(const char *buffer, + size_t length) override; void flush(); private: diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index 01e07ca7..64a41375 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -179,11 +179,11 @@ using InstDeratingFactorsMap = std::map; using CellDeratingFactorsMap = std::map; using ClockGroupsSet = std::set; using ClockGroupsClkMap = std::map; -using ClockGroupsNameMap = std::map; +using ClockGroupsNameMap = std::map; using ClockSenseMap = std::map; using ClkHpinDisables = std::set; using GroupPathSet = std::set; -using GroupPathMap = std::map; +using GroupPathMap = std::map; using ClockPairSet = std::set; using NetVoltageMap = std::map; @@ -499,7 +499,7 @@ public: Clock *to_clk, const RiseFallBoth *to_rf, const SetupHoldAll *setup_hold); - ClockGroups *makeClockGroups(const char *name, + ClockGroups *makeClockGroups(const std::string &name, bool logically_exclusive, bool physically_exclusive, bool asynchronous, @@ -507,11 +507,13 @@ public: const char *comment); void makeClockGroup(ClockGroups *clk_groups, ClockSet *clks); - void removeClockGroups(const char *name); - // nullptr name removes all. - void removeClockGroupsLogicallyExclusive(const char *name); - void removeClockGroupsPhysicallyExclusive(const char *name); - void removeClockGroupsAsynchronous(const char *name); + void removeClockGroups(const std::string &name); + void removeClockGroupsLogicallyExclusive(); + void removeClockGroupsLogicallyExclusive(const std::string &name); + void removeClockGroupsPhysicallyExclusive(); + void removeClockGroupsPhysicallyExclusive(const std::string &name); + void removeClockGroupsAsynchronous(); + void removeClockGroupsAsynchronous(const std::string &name); bool sameClockGroup(const Clock *clk1, const Clock *clk2) const; // Clocks explicitly excluded by set_clock_group. @@ -756,7 +758,7 @@ public: ExceptionThruSeq *thrus, ExceptionTo *to, const MinMaxAll *min_max); - void makeGroupPath(const char *name, + void makeGroupPath(const std::string &name, bool is_default, ExceptionFrom *from, ExceptionThruSeq *thrus, @@ -1266,7 +1268,7 @@ protected: void makeClkGroupExclusions(ClockGroupSet *groups); void makeClkGroupSame(ClockGroup *group); void clearClkGroupExclusions(); - char *makeClockGroupsName(); + std::string makeClockGroupsName(); void setClockSense(const Pin *pin, const Clock *clk, ClockSense sense); diff --git a/include/sta/SdcNetwork.hh b/include/sta/SdcNetwork.hh index e462af6d..3c2c84be 100644 --- a/include/sta/SdcNetwork.hh +++ b/include/sta/SdcNetwork.hh @@ -274,7 +274,7 @@ protected: const PatternMatch *pattern, InstanceSeq &matches) const; - const char *staToSdc(const char *sta_name) const; + const char *staToSdc(std::string_view sta_name) const; }; // Encapsulate a network to map names to/from the sdc namespace. diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index e5f7115a..75cebb83 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -434,19 +434,21 @@ public: const RiseFallBoth *to_rf, const SetupHoldAll *setup_hold, Sdc *sdc); - ClockGroups *makeClockGroups(const char *name, + ClockGroups *makeClockGroups(const std::string &name, bool logically_exclusive, bool physically_exclusive, bool asynchronous, bool allow_paths, const char *comment, Sdc *sdc); - // nullptr name removes all. - void removeClockGroupsLogicallyExclusive(const char *name, + void removeClockGroupsLogicallyExclusive(Sdc *sdc); + void removeClockGroupsLogicallyExclusive(const std::string &name, Sdc *sdc); - void removeClockGroupsPhysicallyExclusive(const char *name, + void removeClockGroupsPhysicallyExclusive(Sdc *sdc); + void removeClockGroupsPhysicallyExclusive(const std::string &name, Sdc *sdc); - void removeClockGroupsAsynchronous(const char *name, + void removeClockGroupsAsynchronous(Sdc *sdc); + void removeClockGroupsAsynchronous(const std::string &name, Sdc *sdc); void makeClockGroup(ClockGroups *clk_groups, ClockSet *clks, @@ -640,7 +642,7 @@ public: float delay, const char *comment, Sdc *sdc); - void makeGroupPath(const char *name, + void makeGroupPath(const std::string &name, bool is_default, ExceptionFrom *from, ExceptionThruSeq *thrus, @@ -982,11 +984,11 @@ public: bool report_cap, bool report_slew, bool report_fanout, + bool report_variation, bool report_src_attr); ReportField *findReportPathField(const char *name); void setReportPathDigits(int digits); void setReportPathNoSplit(bool no_split); - void setReportPathSigmas(bool report_sigmas); void reportPathEnd(PathEnd *end); void reportPathEnds(PathEndSeq *ends); ReportPath *reportPath() { return report_path_; } @@ -998,7 +1000,7 @@ public: const SetupHold *setup_hold, bool include_internal_latency, int digits); - float findWorstClkSkew(const SetupHold *setup_hold, + Delay findWorstClkSkew(const SetupHold *setup_hold, bool include_internal_latency); void reportClkLatency(ConstClockSeq &clks, @@ -1131,12 +1133,15 @@ public: void reportArrivalWrtClks(const Pin *pin, const Scene *scene, + bool report_variance, int digits); void reportRequiredWrtClks(const Pin *pin, const Scene *scene, + bool report_variance, int digits); void reportSlackWrtClks(const Pin *pin, const Scene *scene, + bool report_variance, int digits); Slew slew(Vertex *vertex, @@ -1144,9 +1149,9 @@ public: const SceneSeq &scenes, const MinMax *min_max); - ArcDelay arcDelay(Edge *edge, - TimingArc *arc, - DcalcAPIndex ap_index); + const ArcDelay arcDelay(Edge *edge, + TimingArc *arc, + DcalcAPIndex ap_index); // True if the timing arc has been back-annotated. bool arcDelayAnnotated(Edge *edge, TimingArc *arc, @@ -1408,12 +1413,13 @@ public: // TCL variable sta_crpr_mode. CrprMode crprMode() const; void setCrprMode(CrprMode mode); - // TCL variable sta_pocv_enabled. + // TCL variable sta_pocv_mode. // Parametric on chip variation (statisical sta). - bool pocvEnabled() const; - void setPocvEnabled(bool enabled); + PocvMode pocvMode() const; + void setPocvMode(PocvMode mode); // Number of std deviations from mean to use for normal distributions. - void setSigmaFactor(float factor); + float pocvQuantile(); + void setPocvQuantile(float quantile); // TCL variable sta_propagate_gated_clock_enable. // Propagate gated clock enable arrivals. bool propagateGatedClockEnable() const; @@ -1510,17 +1516,20 @@ protected: void reportDelaysWrtClks(const Pin *pin, const Scene *scene, + bool report_variance, int digits, bool find_required, PathDelayFunc get_path_delay); void reportDelaysWrtClks(Vertex *vertex, const Scene *scene, + bool report_variance, int digits, bool find_required, PathDelayFunc get_path_delay); void reportDelaysWrtClks(Vertex *vertex, const ClockEdge *clk_edge, const Scene *scene, + bool report_variance, int digits, PathDelayFunc get_path_delay); RiseFallMinMaxDelay findDelaysWrtClks(Vertex *vertex, @@ -1530,6 +1539,7 @@ protected: std::string formatDelay(const RiseFall *rf, const MinMax *min_max, const RiseFallMinMaxDelay &delays, + bool report_variance, int digits); void connectDrvrPinAfter(Vertex *vertex); diff --git a/include/sta/StaState.hh b/include/sta/StaState.hh index 2cfbede4..8f96e137 100644 --- a/include/sta/StaState.hh +++ b/include/sta/StaState.hh @@ -47,6 +47,7 @@ class GraphDelayCalc; class Latches; class DispatchQueue; class Variables; +class DelayOps; using ModeSeq = std::vector; using ModeSet = std::set; @@ -96,10 +97,10 @@ public: GraphDelayCalc *graphDelayCalc() const { return graph_delay_calc_; } Search *search() { return search_; } Search *search() const { return search_; } + const DelayOps *delayOps() const { return delay_ops_; } Latches *latches() { return latches_; } Latches *latches() const { return latches_; } unsigned threadCount() const { return thread_count_; } - float sigmaFactor() const { return sigma_factor_; } bool crprActive(const Mode *mode) const; Variables *variables() { return variables_; } const Variables *variables() const { return variables_; } @@ -133,11 +134,11 @@ protected: ArcDelayCalc *arc_delay_calc_; GraphDelayCalc *graph_delay_calc_; Search *search_; + DelayOps *delay_ops_; Latches *latches_; Variables *variables_; int thread_count_; DispatchQueue *dispatch_queue_; - float sigma_factor_; }; } // namespace diff --git a/include/sta/StringUtil.hh b/include/sta/StringUtil.hh index b12ae00d..c2cfb13d 100644 --- a/include/sta/StringUtil.hh +++ b/include/sta/StringUtil.hh @@ -143,14 +143,6 @@ public: char * stringCopy(const char *str); -inline void -stringAppend(char *&str1, - const char *str2) -{ - strcpy(str1, str2); - str1 += strlen(str2); -} - void stringDeleteCheck(const char *str); @@ -164,32 +156,6 @@ stringDelete(const char *str) bool isDigits(const char *str); -// Print to a new string. -// Caller owns returned string. -char * -stringPrint(const char *fmt, - ...) __attribute__((format (printf, 1, 2))); -std::string -stdstrPrint(const char *fmt, - ...) __attribute__((format (printf, 1, 2))); -char * -stringPrintArgs(const char *fmt, - va_list args); -void -stringPrint(std::string &str, - const char *fmt, - ...) __attribute__((format (printf, 2, 3))); -// Formated append to std::string. -void -stringAppend(std::string &str, - const char *fmt, - ...) __attribute__((format (printf, 2, 3))); - -// Print to a temporary string. -char * -stringPrintTmp(const char *fmt, - ...) __attribute__((format (printf, 1, 2))); - char * makeTmpString(size_t length); char * diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index 59e26ba0..95b51132 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -33,12 +33,14 @@ #include "Transition.hh" #include "LibertyClass.hh" #include "TimingModel.hh" +#include "Variables.hh" namespace sta { class Unit; class Units; class Report; +class TableModels; class Table; class TableModel; class TableAxis; @@ -63,43 +65,41 @@ class GateTableModel : public GateTimingModel { public: GateTableModel(LibertyCell *cell, - TableModel *delay_model, - TableModelsEarlyLate delay_sigma_models, - TableModel *slew_model, - TableModelsEarlyLate slew_sigma_models, + TableModels *delay_models, + TableModels *slew_models, ReceiverModelPtr receiver_model, OutputWaveforms *output_waveforms); GateTableModel(LibertyCell *cell, - TableModel *delay_model, - TableModel *slew_model); + TableModels *delay_models, + TableModels *slew_models); ~GateTableModel() override; void gateDelay(const Pvt *pvt, float in_slew, float load_cap, - bool pocv_enabled, // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) const override; - // deprecated 2024-01-07 - // related_out_cap arg removed. - void gateDelay(const Pvt *pvt, - float in_slew, - float load_cap, - float related_out_cap, - bool pocv_enabled, - ArcDelay &gate_delay, - Slew &drvr_slew) const __attribute__ ((deprecated)); + float &gate_delay, + float &drvr_slew) const override; + // Fill in pocv parameters in gate_delay, drvr_slew. + void gateDelayPocv(const Pvt *pvt, + float in_slew, + float load_cap, + const MinMax *min_max, + PocvMode pocv_mode, + // Return values. + ArcDelay &gate_delay, + Slew &drvr_slew) const override; std::string reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - bool pocv_enabled, + const MinMax *min_max, + PocvMode pocv_mode, int digits) const override; float driveResistance(const Pvt *pvt) const override; - const TableModel *delayModel() const { return delay_model_.get(); } - const TableModel *slewModel() const { return slew_model_.get(); } - const TableModel *delaySigmaModel(const EarlyLate *el) const; - const TableModel *slewSigmaModel(const EarlyLate *el) const; + const TableModels *delayModels() const { return delay_models_.get(); } + const TableModel *delayModel() const; + const TableModels *slewModels() const { return slew_models_.get(); } + const TableModel *slewModel() const; const ReceiverModel *receiverModel() const { return receiver_model_.get(); } OutputWaveforms *outputWaveforms() const { return output_waveforms_.get(); } // Check the axes before making the model. @@ -138,10 +138,8 @@ protected: float &axis_value3) const; static bool checkAxis(const TableAxis *axis); - std::unique_ptr delay_model_; - TableModelsEarlyLate delay_sigma_models_; - std::unique_ptr slew_model_; - TableModelsEarlyLate slew_sigma_models_; + std::unique_ptr delay_models_; + std::unique_ptr slew_models_; ReceiverModelPtr receiver_model_; std::unique_ptr output_waveforms_; }; @@ -150,25 +148,24 @@ class CheckTableModel : public CheckTimingModel { public: CheckTableModel(LibertyCell *cell, - TableModel *model, - TableModelsEarlyLate sigma_models); - CheckTableModel(LibertyCell *cell, - TableModel *model); + TableModels *check_models); ~CheckTableModel() override; ArcDelay checkDelay(const Pvt *pvt, float from_slew, float to_slew, float related_out_cap, - bool pocv_enabled) const override; + const MinMax *min_max, + PocvMode pocv_mode) const override; std::string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, float to_slew, float related_out_cap, - bool pocv_enabled, + const MinMax *min_max, + PocvMode pocv_mode, int digits) const override; - const TableModel *model() const { return model_.get(); } - const TableModel *sigmaModel(const EarlyLate *el) const; + const TableModels *checkModels() const { return check_models_.get(); } + const TableModel *checkModel() const; // Check the axes before making the model. // Return true if the model axes are supported. @@ -202,8 +199,7 @@ protected: int digits) const; static bool checkAxis(const TableAxis *axis); - std::unique_ptr model_; - TableModelsEarlyLate sigma_models_; + std::unique_ptr check_models_; }; class TableAxis @@ -311,6 +307,8 @@ public: private: void clear(); + float findValueOrder2(float axis_value1, float axis_value2) const; + float findValueOrder3(float axis_value1, float axis_value2, float axis_value3) const; std::string reportValueOrder0(const char *result_name, const char *comment1, const Unit *table_unit, @@ -408,6 +406,34 @@ protected: bool is_scaled_:1; }; +// cell/transition/check nldm/ocv/lvf models for one rise/fall edge. +class TableModels +{ +public: + TableModels(); + TableModels(TableModel *model); + ~TableModels(); + TableModel *model() const { return model_.get(); } + void setModel(TableModel *model); + TableModel *sigma(const EarlyLate *early_late) const; + void setSigma(TableModel *table, + const EarlyLate *early_late); + TableModel *meanShift() const { return mean_shift_.get(); } + void setMeanShift(TableModel *table); + TableModel *skewness() const { return skewness_.get(); } + void setSkewness(TableModel *table); + TableModel *stdDev() const { return std_dev_.get(); } + void setStdDev(TableModel *table); + +protected: + std::unique_ptr model_; + // Note early/late can point to the same model. + std::array sigma_; + std::unique_ptr std_dev_; + std::unique_ptr mean_shift_; + std::unique_ptr skewness_; +}; + //////////////////////////////////////////////////////////////// class ReceiverModel diff --git a/include/sta/TimingModel.hh b/include/sta/TimingModel.hh index db9caf08..0ff157f2 100644 --- a/include/sta/TimingModel.hh +++ b/include/sta/TimingModel.hh @@ -28,6 +28,7 @@ #include "Delay.hh" #include "LibertyClass.hh" +#include "Variables.hh" namespace sta { @@ -52,14 +53,23 @@ public: virtual void gateDelay(const Pvt *pvt, float in_slew, float load_cap, - bool pocv_enabled, // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) const = 0; + float &gate_delay, + float &drvr_slew) const = 0; + // Fill in pocv parameters in gate_delay, drvr_slew. + virtual void gateDelayPocv(const Pvt *pvt, + float in_slew, + float load_cap, + const MinMax *min_max, + PocvMode pocv_mode, + // Return values. + ArcDelay &gate_delay, + Slew &drvr_slew) const = 0; virtual std::string reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - bool pocv_enabled, + const MinMax *min_max, + PocvMode pocv_mode, int digits) const = 0; virtual float driveResistance(const Pvt *pvt) const = 0; }; @@ -74,13 +84,15 @@ public: float from_slew, float to_slew, float related_out_cap, - bool pocv_enabled) const = 0; + const MinMax *min_max, + PocvMode pocv_mode) const = 0; virtual std::string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, float to_slew, float related_out_cap, - bool pocv_enabled, + const MinMax *min_max, + PocvMode pocv_mode, int digits) const = 0; }; diff --git a/include/sta/Units.hh b/include/sta/Units.hh index 3390c103..8c3475f5 100644 --- a/include/sta/Units.hh +++ b/include/sta/Units.hh @@ -56,9 +56,8 @@ public: void setDigits(int digits); // Does not include suffix. int width() const; - const char *asString(float value) const; - const char *asString(double value) const; - const char *asString(float value, + std::string asString(float value) const; + std::string asString(float value, int digits) const; private: diff --git a/include/sta/Variables.hh b/include/sta/Variables.hh index 9e553193..7e8e7a69 100644 --- a/include/sta/Variables.hh +++ b/include/sta/Variables.hh @@ -24,6 +24,8 @@ #pragma once +#include "PocvMode.hh" + namespace sta { enum class CrprMode { same_pin, same_transition }; @@ -72,8 +74,11 @@ public: // TCL variable sta_input_port_default_clock. bool useDefaultArrivalClock() { return use_default_arrival_clock_; } void setUseDefaultArrivalClock(bool enable); - bool pocvEnabled() const { return pocv_enabled_; } - void setPocvEnabled(bool enabled); + bool pocvEnabled() const; + PocvMode pocvMode() const { return pocv_mode_; } + void setPocvMode(PocvMode mode); + float pocvQuantile() const { return pocv_quantile_; } + void setPocvQuantile(float quartile); private: bool crpr_enabled_; @@ -88,7 +93,8 @@ private: bool dynamic_loop_breaking_; bool propagate_all_clks_; bool use_default_arrival_clock_; - bool pocv_enabled_; + PocvMode pocv_mode_; + float pocv_quantile_; }; } // namespace diff --git a/include/sta/VerilogNamespace.hh b/include/sta/VerilogNamespace.hh index 8649c2d7..bcdddb52 100644 --- a/include/sta/VerilogNamespace.hh +++ b/include/sta/VerilogNamespace.hh @@ -29,21 +29,21 @@ namespace sta { std::string -cellVerilogName(const char *sta_name); +cellVerilogName(std::string sta_name); std::string -instanceVerilogName(const char *sta_name); +instanceVerilogName(std::string sta_name); std::string -netVerilogName(const char *sta_name); +netVerilogName(std::string sta_name); std::string -portVerilogName(const char *sta_name); +portVerilogName(std::string sta_name); std::string -moduleVerilogToSta(const std::string *sta_name); +moduleVerilogToSta(std::string sta_name); std::string -instanceVerilogToSta(const std::string *sta_name); +instanceVerilogToSta(std::string sta_name); std::string -netVerilogToSta(const std::string *sta_name); +netVerilogToSta(std::string sta_name); std::string -portVerilogToSta(const std::string *sta_name); +portVerilogToSta(std::string sta_name); } // namespace diff --git a/include/sta/VerilogReader.hh b/include/sta/VerilogReader.hh index 35311f6d..64499238 100644 --- a/include/sta/VerilogReader.hh +++ b/include/sta/VerilogReader.hh @@ -25,9 +25,12 @@ #pragma once #include +#include #include #include +#include "Format.hh" +#include "Report.hh" #include "StringUtil.hh" #include "NetworkClass.hh" @@ -59,8 +62,32 @@ class StringRegistry; class VerilogBindingTbl; class VerilogNetNameIterator; class VerilogNetPortRef; -class VerilogError; class LibertyCell; +class VerilogErrorCmp; + +class VerilogError +{ +public: + VerilogError(int id, + std::string_view filename, + int line, + std::string_view msg, + bool warn); + const char *msg() const { return msg_.c_str(); } + const char *filename() const { return filename_.c_str(); } + int id() const { return id_; } + int line() const { return line_; } + bool warn() const { return warn_; } + +private: + int id_; + std::string filename_; + int line_; + std::string msg_; + bool warn_; + + friend class VerilogErrorCmp; +}; using VerilogModuleMap = std::map; using VerilogStmtSeq = std::vector; @@ -148,14 +175,24 @@ public: const char *filename() const { return filename_.c_str(); } void incrLine(); Report *report() const { return report_; } + template void error(int id, - const char *filename, + std::string_view filename, int line, - const char *fmt, ...); + std::string_view fmt, + Args &&...args) + { + report_->fileError(id, filename, line, fmt, std::forward(args)...); + } + template void warn(int id, - const char *filename, + std::string_view filename, int line, - const char *fmt, ...); + std::string_view fmt, + Args &&...args) + { + report_->fileWarn(id, filename, line, fmt, std::forward(args)...); + } const std::string &zeroNetName() const { return zero_net_name_; } const std::string &oneNetName() const { return one_net_name_; } void deleteModules(); @@ -231,16 +268,26 @@ protected: Instance *parent, VerilogBindingTbl *parent_bindings, bool is_leaf); + template void linkWarn(int id, - const char *filename, + std::string_view filename, int line, - const char *msg, ...) - __attribute__((format (printf, 5, 6))); + std::string_view msg, + Args &&...args) + { + std::string msg_str = sta::formatRuntime(msg, std::forward(args)...); + link_errors_.push_back(new VerilogError(id, filename, line, msg_str, true)); + } + template void linkError(int id, - const char *filename, + std::string_view filename, int line, - const char *msg, ...) - __attribute__((format (printf, 5, 6))); + std::string_view msg, + Args &&...args) + { + std::string msg_str = sta::formatRuntime(msg, std::forward(args)...); + link_errors_.push_back(new VerilogError(id, filename, line, msg_str, false)); + } bool reportLinkErrors(); bool haveLinkErrors(); Cell *makeBlackBox(VerilogModuleInst *mod_inst, diff --git a/liberty/InternalPower.cc b/liberty/InternalPower.cc index 5380a359..d9ecd617 100644 --- a/liberty/InternalPower.cc +++ b/liberty/InternalPower.cc @@ -37,7 +37,7 @@ InternalPower::InternalPower(LibertyPort *port, LibertyPort *related_port, LibertyPort *related_pg_pin, const std::shared_ptr &when, - InternalPowerModels &models) : + const InternalPowerModels &models) : port_(port), related_port_(related_port), related_pg_pin_(related_pg_pin), @@ -52,36 +52,32 @@ InternalPower::libertyCell() const return port_->libertyCell(); } +const InternalPowerModel & +InternalPower::model(const RiseFall *rf) const +{ + return models_[rf->index()]; +} + float InternalPower::power(const RiseFall *rf, const Pvt *pvt, float in_slew, float load_cap) const { - const std::shared_ptr &model = models_[rf->index()]; - if (model) - return model->power(libertyCell(), pvt, in_slew, load_cap); - else - return 0.0; -} - -const InternalPowerModel * -InternalPower::model(const RiseFall *rf) const -{ - const std::shared_ptr &m = models_[rf->index()]; - return m.get(); + const InternalPowerModel &model = models_[rf->index()]; + return model.power(libertyCell(), pvt, in_slew, load_cap); } //////////////////////////////////////////////////////////////// -InternalPowerModel::InternalPowerModel(TableModel *model) : - model_(model) +InternalPowerModel::InternalPowerModel() : + model_(nullptr) { } -InternalPowerModel::~InternalPowerModel() +InternalPowerModel::InternalPowerModel(std::shared_ptr model) : + model_(model) { - delete model_; } float diff --git a/liberty/LibExprReader.cc b/liberty/LibExprReader.cc index c3e1e5f9..1b2fc037 100644 --- a/liberty/LibExprReader.cc +++ b/liberty/LibExprReader.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "FuncExpr.hh" @@ -80,8 +80,7 @@ LibExprReader::makeFuncExprPort(const char *port_name) if (port) expr = FuncExpr::makePort(port); else - report_->warn(1130, "%s references unknown port %s.", - error_msg_, port_name); + report_->warn(1130, "{} references unknown port {}.", error_msg_, port_name); stringDelete(port_name); return expr; } @@ -134,7 +133,7 @@ LibExprReader::setResult(FuncExpr *result) void LibExprReader::parseError(const char *msg) { - report_->error(1131, "%s %s.", error_msg_, msg); + report_->error(1131, "{} {}.", error_msg_, msg); } //////////////////////////////////////////////////////////////// @@ -144,4 +143,4 @@ LibExprScanner::LibExprScanner(std::istringstream &stream) : { } -} // namespace +} // namespace sta diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index da8fe383..7d9bf9bd 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -25,6 +25,7 @@ #include "Liberty.hh" #include "ContainerHelpers.hh" +#include "Format.hh" #include "Mutex.hh" #include "EnumNameMap.hh" #include "Report.hh" @@ -775,7 +776,7 @@ LibertyLibrary::makeSceneMap(LibertyCell *cell1, port1->setScenePort(port2, ap_index); } else - report->warn(1110, "cell %s/%s port %s not found in cell %s/%s.", + report->warn(1110, "cell {}/{} port {} not found in cell {}/{}.", cell1->library()->name(), cell1->name(), port_name, @@ -801,7 +802,7 @@ LibertyLibrary::makeSceneMap(LibertyCell *cell1, } } else - report->warn(1111, "cell %s/%s %s -> %s timing group %s not found in cell %s/%s.", + report->warn(1111, "cell {}/{} {} -> {} timing group {} not found in cell {}/{}.", cell1->library()->name(), cell1->name(), arc_set1->from() ? arc_set1->from()->name() : "", @@ -820,7 +821,7 @@ LibertyLibrary::checkScenes(LibertyCell *cell, for (const Scene *scene : scenes) { for (auto min_max : MinMax::range()) { if (!cell->checkSceneCell(scene, min_max)) - report->error(1112, "Liberty cell %s/%s for corner %s/%s not found.", + report->error(1112, "Liberty cell {}/{} for corner {}/{} not found.", cell->libertyLibrary()->name(), cell->name(), scene->name().c_str(), @@ -1262,7 +1263,7 @@ LibertyCell::makeInternalPower(LibertyPort *port, LibertyPort *related_port, LibertyPort *related_pg_pin, const std::shared_ptr &when, - InternalPowerModels &models) + const InternalPowerModels &models) { internal_powers_.emplace_back(port, related_port, related_pg_pin, when, models); port_internal_powers_[port].push_back(internal_powers_.size() - 1); @@ -1703,7 +1704,7 @@ LibertyCell::makeLatchEnables(Report *report, TimingSense en_sense = en_func->portTimingSense(en); if (en_sense == TimingSense::positive_unate && en_rf != RiseFall::rise()) - report->warn(1114, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense.", + report->warn(1114, "cell {}/{} {} -> {} latch enable {}_edge is inconsistent with latch group enable function positive sense.", library_->name(), name(), en->name(), @@ -1711,7 +1712,7 @@ LibertyCell::makeLatchEnables(Report *report, en_rf == RiseFall::rise()?"rising":"falling"); else if (en_sense == TimingSense::negative_unate && en_rf != RiseFall::fall()) - report->warn(1115, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense.", + report->warn(1115, "cell {}/{} {} -> {} latch enable {}_edge is inconsistent with latch group enable function negative sense.", library_->name(), name(), en->name(), @@ -1721,7 +1722,7 @@ LibertyCell::makeLatchEnables(Report *report, } } else - report->warn(1121, "cell %s/%s no latch enable found for %s -> %s.", + report->warn(1121, "cell {}/{} no latch enable found for {} -> {}.", library_->name(), name(), d->name(), @@ -1767,7 +1768,7 @@ LibertyCell::findLatchSetup(const LibertyPort *d, for (TimingArc *arc : arc_set->arcs()) { const RiseFall *from_rf = arc->fromEdge()->asRiseFall(); if (from_rf == en_rf) { - report->warn(1113, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with %s -> %s setup_%s check.", + report->warn(1113, "cell {}/{} {} -> {} latch enable {}_edge is inconsistent with {} -> {} setup_{} check.", library_->name(), name(), en->name(), @@ -1824,7 +1825,7 @@ LibertyCell::makeLatchEnable(LibertyPort *d, latch_check_map_[setup_check] = idx; d->setIsLatchData(true); debugPrint(debug, "liberty_latch", 1, - "latch %s -> %s | %s %s -> %s | %s %s -> %s setup", + "latch {} -> {} | {} {} -> {} | {} {} -> {} setup", d->name(), q->name(), en->name(), @@ -2904,7 +2905,7 @@ ModeDef::defineValue(const char *value, const char *sdf_cond) { std::string key = value; - std::string sdf = sdf_cond ? std::string(sdf_cond) : std::string(); + std::string sdf = sdf_cond ? sdf_cond : std::string(); auto [it, inserted] = values_.try_emplace(key, key, cond, std::move(sdf)); return &it->second; } @@ -3202,27 +3203,27 @@ ScaleFactors::report(Report *report) std::string line = " "; for (int pvt_index = 0; pvt_index < scale_factor_pvt_count; pvt_index++) { ScaleFactorPvt pvt = (ScaleFactorPvt) pvt_index; - stringAppend(line, "%10s", scaleFactorPvtName(pvt)); + line += sta::format("{:>10}", scaleFactorPvtName(pvt)); } - report->reportLineString(line); + report->reportLine(line); for (int type_index = 0; type_index < scale_factor_type_count; type_index++) { ScaleFactorType type = (ScaleFactorType) type_index; - stringPrint(line, "%10s ", scaleFactorTypeName(type)); + std::string line = sta::format("{:>10}", scaleFactorTypeName(type)); for (int pvt_index = 0; pvt_index < scale_factor_pvt_count; pvt_index++) { if (scaleFactorTypeRiseFallSuffix(type) || scaleFactorTypeRiseFallPrefix(type) || scaleFactorTypeLowHighSuffix(type)) { - stringAppend(line, " %.3f,%.3f", + line += sta::format(" {:.3f},{:.3f}", scales_[type_index][pvt_index][RiseFall::riseIndex()], scales_[type_index][pvt_index][RiseFall::fallIndex()]); } else { - stringAppend(line, " %.3f", + line += sta::format(" {:.3f}", scales_[type_index][pvt_index][0]); } } - report->reportLineString(line); + report->reportLine(line); } } diff --git a/liberty/Liberty.i b/liberty/Liberty.i index 2e1814ee..07529526 100644 --- a/liberty/Liberty.i +++ b/liberty/Liberty.i @@ -367,16 +367,13 @@ std::string to_string() { return self->to_string(); } const TimingRole *role() { return self->role(); } const char *sdf_cond() { return self->sdfCond().c_str(); } -const char * +std::string full_name() { const char *from = self->from()->name(); const char *to = self->to()->name(); const char *cell_name = self->libertyCell()->name(); - return stringPrintTmp("%s %s -> %s", - cell_name, - from, - to); + return sta::format("{} {} -> {}", cell_name, from, to); } const std::string diff --git a/liberty/LibertyBuilder.cc b/liberty/LibertyBuilder.cc index 72a72b1f..52cd97d5 100644 --- a/liberty/LibertyBuilder.cc +++ b/liberty/LibertyBuilder.cc @@ -102,12 +102,8 @@ LibertyBuilder::makeBusPortBit(ConcreteLibrary *library, const char *bus_name, int bit_index) { - std::string bit_name; - stringPrint(bit_name, "%s%c%d%c", - bus_name, - library->busBrktLeft(), - bit_index, - library->busBrktRight()); + std::string bit_name = std::string(bus_name) + library->busBrktLeft() + + std::to_string(bit_index) + library->busBrktRight(); LibertyPort *port = makePort(cell, bit_name.c_str(), bit_index); bus_port->addPortBit(port); cell->addPortBit(port); diff --git a/liberty/LibertyParse.yy b/liberty/LibertyParse.yy index 35ca7180..b20b5c6c 100644 --- a/liberty/LibertyParse.yy +++ b/liberty/LibertyParse.yy @@ -45,7 +45,7 @@ sta::LibertyParse::error(const location_type &loc, const std::string &msg) { reader->report()->fileError(164, reader->filename().c_str(), - loc.begin.line, "%s", msg.c_str()); + loc.begin.line, "{}", msg); } %} @@ -169,13 +169,13 @@ attr_value: /* Crafted to avoid conflicts with expr */ volt_expr: FLOAT volt_op FLOAT - { $$ = sta::stdstrPrint("%e%c%e", $1, $2, $3); } + { $$ = sta::format("{}{}{}", $1, $2, $3); } | string volt_op FLOAT - { $$ = sta::stdstrPrint("%s%c%e", $1.c_str(), $2, $3); } + { $$ = sta::format("{}{}{}", $1, $2, $3); } | FLOAT volt_op string - { $$ = sta::stdstrPrint("%e%c%s", $1, $2, $3.c_str()); } + { $$ = sta::format("{}{}{}", $1, $2, $3); } | volt_expr volt_op FLOAT - { $$ = sta::stdstrPrint("%s%c%e", $1.c_str(), $2, $3); } + { $$ = sta::format("{}{}{}", $1, $2, $3); } ; volt_op: @@ -192,7 +192,7 @@ volt_op: expr: expr_term1 | expr_term1 expr_op expr - { $$ = sta::stdstrPrint("%s%c%s", $1.c_str(), $2, $3.c_str()); } + { $$ = sta::format("{}{}{}", $1.c_str(), $2, $3.c_str()); } ; expr_term: diff --git a/liberty/LibertyParser.cc b/liberty/LibertyParser.cc index 5d16566d..b3cefe9a 100644 --- a/liberty/LibertyParser.cc +++ b/liberty/LibertyParser.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "LibertyParser.hh" @@ -130,10 +130,8 @@ LibertyParser::groupBegin(const std::string type, LibertyAttrValueSeq *params, int line) { - LibertyGroup *group = - new LibertyGroup(std::move(type), - params ? std::move(*params) : LibertyAttrValueSeq(), - line); + LibertyGroup *group = new LibertyGroup( + std::move(type), params ? std::move(*params) : LibertyAttrValueSeq(), line); delete params; LibertyGroup *parent_group = group_stack_.empty() ? nullptr : group_stack_.back(); group_visitor_->begin(group, parent_group); @@ -145,8 +143,7 @@ LibertyParser::groupEnd() { LibertyGroup *group = this->group(); group_stack_.pop_back(); - LibertyGroup *parent = - group_stack_.empty() ? nullptr : group_stack_.back(); + LibertyGroup *parent = group_stack_.empty() ? nullptr : group_stack_.back(); if (parent) parent->addSubgroup(group); group_visitor_->end(group, parent); @@ -170,8 +167,8 @@ LibertyParser::makeSimpleAttr(const std::string name, const LibertyAttrValue *value, int line) { - LibertySimpleAttr *attr = new LibertySimpleAttr(std::move(name), - std::move(*value), line); + LibertySimpleAttr *attr = + new LibertySimpleAttr(std::move(name), std::move(*value), line); delete value; LibertyGroup *group = this->group(); group->addAttr(attr); @@ -191,9 +188,8 @@ LibertyParser::makeComplexAttr(const std::string name, return nullptr; // Define is not a complex attr; already added to group } else { - LibertyComplexAttr *attr = new LibertyComplexAttr(std::move(name), - std::move(*values), - line); + LibertyComplexAttr *attr = + new LibertyComplexAttr(std::move(name), std::move(*values), line); delete values; LibertyGroup *group = this->group(); group->addAttr(attr); @@ -266,7 +262,7 @@ LibertyScanner::includeBegin() } else { report_->fileWarn(25, filename_.c_str(), yylineno, - "cannot open include file %s.", filename.c_str()); + "cannot open include file {}.", filename); delete stream; } } @@ -291,7 +287,7 @@ LibertyScanner::fileEnd() void LibertyScanner::error(const char *msg) { - report_->fileError(1866, filename_.c_str(), lineno(), "%s", msg); + report_->fileError(1866, filename_.c_str(), lineno(), "{}", msg); } //////////////////////////////////////////////////////////////// @@ -305,10 +301,7 @@ LibertyGroup::LibertyGroup(std::string type, { } -LibertyGroup::~LibertyGroup() -{ - clear(); -} +LibertyGroup::~LibertyGroup() { clear(); } void LibertyGroup::clear() @@ -327,19 +320,15 @@ LibertyGroup::clear() bool LibertyGroup::empty() const { - return subgroups_.empty() - && simple_attr_map_.empty() - && complex_attr_map_.empty() - && define_map_.empty(); + return subgroups_.empty() && simple_attr_map_.empty() && complex_attr_map_.empty() + && define_map_.empty(); } bool LibertyGroup::oneGroupOnly() const { - return subgroups_.size() == 1 - && simple_attr_map_.empty() - && complex_attr_map_.empty() - && define_map_.empty(); + return subgroups_.size() == 1 && simple_attr_map_.empty() + && complex_attr_map_.empty() && define_map_.empty(); } void @@ -483,7 +472,7 @@ LibertyGroup::findAttrFloat(const std::string attr_name, const std::string &float_str = attr_value.stringValue(); char *end = nullptr; value = std::strtof(float_str.c_str(), &end); - if (end) { + if (end) { exists = true; return; } @@ -538,10 +527,7 @@ LibertyComplexAttr::LibertyComplexAttr(std::string name, { } -LibertyComplexAttr::~LibertyComplexAttr() -{ - deleteContents(values_); -} +LibertyComplexAttr::~LibertyComplexAttr() { deleteContents(values_); } const LibertyAttrValue * LibertyComplexAttr::firstValue() const @@ -585,9 +571,9 @@ LibertyAttrValue::floatValue() const } void -LibertyAttrValue::floatValue(// Return values. - float &value, - bool &valid) const +LibertyAttrValue::floatValue( // Return values. + float &value, + bool &valid) const { valid = false; if (string_value_.empty()) { @@ -598,8 +584,7 @@ LibertyAttrValue::floatValue(// Return values. // Some floats are enclosed in quotes. char *end; value = strtof(string_value_.c_str(), &end); - if ((*end == '\0' - || isspace(*end)) + if ((*end == '\0' || isspace(*end)) // strtof support INF as a valid float. && string_value_ != "inf") { valid = true; @@ -631,4 +616,4 @@ LibertyVariable::LibertyVariable(std::string var, { } -} // namespace +} // namespace sta diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 32e551b4..a873a881 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -172,12 +172,12 @@ LibertyReader::endCell(const LibertyGroup *cell_group, const char *name = cell_group->firstName(); if (name) { - debugPrint(debug_, "liberty", 1, "cell %s", name); + debugPrint(debug_, "liberty", 1, "cell {}", name); LibertyCell *cell = builder_.makeCell(library_, name, filename_); readCell(cell, cell_group); } else - libWarn(1193, cell_group, "cell missing name."); + warn(1193, cell_group, "cell missing name."); // Delete the cell group and preceding library attributes // and groups so they are not revisited and reduce memory peak. @@ -267,7 +267,7 @@ LibertyReader::makeLibrary(const LibertyGroup *libary_group) if (name) { LibertyLibrary *library = network_->findLiberty(name); if (library) - libWarn(1140, libary_group, "library %s already exists.", name); + warn(1140, libary_group, "library {} already exists.", name); // Make a new library even if a library with the same name exists. // Both libraries may be accessed by min/max analysis points. library_ = network_->makeLibertyLibrary(name, filename_); @@ -296,7 +296,7 @@ LibertyReader::makeLibrary(const LibertyGroup *libary_group) library_->setDelayModelType(DelayModelType::cmos_linear); } else - libError(1141, libary_group, "library missing name."); + error(1141, libary_group, "library missing name."); } // Energy scale is derived from other units. @@ -366,18 +366,18 @@ LibertyReader::readLibraryUnits(const LibertyGroup *library_group) else if (stringEqual(suffix.c_str(), "pf")) cap_scale_ = scale * 1E-12F; else - libWarn(1154, cap_attr, "capacitive_load_units are not ff or pf."); + warn(1154, cap_attr, "capacitive_load_units are not ff or pf."); } else - libWarn(1155, cap_attr, "capacitive_load_units are not a string."); + warn(1155, cap_attr, "capacitive_load_units are not a string."); } else - libWarn(1157, cap_attr, "capacitive_load_units scale is not a float."); + warn(1157, cap_attr, "capacitive_load_units scale is not a float."); } else if (values.size() == 1) - libWarn(1156, cap_attr, "capacitive_load_units missing suffix."); + warn(1156, cap_attr, "capacitive_load_units missing suffix."); else - libWarn(1158, cap_attr, "capacitive_load_units missing scale and suffix."); + warn(1158, cap_attr, "capacitive_load_units missing scale and suffix."); library_->units()->capacitanceUnit()->setScale(cap_scale_); } } @@ -409,7 +409,7 @@ LibertyReader::readUnit(const char *unit_attr_name, else if (unit_mult == "100") mult = 100.0F; else - libWarn(1150, unit_attr, "unknown unit multiplier %s.", unit_mult.c_str()); + warn(1150, unit_attr, "unknown unit multiplier {}.", unit_mult); } else scale_suffix = *units; @@ -432,13 +432,13 @@ LibertyReader::readUnit(const char *unit_attr_name, else if (scale_char == 'f') scale_mult = 1E-15F; else - libWarn(1151, unit_attr, "unknown unit scale %c.", scale_char); + warn(1151, unit_attr, "unknown unit scale {}.", scale_char); } else - libWarn(1152, unit_attr, "unknown unit suffix %s.", suffix.c_str()); + warn(1152, unit_attr, "unknown unit suffix {}.", suffix); } else if (!stringEqual(scale_suffix.c_str(), unit_suffix)) - libWarn(1153, unit_attr, "unknown unit suffix %s.", scale_suffix.c_str()); + warn(1153, unit_attr, "unknown unit suffix {}.", scale_suffix); scale_var = scale_mult * mult; unit->setScale(scale_var); } @@ -456,23 +456,23 @@ LibertyReader::readDelayModel(const LibertyGroup *library_group) library_->setDelayModelType(DelayModelType::cmos_linear); else if (*type_name == "piecewise_cmos") { library_->setDelayModelType(DelayModelType::cmos_pwl); - libWarn(1160, library_group, "delay_model %s not supported.", type_name->c_str()); + warn(1160, library_group, "delay_model {} not supported.", *type_name); } else if (*type_name == "cmos2") { library_->setDelayModelType(DelayModelType::cmos2); - libWarn(1161, library_group, "delay_model %s not supported.", type_name->c_str()); + warn(1161, library_group, "delay_model {} not supported.", *type_name); } else if (*type_name == "polynomial") { library_->setDelayModelType(DelayModelType::polynomial); - libWarn(1162, library_group, "delay_model %s not supported.", type_name->c_str()); + warn(1162, library_group, "delay_model {} not supported.", *type_name); } // Evil IBM garbage. else if (*type_name == "dcm") { library_->setDelayModelType(DelayModelType::dcm); - libWarn(1163, library_group, "delay_model %s not supported..", type_name->c_str()); + warn(1163, library_group, "delay_model {} not supported..", *type_name); } else - libWarn(1164, library_group, "unknown delay_model %s.", type_name->c_str()); + warn(1164, library_group, "unknown delay_model {}.", *type_name); } } @@ -489,7 +489,7 @@ LibertyReader::readBusStyle(const LibertyGroup *library_group) && (*bus_style)[4] == 'd') library_->setBusBrkts((*bus_style)[2], (*bus_style)[5]); else - libWarn(1165, library_group, "unknown bus_naming_style format."); + warn(1165, library_group, "unknown bus_naming_style format."); } } @@ -511,9 +511,9 @@ LibertyReader::readBusTypes(LibertyCell *cell, library_->makeBusDcl(name, from, to); } else if (!from_exists) - libWarn(1179, type_group, "bus type missing bit_from."); + warn(1179, type_group, "bus type missing bit_from."); else if (!to_exists) - libWarn(1180, type_group, "bus type missing bit_to."); + warn(1180, type_group, "bus type missing bit_to."); } } } @@ -539,13 +539,13 @@ LibertyReader::checkThresholds(const LibertyGroup *library_group) const { for (const RiseFall *rf : RiseFall::range()) { if (library_->inputThreshold(rf) == 0.0) - libWarn(1145, library_group, "input_threshold_pct_%s not found.", rf->name()); + warn(1145, library_group, "input_threshold_pct_{} not found.", rf->name()); if (library_->outputThreshold(rf) == 0.0) - libWarn(1146, library_group, "output_threshold_pct_%s not found.", rf->name()); + warn(1146, library_group, "output_threshold_pct_{} not found.", rf->name()); if (library_->slewLowerThreshold(rf) == 0.0) - libWarn(1147, library_group, "slew_lower_threshold_pct_%s not found.", rf->name()); + warn(1147, library_group, "slew_lower_threshold_pct_{} not found.", rf->name()); if (library_->slewUpperThreshold(rf) == 0.0) - libWarn(1148, library_group, "slew_upper_threshold_pct_%s not found.", rf->name()); + warn(1148, library_group, "slew_upper_threshold_pct_{} not found.", rf->name()); } } @@ -579,7 +579,7 @@ LibertyReader::readTableTemplates(const LibertyGroup *library_group, tbl_template->setAxis3(axis3); } else - libWarn(1175, template_group, "table template missing name."); + warn(1175, template_group, "table template missing name."); } } @@ -592,7 +592,7 @@ LibertyReader::makeTableTemplateAxis(const LibertyGroup *template_group, if (var_name) { TableAxisVariable axis_var = stringTableAxisVariable(var_name->c_str()); if (axis_var == TableAxisVariable::unknown) - libWarn(1297, template_group, "axis type %s not supported.", var_name->c_str()); + warn(1297, template_group, "axis type {} not supported.", *var_name); else { std::string index_attr_name = "index_" + std::to_string(axis_index); const LibertyComplexAttr *index_attr = @@ -605,7 +605,7 @@ LibertyReader::makeTableTemplateAxis(const LibertyGroup *template_group, for (size_t i = 1; i < axis_values.size(); i++) { float value = axis_values[i]; if (value <= prev) { - libWarn(1178, template_group, "non-increasing table index values."); + warn(1178, template_group, "non-increasing table index values."); break; } prev = value; @@ -644,7 +644,7 @@ LibertyReader::readVoltateMaps(const LibertyGroup *library_group) if (valid) library_->addSupplyVoltage(volt_name.c_str(), volt); else - libWarn(1166, volt_attr, "voltage_map voltage is not a float."); + warn(1166, volt_attr, "voltage_map voltage is not a float."); } } } @@ -684,8 +684,8 @@ LibertyReader::readOperatingConds(const LibertyGroup *library_group) if (op_cond) library_->setDefaultOperatingConditions(op_cond); else - libWarn(1144, library_group, "default_operating_condition %s not found.", - default_op_cond->c_str()); + warn(1144, library_group, "default_operating_condition {} not found.", + *default_op_cond); } } @@ -774,11 +774,11 @@ LibertyReader::readWireloads(const LibertyGroup *library_group) if (exists) wireload->addFanoutLength(fanout, length); else - libWarn(1185, fanout_attr, "fanout_length is missing length and fanout."); + warn(1185, fanout_attr, "fanout_length is missing length and fanout."); } } else - libWarn(1184, wl_group, "wire_load missing name."); + warn(1184, wl_group, "wire_load missing name."); } } @@ -810,20 +810,20 @@ LibertyReader::readWireloadSelection(const LibertyGroup *library_group) wireload_selection->addWireloadFromArea(min_area, max_area, wireload); else - libWarn(1187, area_attr, "wireload %s not found.", wireload_name.c_str()); + warn(1187, area_attr, "wireload {} not found.", wireload_name); } else - libWarn(1188, area_attr, + warn(1188, area_attr, "wire_load_from_area wireload name not a string."); } else - libWarn(1189, area_attr, "wire_load_from_area min not a float."); + warn(1189, area_attr, "wire_load_from_area min not a float."); } else - libWarn(1190, area_attr, "wire_load_from_area max not a float."); + warn(1190, area_attr, "wire_load_from_area max not a float."); } else - libWarn(1191, area_attr, "wire_load_from_area missing parameters."); + warn(1191, area_attr, "wire_load_from_area missing parameters."); } } } @@ -837,8 +837,8 @@ LibertyReader::readDefaultWireLoad(const LibertyGroup *library_group) if (wireload) library_->setDefaultWireload(wireload); else - libWarn(1142, library_group, "default_wire_load %s not found.", - wireload_name->c_str()); + warn(1142, library_group, "default_wire_load {} not found.", + *wireload_name); } } @@ -852,8 +852,8 @@ LibertyReader::readDefaultWireLoadMode(const LibertyGroup *library_group) if (mode != WireloadMode::unknown) library_->setDefaultWireloadMode(mode); else - libWarn(1174, library_group, "default_wire_load_mode %s not found.", - wire_load_mode->c_str()); + warn(1174, library_group, "default_wire_load_mode {} not found.", + *wire_load_mode); } } @@ -868,8 +868,8 @@ LibertyReader::readDefaultWireLoadSelection(const LibertyGroup *library_group) if (selection) library_->setDefaultWireloadSelection(selection); else - libWarn(1143, library_group, "default_wire_selection %s not found.", - selection_name->c_str()); + warn(1143, library_group, "default_wire_selection {} not found.", + *selection_name); } } @@ -897,11 +897,11 @@ LibertyReader::readModeDefs(LibertyCell *cell, } } else - libWarn(1264, value_group, "mode value missing name."); + warn(1264, value_group, "mode value missing name."); } } else - libWarn(1263, mode_group, "mode definition missing name."); + warn(1263, mode_group, "mode definition missing name."); } } @@ -920,7 +920,7 @@ LibertyReader::readSlewDegradations(const LibertyGroup *library_group) if (LibertyLibrary::checkSlewDegradationAxes(table_model)) library_->setWireSlewDegradationTable(table_model, rf); else - libWarn(1254, degradation_group, "unsupported model axis."); + warn(1254, degradation_group, "unsupported model axis."); } } } @@ -966,9 +966,9 @@ LibertyReader::readLibAttrFloatWarnZero(const LibertyGroup *library_group, if (value == 0.0F) { const LibertySimpleAttr *attr = library_group->findSimpleAttr(attr_name); if (attr) - libWarn(1171, attr, "%s is 0.0.", attr_name); + warn(1171, attr, "{} is 0.0.", attr_name); else - libWarn(1172, library_group, "%s is 0.0.", attr_name); + warn(1172, library_group, "{} is 0.0.", attr_name); } (library_->*set_func)(value * scale); } @@ -1016,7 +1016,7 @@ LibertyReader::readScaledCell(const LibertyGroup *scaled_cell_group) if (op_cond_name) { OperatingConditions *op_cond = library_->findOperatingConditions(op_cond_name); if (op_cond) { - debugPrint(debug_, "liberty", 1, "scaled cell %s %s", + debugPrint(debug_, "liberty", 1, "scaled cell {} {}", name, op_cond_name); LibertyCell *scaled_cell = library_->makeScaledCell(name, filename_); readCell(scaled_cell, scaled_cell_group); @@ -1025,17 +1025,17 @@ LibertyReader::readScaledCell(const LibertyGroup *scaled_cell_group) owner->addScaledCell(op_cond, scaled_cell); } else - libWarn(1202, scaled_cell_group, "operating conditions %s not found.", + warn(1202, scaled_cell_group, "operating conditions {} not found.", op_cond_name); } else - libWarn(1203, scaled_cell_group, "scaled_cell missing operating condition."); + warn(1203, scaled_cell_group, "scaled_cell missing operating condition."); } else - libWarn(1204, scaled_cell_group, "scaled_cell cell %s has not been defined.", name); + warn(1204, scaled_cell_group, "scaled_cell cell {} has not been defined.", name); } else - libWarn(1205, scaled_cell_group, "scaled_cell missing name."); + warn(1205, scaled_cell_group, "scaled_cell missing name."); } // Minimal check that is not very specific about where the discrepancies are. @@ -1047,20 +1047,20 @@ LibertyReader::checkScaledCell(LibertyCell *scaled_cell, { if (equivCellPorts(scaled_cell, owner)) { if (!equivCellPorts(scaled_cell, owner)) - libWarn(1206, scaled_cell_group, "scaled_cell %s, %s ports do not match cell ports", + warn(1206, scaled_cell_group, "scaled_cell {}, {} ports do not match cell ports", scaled_cell->name(), op_cond_name); if (!equivCellFuncs(scaled_cell, owner)) - libWarn(1206, scaled_cell_group, - "scaled_cell %s, %s port functions do not match cell port functions.", + warn(1206, scaled_cell_group, + "scaled_cell {}, {} port functions do not match cell port functions.", scaled_cell->name(), op_cond_name); } else - libWarn(1207, scaled_cell_group, "scaled_cell ports do not match cell ports."); + warn(1207, scaled_cell_group, "scaled_cell ports do not match cell ports."); if (!equivCellTimingArcSets(scaled_cell, owner)) - libWarn(1208, scaled_cell_group, - "scaled_cell %s, %s timing does not match cell timing.", + warn(1208, scaled_cell_group, + "scaled_cell {}, {} timing does not match cell timing.", scaled_cell->name(), op_cond_name); } @@ -1112,7 +1112,7 @@ LibertyReader::makeBusPort(LibertyCell *cell, if (bus_dcl == nullptr) bus_dcl = library_->findBusDcl(bus_type->c_str()); if (bus_dcl) { - debugPrint(debug_, "liberty", 1, " bus %s", port_name.c_str()); + debugPrint(debug_, "liberty", 1, " bus {}", port_name); LibertyPort *bus_port = makeBusPort(cell, port_name.c_str(), bus_dcl->from(), bus_dcl->to(), bus_dcl); @@ -1121,11 +1121,11 @@ LibertyReader::makeBusPort(LibertyCell *cell, makeBusPinPorts(cell, bus_group, port_group_map); } else - libWarn(1235, bus_type_attr, "bus_type %s not found.", bus_type->c_str()); + warn(1235, bus_type_attr, "bus_type {} not found.", *bus_type); } } else - libWarn(1236, bus_type_attr, "bus_type not found."); + warn(1236, bus_type_attr, "bus_type not found."); } } @@ -1138,7 +1138,7 @@ LibertyReader::makeBusPinPorts(LibertyCell *cell, for (const LibertyAttrValue *param : pin_group->params()) { if (param->isString()) { const std::string pin_name = param->stringValue(); - debugPrint(debug_, "liberty", 1, " bus pin port %s", pin_name.c_str()); + debugPrint(debug_, "liberty", 1, " bus pin port {}", pin_name); // Expand foo[3:0] port names. PortNameBitIterator name_iter(cell, pin_name.c_str(), this, pin_group->line()); while (name_iter.hasNext()) { @@ -1147,11 +1147,11 @@ LibertyReader::makeBusPinPorts(LibertyCell *cell, port_group_map[pin_group].push_back(pin_port); } else - libWarn(1232, pin_group, "pin %s not found.", pin_name.c_str()); + warn(1232, pin_group, "pin {} not found.", pin_name); } } else - libWarn(1233, pin_group, "pin name is not a string."); + warn(1233, pin_group, "pin name is not a string."); } } } @@ -1162,7 +1162,7 @@ LibertyReader::makeBundlePort(LibertyCell *cell, LibertyPortGroupMap &port_group_map) { const std::string &bundle_name = bundle_group->firstName(); - debugPrint(debug_, "liberty", 1, " bundle %s", bundle_name.c_str()); + debugPrint(debug_, "liberty", 1, " bundle {}", bundle_name); const LibertyComplexAttr *member_attr = bundle_group->findComplexAttr("members"); ConcretePortSeq *members = new ConcretePortSeq; @@ -1191,14 +1191,14 @@ LibertyReader::makeBundlePinPorts(LibertyCell *cell, for (LibertyAttrValue *param : pin_group->params()) { if (param->isString()) { const std::string pin_name = param->stringValue(); - debugPrint(debug_, "liberty", 1, " bundle pin port %s", pin_name.c_str()); + debugPrint(debug_, "liberty", 1, " bundle pin port {}", pin_name); LibertyPort *pin_port = cell->findLibertyPort(pin_name.c_str()); if (pin_port == nullptr) pin_port = makePort(cell, pin_name.c_str()); port_group_map[pin_group].push_back(pin_port); } else - libWarn(1234, pin_group, "pin name is not a string."); + warn(1234, pin_group, "pin name is not a string."); } } } @@ -1226,7 +1226,7 @@ LibertyReader::makePgPinPort(LibertyCell *cell, dir = PortDirection::power(); break; case PwrGndType::none: - libError(1291, pg_pin_group, "unknown pg_type."); + error(1291, pg_pin_group, "unknown pg_type."); break; default: break; @@ -1349,10 +1349,10 @@ LibertyReader::readPortAttrBool(const char *attr_name, (port->*set_func)(false); } else - libWarn(1238, attr, "%s attribute is not boolean.", attr_name); + warn(1238, attr, "{} attribute is not boolean.", attr_name); } else - libWarn(1239, attr, "%s attribute is not boolean.", attr_name); + warn(1239, attr, "{} attribute is not boolean.", attr_name); } } @@ -1399,7 +1399,7 @@ LibertyReader::readPulseClock(const LibertyPortSeq &ports, sense = RiseFall::fall(); } else - libWarn(1242, port_group, "pulse_latch unknown pulse type."); + warn(1242, port_group, "pulse_latch unknown pulse type."); if (trigger) { for (LibertyPort *port : ports) port->setPulseClk(trigger, sense); @@ -1437,7 +1437,7 @@ LibertyReader::readSignalType(LibertyCell *cell, else if (*type == "test_scan_out_inverted") signal_type = ScanSignalType::output_inverted; else { - libWarn(1299, port_group, "unknown signal_type %s.", type->c_str()); + warn(1299, port_group, "unknown signal_type {}.", *type); return; } for (LibertyPort *port : ports) @@ -1464,7 +1464,7 @@ LibertyReader::readPortDir(const LibertyPortSeq &ports, else if (*dir == "internal") port_dir = PortDirection::internal(); else - libWarn(1240, dir_attr, "unknown port direction."); + warn(1240, dir_attr, "unknown port direction."); for (LibertyPort *port : ports) port->setDirection(port_dir); } @@ -1522,7 +1522,7 @@ LibertyReader::readCapacitance(const LibertyPortSeq &ports, port_group->findAttrFloat(attr_name, limit, exists); if (exists) { if (min_max == MinMax::max() && limit == 0.0) - libWarn(1241, port_group, "max_transition is 0.0."); + warn(1241, port_group, "max_transition is 0.0."); port->setSlewLimit(limit * time_scale_, min_max); } } @@ -1604,8 +1604,8 @@ LibertyReader::makePortFuncs(LibertyCell *cell, for (LibertyPort *port : ports) { port->setFunction(func_expr); if (func_expr->checkSize(port)) { - libWarn(1195, func_attr->line(), - "port %s function size does not match port size.", + warn(1195, func_attr->line(), + "port {} function size does not match port size.", port->name()); } } @@ -1694,8 +1694,8 @@ LibertyReader::makeSeqFunc(LibertyCell *cell, if (attr) { expr = parseFunc(attr->c_str(), attr_name, cell, seq_group->line()); if (expr && expr->checkSize(size)) { - libWarn(1196, seq_group, "%s %s bus width mismatch.", - seq_group->type().c_str(), attr_name); + warn(1196, seq_group, "{} {} bus width mismatch.", + seq_group->type(), attr_name); delete expr; expr = nullptr; } @@ -1832,8 +1832,7 @@ LibertyReader::readScaleFactors(LibertyCell *cell, if (scale_factors) cell->setScaleFactors(scale_factors); else - libWarn(1230, cell_group, "scaling_factors %s not found.", - scale_factors_name->c_str()); + warn(1230, cell_group, "scaling_factors {} not found.", *scale_factors_name); } } @@ -1878,10 +1877,10 @@ LibertyReader::readCellAttrBool(const char *attr_name, else if (stringEqual(value.c_str(), "false")) (cell->*set_func)(false); else - libWarn(1279, attr, "%s attribute is not boolean.", attr_name); + warn(1279, attr, "{} attribute is not boolean.", attr_name); } else - libWarn(1280, attr, "%s attribute is not boolean.", attr_name); + warn(1280, attr, "{} attribute is not boolean.", attr_name); } } @@ -1906,18 +1905,18 @@ LibertyReader::makeTimingArcs(LibertyCell *cell, for (LibertyPort *to_port : ports) { if (timing_type == TimingType::combinational && to_port->direction()->isInput()) - libWarn(1209, timing_group, "combinational timing to an input port."); + warn(1209, timing_group, "combinational timing to an input port."); if (related_port_names.size() || related_bus_names.size()) { for (const std::string &from_port_name : related_port_names) { - debugPrint(debug_, "liberty", 2, " timing %s -> %s", - from_port_name.c_str(), to_port->name()); + debugPrint(debug_, "liberty", 2, " timing {} -> {}", + from_port_name, to_port->name()); makeTimingArcs(cell, from_port_name, to_port, related_output_port, true, timing_attrs, timing_group->line()); } for (const std::string &from_port_name : related_bus_names) { - debugPrint(debug_, "liberty", 2, " timing %s -> %s", - from_port_name.c_str(), to_port->name()); + debugPrint(debug_, "liberty", 2, " timing {} -> {}", + from_port_name, to_port->name()); makeTimingArcs(cell, from_port_name, to_port, related_output_port, false, timing_attrs, timing_group->line()); } @@ -1926,7 +1925,7 @@ LibertyReader::makeTimingArcs(LibertyCell *cell, || timing_type == TimingType::minimum_period || timing_type == TimingType::min_clock_tree_path || timing_type == TimingType::max_clock_tree_path)) - libWarn(1243, timing_group, "timing group missing related_pin/related_bus_pin."); + warn(1243, timing_group, "timing group missing related_pin/related_bus_pin."); else makeTimingArcs(cell, to_port, related_output_port, timing_attrs, timing_group->line()); @@ -1975,7 +1974,7 @@ LibertyReader::readTimingSense(const LibertyGroup *timing_group, else if (*sense_name == "negative_unate") timing_attrs->setTimingSense(TimingSense::negative_unate); else - libWarn(1245, timing_group, "unknown timing_sense %s.", sense_name->c_str()); + warn(1245, timing_group, "unknown timing_sense {}.", *sense_name); } } } @@ -1991,7 +1990,7 @@ LibertyReader::readTimingType(const LibertyGroup *timing_group, if (type_name) { type = findTimingType(type_name->c_str()); if (type == TimingType::unknown) { - libWarn(1244, type_attr, "unknown timing_type %s.", type_name->c_str()); + warn(1244, type_attr, "unknown timing_type {}.", *type_name); type = TimingType::combinational; } } @@ -2046,16 +2045,16 @@ LibertyReader::readTimingMode(const LibertyGroup *timing_group, if (value->isString()) timing_attrs->setModeName(value->stringValue()); else - libWarn(1248, mode_attr, "mode name is not a string."); + warn(1248, mode_attr, "mode name is not a string."); value = mode_values[1]; if (value->isString()) timing_attrs->setModeValue(value->stringValue()); else - libWarn(1246, mode_attr, "mode value is not a string."); + warn(1246, mode_attr, "mode value is not a string."); } else - libWarn(1249, mode_attr, "mode requirees 2 values."); + warn(1249, mode_attr, "mode requirees 2 values."); } } @@ -2122,80 +2121,76 @@ LibertyReader::makeTableModels(LibertyCell *cell, { bool found_model = false; for (const RiseFall *rf : RiseFall::range()) { - std::string delay_attr_name = "cell_" + rf->to_string(); - TableModel *delay = readGateTableModel(timing_group, delay_attr_name.c_str(), rf, - TableTemplateType::delay, time_scale_, - ScaleFactorType::cell); - std::string transition_attr_name = rf->to_string() + "_transition"; - TableModel *transition = readGateTableModel(timing_group, - transition_attr_name.c_str(), - rf, TableTemplateType::delay, - time_scale_, - ScaleFactorType::transition); - if (delay || transition) { - std::string delay_sigma_attr_name = "ocv_sigma_cell_" + rf->to_string(); - TableModelsEarlyLate delay_sigmas = - readEarlyLateTableModels(timing_group, - delay_sigma_attr_name.c_str(), - rf, TableTemplateType::delay, - time_scale_, - ScaleFactorType::unknown); + TableModel *delay_model = readTableModel(timing_group, + "cell_" + rf->to_string(), + rf, TableTemplateType::delay, + time_scale_, + ScaleFactorType::cell, + GateTableModel::checkAxes); + TableModel *slew_model = readTableModel(timing_group, + rf->to_string() + "_transition", + rf, TableTemplateType::delay, + time_scale_, + ScaleFactorType::transition, + GateTableModel::checkAxes); + if (delay_model || slew_model) { + TableModels *delay_models = new TableModels(delay_model); + readLvfModels(timing_group, + "ocv_sigma_cell_" + rf->to_string(), + "ocv_std_dev_cell_" + rf->to_string(), + "ocv_mean_shift_cell_" + rf->to_string(), + "ocv_skewness_cell_" + rf->to_string(), + rf, delay_models, GateTableModel::checkAxes); - std::string slew_sigma_attr_name = "ocv_sigma_" + rf->to_string() - + "_transition"; - TableModelsEarlyLate slew_sigmas = - readEarlyLateTableModels(timing_group, - slew_sigma_attr_name.c_str(), - rf, TableTemplateType::delay, - time_scale_, - ScaleFactorType::unknown); + TableModels *slew_models = new TableModels(slew_model); + readLvfModels(timing_group, + "ocv_sigma_" + rf->to_string() + "_transition", + "ocv_std_dev_" + rf->to_string() + "_transition", + "ocv_mean_shift_" + rf->to_string() + "_transition", + "ocv_skewness_" + rf->to_string() + "_transition", + rf, slew_models, GateTableModel::checkAxes); ReceiverModelPtr receiver_model = readReceiverCapacitance(timing_group, rf); OutputWaveforms *output_waveforms = readOutputWaveforms(timing_group, rf); - timing_attrs->setModel(rf, new GateTableModel(cell, delay, - std::move(delay_sigmas), - transition, - std::move(slew_sigmas), + timing_attrs->setModel(rf, new GateTableModel(cell, delay_models, + slew_models, receiver_model, output_waveforms)); TimingType timing_type = timing_attrs->timingType(); if (isGateTimingType(timing_type)) { - if (transition == nullptr) - libWarn(1210, timing_group, "missing %s_transition.", rf->name()); - if (delay == nullptr) - libWarn(1211, timing_group, "missing cell_%s.", rf->name()); + if (slew_model == nullptr) + warn(1210, timing_group, "missing {}_transition.", rf->name()); + if (delay_model == nullptr) + warn(1211, timing_group, "missing cell_{}.", rf->name()); } found_model = true; } - else { - std::string constraint_attr_name = rf->to_string() + "_constraint"; - ScaleFactorType scale_factor_type = - timingTypeScaleFactorType(timing_attrs->timingType()); - TableModel *constraint = readCheckTableModel(timing_group, - constraint_attr_name.c_str(), - rf, TableTemplateType::delay, - time_scale_, scale_factor_type); - if (constraint) { - std::string constraint_sigma_attr_name = "ocv_sigma_" + rf->to_string() - + "_constraint"; - TableModelsEarlyLate constraint_sigmas = - readEarlyLateTableModels(timing_group, - constraint_sigma_attr_name.c_str(), - rf, TableTemplateType::delay, - time_scale_, - ScaleFactorType::unknown); - timing_attrs->setModel(rf, new CheckTableModel(cell, constraint, - std::move(constraint_sigmas))); - found_model = true; - } + + std::string constraint_attr_name = rf->to_string() + "_constraint"; + ScaleFactorType scale_factor_type = + timingTypeScaleFactorType(timing_attrs->timingType()); + TableModel *check_model = readTableModel(timing_group, + constraint_attr_name.c_str(), + rf, TableTemplateType::delay, + time_scale_, scale_factor_type, + CheckTableModel::checkAxes); + if (check_model) { + TableModels *check_models = new TableModels(check_model); + readLvfModels(timing_group, + "ocv_sigma_" + rf->to_string() + "_constraint", + "ocv_std_dev_" + rf->to_string() + "_constraint", + "ocv_mean_shift_" + rf->to_string() + "_constraint", + "ocv_skewness_" + rf->to_string() + "_constraint", + rf, check_models, CheckTableModel::checkAxes); + timing_attrs->setModel(rf, new CheckTableModel(cell, check_models)); + found_model = true; } } if (!found_model) - libWarn(1311, timing_group, "no table models found in timing group."); + warn(1311, timing_group, "no table models found in timing group."); } - bool LibertyReader::isGateTimingType(TimingType timing_type) { @@ -2215,41 +2210,66 @@ LibertyReader::isGateTimingType(TimingType timing_type) } TableModel * -LibertyReader::readGateTableModel(const LibertyGroup *timing_group, - const char *table_group_name, - const RiseFall *rf, - TableTemplateType template_type, - float scale, - ScaleFactorType scale_factor_type) +LibertyReader::readTableModel(const LibertyGroup *timing_group, + const std::string &table_group_name, + const RiseFall *rf, + TableTemplateType template_type, + float scale, + ScaleFactorType scale_factor_type, + const std::function check_axes) { const LibertyGroup *table_group = timing_group->findSubgroup(table_group_name); - if (table_group) { - TableModel *model = readTableModel(table_group, rf, template_type, scale, - scale_factor_type); - if (model && !GateTableModel::checkAxes(model)) - libWarn(1251, table_group, "unsupported model axis."); - return model; - } + if (table_group) + return readTableModel(table_group, rf, template_type, scale, + scale_factor_type, check_axes); return nullptr; } -TableModel * -LibertyReader::readCheckTableModel(const LibertyGroup *timing_group, - const char *table_group_name, - const RiseFall *rf, - TableTemplateType template_type, - float scale, - ScaleFactorType scale_factor_type) +void +LibertyReader::readLvfModels(const LibertyGroup *timing_group, + const std::string &sigma_group_name, + const std::string &std_dev_group_name, + const std::string &mean_shift_group_name, + const std::string &skewness_group_name, + const RiseFall *rf, + TableModels *table_models, + const std::function check_axes) { - const LibertyGroup *table_group = timing_group->findSubgroup(table_group_name); - if (table_group) { - TableModel *model = readTableModel(table_group, rf, template_type, scale, - scale_factor_type); - if (model && !CheckTableModel::checkAxes(model)) - libWarn(1252, table_group, "unsupported model axis."); - return model; + TableModelsEarlyLate sigmas = + readEarlyLateTableModels(timing_group, + sigma_group_name.c_str(), + rf, TableTemplateType::delay, + time_scale_, + ScaleFactorType::unknown, + check_axes); + for (const EarlyLate *early_late : EarlyLate::range()) + table_models->setSigma(sigmas[early_late->index()], early_late); + + const LibertyGroup *std_dev_group = timing_group->findSubgroup(std_dev_group_name); + if (std_dev_group) { + TableModel *std_dev = readTableModel(std_dev_group, rf, TableTemplateType::delay, + time_scale_, ScaleFactorType::unknown, + check_axes); + table_models->setStdDev(std_dev); + } + + const LibertyGroup *mean_shift_group=timing_group->findSubgroup(mean_shift_group_name); + if (mean_shift_group) { + TableModel *mean_shift = readTableModel(mean_shift_group, rf, + TableTemplateType::delay, + time_scale_, ScaleFactorType::unknown, + check_axes); + table_models->setMeanShift(mean_shift); + } + + const LibertyGroup *skewness_group = timing_group->findSubgroup(skewness_group_name); + if (skewness_group) { + TableModel *skewness = readTableModel(skewness_group, rf, + TableTemplateType::delay, + 1.0, ScaleFactorType::unknown, + check_axes); + table_models->setSkewness(skewness); } - return nullptr; } TableModelsEarlyLate @@ -2258,12 +2278,13 @@ LibertyReader::readEarlyLateTableModels(const LibertyGroup *timing_group, const RiseFall *rf, TableTemplateType template_type, float scale, - ScaleFactorType scale_factor_type) + ScaleFactorType scale_factor_type, + const std::function check_axes) { TableModelsEarlyLate models{}; for (const LibertyGroup *table_group : timing_group->findSubgroups(table_group_name)) { TableModel *model = readTableModel(table_group, rf, template_type, scale, - scale_factor_type); + scale_factor_type, check_axes); const std::string *early_late = table_group->findAttrString("sigma_type"); if (early_late == nullptr || *early_late == "early_and_late") { @@ -2274,9 +2295,6 @@ LibertyReader::readEarlyLateTableModels(const LibertyGroup *timing_group, models[EarlyLate::early()->index()] = model; else if (*early_late == "late") models[EarlyLate::late()->index()] = model; - - //if (model && !GateTableModel::checkAxes(model)) - // libWarn(1182, table_group, "unsupported model axis."); } return models; } @@ -2324,7 +2342,7 @@ LibertyReader::readReceiverCapacitance(const LibertyGroup *timing_group, receiver_model->setCapacitanceModel(std::move(*model), index, rf); } else - libWarn(1219, cap_group, "unsupported model axis."); + warn(1219, cap_group, "unsupported model axis."); delete model; } } @@ -2371,13 +2389,13 @@ LibertyReader::readOutputWaveforms(const LibertyGroup *timing_group, output_currents.emplace_back(slew, cap, table1, ref_time); } else - libWarn(1223, vector_group, + warn(1223, vector_group, "vector index_1 and index_2 must have exactly one value."); } delete table; } else - libWarn(1224, vector_group, "vector reference_time not found."); + warn(1224, vector_group, "vector reference_time not found."); } if (!output_currents.empty()) return makeOutputWaveforms(current_group, output_currents, rf); @@ -2429,7 +2447,7 @@ LibertyReader::makeOutputWaveforms(const LibertyGroup *current_group, ref_times[slew_index] = waveform.referenceTime(); } else - libWarn(1221, current_group, "output current waveform %.2e %.2e not found.", + warn(1221, current_group, "output current waveform {:.2e} {:.2e} not found.", waveform.slew(), waveform.cap()); } @@ -2445,7 +2463,8 @@ LibertyReader::readTableModel(const LibertyGroup *table_group, const RiseFall *rf, TableTemplateType template_type, float scale, - ScaleFactorType scale_factor_type) + ScaleFactorType scale_factor_type, + const std::function &check_axes) { const char *template_name = table_group->firstName(); if (library_ && template_name) { @@ -2456,11 +2475,14 @@ LibertyReader::readTableModel(const LibertyGroup *table_group, if (table) { TableModel *table_model = new TableModel(table, tbl_template, scale_factor_type, rf); + if (!check_axes(table_model)) { + warn(1251, table_group, "unsupported model axis."); + } return table_model; } } else - libWarn(1253, table_group, "table template %s not found.", template_name); + warn(1253, table_group, "table template {} not found.", template_name); } return nullptr; } @@ -2499,7 +2521,7 @@ LibertyReader::readTableModel(const LibertyGroup *table_group, } } else - libWarn(1257, table_group, "%s is missing values.", table_group->type().c_str()); + warn(1257, table_group, "{} is missing values.", table_group->type()); return nullptr; } @@ -2512,14 +2534,14 @@ LibertyReader::makeTableAxis(const LibertyGroup *table_group, if (index_attr) { FloatSeq axis_values = readFloatSeq(index_attr, 1.0F); if (axis_values.empty()) - libWarn(1177, index_attr, "missing table index values."); + warn(1177, index_attr, "missing table index values."); else { // Check monotonicity of the values. float prev = axis_values[0]; for (size_t i = 1; i < axis_values.size(); i++) { float value = axis_values[i]; if (value <= prev) - libWarn(1173, index_attr, "non-increasing table index values."); + warn(1173, index_attr, "non-increasing table index values."); prev = value; } @@ -2550,7 +2572,7 @@ LibertyReader::makeTimingArcs(LibertyCell *cell, if (from_port_iter.hasNext()) { LibertyPort *from_port = from_port_iter.next(); if (from_port->direction()->isOutput()) - libWarn(1212, timing_line, "timing group from output port."); + warn(1212, timing_line, "timing group from output port."); builder_.makeTimingArcs(cell, from_port, to_port, related_out_port, timing_attrs, timing_line); } @@ -2560,7 +2582,7 @@ LibertyReader::makeTimingArcs(LibertyCell *cell, while (from_port_iter.hasNext()) { LibertyPort *from_port = from_port_iter.next(); if (from_port->direction()->isOutput()) - libWarn(1213, timing_line, "timing group from output port."); + warn(1213, timing_line, "timing group from output port."); builder_.makeTimingArcs(cell, from_port, to_port, related_out_port, timing_attrs, timing_line); } @@ -2570,7 +2592,7 @@ LibertyReader::makeTimingArcs(LibertyCell *cell, if (from_port_iter.hasNext()) { LibertyPort *from_port = from_port_iter.next(); if (from_port->direction()->isOutput()) - libWarn(1214, timing_line, "timing group from output port."); + warn(1214, timing_line, "timing group from output port."); LibertyPortMemberIterator bit_iter(to_port); while (bit_iter.hasNext()) { LibertyPort *to_port_bit = bit_iter.next(); @@ -2587,8 +2609,8 @@ LibertyReader::makeTimingArcs(LibertyCell *cell, LibertyPortMemberIterator to_port_iter(to_port); // warn about different sizes if (from_size != to_size) - libWarn(1216, timing_line, - "timing port %s and related port %s are different sizes.", + warn(1216, timing_line, + "timing port {} and related port {} are different sizes.", from_port_name.c_str(), to_port->name()); // align to/from iterators for one-to-one mapping @@ -2605,7 +2627,7 @@ LibertyReader::makeTimingArcs(LibertyCell *cell, LibertyPort *from_port_bit = from_port_iter.next(); LibertyPort *to_port_bit = to_port_iter.next(); if (from_port_bit->direction()->isOutput()) - libWarn(1215, timing_line, "timing group from output port."); + warn(1215, timing_line, "timing group from output port."); builder_.makeTimingArcs(cell, from_port_bit, to_port_bit, related_out_port, timing_attrs, timing_line); @@ -2665,7 +2687,7 @@ LibertyReader::readLeagageGrouops(LibertyCell *cell, cell->makeLeakagePower(related_pg_port, when, power * power_scale_); } else - libWarn(1307, leak_group, "leakage_power missing value."); + warn(1307, leak_group, "leakage_power missing value."); } } @@ -2682,7 +2704,7 @@ LibertyReader::readInternalPowerGroups(LibertyCell *cell, FuncExpr *when1 = readFuncExpr(cell, ipwr_group, "when"); if (when1) when = std::shared_ptr(when1); - InternalPowerModels models; + InternalPowerModels models{}; // rise/fall_power group for (const RiseFall *rf : RiseFall::range()) { std::string pwr_attr_name = rf->to_string() + "_power"; @@ -2691,7 +2713,9 @@ LibertyReader::readInternalPowerGroups(LibertyCell *cell, TableModel *model = readTableModel(pwr_group, rf, TableTemplateType::power, energyScale(), ScaleFactorType::internal_power); - models[rf->index()] = std::make_shared(model); + std::shared_ptr table_model(model); + InternalPowerModel pwr_model(table_model); + models[rf->index()] = pwr_model; } } // power group (rise/fall power are the same) @@ -2701,9 +2725,11 @@ LibertyReader::readInternalPowerGroups(LibertyCell *cell, TableTemplateType::power, energyScale(), ScaleFactorType::internal_power); - auto pwr_model = std::make_shared(model); - for (const RiseFall *rf : RiseFall::range()) + std::shared_ptr table_model(model); + for (const RiseFall *rf : RiseFall::range()) { + InternalPowerModel pwr_model(table_model); models[rf->index()] = pwr_model; + } } if (related_ports.empty()) cell->makeInternalPower(port, nullptr, related_pg_port, when, models); @@ -2742,7 +2768,7 @@ LibertyReader::findLibertyPort(LibertyCell *cell, if (port) return port; else - libWarn(1290, attr, "port %s not found.", port_name->c_str()); + warn(1290, attr, "port {} not found.", *port_name); } } return nullptr; @@ -2774,7 +2800,7 @@ LibertyReader::findLibertyPorts(LibertyCell *cell, if (port) ports.push_back(port); else - libWarn(1306, group, "port %s not found.", port_name.c_str()); + warn(1306, group, "port {} not found.", port_name); } return ports; } @@ -2792,9 +2818,9 @@ LibertyReader::makeScalarCheckModel(LibertyCell *cell, library_->findTableTemplate("scalar", TableTemplateType::delay); TableModel *table_model = new TableModel(table, tbl_template, scale_factor_type, rf); - TableModelsEarlyLate sigmas{}; - CheckTableModel *check_model = new CheckTableModel(cell, table_model, - std::move(sigmas)); + + TableModels *check_models = new TableModels(table_model); + TimingModel *check_model = new CheckTableModel(cell, check_models); return check_model; } @@ -2810,12 +2836,12 @@ LibertyReader::checkLatchEnableSense(FuncExpr *enable_func, case TimingSense::negative_unate: break; case TimingSense::non_unate: - libWarn(1200, line, "latch enable function is non-unate for port %s.", + warn(1200, line, "latch enable function is non-unate for port {}.", enable_port->name()); break; case TimingSense::none: case TimingSense::unknown: - libWarn(1201, line, "latch enable function is unknown for port %s.", + warn(1201, line, "latch enable function is unknown for port {}.", enable_port->name()); break; } @@ -2834,19 +2860,19 @@ LibertyReader::readNormalizedDriverWaveform(const LibertyGroup *library_group) TableTemplate *tbl_template = library_->findTableTemplate(template_name, TableTemplateType::delay); if (!tbl_template) { - libWarn(1256, waveform_group, "table template %s not found.", template_name); + warn(1256, waveform_group, "table template {} not found.", template_name); continue; } TablePtr table = readTableModel(waveform_group, tbl_template, time_scale_); if (!table) continue; if (table->axis1()->variable() != TableAxisVariable::input_net_transition) { - libWarn(1265, waveform_group, + warn(1265, waveform_group, "normalized_driver_waveform variable_1 must be input_net_transition"); continue; } if (table->axis2()->variable() != TableAxisVariable::normalized_voltage) { - libWarn(1225, waveform_group, + warn(1225, waveform_group, "normalized_driver_waveform variable_2 must be normalized_voltage"); continue; } @@ -2857,7 +2883,7 @@ LibertyReader::readNormalizedDriverWaveform(const LibertyGroup *library_group) library_->makeDriverWaveform(driver_waveform_name, table); } else - libWarn(1227, waveform_group, "normalized_driver_waveform missing template."); + warn(1227, waveform_group, "normalized_driver_waveform missing template."); } } @@ -2876,7 +2902,7 @@ LibertyReader::readLevelShifterType(LibertyCell *cell, else if (*level_shifter_type == "HL_LH") cell->setLevelShifterType(LevelShifterType::HL_LH); else - libWarn(1228, cell_group, "level_shifter_type must be HL, LH, or HL_LH"); + warn(1228, cell_group, "level_shifter_type must be HL, LH, or HL_LH"); } } @@ -2891,7 +2917,7 @@ LibertyReader::readSwitchCellType(LibertyCell *cell, else if (*switch_cell_type == "fine_grain") cell->setSwitchCellType(SwitchCellType::fine_grain); else - libWarn(1229, cell_group, "switch_cell_type must be coarse_grain or fine_grain"); + warn(1229, cell_group, "switch_cell_type must be coarse_grain or fine_grain"); } } @@ -2907,8 +2933,8 @@ LibertyReader::readCellOcvDerateGroup(LibertyCell *cell, if (derate) cell->setOcvDerate(derate); else - libWarn(1237, cell_group, "OCV derate group named %s not found.", - derate_name->c_str()); + warn(1237, cell_group, "OCV derate group named {} not found.", + *derate_name); } } @@ -2937,25 +2963,25 @@ LibertyReader::readStatetable(LibertyCell *cell, for (const std::string &row : table_rows) { const StringSeq row_groups = parseTokens(row, ':'); if (row_groups.size() != 3) { - libWarn(1300, table_attr, "table row must have 3 groups separated by ':'."); + warn(1300, table_attr, "table row must have 3 groups separated by ':'."); break; } StringSeq inputs = parseTokens(row_groups[0], ' '); if (inputs.size() != input_count) { - libWarn(1301,table_attr,"table row has %zu input values but %zu are required.", + warn(1301, table_attr, "table row has {} input values but {} are required.", inputs.size(), input_count); break; } StringSeq currents = parseTokens(row_groups[1], ' '); if (currents.size() != internal_count) { - libWarn(1302,table_attr, - "table row has %zu current values but %zu are required.", + warn(1302,table_attr, + "table row has {} current values but {} are required.", currents.size(), internal_count); break; } StringSeq nexts = parseTokens(row_groups[2], ' '); if (nexts.size() != internal_count) { - libWarn(1303, table_attr, "table row has %zu next values but %zu are required.", + warn(1303, table_attr, "table row has {} next values but {} are required.", nexts.size(), internal_count); break; } @@ -2975,8 +3001,8 @@ LibertyReader::readStatetable(LibertyCell *cell, if (port) input_port_ptrs.push_back(port); else - libWarn(1298, statetable_group, "statetable input port %s not found.", - input.c_str()); + warn(1298, statetable_group, "statetable input port {} not found.", + input); } LibertyPortSeq internal_port_ptrs; for (const std::string &internal : internal_ports) { @@ -2997,7 +3023,7 @@ LibertyReader::readTestCell(LibertyCell *cell, const LibertyGroup *test_cell_group = cell_group->findSubgroup("test_cell"); if (test_cell_group) { if (cell->testCell()) - libWarn(1262, test_cell_group, "cell %s test_cell redefinition.", cell->name()); + warn(1262, test_cell_group, "cell {} test_cell redefinition.", cell->name()); else { std::string test_cell_name = std::string(cell->name()) + "/test_cell"; TestCell *test_cell = new TestCell(cell->libertyLibrary(), @@ -3104,8 +3130,8 @@ LibertyReader::parseStateInputValues(StringSeq &inputs, StateInputValue value; state_input_value_name_map.find(input.c_str(), value, exists); if (!exists) { - libWarn(1304, attr, "table input value '%s' not recognized.", - input.c_str()); + warn(1304, attr, "table input value '{}' not recognized.", + input); value = StateInputValue::dont_care; } input_values.push_back(value); @@ -3123,8 +3149,8 @@ LibertyReader::parseStateInternalValues(StringSeq &states, StateInternalValue value; state_internal_value_name_map.find(state.c_str(), value, exists); if (!exists) { - libWarn(1305, attr, "table internal value '%s' not recognized.", - state.c_str()); + warn(1305, attr, "table internal value '{}' not recognized.", + state); value = StateInternalValue::unknown; } state_values.push_back(value); @@ -3151,11 +3177,11 @@ LibertyReader::makeFloatTable(const LibertyComplexAttr *values_attr, else if (value->isFloat()) row.push_back(value->floatValue() * scale); else - libWarn(1258, values_attr, "%s is not a list of floats.", - values_attr->name().c_str()); + warn(1258, values_attr, "{} is not a list of floats.", + values_attr->name()); if (row.size() != cols) { - libWarn(1259, values_attr, "%s row has %zu columns but axis has %zu.", - table_group->type().c_str(), + warn(1259, values_attr, "{} row has {} columns but axis has {}.", + table_group->type(), row.size(), cols); for (size_t c = row.size(); c < cols; c++) @@ -3165,11 +3191,11 @@ LibertyReader::makeFloatTable(const LibertyComplexAttr *values_attr, } if (table.size() != rows) { if (rows == 0) - libWarn(1260, values_attr, "%s missing axis values.", - table_group->type().c_str()); + warn(1260, values_attr, "{} missing axis values.", + table_group->type()); else - libWarn(1261, values_attr, "%s has %zu rows but axis has %zu.", - table_group->type().c_str(), + warn(1261, values_attr, "{} has {} rows but axis has {}.", + table_group->type(), table.size(), rows); for (size_t r = table.size(); r < rows; r++) { @@ -3197,7 +3223,7 @@ LibertyReader::getAttrInt(const LibertySimpleAttr *attr, exists = true; } else - libWarn(1268, attr, "%s attribute is not an integer.",attr->name().c_str()); + warn(1268, attr, "{} attribute is not an integer.", attr->name()); } // Get two floats in a complex attribute. @@ -3215,15 +3241,15 @@ LibertyReader::getAttrFloat2(const LibertyComplexAttr *attr, LibertyAttrValue *value = values[0]; getAttrFloat(attr, value, value1, exists); if (!exists) - libWarn(1272, attr, "%s is not a float.", attr->name().c_str()); + warn(1272, attr, "{} is not a float.", attr->name()); value = values[1]; getAttrFloat(attr, value, value2, exists); if (!exists) - libWarn(1273, attr, "%s is not a float.", attr->name().c_str()); + warn(1273, attr, "{} is not a float.", attr->name()); } else - libWarn(1274, attr, "%s requires 2 valules.", attr->name().c_str()); + warn(1274, attr, "{} requires 2 valules.", attr->name()); } void @@ -3245,9 +3271,9 @@ LibertyReader::getAttrFloat(const LibertyComplexAttr *attr, value = strtof(str.c_str(), &end); if ((*end && !isspace(*end)) || str == "inf") - libWarn(1183, attr->line(), "%s value %s is not a float.", - attr->name().c_str(), - str.c_str()); + warn(1183, attr->line(), "{} value {} is not a float.", + attr->name(), + str); valid = true; } } @@ -3281,7 +3307,7 @@ LibertyReader::parseStringFloatList(const std::string &float_list, for (const char *t = token; t <= end; t++) token_end += *t; } - libWarn(1310, attr, "%s is not a float.", token_end.c_str()); + warn(1310, attr, "{} is not a float.", token_end); token += token_end.size(); } else { @@ -3318,7 +3344,7 @@ LibertyReader::parseStringFloatList(const std::string &float_list, for (const char *t = token; t <= end; t++) token_end += *t; } - libWarn(1275, attr, "%s is not a float.", token_end.c_str()); + warn(1275, attr, "{} is not a float.", token_end); token += token_end.size(); } else { @@ -3346,7 +3372,7 @@ LibertyReader::readFloatSeq(const LibertyComplexAttr *attr, values.push_back(value->floatValue() * scale); } else - libWarn(1276, attr, "%s is missing values.", attr->name().c_str()); + warn(1276, attr, "{} is missing values.", attr->name()); } else if (attr_values.size() > 1) { for (LibertyAttrValue *val : attr_values) { @@ -3359,7 +3385,7 @@ LibertyReader::readFloatSeq(const LibertyComplexAttr *attr, } } else - libWarn(1277, attr, "%s has no values.", attr->name().c_str()); + warn(1277, attr, "{} has no values.", attr->name()); return values; } @@ -3384,10 +3410,10 @@ LibertyReader::getAttrBool(const LibertySimpleAttr *attr, exists = true; } else - libWarn(1288, attr, "%s attribute is not boolean.", attr->name().c_str()); + warn(1288, attr, "{} attribute is not boolean.", attr->name()); } else - libWarn(1289, attr, "%s attribute is not boolean.", attr->name().c_str()); + warn(1289, attr, "{} attribute is not boolean.", attr->name()); } // Read L/H/X string attribute values as bool. @@ -3403,8 +3429,8 @@ LibertyReader::getAttrLogicValue(const LibertySimpleAttr *attr) else if (*str == "X") return LogicValue::unknown; else - libWarn(1282, attr, "attribute %s value %s not recognized.", - attr->name().c_str(), str->c_str()); + warn(1282, attr, "attribute {} value {} not recognized.", + attr->name(), *str); // fall thru } return LogicValue::unknown; @@ -3421,7 +3447,7 @@ LibertyReader::getAttrEarlyLate(const LibertySimpleAttr *attr) else if (*value == "early_and_late") return EarlyLateAll::all(); else { - libWarn(1283, attr, "unknown early/late value."); + warn(1283, attr, "unknown early/late value."); return EarlyLateAll::all(); } } @@ -3434,11 +3460,10 @@ LibertyReader::parseFunc(const char *func, const LibertyCell *cell, int line) { - std::string error_msg; - stringPrint(error_msg, "%s, line %d %s", - filename_, - line, - attr_name); + std::string error_msg = format("{}, line {}{}", + filename_, + line, + attr_name); return parseFuncExpr(func, cell, error_msg.c_str(), report_); } @@ -3464,92 +3489,6 @@ LibertyReader::variableValue(const char *var, //////////////////////////////////////////////////////////////// -void -LibertyReader::libWarn(int id, - const LibertyGroup *group, - const char *fmt, - ...) const -{ - va_list args; - va_start(args, fmt); - report_->vfileWarn(id, filename_, group->line(), fmt, args); - va_end(args); -} - -void -LibertyReader::libWarn(int id, - const LibertySimpleAttr *attr, - const char *fmt, - ...) const -{ - va_list args; - va_start(args, fmt); - report_->vfileWarn(id, filename_, attr->line(), fmt, args); - va_end(args); -} - -void -LibertyReader::libWarn(int id, - const LibertyComplexAttr *attr, - const char *fmt, - ...) const -{ - va_list args; - va_start(args, fmt); - report_->vfileWarn(id, filename_, attr->line(), fmt, args); - va_end(args); -} - -void -LibertyReader::libWarn(int id, - int line, - const char *fmt, - ...) const -{ - va_list args; - va_start(args, fmt); - report_->vfileWarn(id, filename_, line, fmt, args); - va_end(args); -} - -void -LibertyReader::libError(int id, - const LibertyGroup *group, - const char *fmt, - ...) const -{ - va_list args; - va_start(args, fmt); - report_->vfileError(id, filename_, group->line(), fmt, args); - va_end(args); -} - -void -LibertyReader::libError(int id, - const LibertySimpleAttr *attr, - const char *fmt, - ...) const -{ - va_list args; - va_start(args, fmt); - report_->vfileError(id, filename_, attr->line(), fmt, args); - va_end(args); -} - -void -LibertyReader::libError(int id, - const LibertyComplexAttr *attr, - const char *fmt, - ...) const -{ - va_list args; - va_start(args, fmt); - report_->vfileError(id, filename_, attr->line(), fmt, args); - va_end(args); -} - -//////////////////////////////////////////////////////////////// - void LibertyReader::readDefaultOcvDerateGroup(const LibertyGroup *library_group) { @@ -3560,8 +3499,8 @@ LibertyReader::readDefaultOcvDerateGroup(const LibertyGroup *library_group) if (derate) library_->setDefaultOcvDerate(derate); else - libWarn(1284, library_group, "OCV derate group named %s not found.", - derate_name->c_str()); + warn(1284, library_group, "OCV derate group named {} not found.", + *derate_name); } } @@ -3589,7 +3528,7 @@ LibertyReader::readOcvDerateFactors(LibertyCell *cell, else if (*rf_attr == "rise_and_fall") rf_type = RiseFallBoth::riseFall(); else - libError(1286, factors_group, "unknown rise/fall."); + error(1286, factors_group, "unknown rise/fall."); } const EarlyLateAll *derate_type = EarlyLateAll::all(); @@ -3602,7 +3541,7 @@ LibertyReader::readOcvDerateFactors(LibertyCell *cell, else if (*derate_attr == "early_and_late") derate_type = EarlyLateAll::all(); else { - libWarn(1309, factors_group, "unknown early/late value."); + warn(1309, factors_group, "unknown early/late value."); } } @@ -3616,7 +3555,7 @@ LibertyReader::readOcvDerateFactors(LibertyCell *cell, else if (*path_attr == "clock_and_data") path_type = PathType::clk_and_data; else - libWarn(1287, factors_group, "unknown derate type."); + warn(1287, factors_group, "unknown derate type."); } const char *template_name = factors_group->firstName(); @@ -3639,12 +3578,12 @@ LibertyReader::readOcvDerateFactors(LibertyCell *cell, } } else - libWarn(1308, factors_group, "table template %s not found.", template_name); + warn(1308, factors_group, "table template {} not found.", template_name); } } } else - libWarn(1285, ocv_derate_group, "ocv_derate missing name."); + warn(1285, ocv_derate_group, "ocv_derate missing name."); } } @@ -3698,13 +3637,13 @@ PortNameBitIterator::init(const char *port_name) range_bit_ = from; } else - visitor_->libWarn(1292, line_, "port %s subscript out of range.", + visitor_->warn(1292, line_, "port {} subscript out of range.", port_name); } else - visitor_->libWarn(1293, line_, "port range %s of non-bus port %s.", + visitor_->warn(1293, line_, "port range {} of non-bus port {}.", port_name, - bus_name.c_str()); + bus_name); } else { range_bus_name_ = bus_name; @@ -3713,10 +3652,10 @@ PortNameBitIterator::init(const char *port_name) range_bit_ = from; findRangeBusNameNext(); } - size_ = abs(from - to) + 1; + size_ = std::abs(from - to) + 1; } else - visitor_->libWarn(1294, line_, "port %s not found.", port_name); + visitor_->warn(1294, line_, "port {} not found.", port_name); } } @@ -3782,7 +3721,7 @@ PortNameBitIterator::findRangeBusNameNext() range_bit_++; } else - visitor_->libWarn(1295, line_, "port %s not found.", bus_bit_name.c_str()); + visitor_->warn(1295, line_, "port {} not found.", bus_bit_name); } else range_name_next_ = nullptr; diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index 474cc799..e1307b7d 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,7 @@ #include "LibertyParser.hh" #include "LibertyReader.hh" #include "LibertyBuilder.hh" +#include "Report.hh" namespace sta { @@ -232,25 +234,21 @@ protected: const LibertyPortSeq &ports, const LibertyGroup *port_group); bool isGateTimingType(TimingType timing_type); - TableModel *readGateTableModel(const LibertyGroup *timing_group, - const char *table_group_name, - const RiseFall *rf, - TableTemplateType template_type, - float scale, - ScaleFactorType scale_factor_type); + TableModel *readTableModel(const LibertyGroup *timing_group, + const std::string &table_group_name, + const RiseFall *rf, + TableTemplateType template_type, + float scale, + ScaleFactorType scale_factor_type, + const std::function check_axes); TableModelsEarlyLate readEarlyLateTableModels(const LibertyGroup *timing_group, const char *table_group_name, const RiseFall *rf, TableTemplateType template_type, float scale, - ScaleFactorType scale_factor_type); - TableModel *readCheckTableModel(const LibertyGroup *timing_group, - const char *table_group_name, - const RiseFall *rf, - TableTemplateType template_type, - float scale, - ScaleFactorType scale_factor_type); + ScaleFactorType scale_factor_type, + const std::function check_axes); ReceiverModelPtr readReceiverCapacitance(const LibertyGroup *timing_group, const RiseFall *rf); void readReceiverCapacitance(const LibertyGroup *timing_group, @@ -268,7 +266,9 @@ protected: const RiseFall *rf, TableTemplateType template_type, float scale, - ScaleFactorType scale_factor_type); + ScaleFactorType scale_factor_type, + const std::function &check_axes = + [](TableModel *) { return true; }); TablePtr readTableModel(const LibertyGroup *table_group, const TableTemplate *tbl_template, float scale); @@ -281,6 +281,14 @@ protected: void makeTableModels(LibertyCell *cell, const LibertyGroup *timing_group, TimingArcAttrsPtr timing_attrs); + void readLvfModels(const LibertyGroup *timing_group, + const std::string &sigma_group_name, + const std::string &std_dev_group_name, + const std::string &mean_shift_group_name, + const std::string &skewness_group_name, + const RiseFall *rf, + TableModels *table_models, + const std::function check_axes); TableAxisPtr makeTableAxis(const LibertyGroup *table_group, const char *index_attr_name, @@ -445,38 +453,65 @@ protected: const char *attr_name, const LibertyCell *cell, int line); - void libWarn(int id, + template + void warn(int id, const LibertyGroup *group, - const char *fmt, - ...) const - __attribute__((format (printf, 4, 5))); - void libWarn(int id, + std::string_view fmt, + Args &&...args) const + { + report_->fileWarn(id, filename_, group->line(), fmt, std::forward(args)...); + } + template + void warn(int id, const LibertySimpleAttr *attr, - const char *fmt, - ...) const - __attribute__((format (printf, 4, 5))); - void libWarn(int id, + std::string_view fmt, + Args &&...args) const + { + report_->fileWarn(id, filename_, attr->line(), fmt, std::forward(args)...); + } + template + void warn(int id, const LibertyComplexAttr *attr, - const char *fmt, - ...) const - __attribute__((format (printf, 4, 5))); - void libWarn(int id, + std::string_view fmt, + Args &&...args) const + { + report_->fileWarn(id, filename_, attr->line(), fmt, std::forward(args)...); + } + template + void warn(int id, int line, - const char *fmt, - ...) const - __attribute__((format (printf, 4, 5))); - void libError(int id, + std::string_view fmt, + Args &&...args) const + { + report_->fileWarn(id, filename_, line, fmt, std::forward(args)...); + } + template + void error(int id, const LibertyGroup *group, - const char *fmt, ...) const - __attribute__((format (printf, 4, 5))); - void libError(int id, + std::string_view fmt, + Args &&...args) const + { + report_->fileError(id, filename_, group->line(), fmt, + std::forward(args)...); + } + template + void error(int id, const LibertySimpleAttr *attr, - const char *fmt, ...) const - __attribute__((format (printf, 4, 5))); - void libError(int id, + std::string_view fmt, + Args &&...args) const + { + report_->fileError(id, filename_, attr->line(), fmt, + std::forward(args)...); + } + template + void error(int id, const LibertyComplexAttr *attr, - const char *fmt, ...) const - __attribute__((format (printf, 4, 5))); + std::string_view fmt, + Args &&...args) const + { + report_->fileError(id, filename_, attr->line(), fmt, + std::forward(args)...); + } const char *filename_; bool infer_latches_; diff --git a/liberty/LibertyScanner.hh b/liberty/LibertyScanner.hh index b32369cd..3623940c 100644 --- a/liberty/LibertyScanner.hh +++ b/liberty/LibertyScanner.hh @@ -24,7 +24,9 @@ #pragma once -#include "LibertyLocation.hh" +#include +#include + #include "LibertyParse.hh" #ifndef __FLEX_LEXER_H diff --git a/liberty/LibertyWriter.cc b/liberty/LibertyWriter.cc index 19e08729..5e22ce6d 100644 --- a/liberty/LibertyWriter.cc +++ b/liberty/LibertyWriter.cc @@ -1,32 +1,34 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "LibertyWriter.hh" #include #include +#include +#include "Format.hh" #include "Units.hh" #include "FuncExpr.hh" #include "PortDirection.hh" @@ -44,7 +46,7 @@ class LibertyWriter public: LibertyWriter(const LibertyLibrary *lib, const char *filename, - FILE *stream, + std::ofstream &stream, Report *report); void writeLibrary(); @@ -80,7 +82,7 @@ protected: const LibertyLibrary *library_; const char *filename_; - FILE *stream_; + std::ofstream &stream_; Report *report_; const Unit *time_unit_; const Unit *cap_unit_; @@ -91,11 +93,10 @@ writeLiberty(LibertyLibrary *lib, const char *filename, StaState *sta) { - FILE *stream = fopen(filename, "w"); - if (stream) { + std::ofstream stream(filename); + if (stream.is_open()) { LibertyWriter writer(lib, filename, stream, sta->report()); writer.writeLibrary(); - fclose(stream); } else throw FileNotWritable(filename); @@ -103,7 +104,7 @@ writeLiberty(LibertyLibrary *lib, LibertyWriter::LibertyWriter(const LibertyLibrary *lib, const char *filename, - FILE *stream, + std::ofstream &stream, Report *report) : library_(lib), filename_(filename), @@ -118,87 +119,87 @@ void LibertyWriter::writeLibrary() { writeHeader(); - fprintf(stream_, "\n"); + sta::print(stream_, "\n"); writeTableTemplates(); writeBusDcls(); - fprintf(stream_, "\n"); + sta::print(stream_, "\n"); writeCells(); writeFooter(); } - + void LibertyWriter::writeHeader() { - fprintf(stream_, "library (%s) {\n", library_->name()); - fprintf(stream_, " comment : \"\";\n"); - fprintf(stream_, " delay_model : table_lookup;\n"); - fprintf(stream_, " simulation : false;\n"); + sta::print(stream_, "library ({}) {{\n", library_->name()); + sta::print(stream_, " comment : \"\";\n"); + sta::print(stream_, " delay_model : table_lookup;\n"); + sta::print(stream_, " simulation : false;\n"); const Unit *cap_unit = library_->units()->capacitanceUnit(); - fprintf(stream_, " capacitive_load_unit (1,%s);\n", - cap_unit->scaleAbbrevSuffix().c_str()); - fprintf(stream_, " leakage_power_unit : 1pW;\n"); + sta::print(stream_, " capacitive_load_unit (1,{});\n", + cap_unit->scaleAbbrevSuffix()); + sta::print(stream_, " leakage_power_unit : 1pW;\n"); const Unit *current_unit = library_->units()->currentUnit(); - fprintf(stream_, " current_unit : \"1%s\";\n", - current_unit->scaleAbbrevSuffix().c_str()); + sta::print(stream_, " current_unit : \"1{}\";\n", + current_unit->scaleAbbrevSuffix()); const Unit *res_unit = library_->units()->resistanceUnit(); - fprintf(stream_, " pulling_resistance_unit : \"1%s\";\n", - res_unit->scaleAbbrevSuffix().c_str()); + sta::print(stream_, " pulling_resistance_unit : \"1{}\";\n", + res_unit->scaleAbbrevSuffix()); const Unit *time_unit = library_->units()->timeUnit(); - fprintf(stream_, " time_unit : \"1%s\";\n", - time_unit->scaleAbbrevSuffix().c_str()); + sta::print(stream_, " time_unit : \"1{}\";\n", + time_unit->scaleAbbrevSuffix()); const Unit *volt_unit = library_->units()->voltageUnit(); - fprintf(stream_, " voltage_unit : \"1%s\";\n", - volt_unit->scaleAbbrevSuffix().c_str()); - fprintf(stream_, " library_features(report_delay_calculation);\n"); - fprintf(stream_, "\n"); + sta::print(stream_, " voltage_unit : \"1{}\";\n", + volt_unit->scaleAbbrevSuffix()); + sta::print(stream_, " library_features(report_delay_calculation);\n"); + sta::print(stream_, "\n"); - fprintf(stream_, " input_threshold_pct_rise : %.0f;\n", - library_->inputThreshold(RiseFall::rise()) * 100); - fprintf(stream_, " input_threshold_pct_fall : %.0f;\n", - library_->inputThreshold(RiseFall::fall()) * 100); - fprintf(stream_, " output_threshold_pct_rise : %.0f;\n", - library_->inputThreshold(RiseFall::rise()) * 100); - fprintf(stream_, " output_threshold_pct_fall : %.0f;\n", - library_->inputThreshold(RiseFall::fall()) * 100); - fprintf(stream_, " slew_lower_threshold_pct_rise : %.0f;\n", - library_->slewLowerThreshold(RiseFall::rise()) * 100); - fprintf(stream_, " slew_lower_threshold_pct_fall : %.0f;\n", - library_->slewLowerThreshold(RiseFall::fall()) * 100); - fprintf(stream_, " slew_upper_threshold_pct_rise : %.0f;\n", - library_->slewUpperThreshold(RiseFall::rise()) * 100); - fprintf(stream_, " slew_upper_threshold_pct_fall : %.0f;\n", - library_->slewUpperThreshold(RiseFall::rise()) * 100); - fprintf(stream_, " slew_derate_from_library : %.1f;\n", - library_->slewDerateFromLibrary()); - fprintf(stream_, "\n"); + sta::print(stream_, " input_threshold_pct_rise : {:.0f};\n", + library_->inputThreshold(RiseFall::rise()) * 100); + sta::print(stream_, " input_threshold_pct_fall : {:.0f};\n", + library_->inputThreshold(RiseFall::fall()) * 100); + sta::print(stream_, " output_threshold_pct_rise : {:.0f};\n", + library_->inputThreshold(RiseFall::rise()) * 100); + sta::print(stream_, " output_threshold_pct_fall : {:.0f};\n", + library_->inputThreshold(RiseFall::fall()) * 100); + sta::print(stream_, " slew_lower_threshold_pct_rise : {:.0f};\n", + library_->slewLowerThreshold(RiseFall::rise()) * 100); + sta::print(stream_, " slew_lower_threshold_pct_fall : {:.0f};\n", + library_->slewLowerThreshold(RiseFall::fall()) * 100); + sta::print(stream_, " slew_upper_threshold_pct_rise : {:.0f};\n", + library_->slewUpperThreshold(RiseFall::rise()) * 100); + sta::print(stream_, " slew_upper_threshold_pct_fall : {:.0f};\n", + library_->slewUpperThreshold(RiseFall::rise()) * 100); + sta::print(stream_, " slew_derate_from_library : {:.1f};\n", + library_->slewDerateFromLibrary()); + sta::print(stream_, "\n"); bool exists; float max_fanout; library_->defaultFanoutLoad(max_fanout, exists); if (exists) - fprintf(stream_, " default_max_fanout : %.0f;\n", max_fanout); + sta::print(stream_, " default_max_fanout : {:.0f};\n", max_fanout); float max_slew; library_->defaultMaxSlew(max_slew, exists); if (exists) - fprintf(stream_, " default_max_transition : %s;\n", - time_unit_->asString(max_slew, 3)); + sta::print(stream_, " default_max_transition : {};\n", + time_unit_->asString(max_slew, 3)); float max_cap; library_->defaultMaxCapacitance(max_cap, exists); if (exists) - fprintf(stream_, " default_max_capacitance : %s;\n", - cap_unit_->asString(max_cap, 3)); + sta::print(stream_, " default_max_capacitance : {};\n", + cap_unit_->asString(max_cap, 3)); float fanout_load; library_->defaultFanoutLoad(fanout_load, exists); if (exists) - fprintf(stream_, " default_fanout_load : %.2f;\n", fanout_load); - fprintf(stream_, "\n"); + sta::print(stream_, " default_fanout_load : {:.2f};\n", fanout_load); + sta::print(stream_, "\n"); - fprintf(stream_, " nom_process : %.1f;\n", - library_->nominalProcess()); - fprintf(stream_, " nom_temperature : %.1f;\n", - library_->nominalTemperature()); - fprintf(stream_, " nom_voltage : %.2f;\n", - library_->nominalVoltage()); + sta::print(stream_, " nom_process : {:.1f};\n", + library_->nominalProcess()); + sta::print(stream_, " nom_temperature : {:.1f};\n", + library_->nominalTemperature()); + sta::print(stream_, " nom_voltage : {:.2f};\n", + library_->nominalVoltage()); } void @@ -216,22 +217,22 @@ LibertyWriter::writeTableTemplate(const TableTemplate *tbl_template) const TableAxis *axis3 = tbl_template->axis3(); // skip scalar templates if (axis1) { - fprintf(stream_, " lu_table_template(%s) {\n", tbl_template->name().c_str()); - fprintf(stream_, " variable_1 : %s;\n", - tableVariableString(axis1->variable())); + sta::print(stream_, " lu_table_template({}) {{\n", tbl_template->name()); + sta::print(stream_, " variable_1 : {};\n", + tableVariableString(axis1->variable())); if (axis2) - fprintf(stream_, " variable_2 : %s;\n", - tableVariableString(axis2->variable())); + sta::print(stream_, " variable_2 : {};\n", + tableVariableString(axis2->variable())); if (axis3) - fprintf(stream_, " variable_3 : %s;\n", - tableVariableString(axis3->variable())); + sta::print(stream_, " variable_3 : {};\n", + tableVariableString(axis3->variable())); if (axis1 && !axis1->values().empty()) writeTableAxis4(axis1, 1); if (axis2 && !axis2->values().empty()) writeTableAxis4(axis2, 2); if (axis3 && !axis3->values().empty()) writeTableAxis4(axis3, 3); - fprintf(stream_, " }\n"); + sta::print(stream_, " }}\n"); } } @@ -240,16 +241,16 @@ void LibertyWriter::writeTableAxis4(const TableAxis *axis, int index) { - fprintf(stream_, " index_%d(\"", index); + sta::print(stream_, " index_{}(\"", index); const Unit *unit = tableVariableUnit(axis->variable(), library_->units()); bool first = true; for (size_t i = 0; i < axis->size(); i++) { if (!first) - fprintf(stream_, ", "); - fprintf(stream_, "%s", unit->asString(axis->axisValue(i), 5)); + sta::print(stream_, ", "); + sta::print(stream_, "{}", unit->asString(axis->axisValue(i), 5)); first = false; } - fprintf(stream_, "\");\n"); + sta::print(stream_, "\");\n"); } // indent 10 @@ -257,7 +258,7 @@ void LibertyWriter::writeTableAxis10(const TableAxis *axis, int index) { - fprintf(stream_, " "); + sta::print(stream_, " "); writeTableAxis4(axis, index); } @@ -266,13 +267,13 @@ LibertyWriter::writeBusDcls() { BusDclSeq dcls = library_->busDcls(); for (BusDcl *dcl : dcls) { - fprintf(stream_, " type (\"%s\") {\n", dcl->name().c_str()); - fprintf(stream_, " base_type : array;\n"); - fprintf(stream_, " data_type : bit;\n"); - fprintf(stream_, " bit_width : %d;\n", std::abs(dcl->from() - dcl->to() + 1)); - fprintf(stream_, " bit_from : %d;\n", dcl->from()); - fprintf(stream_, " bit_to : %d;\n", dcl->to()); - fprintf(stream_, " }\n"); + sta::print(stream_, " type (\"{}\") {{\n", dcl->name()); + sta::print(stream_, " base_type : array;\n"); + sta::print(stream_, " data_type : bit;\n"); + sta::print(stream_, " bit_width : {};\n", std::abs(dcl->from() - dcl->to() + 1)); + sta::print(stream_, " bit_from : {};\n", dcl->from()); + sta::print(stream_, " bit_to : {};\n", dcl->to()); + sta::print(stream_, " }}\n"); } } @@ -289,21 +290,20 @@ LibertyWriter::writeCells() void LibertyWriter::writeCell(const LibertyCell *cell) { - fprintf(stream_, " cell (\"%s\") {\n", cell->name()); + sta::print(stream_, " cell (\"{}\") {{\n", cell->name()); float area = cell->area(); if (area > 0.0) - fprintf(stream_, " area : %.3f \n", area); + sta::print(stream_, " area : {:.3f} \n", area); if (cell->isMacro()) - fprintf(stream_, " is_macro_cell : true;\n"); + sta::print(stream_, " is_macro_cell : true;\n"); if (cell->interfaceTiming()) - fprintf(stream_, " interface_timing : true;\n"); + sta::print(stream_, " interface_timing : true;\n"); const char *footprint = cell->footprint(); if (footprint) - fprintf(stream_, " cell_footprint : \"%s\";\n", footprint); + sta::print(stream_, " cell_footprint : \"{}\";\n", footprint); const char *user_function_class = cell->userFunctionClass(); if (user_function_class) - fprintf(stream_, " user_function_class : \"%s\";\n", - user_function_class); + sta::print(stream_, " user_function_class : \"{}\";\n", user_function_class); LibertyCellPortIterator port_iter(cell); while (port_iter.hasNext()) { @@ -314,24 +314,23 @@ LibertyWriter::writeCell(const LibertyCell *cell) else if (port->isBus()) writeBusPort(port); else if (port->isBundle()) - report_->error(1340, "%s/%s bundled ports not supported.", - library_->name(), + report_->error(1340, "{}/{} bundled ports not supported.", library_->name(), cell->name()); else writePort(port); } } - fprintf(stream_, " }\n"); - fprintf(stream_, "\n"); + sta::print(stream_, " }}\n"); + sta::print(stream_, "\n"); } void LibertyWriter::writeBusPort(const LibertyPort *port) { - fprintf(stream_, " bus(\"%s\") {\n", port->name()); + sta::print(stream_, " bus(\"{}\") {{\n", port->name()); if (port->busDcl()) - fprintf(stream_, " bus_type : %s;\n", port->busDcl()->name().c_str()); + sta::print(stream_, " bus_type : {};\n", port->busDcl()->name()); writePortAttrs(port); LibertyPortMemberIterator member_iter(port); @@ -339,56 +338,53 @@ LibertyWriter::writeBusPort(const LibertyPort *port) LibertyPort *member = member_iter.next(); writePort(member); } - fprintf(stream_, " }\n"); + sta::print(stream_, " }}\n"); } void LibertyWriter::writePort(const LibertyPort *port) { - fprintf(stream_, " pin(\"%s\") {\n", port->name()); + sta::print(stream_, " pin(\"{}\") {{\n", port->name()); writePortAttrs(port); - fprintf(stream_, " }\n"); + sta::print(stream_, " }}\n"); } void LibertyWriter::writePortAttrs(const LibertyPort *port) { - fprintf(stream_, " direction : %s;\n" , asString(port->direction())); + sta::print(stream_, " direction : {};\n", asString(port->direction())); auto func = port->function(); if (func // cannot ref internal ports until sequentials are written - && !(func->port() - && func->port()->direction()->isInternal())) - fprintf(stream_, " function : \"%s\";\n", func->to_string().c_str()); + && !(func->port() && func->port()->direction()->isInternal())) + sta::print(stream_, " function : \"{}\";\n", func->to_string()); auto tristate_enable = port->tristateEnable(); if (tristate_enable) { if (tristate_enable->op() == FuncExpr::Op::not_) { FuncExpr *three_state = tristate_enable->left(); - fprintf(stream_, " three_state : \"%s\";\n", - three_state->to_string().c_str()); + sta::print(stream_, " three_state : \"{}\";\n", + three_state->to_string()); } else { FuncExpr *three_state = tristate_enable->copy()->invert(); - fprintf(stream_, " three_state : \"%s\";\n", - three_state->to_string().c_str()); + sta::print(stream_, " three_state : \"{}\";\n", + three_state->to_string()); delete three_state; } } if (port->isClock()) - fprintf(stream_, " clock : true;\n"); - fprintf(stream_, " capacitance : %s;\n", - cap_unit_->asString(port->capacitance(), 4)); - + sta::print(stream_, " clock : true;\n"); + sta::print(stream_, " capacitance : {};\n", + cap_unit_->asString(port->capacitance(), 4)); + float limit; bool exists; port->slewLimit(MinMax::max(), limit, exists); if (exists) - fprintf(stream_, " max_transition : %s;\n", - time_unit_->asString(limit, 3)); + sta::print(stream_, " max_transition : {};\n", time_unit_->asString(limit, 3)); port->capacitanceLimit(MinMax::max(), limit, exists); if (exists) - fprintf(stream_, " max_capacitance : %s;\n", - cap_unit_->asString(limit, 3)); + sta::print(stream_, " max_capacitance : {};\n", cap_unit_->asString(limit, 3)); for (TimingArcSet *arc_set : port->libertyCell()->timingArcSetsTo(port)) { if (!isAutoWidthArc(port, arc_set)) @@ -399,10 +395,10 @@ LibertyWriter::writePortAttrs(const LibertyPort *port) void LibertyWriter::writePwrGndPort(const LibertyPort *port) { - fprintf(stream_, " pg_pin(\"%s\") {\n", port->name()); - fprintf(stream_, " pg_type : \"%s\";\n", pwrGndTypeName(port->pwrGndType())); - fprintf(stream_, " voltage_name : \"%s\";\n", port->voltageName()); - fprintf(stream_, " }\n"); + sta::print(stream_, " pg_pin(\"{}\") {{\n", port->name()); + sta::print(stream_, " pg_type : \"{}\";\n", pwrGndTypeName(port->pwrGndType())); + sta::print(stream_, " voltage_name : \"{}\";\n", port->voltageName()); + sta::print(stream_, " }}\n"); } // Check if arc is added for port min_pulse_width_high/low attribute. @@ -423,30 +419,27 @@ LibertyWriter::isAutoWidthArc(const LibertyPort *port, void LibertyWriter::writeTimingArcSet(const TimingArcSet *arc_set) { - fprintf(stream_, " timing() {\n"); + sta::print(stream_, " timing() {{\n"); if (arc_set->from()) - fprintf(stream_, " related_pin : \"%s\";\n", arc_set->from()->name()); + sta::print(stream_, " related_pin : \"{}\";\n", arc_set->from()->name()); TimingSense sense = arc_set->sense(); - if (sense != TimingSense::unknown - && sense != TimingSense::non_unate) - fprintf(stream_, " timing_sense : %s;\n", - to_string(sense)); + if (sense != TimingSense::unknown && sense != TimingSense::non_unate) + sta::print(stream_, " timing_sense : {};\n", to_string(sense)); const char *timing_type = timingTypeString(arc_set); if (timing_type) - fprintf(stream_, " timing_type : %s;\n", timing_type); + sta::print(stream_, " timing_type : {};\n", timing_type); for (const RiseFall *rf : RiseFall::range()) { TimingArc *arc = arc_set->arcTo(rf); if (arc) { // Min pulse width arcs are wrt to the leading edge of the pulse. - const RiseFall *model_rf = (arc_set->role() == TimingRole::width()) - ? rf->opposite() - : rf; + const RiseFall *model_rf = + (arc_set->role() == TimingRole::width()) ? rf->opposite() : rf; writeTimingModels(arc, model_rf); } } - fprintf(stream_, " }\n"); + sta::print(stream_, " }}\n"); } void @@ -454,53 +447,53 @@ LibertyWriter::writeTimingModels(const TimingArc *arc, const RiseFall *rf) { TimingModel *model = arc->model(); - const GateTableModel *gate_model = dynamic_cast(model); - const CheckTableModel *check_model = dynamic_cast(model); + const GateTableModel *gate_model = dynamic_cast(model); + const CheckTableModel *check_model = dynamic_cast(model); if (gate_model) { const TableModel *delay_model = gate_model->delayModel(); const std::string &template_name = delay_model->tblTemplate()->name(); - fprintf(stream_, " cell_%s(%s) {\n", rf->name(), template_name.c_str()); + sta::print(stream_, " cell_{}({}) {{\n", rf->name(), template_name); writeTableModel(delay_model); - fprintf(stream_, " }\n"); + sta::print(stream_, " }}\n"); const TableModel *slew_model = gate_model->slewModel(); if (slew_model) { const std::string &slew_template_name = slew_model->tblTemplate()->name(); - fprintf(stream_, " %s_transition(%s) {\n", rf->name(), slew_template_name.c_str()); + sta::print(stream_, " {}_transition({}) {{\n", rf->name(), + slew_template_name); writeTableModel(slew_model); - fprintf(stream_, " }\n"); + sta::print(stream_, " }}\n"); } } else if (check_model) { - const TableModel *model = check_model->model(); + const TableModel *model = check_model->checkModel(); const std::string &template_name = model->tblTemplate()->name(); - fprintf(stream_, " %s_constraint(%s) {\n", rf->name(), template_name.c_str()); + sta::print(stream_, " {}_constraint({}) {{\n", rf->name(), + template_name); writeTableModel(model); - fprintf(stream_, " }\n"); + sta::print(stream_, " }}\n"); } else - report_->error(1341, "%s/%s/%s timing model not supported.", - library_->name(), - arc->from()->libertyCell()->name(), - arc->from()->name()); + report_->error(1341, "{}/{}/{} timing model not supported.", library_->name(), + arc->from()->libertyCell()->name(), arc->from()->name()); } void LibertyWriter::writeTableModel(const TableModel *model) { switch (model->order()) { - case 0: - writeTableModel0(model); - break; - case 1: - writeTableModel1(model); - break; - case 2: - writeTableModel2(model); - break; - case 3: - report_->error(1342, "3 axis table models not supported."); - break; + case 0: + writeTableModel0(model); + break; + case 1: + writeTableModel1(model); + break; + case 2: + writeTableModel2(model); + break; + case 3: + report_->error(1342, "3 axis table models not supported."); + break; } } @@ -508,24 +501,23 @@ void LibertyWriter::writeTableModel0(const TableModel *model) { float value = model->value(0, 0, 0); - fprintf(stream_, " values(\"%s\");\n", - time_unit_->asString(value, 5)); + sta::print(stream_, " values(\"{}\");\n", time_unit_->asString(value, 5)); } void LibertyWriter::writeTableModel1(const TableModel *model) { writeTableAxis10(model->axis1(), 1); - fprintf(stream_, " values(\""); + sta::print(stream_, " values(\""); bool first_col = true; for (size_t index1 = 0; index1 < model->axis1()->size(); index1++) { float value = model->value(index1, 0, 0); if (!first_col) - fprintf(stream_, ","); - fprintf(stream_, "%s", time_unit_->asString(value, 5)); + sta::print(stream_, ","); + sta::print(stream_, "{}", time_unit_->asString(value, 5)); first_col = false; } - fprintf(stream_, "\");\n"); + sta::print(stream_, "\");\n"); } void @@ -533,31 +525,31 @@ LibertyWriter::writeTableModel2(const TableModel *model) { writeTableAxis10(model->axis1(), 1); writeTableAxis10(model->axis2(), 2); - fprintf(stream_, " values(\""); + sta::print(stream_, " values(\""); bool first_row = true; for (size_t index1 = 0; index1 < model->axis1()->size(); index1++) { if (!first_row) { - fprintf(stream_, "\\\n"); - fprintf(stream_, " \""); + sta::print(stream_, "\\\n"); + sta::print(stream_, " \""); } bool first_col = true; for (size_t index2 = 0; index2 < model->axis2()->size(); index2++) { float value = model->value(index1, index2, 0); if (!first_col) - fprintf(stream_, ","); - fprintf(stream_, "%s", time_unit_->asString(value, 5)); + sta::print(stream_, ","); + sta::print(stream_, "{}", time_unit_->asString(value, 5)); first_col = false; } - fprintf(stream_, "\""); + sta::print(stream_, "\""); first_row = false; } - fprintf(stream_, ");\n"); + sta::print(stream_, ");\n"); } void LibertyWriter::writeFooter() { - fprintf(stream_, "}\n"); + sta::print(stream_, "}}\n"); } const char * @@ -571,15 +563,13 @@ LibertyWriter::asString(const PortDirection *dir) { if (dir == PortDirection::input()) return "input"; - else if (dir == PortDirection::output() - || (dir == PortDirection::tristate())) + else if (dir == PortDirection::output() || (dir == PortDirection::tristate())) return "output"; else if (dir == PortDirection::internal()) return "internal"; else if (dir == PortDirection::bidirect()) return "inout"; - else if (dir == PortDirection::ground() - || dir == PortDirection::power()) + else if (dir == PortDirection::ground() || dir == PortDirection::power()) return "input"; return "unknown"; } @@ -594,8 +584,7 @@ LibertyWriter::timingTypeString(const TimingArcSet *arc_set) return "three_state_disable"; else if (role == TimingRole::tristateEnable()) return "three_state_enable"; - else if (role == TimingRole::regClkToQ() - || role == TimingRole::latchEnToQ()) { + else if (role == TimingRole::regClkToQ() || role == TimingRole::latchEnToQ()) { const TimingArc *arc = arc_set->arcs()[0]; if (arc->fromEdge()->asRiseFall() == RiseFall::rise()) return "rising_edge"; @@ -611,16 +600,14 @@ LibertyWriter::timingTypeString(const TimingArcSet *arc_set) else return "clear"; } - else if (role == TimingRole::setup() - || role == TimingRole::recovery()) { + else if (role == TimingRole::setup() || role == TimingRole::recovery()) { const TimingArc *arc = arc_set->arcs()[0]; if (arc->fromEdge()->asRiseFall() == RiseFall::rise()) return "setup_rising"; else return "setup_falling"; } - else if (role == TimingRole::hold() - || role == TimingRole::removal()) { + else if (role == TimingRole::hold() || role == TimingRole::removal()) { const TimingArc *arc = arc_set->arcs()[0]; if (arc->fromEdge()->asRiseFall() == RiseFall::rise()) return "hold_rising"; @@ -648,13 +635,11 @@ LibertyWriter::timingTypeString(const TimingArcSet *arc_set) else if (role == TimingRole::width()) return "min_pulse_width"; else { - report_->error(1343, "%s/%s/%s timing arc type %s not supported.", - library_->name(), - arc_set->to()->libertyCell()->name(), - arc_set->to()->name(), - role->to_string().c_str()); + report_->error(1343, "{}/{}/{} timing arc type {} not supported.", + library_->name(), arc_set->to()->libertyCell()->name(), + arc_set->to()->name(), role->to_string()); return nullptr; } } -} // namespace +} // namespace sta diff --git a/liberty/LinearModel.cc b/liberty/LinearModel.cc index 85d158e7..b8e6a78c 100644 --- a/liberty/LinearModel.cc +++ b/liberty/LinearModel.cc @@ -42,20 +42,32 @@ void GateLinearModel::gateDelay(const Pvt *, float, float load_cap, - bool, // return values - ArcDelay &gate_delay, - Slew &drvr_slew) const + float &gate_delay, + float &drvr_slew) const { gate_delay = intrinsic_ + resistance_ * load_cap; drvr_slew = 0.0; } +void +GateLinearModel::gateDelayPocv(const Pvt *, + float, + float, + const MinMax *, + PocvMode, + // return values + ArcDelay &, + Slew &) const +{ +} + std::string GateLinearModel::reportGateDelay(const Pvt *, float, float load_cap, - bool, + const MinMax *, + PocvMode, int digits) const { const LibertyLibrary *library = cell_->libertyLibrary(); @@ -98,7 +110,8 @@ CheckLinearModel::checkDelay(const Pvt *, float, float, float, - bool) const + const MinMax *, + PocvMode) const { return intrinsic_; } @@ -109,7 +122,8 @@ CheckLinearModel::reportCheckDelay(const Pvt *, const char *, float, float, - bool, + const MinMax *, + PocvMode, int digits) const { const LibertyLibrary *library = cell_->libertyLibrary(); diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 0d5257a8..46dd6d6b 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "TableModel.hh" @@ -38,8 +38,6 @@ namespace sta { size_t findValueIndex(float value, const FloatSeq *values); -static void -sigmaModelsDelete(TableModelsEarlyLate &models); static std::string reportPvt(const LibertyCell *cell, const Pvt *pvt, @@ -53,139 +51,189 @@ TimingModel::TimingModel(LibertyCell *cell) : { } +//////////////////////////////////////////////////////////////// + GateTableModel::GateTableModel(LibertyCell *cell, - TableModel *delay_model, - TableModelsEarlyLate delay_sigma_models, - TableModel *slew_model, - TableModelsEarlyLate slew_sigma_models, + TableModels *delay_models, + TableModels *slew_models, ReceiverModelPtr receiver_model, OutputWaveforms *output_waveforms) : GateTimingModel(cell), - delay_model_(delay_model), - delay_sigma_models_(std::move(delay_sigma_models)), - slew_model_(slew_model), - slew_sigma_models_(std::move(slew_sigma_models)), + delay_models_(delay_models), + slew_models_(slew_models), receiver_model_(receiver_model), output_waveforms_(output_waveforms) { } GateTableModel::GateTableModel(LibertyCell *cell, - TableModel *delay_model, - TableModel *slew_model) : + TableModels *delay_models, + TableModels *slew_models) : GateTimingModel(cell), - delay_model_(delay_model), - delay_sigma_models_{}, - slew_model_(slew_model), - slew_sigma_models_{}, + delay_models_(delay_models), + slew_models_(slew_models), receiver_model_(nullptr), output_waveforms_(nullptr) { } -GateTableModel::~GateTableModel() +GateTableModel::~GateTableModel() = default; + +const TableModel * +GateTableModel::delayModel() const { - sigmaModelsDelete(slew_sigma_models_); - sigmaModelsDelete(delay_sigma_models_); + return delay_models_ ? delay_models_->model() : nullptr; } -static void -sigmaModelsDelete(TableModelsEarlyLate &models) +const TableModel * +GateTableModel::slewModel() const { - TableModel *early_model = models[EarlyLate::earlyIndex()]; - TableModel *late_model = models[EarlyLate::lateIndex()]; - if (early_model == late_model) - delete early_model; - else { - delete early_model; - delete late_model; - } + return slew_models_ ? slew_models_->model() : nullptr;; } void GateTableModel::setIsScaled(bool is_scaled) { - if (delay_model_) - delay_model_->setIsScaled(is_scaled); - if (slew_model_) - slew_model_->setIsScaled(is_scaled); + if (delay_models_) + delay_models_->model()->setIsScaled(is_scaled); + if (slew_models_) + slew_models_->model()->setIsScaled(is_scaled); } void GateTableModel::gateDelay(const Pvt *pvt, float in_slew, float load_cap, - bool pocv_enabled, // return values - ArcDelay &gate_delay, - Slew &drvr_slew) const + float &gate_delay, + float &drvr_slew) const { - float delay = findValue(pvt, delay_model_.get(), in_slew, load_cap, 0.0); - float sigma_early = 0.0; - float sigma_late = 0.0; - if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()]) - sigma_early = findValue(pvt, delay_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, 0.0); - if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()]) - sigma_late = findValue(pvt, delay_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, 0.0); - gate_delay = makeDelay(delay, sigma_early, sigma_late); - - float slew = findValue(pvt, slew_model_.get(), in_slew, load_cap, 0.0); - if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()]) - sigma_early = findValue(pvt, slew_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, 0.0); - if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()]) - sigma_late = findValue(pvt, slew_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, 0.0); + if (delay_models_) + gate_delay = findValue(pvt, delay_models_->model(), in_slew, load_cap, 0.0); + else + gate_delay = 0.0; + if (slew_models_) + drvr_slew = findValue(pvt, slew_models_->model(), in_slew, load_cap, 0.0); + else + drvr_slew = 0.0; // Clip negative slews to zero. - if (slew < 0.0) - slew = 0.0; - drvr_slew = makeDelay(slew, sigma_early, sigma_late); + if (drvr_slew < 0.0) + drvr_slew = 0.0; } void -GateTableModel::gateDelay(const Pvt *pvt, - float in_slew, - float load_cap, - float, - bool pocv_enabled, - ArcDelay &gate_delay, - Slew &drvr_slew) const +GateTableModel::gateDelayPocv(const Pvt *pvt, + float in_slew, + float load_cap, + const MinMax *min_max, + PocvMode pocv_mode, + // return values + ArcDelay &gate_delay, + Slew &drvr_slew) const { - gateDelay(pvt, in_slew, load_cap, pocv_enabled, gate_delay, drvr_slew); + switch (pocv_mode) { + case PocvMode::normal: { + // Delay + TableModel *std_dev_model = delay_models_->stdDev(); + if (std_dev_model == nullptr) + std_dev_model = delay_models_->sigma(min_max); + if (std_dev_model) { + float std_dev = findValue(pvt, std_dev_model, in_slew, load_cap, 0.0); + gate_delay.setStdDev(std_dev); + } + + // Slew + std_dev_model = slew_models_->stdDev(); + if (std_dev_model == nullptr) + std_dev_model = slew_models_->sigma(min_max); + if (std_dev_model) { + float std_dev = findValue(pvt, std_dev_model, in_slew, load_cap, 0.0); + drvr_slew.setStdDev(std_dev); + } + break; + } + case PocvMode::skew_normal: { + // Delay + if (delay_models_->meanShift()) { + float mean_shift = findValue(pvt, delay_models_->meanShift(), + in_slew, load_cap, 0.0); + gate_delay.setMeanShift(mean_shift); + } + + if (delay_models_->stdDev()) { + float std_dev = findValue(pvt, delay_models_->stdDev(), in_slew, load_cap, 0.0); + gate_delay.setStdDev(std_dev); + } + + if (delay_models_->skewness()) { + float skewness = findValue(pvt, delay_models_->skewness(), in_slew, load_cap, 0.0); + gate_delay.setSkewness(skewness); + } + + // Slew + if (slew_models_->meanShift()) { + float mean_shift = findValue(pvt, slew_models_->meanShift(), + in_slew, load_cap, 0.0); + drvr_slew.setMeanShift(mean_shift); + } + + if (slew_models_->stdDev()) { + float std_dev = findValue(pvt, slew_models_->stdDev(), in_slew, load_cap, 0.0); + drvr_slew.setStdDev(std_dev); + } + + if (slew_models_->skewness()) { + float skewness = findValue(pvt, slew_models_->skewness(), in_slew, load_cap, 0.0); + drvr_slew.setSkewness(skewness); + } + break; + } + default: + break; + } } std::string GateTableModel::reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - bool pocv_enabled, + const MinMax *min_max, + PocvMode pocv_mode, int digits) const { std::string result = reportPvt(cell_, pvt, digits); - result += reportTableLookup("Delay", pvt, delay_model_.get(), in_slew, + result += reportTableLookup("Delay", pvt, delay_models_->model(), in_slew, load_cap, 0.0, digits); - if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()]) - result += reportTableLookup("Delay sigma(early)", pvt, - delay_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, 0.0, digits); - if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()]) - result += reportTableLookup("Delay sigma(late)", pvt, - delay_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, 0.0, digits); - result += '\n'; - result += reportTableLookup("Slew", pvt, slew_model_.get(), in_slew, - load_cap, 9.0, digits); - if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()]) - result += reportTableLookup("Slew sigma(early)", pvt, - slew_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, 0.0, digits); - if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()]) - result += reportTableLookup("Slew sigma(late)", pvt, - slew_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, 0.0, digits); - float drvr_slew = findValue(pvt, slew_model_.get(), in_slew, load_cap, 0.0); + if (pocv_mode != PocvMode::scalar) { + if (delay_models_->sigma(min_max)) + result += reportTableLookup("Delay sigma(early)", pvt, + delay_models_->sigma(min_max), + in_slew, load_cap, 0.0, digits); + if (delay_models_->sigma(EarlyLate::late())) + result += reportTableLookup("Delay sigma(late)", pvt, + delay_models_->sigma(min_max), + in_slew, load_cap, 0.0, digits); + result += '\n'; + + result += reportTableLookup("Slew", pvt, slew_models_->model(), in_slew, + load_cap, 9.0, digits); + + if (slew_models_->sigma(EarlyLate::early())) + result += reportTableLookup("Slew sigma(early)", pvt, + slew_models_->sigma(min_max), + in_slew, load_cap, 0.0, digits); + if (slew_models_->sigma(EarlyLate::late())) + result += reportTableLookup("Slew sigma(late)", pvt, + slew_models_->sigma(min_max), + in_slew, load_cap, 0.0, digits); + } + else { + result += '\n'; + result += reportTableLookup("Slew", pvt, slew_models_->model(), in_slew, + load_cap, 9.0, digits); + } + + float drvr_slew = findValue(pvt, slew_models_->model(), in_slew, load_cap, 0.0); if (drvr_slew < 0.0) result += "Negative slew clipped to 0.0\n"; return result; @@ -202,12 +250,12 @@ GateTableModel::reportTableLookup(const char *result_name, { if (model) { float axis_value1, axis_value2, axis_value3; - findAxisValues(model, in_slew, load_cap, related_out_cap, - axis_value1, axis_value2, axis_value3); + findAxisValues(model, in_slew, load_cap, related_out_cap, axis_value1, + axis_value2, axis_value3); const LibertyLibrary *library = cell_->libertyLibrary(); return model->reportValue(result_name, cell_, pvt, axis_value1, nullptr, - axis_value2, axis_value3, - library->units()->timeUnit(), digits); + axis_value2, axis_value3, library->units()->timeUnit(), + digits); } return ""; } @@ -221,8 +269,8 @@ GateTableModel::findValue(const Pvt *pvt, { if (model) { float axis_value1, axis_value2, axis_value3; - findAxisValues(model, in_slew, load_cap, related_out_cap, - axis_value1, axis_value2, axis_value3); + findAxisValues(model, in_slew, load_cap, related_out_cap, axis_value1, + axis_value2, axis_value3); return model->findValue(cell_, pvt, axis_value1, axis_value2, axis_value3); } else @@ -240,37 +288,31 @@ GateTableModel::findAxisValues(const TableModel *model, float &axis_value3) const { switch (model->order()) { - case 0: - axis_value1 = 0.0; - axis_value2 = 0.0; - axis_value3 = 0.0; - break; - case 1: - axis_value1 = axisValue(model->axis1(), in_slew, load_cap, - related_out_cap); - axis_value2 = 0.0; - axis_value3 = 0.0; - break; - case 2: - axis_value1 = axisValue(model->axis1(), in_slew, load_cap, - related_out_cap); - axis_value2 = axisValue(model->axis2(), in_slew, load_cap, - related_out_cap); - axis_value3 = 0.0; - break; - case 3: - axis_value1 = axisValue(model->axis1(), in_slew, load_cap, - related_out_cap); - axis_value2 = axisValue(model->axis2(), in_slew, load_cap, - related_out_cap); - axis_value3 = axisValue(model->axis3(), in_slew, load_cap, - related_out_cap); - break; - default: - axis_value1 = 0.0; - axis_value2 = 0.0; - axis_value3 = 0.0; - criticalError(239, "unsupported table order"); + case 0: + axis_value1 = 0.0; + axis_value2 = 0.0; + axis_value3 = 0.0; + break; + case 1: + axis_value1 = axisValue(model->axis1(), in_slew, load_cap, related_out_cap); + axis_value2 = 0.0; + axis_value3 = 0.0; + break; + case 2: + axis_value1 = axisValue(model->axis1(), in_slew, load_cap, related_out_cap); + axis_value2 = axisValue(model->axis2(), in_slew, load_cap, related_out_cap); + axis_value3 = 0.0; + break; + case 3: + axis_value1 = axisValue(model->axis1(), in_slew, load_cap, related_out_cap); + axis_value2 = axisValue(model->axis2(), in_slew, load_cap, related_out_cap); + axis_value3 = axisValue(model->axis3(), in_slew, load_cap, related_out_cap); + break; + default: + axis_value1 = 0.0; + axis_value2 = 0.0; + axis_value3 = 0.0; + criticalError(239, "unsupported table order"); } } @@ -284,46 +326,30 @@ GateTableModel::driveResistance(const Pvt *pvt) const return slew / cap; } -const TableModel * -GateTableModel::delaySigmaModel(const EarlyLate *el) const -{ - return delay_sigma_models_[el->index()]; -} - -const TableModel * -GateTableModel::slewSigmaModel(const EarlyLate *el) const -{ - return slew_sigma_models_[el->index()]; -} - void GateTableModel::maxCapSlew(float in_slew, const Pvt *pvt, float &slew, float &cap) const { - if (!slew_model_) { - cap = 1.0; - slew = 0.0; - return; - } - const TableAxis *axis1 = slew_model_->axis1(); - const TableAxis *axis2 = slew_model_->axis2(); - const TableAxis *axis3 = slew_model_->axis3(); + TableModel *model = slew_models_->model(); + const TableAxis *axis1 = model->axis1(); + const TableAxis *axis2 = model->axis2(); + const TableAxis *axis3 = model->axis3(); if (axis1 && axis1->variable() == TableAxisVariable::total_output_net_capacitance) { cap = axis1->axisValue(axis1->size() - 1); - slew = findValue(pvt, slew_model_.get(), in_slew, cap, 0.0); + slew = findValue(pvt, model, in_slew, cap, 0.0); } else if (axis2 - && axis2->variable()==TableAxisVariable::total_output_net_capacitance) { + && axis2->variable() == TableAxisVariable::total_output_net_capacitance) { cap = axis2->axisValue(axis2->size() - 1); - slew = findValue(pvt, slew_model_.get(), in_slew, cap, 0.0); + slew = findValue(pvt, model, in_slew, cap, 0.0); } else if (axis3 - && axis3->variable()==TableAxisVariable::total_output_net_capacitance) { + && axis3->variable() == TableAxisVariable::total_output_net_capacitance) { cap = axis3->axisValue(axis3->size() - 1); - slew = findValue(pvt, slew_model_.get(), in_slew, cap, 0.0); + slew = findValue(pvt, model, in_slew, cap, 0.0); } else { // Table not dependent on capacitance. @@ -376,9 +402,9 @@ GateTableModel::checkAxis(const TableAxis *axis) { TableAxisVariable var = axis->variable(); return var == TableAxisVariable::total_output_net_capacitance - || var == TableAxisVariable::input_transition_time - || var == TableAxisVariable::input_net_transition - || var == TableAxisVariable::related_out_total_output_net_capacitance; + || var == TableAxisVariable::input_transition_time + || var == TableAxisVariable::input_net_transition + || var == TableAxisVariable::related_out_total_output_net_capacitance; } //////////////////////////////////////////////////////////////// @@ -403,12 +429,13 @@ ReceiverModel::checkAxes(const TableModel *table) const TableAxis *axis2 = table->axis2(); const TableAxis *axis3 = table->axis3(); return (axis1 && axis1->variable() == TableAxisVariable::input_net_transition - && axis2 == nullptr + && axis2 == nullptr && axis3 == nullptr) + || (axis1 && axis1->variable() == TableAxisVariable::input_net_transition + && axis2 + && axis2->variable() == TableAxisVariable::total_output_net_capacitance && axis3 == nullptr) - || (axis1 && axis1->variable() == TableAxisVariable::input_net_transition - && axis2 && axis2->variable() == TableAxisVariable::total_output_net_capacitance - && axis3 == nullptr) - || (axis1 && axis1->variable() == TableAxisVariable::total_output_net_capacitance + || (axis1 + && axis1->variable() == TableAxisVariable::total_output_net_capacitance && axis2 && axis2->variable() == TableAxisVariable::input_net_transition && axis3 == nullptr); } @@ -416,38 +443,24 @@ ReceiverModel::checkAxes(const TableModel *table) //////////////////////////////////////////////////////////////// CheckTableModel::CheckTableModel(LibertyCell *cell, - TableModel *model, - TableModelsEarlyLate sigma_models) : + TableModels *check_models) : CheckTimingModel(cell), - model_(model), - sigma_models_(std::move(sigma_models)) + check_models_(check_models) { } -CheckTableModel::CheckTableModel(LibertyCell *cell, - TableModel *model) : - CheckTimingModel(cell), - model_(model), - sigma_models_{} -{ -} +CheckTableModel::~CheckTableModel() = default; -CheckTableModel::~CheckTableModel() +const TableModel * +CheckTableModel::checkModel() const { - sigmaModelsDelete(sigma_models_); + return check_models_ ? check_models_->model() : nullptr; } void CheckTableModel::setIsScaled(bool is_scaled) { - if (model_) - model_->setIsScaled(is_scaled); -} - -const TableModel * -CheckTableModel::sigmaModel(const EarlyLate *el) const -{ - return sigma_models_[el->index()]; + check_models_->model()->setIsScaled(is_scaled); } ArcDelay @@ -455,22 +468,52 @@ CheckTableModel::checkDelay(const Pvt *pvt, float from_slew, float to_slew, float related_out_cap, - bool pocv_enabled) const + const MinMax *min_max, + PocvMode pocv_mode) const { - if (model_) { - float mean = findValue(pvt, model_.get(), from_slew, to_slew, related_out_cap); - float sigma_early = 0.0; - float sigma_late = 0.0; - if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()]) - sigma_early = findValue(pvt, sigma_models_[EarlyLate::earlyIndex()], - from_slew, to_slew, related_out_cap); - if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()]) - sigma_late = findValue(pvt, sigma_models_[EarlyLate::lateIndex()], - from_slew, to_slew, related_out_cap); - return makeDelay(mean, sigma_early, sigma_late); + ArcDelay check_delay; + if (check_models_) { + float margin = findValue(pvt, check_models_->model(), from_slew, + to_slew, related_out_cap); + check_delay.setMean(margin); + + switch (pocv_mode) { + case PocvMode::normal: { + TableModel *std_dev_model = check_models_->stdDev(); + if (std_dev_model == nullptr) + std_dev_model = check_models_->sigma(min_max); + if (std_dev_model) { + float std_dev = findValue(pvt, std_dev_model, from_slew, + to_slew, related_out_cap); + check_delay.setStdDev(std_dev); + } + break; + } + case PocvMode::skew_normal: { + if (check_models_->meanShift()) { + float mean_shift = findValue(pvt, check_models_->meanShift(), + from_slew, to_slew, related_out_cap); + check_delay.setMeanShift(mean_shift); + } + + if (check_models_->stdDev()) { + float std_dev = findValue(pvt, check_models_->stdDev(), + from_slew, to_slew, related_out_cap); + check_delay.setStdDev(std_dev); + } + + if (check_models_->skewness()) { + float skewness = findValue(pvt, check_models_->skewness(), + from_slew, to_slew, related_out_cap); + check_delay.setSkewness(skewness); + } + break; + } + default: + break; + } } - else - return 0.0; + return check_delay; } float @@ -482,8 +525,8 @@ CheckTableModel::findValue(const Pvt *pvt, { if (model) { float axis_value1, axis_value2, axis_value3; - findAxisValues(from_slew, to_slew, related_out_cap, - axis_value1, axis_value2, axis_value3); + findAxisValues(from_slew, to_slew, related_out_cap, axis_value1, axis_value2, + axis_value3); return model->findValue(cell_, pvt, axis_value1, axis_value2, axis_value3); } else @@ -496,22 +539,28 @@ CheckTableModel::reportCheckDelay(const Pvt *pvt, const char *from_slew_annotation, float to_slew, float related_out_cap, - bool pocv_enabled, + const MinMax *min_max, + PocvMode pocv_mode, int digits) const { - std::string result = reportTableDelay("Check", pvt, model_.get(), - from_slew, from_slew_annotation, to_slew, - related_out_cap, digits); - if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()]) - result += reportTableDelay("Check sigma early", pvt, - sigma_models_[EarlyLate::earlyIndex()], - from_slew, from_slew_annotation, to_slew, - related_out_cap, digits); - if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()]) - result += reportTableDelay("Check sigma late", pvt, - sigma_models_[EarlyLate::lateIndex()], - from_slew, from_slew_annotation, to_slew, - related_out_cap, digits); + std::string result = reportTableDelay("Check", pvt, check_models_->model(), + from_slew, from_slew_annotation, to_slew, + related_out_cap, digits); + switch (pocv_mode) { + case PocvMode::normal: + case PocvMode::skew_normal: { + TableModel *check_table = check_models_->stdDev(); + if (check_table == nullptr) + check_table = check_models_->sigma(min_max); + if (check_table) + result += reportTableDelay("Check sigma", pvt, check_table, + from_slew, from_slew_annotation, to_slew, + related_out_cap, digits); + break; + } + default: + break; + } return result; } @@ -527,13 +576,14 @@ CheckTableModel::reportTableDelay(const char *result_name, { if (model) { float axis_value1, axis_value2, axis_value3; - findAxisValues(from_slew, to_slew, related_out_cap, - axis_value1, axis_value2, axis_value3); + findAxisValues(from_slew, to_slew, related_out_cap, axis_value1, axis_value2, + axis_value3); std::string result = reportPvt(cell_, pvt, digits); - result += model_->reportValue(result_name, cell_, pvt, - axis_value1, from_slew_annotation, axis_value2, - axis_value3, - cell_->libertyLibrary()->units()->timeUnit(), digits); + const Unit *time_unit = cell_->libertyLibrary()->units()->timeUnit(); + result += check_models_->model()->reportValue(result_name, cell_, pvt, + axis_value1, from_slew_annotation, + axis_value2, axis_value3, + time_unit, digits); return result; } return ""; @@ -548,31 +598,32 @@ CheckTableModel::findAxisValues(float from_slew, float &axis_value2, float &axis_value3) const { - switch (model_->order()) { + TableModel *model = check_models_->model(); + switch (model->order()) { case 0: axis_value1 = 0.0; axis_value2 = 0.0; axis_value3 = 0.0; break; case 1: - axis_value1 = axisValue(model_->axis1(), from_slew, to_slew, + axis_value1 = axisValue(model->axis1(), from_slew, to_slew, related_out_cap); axis_value2 = 0.0; axis_value3 = 0.0; break; case 2: - axis_value1 = axisValue(model_->axis1(), from_slew, to_slew, + axis_value1 = axisValue(model->axis1(), from_slew, to_slew, related_out_cap); - axis_value2 = axisValue(model_->axis2(), from_slew, to_slew, + axis_value2 = axisValue(model->axis2(), from_slew, to_slew, related_out_cap); axis_value3 = 0.0; break; case 3: - axis_value1 = axisValue(model_->axis1(), from_slew, to_slew, + axis_value1 = axisValue(model->axis1(), from_slew, to_slew, related_out_cap); - axis_value2 = axisValue(model_->axis2(), from_slew, to_slew, + axis_value2 = axisValue(model->axis2(), from_slew, to_slew, related_out_cap); - axis_value3 = axisValue(model_->axis3(), from_slew, to_slew, + axis_value3 = axisValue(model->axis3(), from_slew, to_slew, related_out_cap); break; default: @@ -620,8 +671,77 @@ CheckTableModel::checkAxis(const TableAxis *axis) { TableAxisVariable var = axis->variable(); return var == TableAxisVariable::constrained_pin_transition - || var == TableAxisVariable::related_pin_transition - || var == TableAxisVariable::related_out_total_output_net_capacitance; + || var == TableAxisVariable::related_pin_transition + || var == TableAxisVariable::related_out_total_output_net_capacitance; +} + +//////////////////////////////////////////////////////////////// + +TableModels::TableModels() : + model_(nullptr), + sigma_{}, + std_dev_(nullptr), + mean_shift_(nullptr), + skewness_(nullptr) +{ +} + +TableModels::TableModels(TableModel *model) : + model_(model), + sigma_{}, + std_dev_(nullptr), + mean_shift_(nullptr), + skewness_(nullptr) +{ +} + +TableModels::~TableModels() +{ + TableModel *sigma_early = sigma_[EarlyLate::earlyIndex()]; + TableModel *sigma_late = sigma_[EarlyLate::lateIndex()]; + if (sigma_early == sigma_late) + delete sigma_early; + else { + delete sigma_early; + delete sigma_late; + } +} + +void +TableModels::setModel(TableModel *model) +{ + model_.reset(model); +} + +TableModel * +TableModels::sigma(const EarlyLate *early_late) const +{ + return sigma_[early_late->index()]; +} + +void +TableModels::setSigma(TableModel *table, + const EarlyLate *early_late) +{ + sigma_[early_late->index()] = table; +} + +void +TableModels::setMeanShift(TableModel *table) +{ + mean_shift_.reset(table); +} + +void +TableModels::setSkewness(TableModel *table) +{ + skewness_.reset(table); +} + +void +TableModels::setStdDev(TableModel *table) +{ + std_dev_.reset(table); } //////////////////////////////////////////////////////////////// @@ -713,7 +833,7 @@ TableModel::findValue(const LibertyCell *cell, float axis_value3) const { return table_->findValue(axis_value1, axis_value2, axis_value3) - * scaleFactor(cell, pvt); + * scaleFactor(cell, pvt); } float @@ -725,8 +845,8 @@ TableModel::scaleFactor(const LibertyCell *cell, // nominal pvt. return 1.0F; else - return cell->libertyLibrary()->scaleFactor(static_cast(scale_factor_type_), - rf_index_, cell, pvt); + return cell->libertyLibrary()->scaleFactor( + static_cast(scale_factor_type_), rf_index_, cell, pvt); } std::string @@ -740,14 +860,16 @@ TableModel::reportValue(const char *result_name, const Unit *table_unit, int digits) const { - std::string result = table_->reportValue("Table value", cell, pvt, value1, - comment1, value2, value3, table_unit, digits); + std::string result = + table_->reportValue("Table value", cell, pvt, value1, comment1, value2, value3, + table_unit, digits); result += reportPvtScaleFactor(cell, pvt, digits); result += result_name; result += " = "; - result += table_unit->asString(findValue(cell, pvt, value1, value2, value3), digits); + result += + table_unit->asString(findValue(cell, pvt, value1, value2, value3), digits); result += '\n'; return result; } @@ -760,14 +882,11 @@ reportPvt(const LibertyCell *cell, const LibertyLibrary *library = cell->libertyLibrary(); if (pvt == nullptr) pvt = library->defaultOperatingConditions(); - if (pvt) { - std::string result; - stringPrint(result, "P = %.*f V = %.*f T = %.*f\n", - digits, pvt->process(), - digits, pvt->voltage(), - digits, pvt->temperature()); - return result; - } + if (pvt) + return sta::format("P = {:.{}f} V = {:.{}f} T = {:.{}f}\n", + pvt->process(), digits, + pvt->voltage(), digits, + pvt->temperature(), digits); return ""; } @@ -778,13 +897,9 @@ TableModel::reportPvtScaleFactor(const LibertyCell *cell, { if (pvt == nullptr) pvt = cell->libertyLibrary()->defaultOperatingConditions(); - if (pvt) { - std::string result; - stringPrint(result, "PVT scale factor = %.*f\n", - digits, - scaleFactor(cell, pvt)); - return result; - } + if (pvt) + return sta::formatRuntime("PVT scale factor = {:.{}f}\n", + scaleFactor(cell, pvt), digits); return ""; } @@ -959,51 +1074,65 @@ Table::findValue(float axis_value1, return value_; if (order_ == 1) return findValue(axis_value1); - if (order_ == 2) { - size_t size1 = axis1_->size(); - size_t size2 = axis2_->size(); - if (size1 == 1) { - if (size2 == 1) - return value(0, 0); - size_t axis_index2 = axis2_->findAxisIndex(axis_value2); - double x2 = axis_value2; - double y00 = value(0, axis_index2); - double x2l = axis2_->axisValue(axis_index2); - double x2u = axis2_->axisValue(axis_index2 + 1); - double dx2 = (x2 - x2l) / (x2u - x2l); - double y01 = value(0, axis_index2 + 1); - return (1 - dx2) * y00 + dx2 * y01; - } - if (size2 == 1) { - size_t axis_index1 = axis1_->findAxisIndex(axis_value1); - double x1 = axis_value1; - double y00 = value(axis_index1, 0); - double x1l = axis1_->axisValue(axis_index1); - double x1u = axis1_->axisValue(axis_index1 + 1); - double dx1 = (x1 - x1l) / (x1u - x1l); - double y10 = value(axis_index1 + 1, 0); - return (1 - dx1) * y00 + dx1 * y10; - } - size_t axis_index1 = axis1_->findAxisIndex(axis_value1); + if (order_ == 2) + return findValueOrder2(axis_value1, axis_value2); + else + return findValueOrder3(axis_value1, axis_value2, axis_value3); +} + +float +Table::findValueOrder2(float axis_value1, + float axis_value2) const +{ + size_t size1 = axis1_->size(); + size_t size2 = axis2_->size(); + if (size1 == 1) { + if (size2 == 1) + return value(0, 0); size_t axis_index2 = axis2_->findAxisIndex(axis_value2); - double x1 = axis_value1; double x2 = axis_value2; - double y00 = value(axis_index1, axis_index2); - double x1l = axis1_->axisValue(axis_index1); - double x1u = axis1_->axisValue(axis_index1 + 1); - double dx1 = (x1 - x1l) / (x1u - x1l); - double y10 = value(axis_index1 + 1, axis_index2); - double y11 = value(axis_index1 + 1, axis_index2 + 1); + double y00 = value(0, axis_index2); double x2l = axis2_->axisValue(axis_index2); double x2u = axis2_->axisValue(axis_index2 + 1); double dx2 = (x2 - x2l) / (x2u - x2l); - double y01 = value(axis_index1, axis_index2 + 1); - return (1 - dx1) * (1 - dx2) * y00 - + dx1 * (1 - dx2) * y10 - + dx1 * dx2 * y11 - + (1 - dx1) * dx2 * y01; + double y01 = value(0, axis_index2 + 1); + return (1 - dx2) * y00 + dx2 * y01; } - // order_ == 3 - trilinear interpolation + if (size2 == 1) { + size_t axis_index1 = axis1_->findAxisIndex(axis_value1); + double x1 = axis_value1; + double y00 = value(axis_index1, 0); + double x1l = axis1_->axisValue(axis_index1); + double x1u = axis1_->axisValue(axis_index1 + 1); + double dx1 = (x1 - x1l) / (x1u - x1l); + double y10 = value(axis_index1 + 1, 0); + return (1 - dx1) * y00 + dx1 * y10; + } + size_t axis_index1 = axis1_->findAxisIndex(axis_value1); + size_t axis_index2 = axis2_->findAxisIndex(axis_value2); + double x1 = axis_value1; + double x2 = axis_value2; + double y00 = value(axis_index1, axis_index2); + double x1l = axis1_->axisValue(axis_index1); + double x1u = axis1_->axisValue(axis_index1 + 1); + double dx1 = (x1 - x1l) / (x1u - x1l); + double y10 = value(axis_index1 + 1, axis_index2); + double y11 = value(axis_index1 + 1, axis_index2 + 1); + double x2l = axis2_->axisValue(axis_index2); + double x2u = axis2_->axisValue(axis_index2 + 1); + double dx2 = (x2 - x2l) / (x2u - x2l); + double y01 = value(axis_index1, axis_index2 + 1); + return (1 - dx1) * (1 - dx2) * y00 + + dx1 * (1 - dx2) * y10 + + dx1 * dx2 * y11 + + (1 - dx1) * dx2 * y01; +} + +float +Table::findValueOrder3(float axis_value1, + float axis_value2, + float axis_value3) const +{ size_t axis_index1 = axis1_->findAxisIndex(axis_value1); size_t axis_index2 = axis2_->findAxisIndex(axis_value2); size_t axis_index3 = axis3_->findAxisIndex(axis_value3); @@ -1051,13 +1180,10 @@ Table::findValue(float axis_value1, } return (1 - dx1) * (1 - dx2) * (1 - dx3) * y000 - + (1 - dx1) * (1 - dx2) * dx3 * y001 - + (1 - dx1) * dx2 * (1 - dx3) * y010 - + (1 - dx1) * dx2 * dx3 * y011 - + dx1 * (1 - dx2) * (1 - dx3) * y100 - + dx1 * (1 - dx2) * dx3 * y101 - + dx1 * dx2 * (1 - dx3) * y110 - + dx1 * dx2 * dx3 * y111; + + (1 - dx1) * (1 - dx2) * dx3 * y001 + (1 - dx1) * dx2 * (1 - dx3) * y010 + + (1 - dx1) * dx2 * dx3 * y011 + dx1 * (1 - dx2) * (1 - dx3) * y100 + + dx1 * (1 - dx2) * dx3 * y101 + dx1 * dx2 * (1 - dx3) * y110 + + dx1 * dx2 * dx3 * y111; } void @@ -1141,14 +1267,14 @@ Table::reportValue(const char *result_name, case 0: return reportValueOrder0(result_name, comment1, table_unit, digits); case 1: - return reportValueOrder1(result_name, cell, value1, comment1, - value2, value3, table_unit, digits); + return reportValueOrder1(result_name, cell, value1, comment1, value2, value3, + table_unit, digits); case 2: - return reportValueOrder2(result_name, cell, value1, comment1, - value2, value3, table_unit, digits); + return reportValueOrder2(result_name, cell, value1, comment1, value2, value3, + table_unit, digits); case 3: - return reportValueOrder3(result_name, cell, value1, comment1, - value2, value3, table_unit, digits); + return reportValueOrder3(result_name, cell, value1, comment1, value2, value3, + table_unit, digits); default: return ""; } @@ -1315,12 +1441,12 @@ Table::reportValueOrder3(const char *result_name, result += " "; result += unit1->asString(axis1_->axisValue(axis_index1 + 1), digits); result += " v / "; - result += table_unit->asString(value(axis_index1 + 1, axis_index2, - axis_index3), digits); + result += table_unit->asString(value(axis_index1 + 1, axis_index2, axis_index3), + digits); if (axis3_->size() != 1) { result += " "; - result += table_unit->asString(value(axis_index1 + 1, axis_index2, - axis_index3 + 1), digits); + result += table_unit->asString( + value(axis_index1 + 1, axis_index2, axis_index3 + 1), digits); } } else { @@ -1332,22 +1458,22 @@ Table::reportValueOrder3(const char *result_name, result += " "; result += unit2->asString(axis2_->axisValue(axis_index2), digits); result += " | "; - result += table_unit->asString(value(axis_index1, axis_index2, - axis_index3), digits); + result += + table_unit->asString(value(axis_index1, axis_index2, axis_index3), digits); if (axis3_->size() != 1) { result += " "; - result += table_unit->asString(value(axis_index1, axis_index2, - axis_index3 + 1), digits); + result += table_unit->asString(value(axis_index1, axis_index2, axis_index3 + 1), + digits); } result += '\n'; result += " |/ "; if (axis1_->size() != 1 && axis2_->size() != 1) { - result += table_unit->asString(value(axis_index1 + 1, axis_index2 + 1, - axis_index3), digits); + result += table_unit->asString( + value(axis_index1 + 1, axis_index2 + 1, axis_index3), digits); if (axis3_->size() != 1) { result += " "; - result += table_unit->asString(value(axis_index1 + 1, axis_index2 + 1, - axis_index3 + 1), digits); + result += table_unit->asString( + value(axis_index1 + 1, axis_index2 + 1, axis_index3 + 1), digits); } } result += '\n'; @@ -1355,12 +1481,12 @@ Table::reportValueOrder3(const char *result_name, result += unit2->asString(axis2_->axisValue(axis_index2 + 1), digits); result += " | "; if (axis2_->size() != 1) { - result += table_unit->asString(value(axis_index1, axis_index2 + 1, - axis_index3), digits); + result += table_unit->asString(value(axis_index1, axis_index2 + 1, axis_index3), + digits); if (axis3_->size() != 1) { result += " "; - result += table_unit->asString(value(axis_index1, axis_index2 + 1, - axis_index3 + 1), digits); + result += table_unit->asString( + value(axis_index1, axis_index2 + 1, axis_index3 + 1), digits); } } result += '\n'; @@ -1378,38 +1504,38 @@ Table::report(const Units *units, int digits = 4; const Unit *table_unit = units->timeUnit(); if (order_ == 0) { - report->reportLine("%s", table_unit->asString(value_, digits)); + report->report("{}", table_unit->asString(value_, digits)); return; } if (order_ == 1) { const Unit *unit1 = axis1_->unit(units); - report->reportLine("%s", tableVariableString(axis1_->variable())); - report->reportLine("------------------------------"); + report->report("{}", tableVariableString(axis1_->variable())); + report->report("------------------------------"); std::string line; for (size_t index1 = 0; index1 < axis1_->size(); index1++) { line += unit1->asString(axis1_->axisValue(index1), digits); line += " "; } - report->reportLineString(line); + report->reportLine(line); line.clear(); for (size_t index1 = 0; index1 < axis1_->size(); index1++) { line += table_unit->asString(value(index1), digits); line += " "; } - report->reportLineString(line); + report->reportLine(line); return; } if (order_ == 2) { const Unit *unit1 = axis1_->unit(units); const Unit *unit2 = axis2_->unit(units); - report->reportLine("%s", tableVariableString(axis2_->variable())); - report->reportLine(" ------------------------------"); + report->report("{}", tableVariableString(axis2_->variable())); + report->report(" ------------------------------"); std::string line = " "; for (size_t index2 = 0; index2 < axis2_->size(); index2++) { line += unit2->asString(axis2_->axisValue(index2), digits); line += " "; } - report->reportLineString(line); + report->reportLine(line); for (size_t index1 = 0; index1 < axis1_->size(); index1++) { line = unit1->asString(axis1_->axisValue(index1), digits); line += " |"; @@ -1417,7 +1543,7 @@ Table::report(const Units *units, line += table_unit->asString(value(index1, index2), digits); line += " "; } - report->reportLineString(line); + report->reportLine(line); } return; } @@ -1426,24 +1552,25 @@ Table::report(const Units *units, const Unit *unit2 = axis2_->unit(units); const Unit *unit3 = axis3_->unit(units); for (size_t axis_index1 = 0; axis_index1 < axis1_->size(); axis_index1++) { - report->reportLine("%s %s", tableVariableString(axis1_->variable()), - unit1->asString(axis1_->axisValue(axis_index1), digits)); - report->reportLine("%s", tableVariableString(axis3_->variable())); - report->reportLine(" ------------------------------"); + report->report("{} {}", tableVariableString(axis1_->variable()), + unit1->asString(axis1_->axisValue(axis_index1), digits)); + report->report("{}", tableVariableString(axis3_->variable())); + report->report(" ------------------------------"); std::string line = " "; for (size_t axis_index3 = 0; axis_index3 < axis3_->size(); axis_index3++) { line += unit3->asString(axis3_->axisValue(axis_index3), digits); line += " "; } - report->reportLineString(line); + report->reportLine(line); for (size_t axis_index2 = 0; axis_index2 < axis2_->size(); axis_index2++) { line = unit2->asString(axis2_->axisValue(axis_index2), digits); line += " |"; for (size_t axis_index3 = 0; axis_index3 < axis3_->size(); axis_index3++) { - line += table_unit->asString(value(axis_index1, axis_index2, axis_index3), digits); + line += table_unit->asString(value(axis_index1, axis_index2, axis_index3), + digits); line += " "; } - report->reportLineString(line); + report->reportLine(line); } } } @@ -1488,9 +1615,7 @@ bool TableAxis::inBounds(float value) const { size_t size = values_.size(); - return size > 1 - && value >= values_[0] - && value <= values_[size - 1]; + return size > 1 && value >= values_[0] && value <= values_[size - 1]; } size_t @@ -1532,9 +1657,7 @@ TableAxis::findAxisIndex(float value, bool &exists) const { size_t size = values_.size(); - if (size != 0 - && value >= values_[0] - && value <= values_[size - 1]) { + if (size != 0 && value >= values_[0] && value <= values_[size - 1]) { int lower = -1; int upper = size; while (upper - lower > 1) { @@ -1592,27 +1715,28 @@ TableAxis::unit(const Units *units) //////////////////////////////////////////////////////////////// -static EnumNameMap table_axis_variable_map = - {{TableAxisVariable::total_output_net_capacitance, "total_output_net_capacitance"}, - {TableAxisVariable::equal_or_opposite_output_net_capacitance, "equal_or_opposite_output_net_capacitance"}, - {TableAxisVariable::input_net_transition, "input_net_transition"}, - {TableAxisVariable::input_transition_time, "input_transition_time"}, - {TableAxisVariable::related_pin_transition, "related_pin_transition"}, - {TableAxisVariable::constrained_pin_transition, "constrained_pin_transition"}, - {TableAxisVariable::output_pin_transition, "output_pin_transition"}, - {TableAxisVariable::connect_delay, "connect_delay"}, - {TableAxisVariable::related_out_total_output_net_capacitance, - "related_out_total_output_net_capacitance"}, - {TableAxisVariable::time, "time"}, - {TableAxisVariable::iv_output_voltage, "iv_output_voltage"}, - {TableAxisVariable::input_noise_width, "input_noise_width"}, - {TableAxisVariable::input_noise_height, "input_noise_height"}, - {TableAxisVariable::input_voltage, "input_voltage"}, - {TableAxisVariable::output_voltage, "output_voltage"}, - {TableAxisVariable::path_depth, "path_depth"}, - {TableAxisVariable::path_distance, "path_distance"}, - {TableAxisVariable::normalized_voltage, "normalized_voltage"} - }; +static EnumNameMap table_axis_variable_map = { + {TableAxisVariable::total_output_net_capacitance, + "total_output_net_capacitance"}, + {TableAxisVariable::equal_or_opposite_output_net_capacitance, + "equal_or_opposite_output_net_capacitance"}, + {TableAxisVariable::input_net_transition, "input_net_transition"}, + {TableAxisVariable::input_transition_time, "input_transition_time"}, + {TableAxisVariable::related_pin_transition, "related_pin_transition"}, + {TableAxisVariable::constrained_pin_transition, "constrained_pin_transition"}, + {TableAxisVariable::output_pin_transition, "output_pin_transition"}, + {TableAxisVariable::connect_delay, "connect_delay"}, + {TableAxisVariable::related_out_total_output_net_capacitance, + "related_out_total_output_net_capacitance"}, + {TableAxisVariable::time, "time"}, + {TableAxisVariable::iv_output_voltage, "iv_output_voltage"}, + {TableAxisVariable::input_noise_width, "input_noise_width"}, + {TableAxisVariable::input_noise_height, "input_noise_height"}, + {TableAxisVariable::input_voltage, "input_voltage"}, + {TableAxisVariable::output_voltage, "output_voltage"}, + {TableAxisVariable::path_depth, "path_depth"}, + {TableAxisVariable::path_distance, "path_distance"}, + {TableAxisVariable::normalized_voltage, "normalized_voltage"}}; TableAxisVariable stringTableAxisVariable(const char *variable) @@ -1631,30 +1755,30 @@ tableVariableUnit(TableAxisVariable variable, const Units *units) { switch (variable) { - case TableAxisVariable::total_output_net_capacitance: - case TableAxisVariable::related_out_total_output_net_capacitance: - case TableAxisVariable::equal_or_opposite_output_net_capacitance: - return units->capacitanceUnit(); - case TableAxisVariable::input_net_transition: - case TableAxisVariable::input_transition_time: - case TableAxisVariable::related_pin_transition: - case TableAxisVariable::constrained_pin_transition: - case TableAxisVariable::output_pin_transition: - case TableAxisVariable::connect_delay: - case TableAxisVariable::time: - case TableAxisVariable::input_noise_height: - return units->timeUnit(); - case TableAxisVariable::input_voltage: - case TableAxisVariable::output_voltage: - case TableAxisVariable::iv_output_voltage: - case TableAxisVariable::input_noise_width: - return units->voltageUnit(); - case TableAxisVariable::path_distance: - return units->distanceUnit(); - case TableAxisVariable::path_depth: - case TableAxisVariable::normalized_voltage: - case TableAxisVariable::unknown: - return units->scalarUnit(); + case TableAxisVariable::total_output_net_capacitance: + case TableAxisVariable::related_out_total_output_net_capacitance: + case TableAxisVariable::equal_or_opposite_output_net_capacitance: + return units->capacitanceUnit(); + case TableAxisVariable::input_net_transition: + case TableAxisVariable::input_transition_time: + case TableAxisVariable::related_pin_transition: + case TableAxisVariable::constrained_pin_transition: + case TableAxisVariable::output_pin_transition: + case TableAxisVariable::connect_delay: + case TableAxisVariable::time: + case TableAxisVariable::input_noise_height: + return units->timeUnit(); + case TableAxisVariable::input_voltage: + case TableAxisVariable::output_voltage: + case TableAxisVariable::iv_output_voltage: + case TableAxisVariable::input_noise_width: + return units->voltageUnit(); + case TableAxisVariable::path_distance: + return units->distanceUnit(); + case TableAxisVariable::path_depth: + case TableAxisVariable::normalized_voltage: + case TableAxisVariable::unknown: + return units->scalarUnit(); } // Prevent warnings from lame compilers. return nullptr; @@ -1690,12 +1814,13 @@ OutputWaveforms::checkAxes(const TableTemplate *tbl_template) const TableAxis *axis2 = tbl_template->axis2(); const TableAxis *axis3 = tbl_template->axis3(); return (axis1 && axis1->variable() == TableAxisVariable::input_net_transition - && axis2->variable() == TableAxisVariable::time - && axis3 == nullptr) - || (axis1 && axis1->variable() == TableAxisVariable::input_net_transition - && axis2 && axis2->variable() == TableAxisVariable::total_output_net_capacitance + && axis2->variable() == TableAxisVariable::time && axis3 == nullptr) + || (axis1 && axis1->variable() == TableAxisVariable::input_net_transition + && axis2 + && axis2->variable() == TableAxisVariable::total_output_net_capacitance && axis3->variable() == TableAxisVariable::time) - || (axis1 && axis1->variable() == TableAxisVariable::total_output_net_capacitance + || (axis1 + && axis1->variable() == TableAxisVariable::total_output_net_capacitance && axis2 && axis2->variable() == TableAxisVariable::input_net_transition && axis3->variable() == TableAxisVariable::time); } @@ -1748,8 +1873,8 @@ OutputWaveforms::findVoltages(size_t wave_index, // Make voltage -> current table. FloatSeq axis_volts = volts; - TableAxisPtr volt_axis = - std::make_shared(TableAxisVariable::input_voltage, std::move(axis_volts)); + TableAxisPtr volt_axis = std::make_shared( + TableAxisVariable::input_voltage, std::move(axis_volts)); FloatSeq *currents1 = new FloatSeq(*currents->values()); Table *volt_currents = new Table(currents1, volt_axis); voltage_currents_[wave_index] = volt_currents; @@ -1768,7 +1893,8 @@ OutputWaveforms::currentWaveform(float slew, times->push_back(time); currents->push_back(current); } - TableAxisPtr time_axis = std::make_shared(TableAxisVariable::time, std::move(*times)); + TableAxisPtr time_axis = + std::make_shared(TableAxisVariable::time, std::move(*times)); delete times; return Table(currents, time_axis); } @@ -1850,11 +1976,8 @@ OutputWaveforms::voltageTime1(double volt, double y01 = voltageTime2(volt, wave_index01); double y10 = voltageTime2(volt, wave_index10); double y11 = voltageTime2(volt, wave_index11); - double time - = (1 - dx1) * (1 - dx2) * y00 - + dx1 * (1 - dx2) * y10 - + dx1 * dx2 * y11 - + (1 - dx1) * dx2 * y01; + double time = (1 - dx1) * (1 - dx2) * y00 + dx1 * (1 - dx2) * y10 + dx1 * dx2 * y11 + + (1 - dx1) * dx2 * y01; return time; } @@ -1919,11 +2042,8 @@ OutputWaveforms::waveformValue(float slew, double y01 = waveform01->findValueClip(axis_value); double y10 = waveform10->findValueClip(axis_value); double y11 = waveform11->findValueClip(axis_value); - double wave_value - = (1 - dx1) * (1 - dx2) * y00 - + dx1 * (1 - dx2) * y10 - + dx1 * dx2 * y11 - + (1 - dx1) * dx2 * y01; + double wave_value = (1 - dx1) * (1 - dx2) * y00 + dx1 * (1 - dx2) * y10 + + dx1 * dx2 * y11 + (1 - dx1) * dx2 * y01; return wave_value; } @@ -1945,8 +2065,8 @@ OutputWaveforms::voltageWaveform(float slew, times.push_back(time); volts.push_back(volt); } - TableAxisPtr time_axis = std::make_shared(TableAxisVariable::time, - std::move(times)); + TableAxisPtr time_axis = + std::make_shared(TableAxisVariable::time, std::move(times)); return Table(std::move(volts), time_axis); } @@ -1963,8 +2083,8 @@ OutputWaveforms::voltageWaveformRaw(float slew, float OutputWaveforms::voltageTime(float slew, - float cap, - float volt) + float cap, + float volt) { size_t slew_index = slew_axis_->findAxisIndex(slew); size_t cap_index = cap_axis_->findAxisIndex(cap); @@ -2049,11 +2169,8 @@ OutputWaveforms::beginEndTime(float slew, y11 = waveform11->axis1()->max(); } - float wave_value - = (1 - dx1) * (1 - dx2) * y00 - + dx1 * (1 - dx2) * y10 - + dx1 * dx2 * y11 - + (1 - dx1) * dx2 * y01; + float wave_value = (1 - dx1) * (1 - dx2) * y00 + dx1 * (1 - dx2) * y10 + + dx1 * dx2 * y11 + (1 - dx1) * dx2 * y01; return wave_value; } @@ -2069,8 +2186,8 @@ OutputWaveforms::voltageCurrentWaveform(float slew, volts->push_back(volt); currents->push_back(current); } - TableAxisPtr volt_axis = - std::make_shared(TableAxisVariable::input_voltage, std::move(*volts)); + TableAxisPtr volt_axis = std::make_shared( + TableAxisVariable::input_voltage, std::move(*volts)); delete volts; return Table(currents, volt_axis); } @@ -2112,11 +2229,11 @@ DriverWaveform::waveform(float slew) time_values->push_back(time); volt_values->push_back(volt); } - TableAxisPtr time_axis = std::make_shared(TableAxisVariable::time, - std::move(*time_values)); + TableAxisPtr time_axis = + std::make_shared(TableAxisVariable::time, std::move(*time_values)); delete time_values; Table waveform(volt_values, time_axis); return waveform; } -} // namespace +} // namespace sta diff --git a/liberty/TimingArc.cc b/liberty/TimingArc.cc index 5d77e931..375ad68e 100644 --- a/liberty/TimingArc.cc +++ b/liberty/TimingArc.cc @@ -152,9 +152,8 @@ TimingArc::intrinsicDelay() const { GateTimingModel *model = dynamic_cast(model_); if (model) { - ArcDelay arc_delay; - Slew slew; - model->gateDelay(nullptr, 0.0, 0.0, false, arc_delay, slew); + float arc_delay, slew; + model->gateDelay(nullptr, 0.0, 0.0, arc_delay, slew); return arc_delay; } else diff --git a/liberty/Units.cc b/liberty/Units.cc index 98cad0aa..fb3fcdb6 100644 --- a/liberty/Units.cc +++ b/liberty/Units.cc @@ -26,6 +26,7 @@ #include // abs +#include "Format.hh" #include "StringUtil.hh" #include "MinMax.hh" // INF #include "Fuzzy.hh" @@ -127,7 +128,7 @@ Unit::scaleString() const else if (fuzzyEqual(scale_, 1E-15)) return "1f"; else - return stdstrPrint("%.1e", scale_); + return sta::format("{:.1e}", scale_); } std::string @@ -155,19 +156,13 @@ Unit::width() const return digits_ + 2; } -const char * +std::string Unit::asString(float value) const { return asString(value, digits_); } -const char * -Unit::asString(double value) const -{ - return asString(static_cast(value), digits_); -} - -const char * +std::string Unit::asString(float value, int digits) const { @@ -179,7 +174,7 @@ Unit::asString(float value, // prevent "-0.00" on slowaris if (std::abs(scaled_value) < 1E-6) scaled_value = 0.0; - return stringPrintTmp("%.*f", digits, scaled_value); + return sta::formatRuntime("{:.{}f}", scaled_value, digits); } } diff --git a/network/ConcreteLibrary.cc b/network/ConcreteLibrary.cc index 50bc62b2..1d18d24d 100644 --- a/network/ConcreteLibrary.cc +++ b/network/ConcreteLibrary.cc @@ -222,12 +222,10 @@ ConcreteCell::makeBusPortBit(ConcretePort *bus_port, const char *bus_name, int bit_index) { - std::string bit_name; - stringPrint(bit_name, "%s%c%d%c", - bus_name, - library_->busBrktLeft(), - bit_index, - library_->busBrktRight()); + std::string bit_name = std::string(bus_name) + + library_->busBrktLeft() + + std::to_string(bit_index) + + library_->busBrktRight(); ConcretePort *port = makePort(bit_name.c_str(), bit_index); bus_port->addPortBit(port); addPortBit(port); @@ -465,12 +463,13 @@ ConcretePort::busName() const { if (is_bus_) { ConcreteLibrary *lib = cell_->library(); - return stringPrintTmp("%s%c%d:%d%c", - name(), - lib->busBrktLeft(), - from_index_, - to_index_, - lib->busBrktRight()); + std::string bus_name = sta::format("{}{}{}:{}{}", + name(), + lib->busBrktLeft(), + from_index_, + to_index_, + lib->busBrktRight()); + return makeTmpString(bus_name); } else return name(); diff --git a/network/ConcreteNetwork.cc b/network/ConcreteNetwork.cc index de4b0464..6291d5bc 100644 --- a/network/ConcreteNetwork.cc +++ b/network/ConcreteNetwork.cc @@ -2003,7 +2003,7 @@ ConcreteNetwork::linkNetwork(const char *top_cell_name, return top_instance_ != nullptr; } else { - report->error(1000, "cell type %s can not be linked.", top_cell_name); + report->error(1000, "cell type {} can not be linked.", top_cell_name); return false; } } diff --git a/network/HpinDrvrLoad.cc b/network/HpinDrvrLoad.cc index 2c98c5fa..ab76900d 100644 --- a/network/HpinDrvrLoad.cc +++ b/network/HpinDrvrLoad.cc @@ -293,15 +293,16 @@ HpinDrvrLoad::~HpinDrvrLoad() void HpinDrvrLoad::report(const Network *network) { - printf("%s -> %s: ", - drvr_ ? network->pathName(drvr_) : "-", - load_ ? network->pathName(load_) : "-"); + Report *report = network->report(); + std::string line = sta::format("{} -> {}: ", + drvr_ ? network->pathName(drvr_) : "-", + load_ ? network->pathName(load_) : "-"); for (const Pin *pin : *hpins_from_drvr_) - printf("%s ", network->pathName(pin)); - printf("* "); + line += sta::format("{} ", network->pathName(pin)); + line += "* "; for (const Pin *pin : *hpins_to_load_) - printf("%s ", network->pathName(pin)); - printf("\n"); + line += sta::format("{} ", network->pathName(pin)); + report->report(line); } void diff --git a/network/Network.cc b/network/Network.cc index fe9a9c1d..b0a7d635 100644 --- a/network/Network.cc +++ b/network/Network.cc @@ -262,24 +262,15 @@ Network::pathName(const Instance *instance) const { InstanceSeq inst_path; path(instance, inst_path); - size_t name_length = 0; - for (const Instance *inst : inst_path) - name_length += strlen(name(inst)) + 1; - char *path_name = makeTmpString(name_length + 1); - char *path_ptr = path_name; - // Top instance has null string name, so terminate the string here. - *path_name = '\0'; + std::string path_name; while (inst_path.size()) { const Instance *inst = inst_path.back(); - const char *inst_name = name(inst); - strcpy(path_ptr, inst_name); - path_ptr += strlen(inst_name); + path_name += name(inst); inst_path.pop_back(); - if (inst_path.size()) - *path_ptr++ = pathDivider(); - *path_ptr = '\0'; + if (!inst_path.empty()) + path_name += pathDivider(); } - return path_name; + return makeTmpString(path_name); } bool @@ -376,18 +367,10 @@ Network::pathName(const Pin *pin) const { const Instance *inst = instance(pin); if (inst && inst != topInstance()) { - const char *inst_name = pathName(inst); - size_t inst_name_length = strlen(inst_name); - const char *port_name = portName(pin); - size_t port_name_length = strlen(port_name); - size_t path_name_length = inst_name_length + port_name_length + 2; - char *path_name = makeTmpString(path_name_length); - char *path_ptr = path_name; - strcpy(path_ptr, inst_name); - path_ptr += inst_name_length; - *path_ptr++ = pathDivider(); - strcpy(path_ptr, port_name); - return path_name; + std::string path_name = pathName(inst); + path_name += pathDivider(); + path_name += portName(pin); + return makeTmpString(path_name); } else return portName(pin); @@ -464,18 +447,10 @@ Network::pathName(const Net *net) const { const Instance *inst = instance(net); if (inst && inst != topInstance()) { - const char *inst_name = pathName(inst); - size_t inst_name_length = strlen(inst_name); - const char *net_name = name(net); - size_t net_name_length = strlen(net_name); - size_t path_name_length = inst_name_length + net_name_length + 2; - char *path_name = makeTmpString(path_name_length); - char *path_ptr = path_name; - strcpy(path_ptr, inst_name); - path_ptr += inst_name_length; - *path_ptr++ = pathDivider(); - strcpy(path_ptr, net_name); - return path_name; + std::string path_name = pathName(inst); + path_name += pathDivider(); + path_name += name(net); + return makeTmpString(path_name); } else return name(net); diff --git a/network/Network.i b/network/Network.i index 6495ec8b..c07f6de8 100644 --- a/network/Network.i +++ b/network/Network.i @@ -511,7 +511,7 @@ net_pins(Net *net) return pins; } -const char * +std::string pin_location(const Pin *pin) { Network *network = Sta::sta()->ensureLinked(); @@ -520,12 +520,12 @@ pin_location(const Pin *pin) network->location(pin, x, y, exists); // return x/y as tcl list if (exists) - return sta::stringPrintTmp("%f %f", x, y); + return sta::format("{} {}", x, y); else return ""; } -const char * +std::string port_location(const Port *port) { Network *network = Sta::sta()->ensureLinked(); diff --git a/network/ParseBus.cc b/network/ParseBus.cc index 83f097b3..7bbab7a0 100644 --- a/network/ParseBus.cc +++ b/network/ParseBus.cc @@ -24,35 +24,34 @@ #include "ParseBus.hh" -#include -#include #include +#include #include "StringUtil.hh" namespace sta { bool -isBusName(const char *name, +isBusName(std::string_view name, const char brkt_left, const char brkt_right, char escape) { - size_t len = strlen(name); + size_t len = name.size(); // Shortest bus name is a[0]. if (len >= 4 // Escaped bus brackets are not buses. && name[len - 2] != escape && name[len - 1] == brkt_right) { - const char *left = strrchr(name, brkt_left); - return left != nullptr; + size_t left = name.rfind(brkt_left); + return left != std::string_view::npos; } else return false; } void -parseBusName(const char *name, +parseBusName(std::string_view name, const char brkt_left, const char brkt_right, const char escape, @@ -61,16 +60,15 @@ parseBusName(const char *name, std::string &bus_name, int &index) { - const char brkts_left[2] = {brkt_left, '\0'}; - const char brkts_right[2] = {brkt_right, '\0'}; - parseBusName(name, brkts_left, brkts_right, escape, + parseBusName(name, std::string_view(&brkt_left, 1), + std::string_view(&brkt_right, 1), escape, is_bus, bus_name, index); } void -parseBusName(const char *name, - const char *brkts_left, - const char *brkts_right, +parseBusName(std::string_view name, + std::string_view brkts_left, + std::string_view brkts_right, char escape, // Return values. bool &is_bus, @@ -78,30 +76,28 @@ parseBusName(const char *name, int &index) { is_bus = false; - size_t len = strlen(name); + size_t len = name.size(); // Shortest bus name is a[0]. if (len >= 4 // Escaped bus brackets are not buses. && name[len - 2] != escape) { char last_ch = name[len - 1]; - const char *brkt_right_ptr = strchr(brkts_right, last_ch); - if (brkt_right_ptr) { - size_t brkt_index = brkt_right_ptr - brkts_right; - char brkt_left = brkts_left[brkt_index]; - const char *left = strrchr(name, brkt_left); - if (left) { + size_t brkt_index = brkts_right.find(last_ch); + if (brkt_index != std::string_view::npos) { + char brkt_left_ch = brkts_left[brkt_index]; + size_t left = name.rfind(brkt_left_ch); + if (left != std::string_view::npos) { is_bus = true; - size_t bus_name_len = left - name; - bus_name.append(name, bus_name_len); + bus_name.append(name.data(), left); // Simple bus subscript. - index = atoi(left + 1); + index = std::stoi(std::string(name.substr(left + 1))); } } } } void -parseBusName(const char *name, +parseBusName(std::string_view name, const char brkt_left, const char brkt_right, char escape, @@ -113,16 +109,15 @@ parseBusName(const char *name, int &to, bool &subscript_wild) { - const char brkts_left[2] = {brkt_left, '\0'}; - const char brkts_right[2] = {brkt_right, '\0'}; - parseBusName(name, brkts_left, brkts_right, escape, + parseBusName(name, std::string_view(&brkt_left, 1), + std::string_view(&brkt_right, 1), escape, is_bus, is_range, bus_name, from, to, subscript_wild); } void -parseBusName(const char *name, - const char *brkts_left, - const char *brkts_right, +parseBusName(std::string_view name, + std::string_view brkts_left, + std::string_view brkts_right, char escape, // Return values. bool &is_bus, @@ -135,36 +130,31 @@ parseBusName(const char *name, is_bus = false; is_range = false; subscript_wild = false; - size_t len = strlen(name); + size_t len = name.size(); // Shortest bus is a[0]. if (len >= 4 // Escaped bus brackets are not buses. && name[len - 2] != escape) { char last_ch = name[len - 1]; - const char *brkt_right_ptr = strchr(brkts_right, last_ch); - if (brkt_right_ptr) { - size_t brkt_index = brkt_right_ptr - brkts_right; - char brkt_left = brkts_left[brkt_index]; - const char *left = strrchr(name, brkt_left); - if (left) { + size_t brkt_index = brkts_right.find(last_ch); + if (brkt_index != std::string_view::npos) { + char brkt_left_ch = brkts_left[brkt_index]; + size_t left = name.rfind(brkt_left_ch); + if (left != std::string_view::npos) { is_bus = true; + bus_name.append(name.data(), left); // Check for bus range. - const char range_sep = ':'; - const char *range = strchr(name, range_sep); - if (range) { + size_t range = name.find(':', left); + if (range != std::string_view::npos) { is_range = true; - bus_name.append(name, left - name); - // No need to terminate bus subscript because atoi stops - // scanning at first non-digit character. - from = atoi(left + 1); - to = atoi(range + 1); + from = std::stoi(std::string(name.substr(left + 1))); + to = std::stoi(std::string(name.substr(range + 1))); } else { - bus_name.append(name, left - name); - if (left[1] == '*') + if (left + 1 < len && name[left + 1] == '*') subscript_wild = true; else - from = to = atoi(left + 1); + from = to = std::stoi(std::string(name.substr(left + 1))); } } } @@ -172,22 +162,23 @@ parseBusName(const char *name, } std::string -escapeChars(const char *token, +escapeChars(std::string_view token, const char ch1, const char ch2, const char escape) { std::string escaped; - for (const char *s = token; *s; s++) { - char ch = *s; + escaped.reserve(token.size()); + for (size_t i = 0; i < token.size(); i++) { + char ch = token[i]; if (ch == escape) { - char next_ch = s[1]; - // Make sure we don't skip the null if escape is the last char. - if (next_ch != '\0') { + if (i + 1 < token.size()) { escaped += ch; - escaped += next_ch; - s++; + escaped += token[i + 1]; + i++; } + else + escaped += ch; } else if (ch == ch1 || ch == ch2) { escaped += escape; diff --git a/network/SdcNetwork.cc b/network/SdcNetwork.cc index 5200367e..4cdef63e 100644 --- a/network/SdcNetwork.cc +++ b/network/SdcNetwork.cc @@ -640,28 +640,27 @@ SdcNetwork::SdcNetwork(Network *network) : // Translate sta namespace to sdc namespace. // Remove all escapes. const char * -SdcNetwork::staToSdc(const char *sta_name) const +SdcNetwork::staToSdc(std::string_view sta_name) const { char escape = pathEscape(); - char *sdc_name = makeTmpString(strlen(sta_name) + 1); - char *d = sdc_name; - for (const char *s = sta_name; *s; s++) { - char ch = s[0]; + size_t sta_length = sta_name.length(); + std::string sdc_name; + for (size_t i = 0; i < sta_length; i++) { + char ch = sta_name[i]; if (ch == escape) { - char next_ch = s[1]; + char next_ch = sta_name[i + 1]; // Escaped escape. if (next_ch == escape) { - *d++ = ch; - *d++ = next_ch; - s++; + sdc_name += ch; + sdc_name += next_ch; + i++; } } else // Non escape. - *d++ = ch; + sdc_name += ch; } - *d++ = '\0'; - return sdc_name; + return makeTmpString(sdc_name); } Port * @@ -680,11 +679,11 @@ SdcNetwork::findPort(const Cell *cell, port = network_->findPort(cell, escaped1.c_str()); if (port == nullptr) { // Try escaping base foo\[0\][1] - std::string escaped2; std::string escaped_bus_name = escapeBrackets(bus_name.c_str(), this); - stringPrint(escaped2, "%s[%d]", - escaped_bus_name.c_str(), - index); + std::string escaped2 = escaped_bus_name + + '[' + + std::to_string(index) + + ']'; port = network_->findPort(cell, escaped2.c_str()); } } @@ -966,8 +965,10 @@ SdcNetwork::findPin(const Instance *instance, if (pin == nullptr) { // Try escaping base foo\[0\][1] std::string escaped_bus_name = escapeBrackets(bus_name.c_str(), this); - std::string escaped2; - stringPrint(escaped2, "%s[%d]", escaped_bus_name.c_str(), index); + std::string escaped2 = escaped_bus_name + + '[' + + std::to_string(index) + + ']'; pin = network_->findPin(instance, escaped2.c_str()); } } @@ -1149,46 +1150,39 @@ SdcNetwork::parsePath(const char *path, const char *&path_tail) const { Instance *parent = topInstance(); + std::string inst_path; // Leave room to escape all the dividers and '\0'. - int inst_path_length = path_length + divider_count + 1; - char *inst_path = new char[inst_path_length]; + inst_path.reserve(path_length + divider_count + 1); inst = nullptr; path_tail = path; - char *p = inst_path; for (const char *s = path; *s; s++) { char ch = *s; if (ch == escape_) { // Make sure we don't skip the null if escape is the last char. if (s[1] != '\0') { - *p++ = ch; - *p++ = s[1]; + inst_path += ch; + inst_path += s[1]; s++; } } else if (ch == divider_) { - // Terminate the sub-path up to this divider. - *p = '\0'; - Instance *child = findChild(parent, inst_path); + Instance *child = findChild(parent, inst_path.c_str()); if (child) { // Found an instance for the sub-path up to this divider. parent = inst = child; // Reset the instance path. - p = inst_path; + inst_path.clear(); path_tail = s + 1; } else { // No match for sub-path. Escape the divider and keep looking. - *p++ = escape_; - *p++ = divider_; + inst_path += escape_; + inst_path += divider_; } } else - *p++ = ch; - if (p - inst_path + 1 > inst_path_length) - report_->critical(1500, "inst path std::string lenth estimate busted"); + inst_path += ch; } - *p = '\0'; - stringDelete(inst_path); } // Helper to visit instance path matches. @@ -1207,11 +1201,9 @@ SdcNetwork::visitMatches(const Instance *parent, { int divider_count, path_length; scanPath(pattern->pattern(), divider_count, path_length); - + std::string inst_path; // Leave room to escape all the dividers and '\0'. - int inst_path_length = path_length + divider_count + 1; - char *inst_path = new char[inst_path_length]; - char *p = inst_path; + inst_path.reserve(path_length + divider_count + 1); bool has_brkts = false; bool found_match = false; for (const char *s = pattern->pattern(); *s; s++) { @@ -1219,20 +1211,18 @@ SdcNetwork::visitMatches(const Instance *parent, if (ch == escape_) { // Make sure we don't skip the null if escape is the last char. if (s[1] != '\0') { - *p++ = ch; - *p++ = s[1]; + inst_path += ch; + inst_path += s[1]; s++; } } else if (ch == divider_) { - // Terminate the sub-path up to this divider. - *p = '\0'; - PatternMatch matcher(inst_path, pattern); + PatternMatch matcher(inst_path.c_str(), pattern); InstanceSeq matches; network_->findChildrenMatching(parent, &matcher, matches); if (has_brkts && matches.empty()) { // Look for matches after escaping brackets. - std::string escaped_brkts = escapeBrackets(inst_path, this); + std::string escaped_brkts = escapeBrackets(inst_path.c_str(), this); const PatternMatch escaped_pattern(escaped_brkts, pattern); network_->findChildrenMatching(parent, &escaped_pattern, matches); } @@ -1245,29 +1235,25 @@ SdcNetwork::visitMatches(const Instance *parent, found_match |= visitMatches(match, &tail_pattern, visit_tail); } // Escape the divider and keep looking. - *p++ = escape_; - *p++ = divider_; + inst_path += escape_; + inst_path += divider_; } else { if (ch == '[' || ch == ']') has_brkts = true; - *p++ = ch; + inst_path += ch; } - if (p - inst_path + 1 > inst_path_length) - report_->critical(1501, "inst path std::string lenth estimate exceeded"); } - *p = '\0'; if (!found_match) { - PatternMatch tail_pattern(inst_path, pattern); + PatternMatch tail_pattern(inst_path.c_str(), pattern); found_match |= visit_tail(parent, &tail_pattern); if (!found_match && has_brkts) { // Look for matches after escaping brackets. - std::string escaped_path = escapeBrackets(inst_path, this); + std::string escaped_path = escapeBrackets(inst_path.c_str(), this); const PatternMatch escaped_tail(escaped_path, pattern); found_match |= visit_tail(parent, &escaped_tail); } } - stringDelete(inst_path); return found_match; } diff --git a/network/VerilogNamespace.cc b/network/VerilogNamespace.cc index a018782e..702ca6d2 100644 --- a/network/VerilogNamespace.cc +++ b/network/VerilogNamespace.cc @@ -34,35 +34,34 @@ namespace sta { constexpr char verilog_escape = '\\'; static std::string -staToVerilog(const char *sta_name); +staToVerilog(std::string sta_name); static std::string -staToVerilog2(const char *sta_name); +staToVerilog2(std::string sta_name); static std::string -verilogToSta(const std::string *verilog_name); +verilogToSta(const std::string verilog_name); std::string -cellVerilogName(const char *sta_name) +cellVerilogName(std::string sta_name) { return staToVerilog(sta_name); } std::string -instanceVerilogName(const char *sta_name) +instanceVerilogName(std::string sta_name) { return staToVerilog(sta_name); } std::string -netVerilogName(const char *sta_name) +netVerilogName(std::string sta_name) { bool is_bus; std::string bus_name; int index; - parseBusName(sta_name, '[', ']', verilog_escape, is_bus, bus_name, index); + parseBusName(sta_name.c_str(), '[', ']', verilog_escape, is_bus, bus_name, index); if (is_bus) { std::string bus_vname = staToVerilog(bus_name.c_str()); - std::string vname; - stringPrint(vname, "%s[%d]", bus_vname.c_str(), index); + std::string vname = bus_vname + '[' + std::to_string(index) + ']'; return vname; } else @@ -70,27 +69,28 @@ netVerilogName(const char *sta_name) } std::string -portVerilogName(const char *sta_name) +portVerilogName(std::string sta_name) { return staToVerilog2(sta_name); } static std::string -staToVerilog(const char *sta_name) +staToVerilog(std::string sta_name) { // Leave room for leading escape and trailing space if the name // needs to be escaped. // Assume the name has to be escaped and start copying while scanning. std::string escaped_name = "\\"; bool escaped = false; - for (const char *s = sta_name; *s ; s++) { - char ch = s[0]; + size_t sta_length = sta_name.size(); + for (size_t i = 0; i < sta_length; i++) { + char ch = sta_name[i]; if (ch == verilog_escape) { escaped = true; - char next_ch = s[1]; + char next_ch = sta_name[i + 1]; if (next_ch == verilog_escape) { escaped_name += next_ch; - s++; + i++; } } else { @@ -105,11 +105,11 @@ staToVerilog(const char *sta_name) return escaped_name; } else - return std::string(sta_name); + return sta_name; } static std::string -staToVerilog2(const char *sta_name) +staToVerilog2(std::string sta_name) { constexpr char bus_brkt_left = '['; constexpr char bus_brkt_right = ']'; @@ -118,14 +118,15 @@ staToVerilog2(const char *sta_name) std::string escaped_name = "\\"; // Assume the name has to be escaped and start copying while scanning. bool escaped = false; - for (const char *s = sta_name; *s ; s++) { - char ch = s[0]; + size_t sta_length = sta_name.size(); + for (size_t i = 0; i < sta_length; i++) { + char ch = sta_name[i]; if (ch == verilog_escape) { escaped = true; - char next_ch = s[1]; + char next_ch = sta_name[i + 1]; if (next_ch == verilog_escape) { escaped_name += next_ch; - s++; + i++; } } else { @@ -142,50 +143,50 @@ staToVerilog2(const char *sta_name) return escaped_name; } else - return std::string(sta_name); + return sta_name; } //////////////////////////////////////////////////////////////// std::string -moduleVerilogToSta(const std::string *module_name) +moduleVerilogToSta(std::string module_name) { return verilogToSta(module_name); } std::string -instanceVerilogToSta(const std::string *inst_name) +instanceVerilogToSta(std::string inst_name) { return verilogToSta(inst_name); } std::string -netVerilogToSta(const std::string *net_name) +netVerilogToSta(std::string net_name) { return verilogToSta(net_name); } std::string -portVerilogToSta(const std::string *port_name) +portVerilogToSta(std::string port_name) { return verilogToSta(port_name); } static std::string -verilogToSta(const std::string *verilog_name) +verilogToSta(std::string verilog_name) { - if (verilog_name->front() == '\\') { + if (verilog_name.front() == '\\') { constexpr char divider = '/'; constexpr char bus_brkt_left = '['; constexpr char bus_brkt_right = ']'; - size_t verilog_name_length = verilog_name->size(); - if (isspace(verilog_name->back())) + size_t verilog_name_length = verilog_name.size(); + if (isspace(verilog_name.back())) verilog_name_length--; std::string sta_name; // Ignore leading '\'. for (size_t i = 1; i < verilog_name_length; i++) { - char ch = verilog_name->at(i); + char ch = verilog_name[i]; if (ch == bus_brkt_left || ch == bus_brkt_right || ch == divider @@ -197,7 +198,7 @@ verilogToSta(const std::string *verilog_name) return sta_name; } else - return std::string(*verilog_name); + return verilog_name; } } // namespace diff --git a/parasitics/ConcreteParasitics.cc b/parasitics/ConcreteParasitics.cc index db291c53..e85036ee 100644 --- a/parasitics/ConcreteParasitics.cc +++ b/parasitics/ConcreteParasitics.cc @@ -410,8 +410,10 @@ const char * ConcreteParasiticNode::name(const Network *network) const { if (is_net_) { - const char *net_name = network->pathName(net_pin_.net_); - return stringPrintTmp("%s:%d", net_name, id_); + std::string name = std::string(network->pathName(net_pin_.net_)) + + ':' + + std::to_string(id_); + return makeTmpString(name); } else return network->pathName(net_pin_.pin_); diff --git a/parasitics/Parasitics.cc b/parasitics/Parasitics.cc index 8aaf5fc0..ab304bda 100644 --- a/parasitics/Parasitics.cc +++ b/parasitics/Parasitics.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "Parasitics.hh" @@ -49,38 +49,29 @@ Parasitics::report(const Parasitic *parasitic) const { if (isParasiticNetwork(parasitic)) { const Unit *cap_unit = units_->capacitanceUnit(); - report_->reportLine("Net %s %s", - network_->pathName(net(parasitic)), - cap_unit->asString(capacitance(parasitic))); - report_->reportLine("Nodes:"); + report_->report("Net {} {}", network_->pathName(net(parasitic)), + cap_unit->asString(capacitance(parasitic))); + report_->report("Nodes:"); for (ParasiticNode *node : nodes(parasitic)) - report_->reportLine("%s%s %s", - name(node), - isExternal(node) ? " (ext)" : "", - cap_unit->asString(nodeGndCap(node))); - report_->reportLine("Resistors:"); + report_->report("{}{} {}", name(node), isExternal(node) ? " (ext)" : "", + cap_unit->asString(nodeGndCap(node))); + report_->report("Resistors:"); for (ParasiticResistor *res : resistors(parasitic)) { ParasiticNode *node1 = this->node1(res); ParasiticNode *node2 = this->node2(res); - report_->reportLine("%zu %s%s %s%s %s", - id(res), - name(node1), - isExternal(node1) ? " (ext)" : "", - name(node2), - isExternal(node2) ? " (ext)" : "", - units_->resistanceUnit()->asString(value(res))); + report_->report("{} {}{} {}{} {}", id(res), name(node1), + isExternal(node1) ? " (ext)" : "", name(node2), + isExternal(node2) ? " (ext)" : "", + units_->resistanceUnit()->asString(value(res))); } - report_->reportLine("Coupling Capacitors:"); + report_->report("Coupling Capacitors:"); for (ParasiticCapacitor *cap : capacitors(parasitic)) { ParasiticNode *node1 = this->node1(cap); ParasiticNode *node2 = this->node2(cap); - report_->reportLine("%zu %s%s %s%s %s", - id(cap), - name(node1), - isExternal(node1) ? " (ext)" : "", - name(node2), - isExternal(node2) ? " (ext)" : "", - cap_unit->asString(value(cap))); + report_->report("{} {}{} {}{} {}", id(cap), name(node1), + isExternal(node1) ? " (ext)" : "", name(node2), + isExternal(node2) ? " (ext)" : "", + cap_unit->asString(value(cap))); } } } @@ -138,10 +129,10 @@ Parasitics::parasiticNodeResistorMap(const Parasitic *parasitic) const return resistor_map; } -ParasiticNodeCapacitorMap +ParasiticNodeCapacitorMap Parasitics::parasiticNodeCapacitorMap(const Parasitic *parasitic) const { - ParasiticNodeCapacitorMap capacitor_map; + ParasiticNodeCapacitorMap capacitor_map; for (ParasiticCapacitor *capacitor : capacitors(parasitic)) { ParasiticNode *n1 = node1(capacitor); ParasiticNode *n2 = node2(capacitor); @@ -186,9 +177,8 @@ Parasitics::reduceToPiElmore(const Parasitic *parasitic, const Scene *scene, const MinMax *min_max) { - return sta::reduceToPiElmore(parasitic, drvr_pin, rf, - coupling_cap_factor_, - scene, min_max, this); + return sta::reduceToPiElmore(parasitic, drvr_pin, rf, coupling_cap_factor_, scene, + min_max, this); } Parasitic * @@ -198,8 +188,7 @@ Parasitics::reduceToPiPoleResidue2(const Parasitic *parasitic, const Scene *scene, const MinMax *min_max) { - return sta::reduceToPiPoleResidue2(parasitic, drvr_pin, rf, - coupling_cap_factor_, + return sta::reduceToPiPoleResidue2(parasitic, drvr_pin, rf, coupling_cap_factor_, scene, min_max, this); } @@ -217,10 +206,9 @@ Parasitics::estimatePiElmore(const Pin *drvr_pin, EstimateParasitics estimate(this); float c2, rpi, c1, elmore_res, elmore_cap; bool elmore_use_load_cap; - estimate.estimatePiElmore(drvr_pin, rf, wireload, fanout, net_pin_cap, - scene, min_max, - c2, rpi, c1, - elmore_res, elmore_cap, elmore_use_load_cap); + estimate.estimatePiElmore(drvr_pin, rf, wireload, fanout, net_pin_cap, scene, + min_max, c2, rpi, c1, elmore_res, elmore_cap, + elmore_use_load_cap); if (c1 > 0.0 || c2 > 0.0) { Parasitic *parasitic = makePiElmore(drvr_pin, rf, min_max, c2, rpi, c1); @@ -265,19 +253,19 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin, if (op_cond) tree = op_cond->wireloadTree(); switch (tree) { - case WireloadTree::worst_case: - makeWireloadNetworkWorst(parasitic, drvr_pin, net, wireload_cap, - wireload_res, fanout); - break; - case WireloadTree::balanced: - makeWireloadNetworkBalanced(parasitic, drvr_pin, wireload_cap, - wireload_res, fanout); - break; - case WireloadTree::best_case: - case WireloadTree::unknown: - makeWireloadNetworkBest(parasitic, drvr_pin, wireload_cap, - wireload_res, fanout); - break; + case WireloadTree::worst_case: + makeWireloadNetworkWorst(parasitic, drvr_pin, net, wireload_cap, + wireload_res, fanout); + break; + case WireloadTree::balanced: + makeWireloadNetworkBalanced(parasitic, drvr_pin, wireload_cap, wireload_res, + fanout); + break; + case WireloadTree::best_case: + case WireloadTree::unknown: + makeWireloadNetworkBest(parasitic, drvr_pin, wireload_cap, wireload_res, + fanout); + break; } } return parasitic; @@ -298,12 +286,10 @@ Parasitics::makeWireloadNetworkWorst(Parasitic *parasitic, ParasiticNode *load_node = ensureParasiticNode(parasitic, net, 0, network_); makeResistor(parasitic, resistor_index++, wireload_res, drvr_node, load_node); incrCap(load_node, wireload_cap); - PinConnectedPinIterator *load_iter = - network_->connectedPinIterator(drvr_pin); + PinConnectedPinIterator *load_iter = network_->connectedPinIterator(drvr_pin); while (load_iter->hasNext()) { const Pin *load_pin = load_iter->next(); - if (load_pin != drvr_pin - && network_->isLoad(load_pin)) { + if (load_pin != drvr_pin && network_->isLoad(load_pin)) { ParasiticNode *load_node1 = ensureParasiticNode(parasitic, load_pin, network_); makeResistor(parasitic, resistor_index++, 0.0, load_node, load_node1); } @@ -320,13 +306,11 @@ Parasitics::makeWireloadNetworkBest(Parasitic *parasitic, { ParasiticNode *drvr_node = ensureParasiticNode(parasitic, drvr_pin, network_); incrCap(drvr_node, wireload_cap); - PinConnectedPinIterator *load_iter = - network_->connectedPinIterator(drvr_pin); + PinConnectedPinIterator *load_iter = network_->connectedPinIterator(drvr_pin); size_t resistor_index = 1; while (load_iter->hasNext()) { const Pin *load_pin = load_iter->next(); - if (load_pin != drvr_pin - && network_->isLoad(load_pin)) { + if (load_pin != drvr_pin && network_->isLoad(load_pin)) { ParasiticNode *load_node1 = ensureParasiticNode(parasitic, load_pin, network_); makeResistor(parasitic, resistor_index++, 0.0, drvr_node, load_node1); } @@ -345,15 +329,13 @@ Parasitics::makeWireloadNetworkBalanced(Parasitic *parasitic, float fanout_cap = wireload_cap / fanout; float fanout_res = wireload_res / fanout; ParasiticNode *drvr_node = ensureParasiticNode(parasitic, drvr_pin, network_); - PinConnectedPinIterator *load_iter = - network_->connectedPinIterator(drvr_pin); + PinConnectedPinIterator *load_iter = network_->connectedPinIterator(drvr_pin); size_t resistor_index = 1; while (load_iter->hasNext()) { const Pin *load_pin = load_iter->next(); - if (load_pin != drvr_pin - && network_->isLoad(load_pin)) { + if (load_pin != drvr_pin && network_->isLoad(load_pin)) { ParasiticNode *load_node1 = ensureParasiticNode(parasitic, load_pin, network_); - makeResistor(parasitic, resistor_index++, fanout_res, drvr_node, load_node1); + makeResistor(parasitic, resistor_index++, fanout_res, drvr_node, load_node1); incrCap(load_node1, fanout_cap); } } @@ -391,12 +373,10 @@ ParasiticNodeLess::operator()(const ParasiticNode *node1, unsigned id1 = parasitics_->netId(node1); unsigned id2 = parasitics_->netId(node2); return (pin1 == nullptr && pin2) - || (pin1 && pin2 - && network_->id(pin1) < network_->id(pin2)) - || (pin1 == nullptr && pin2 == nullptr - && (network_->id(net1) < network_->id(net2) - || (net1 == net2 - && id1 < id2))); + || (pin1 && pin2 && network_->id(pin1) < network_->id(pin2)) + || (pin1 == nullptr && pin2 == nullptr + && (network_->id(net1) < network_->id(net2) + || (net1 == net2 && id1 < id2))); } -} // namespace +} // namespace sta diff --git a/parasitics/ReduceParasitics.cc b/parasitics/ReduceParasitics.cc index 6dbab37d..4282a7f4 100644 --- a/parasitics/ReduceParasitics.cc +++ b/parasitics/ReduceParasitics.cc @@ -147,7 +147,7 @@ ReduceToPi::reduceToPi(const Parasitic *parasitic_network, rpi = -y3 * y3 / (y2 * y2 * y2); } debugPrint(debug_, "parasitic_reduce", 2, - " Pi model c2=%.3g rpi=%.3g c1=%.3g max_r=%.3g", + " Pi model c2={:.3g} rpi={:.3g} c1={:.3g} max_r={:.3g}", c2, rpi, c1, max_resistance); } @@ -185,7 +185,7 @@ ReduceToPi::reducePiDfs(const Pin *drvr_pin, && resistor != from_res) { if (isVisited(onode)) { // Resistor loop. - debugPrint(debug_, "parasitic_reduce", 2, " loop detected thru resistor %zu", + debugPrint(debug_, "parasitic_reduce", 2, " loop detected thru resistor {}", parasitics_->id(resistor)); markLoopResistor(resistor); } @@ -208,7 +208,7 @@ ReduceToPi::reducePiDfs(const Pin *drvr_pin, setDownstreamCap(node, dwn_cap); leave(node); debugPrint(debug_, "parasitic_reduce", 3, - " node %s y1=%.3g y2=%.3g y3=%.3g cap=%.3g", + " node {} y1={:.3g} y2={:.3g} y3={:.3g} cap={:.3g}", parasitics_->name(node), y1, y2, y3, dwn_cap); } @@ -309,10 +309,10 @@ reduceToPiElmore(const Parasitic *parasitic_network, ParasiticNode *drvr_node = parasitics->findParasiticNode(parasitic_network, drvr_pin); if (drvr_node) { - debugPrint(sta->debug(), "parasitic_reduce", 1, "Reduce driver %s %s %s", + debugPrint(sta->debug(), "parasitic_reduce", 1, "Reduce driver {} {} {}", sta->network()->pathName(drvr_pin), rf->shortName(), - min_max->to_string().c_str()); + min_max->to_string()); ReduceToPiElmore reducer(sta); return reducer.makePiElmore(parasitic_network, drvr_pin, drvr_node, coupling_cap_factor, rf, scene, min_max); @@ -356,7 +356,7 @@ ReduceToPiElmore::reduceElmoreDfs(const Pin *drvr_pin, const Pin *pin = parasitics_->pin(node); if (from_res && pin) { if (network_->isLoad(pin)) { - debugPrint(debug_, "parasitic_reduce", 2, " Load %s elmore=%.3g", + debugPrint(debug_, "parasitic_reduce", 2, " Load {} elmore={:.3g}", network_->pathName(pin), elmore); parasitics_->setElmore(pi_elmore, pin, elmore); @@ -456,7 +456,7 @@ reduceToPiPoleResidue2(const Parasitic *parasitic_network, ParasiticNode *drvr_node = parasitics->findParasiticNode(parasitic_network, drvr_pin); if (drvr_node) { - debugPrint(sta->debug(), "parasitic_reduce", 1, "Reduce driver %s", + debugPrint(sta->debug(), "parasitic_reduce", 1, "Reduce driver {}", sta->network()->pathName(drvr_pin)); ReduceToPiPoleResidue2 reducer(sta); return reducer.makePiPoleResidue2(parasitic_network, drvr_pin, drvr_node, @@ -564,7 +564,7 @@ ReduceToPiPoleResidue2::findBranchCurrents(const Pin *drvr_pin, leave(node); if (from_res) { setCurrent(from_res, branch_i); - debugPrint(debug_, "parasitic_reduce", 3, " res i=%.3g", branch_i); + debugPrint(debug_, "parasitic_reduce", 3, " res i={:.3g}", branch_i); } return branch_i; } @@ -589,7 +589,7 @@ ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin, double r_volt = r * current(resistor); double onode_volt = from_volt - r_volt; setMoment(onode, onode_volt, moment_index); - debugPrint(debug_, "parasitic_reduce", 3, " moment %s %d %.3g", + debugPrint(debug_, "parasitic_reduce", 3, " moment {} {} {:.3g}", parasitics_->name(onode), moment_index, onode_volt); @@ -655,7 +655,7 @@ ReduceToPiPoleResidue2::findPolesResidues(Parasitic *pi_pole_residue, || m1 / m2 == m2 / m3) { double p1 = -1.0 / m1; double k1 = 1.0; - debugPrint(debug_, "parasitic_reduce", 3, " load %s p1=%.3g k1=%.3g", + debugPrint(debug_, "parasitic_reduce", 3, " load {} p1={:.3g} k1={:.3g}", network_->pathName(load_pin), p1, k1); ComplexFloatSeq *poles = new ComplexFloatSeq(1); ComplexFloatSeq *residues = new ComplexFloatSeq(1); @@ -675,7 +675,7 @@ ReduceToPiPoleResidue2::findPolesResidues(Parasitic *pi_pole_residue, k1 = k; } debugPrint(debug_, "parasitic_reduce", 3, - " load %s p1=%.3g p2=%.3g k1=%.3g k2=%.3g", + " load {} p1={:.3g} p2={:.3g} k1={:.3g} k2={:.3g}", network_->pathName(load_pin), p1, p2, k1, k2); ComplexFloatSeq *poles = new ComplexFloatSeq(2); diff --git a/parasitics/ReportParasiticAnnotation.cc b/parasitics/ReportParasiticAnnotation.cc index a6726911..f91db926 100644 --- a/parasitics/ReportParasiticAnnotation.cc +++ b/parasitics/ReportParasiticAnnotation.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "ReportParasiticAnnotation.hh" @@ -65,8 +65,8 @@ reportParasiticAnnotation(Parasitics *parasitics, const Scene *scene, StaState *sta) { - ReportParasiticAnnotation report_annotation(parasitics, report_unannotated, - scene, sta); + ReportParasiticAnnotation report_annotation(parasitics, report_unannotated, scene, + sta); report_annotation.report(); } @@ -92,25 +92,26 @@ ReportParasiticAnnotation::report() void ReportParasiticAnnotation::reportAnnotationCounts() { - report_->reportLine("Found %zu unannotated drivers.", unannotated_.size()); + report_->report("Found {} unannotated drivers.", unannotated_.size()); if (report_unannotated_) { sort(unannotated_, PinPathNameLess(network_)); for (const Pin *drvr_pin : unannotated_) - report_->reportLine(" %s", network_->pathName(drvr_pin)); + report_->report(" {}", network_->pathName(drvr_pin)); } - report_->reportLine("Found %zu partially unannotated drivers.", - partially_annotated_.size()); + report_->report("Found {} partially unannotated drivers.", + partially_annotated_.size()); if (report_unannotated_) { sort(partially_annotated_, PinPathNameLess(network_)); for (const Pin *drvr_pin : partially_annotated_) { - report_->reportLine(" %s", network_->pathName(drvr_pin)); + report_->report(" {}", network_->pathName(drvr_pin)); Parasitic *parasitic = parasitics_->findParasiticNetwork(drvr_pin); if (parasitic) { - PinSet unannotated_loads = parasitics_->unannotatedLoads(parasitic, drvr_pin); + PinSet unannotated_loads = + parasitics_->unannotatedLoads(parasitic, drvr_pin); for (const Pin *load_pin : unannotated_loads) - report_->reportLine(" %s", network_->pathName(load_pin)); + report_->report(" {}", network_->pathName(load_pin)); } } } @@ -124,21 +125,20 @@ ReportParasiticAnnotation::findCounts() Vertex *vertex = vertex_iter.next(); Pin *pin = vertex->pin(); PortDirection *dir = network_->direction(pin); - if (vertex->isDriver(network_) - && !dir->isInternal()) { + if (vertex->isDriver(network_) && !dir->isInternal()) { Parasitic *parasitic = parasitics_->findParasiticNetwork(pin); if (parasitic == nullptr) - parasitic = arc_delay_calc_->findParasitic(pin, RiseFall::rise(), - scene_, min_max_); + parasitic = + arc_delay_calc_->findParasitic(pin, RiseFall::rise(), scene_, min_max_); if (parasitic) { PinSet unannotated_loads = parasitics_->unannotatedLoads(parasitic, pin); if (unannotated_loads.size() > 0) partially_annotated_.push_back(pin); } - else + else unannotated_.push_back(pin); } } } -} // namespace +} // namespace sta diff --git a/parasitics/SpefParse.yy b/parasitics/SpefParse.yy index 42983f0b..a88e2d26 100755 --- a/parasitics/SpefParse.yy +++ b/parasitics/SpefParse.yy @@ -41,8 +41,7 @@ void sta::SpefParse::error(const location_type &loc, const std::string &msg) { - reader->report()->fileError(164,reader->filename().c_str(), - loc.begin.line,"%s",msg.c_str()); + reader->report()->fileError(1670,reader->filename(), loc.begin. line, "{}", msg); } %} @@ -831,7 +830,7 @@ pos_integer: INTEGER { int value = $1; if (value < 0) - reader->warn(1525, "%d is not positive.", value); + reader->warn(1525, "{} is not positive.", value); $$ = value; } ; @@ -840,13 +839,13 @@ pos_number: INTEGER { float value = static_cast($1); if (value < 0) - reader->warn(1526, "%.4f is not positive.", value); + reader->warn(1526, "{:.4f} is not positive.", value); $$ = value; } | FLOAT { float value = static_cast($1); if (value < 0) - reader->warn(1527, "%.4f is not positive.", value); + reader->warn(1527, "{:.4f} is not positive.", value); $$ = value; } ; diff --git a/parasitics/SpefReader.cc b/parasitics/SpefReader.cc index 99c53633..2bc516ae 100644 --- a/parasitics/SpefReader.cc +++ b/parasitics/SpefReader.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "SpefReader.hh" @@ -55,9 +55,8 @@ readSpefFile(const std::string &filename, Parasitics *parasitics, StaState *sta) { - SpefReader reader(filename, instance, pin_cap_included, - keep_coupling_caps, coupling_cap_factor, - reduce, scene, min_max, parasitics, sta); + SpefReader reader(filename, instance, pin_cap_included, keep_coupling_caps, + coupling_cap_factor, reduce, scene, min_max, parasitics, sta); bool success = reader.read(); return success; } @@ -98,9 +97,7 @@ SpefReader::SpefReader(const std::string &filename, parasitics->setCouplingCapFactor(coupling_cap_factor); } -SpefReader::~SpefReader() -{ -} +SpefReader::~SpefReader() {} bool SpefReader::read() @@ -112,13 +109,13 @@ SpefReader::read() SpefScanner scanner(&stream, filename_, this, report_); scanner_ = &scanner; SpefParse parser(&scanner, this); - //parser.set_debug_level(1); - // yyparse returns 0 on success. + // parser.set_debug_level(1); + // yyparse returns 0 on success. success = (parser.parse() == 0); stats.report("Read spef"); } else - throw FileNotReadable(filename_.c_str()); + throw FileNotReadable(filename_); return success; } @@ -138,12 +135,9 @@ void SpefReader::setBusBrackets(char left, char right) { - if (!((left == '[' && right == ']') - || (left == '{' && right == '}') - || (left == '(' && right == ')') - || (left == '<' && right == '>') - || (left == ':' && right == '\0') - || (left == '.' && right == '\0'))) + if (!((left == '[' && right == ']') || (left == '{' && right == '}') + || (left == '(' && right == ')') || (left == '<' && right == '>') + || (left == ':' && right == '\0') || (left == '.' && right == '\0'))) warn(1640, "illegal bus delimiters."); bus_brkt_left_ = left; bus_brkt_right_ = right; @@ -181,19 +175,16 @@ SpefReader::findPortPinRelative(const char *name) char * SpefReader::translated(const char *token) { - return spefToSta(token, divider_, network_->pathDivider(), - network_->pathEscape()); + return spefToSta(token, divider_, network_->pathDivider(), network_->pathEscape()); } -void -SpefReader::warn(int id, const char *fmt, ...) +int +SpefReader::warnLine() const { - va_list args; - va_start(args, fmt); - report_->vfileWarn(id, filename_.c_str(), scanner_->line(), fmt, args); - va_end(args); + return scanner_->line(); } + void SpefReader::setTimeScale(float scale, const char *units) @@ -203,7 +194,7 @@ SpefReader::setTimeScale(float scale, else if (stringEq(units, "PS")) time_scale_ = scale * 1E-12F; else - warn(1641, "unknown units %s.", units); + warn(1641, "unknown units {}.", units); stringDelete(units); } @@ -216,7 +207,7 @@ SpefReader::setCapScale(float scale, else if (stringEq(units, "FF")) cap_scale_ = scale * 1E-15F; else - warn(1642, "unknown units %s.", units); + warn(1642, "unknown units {}.", units); stringDelete(units); } @@ -229,7 +220,7 @@ SpefReader::setResScale(float scale, else if (stringEq(units, "KOHM")) res_scale_ = scale * 1E+3F; else - warn(1643, "unknown units %s.", units); + warn(1643, "unknown units {}.", units); stringDelete(units); } @@ -244,7 +235,7 @@ SpefReader::setInductScale(float scale, else if (stringEq(units, "UH")) induct_scale_ = scale * 1E-6F; else - warn(1644, "unknown units %s.", units); + warn(1644, "unknown units {}.", units); stringDelete(units); } @@ -267,7 +258,7 @@ SpefReader::nameMapLookup(const char *name) if (itr != name_map_.end()) return itr->second.c_str(); else { - warn(1645, "no name map entry for %d.", index); + warn(1645, "no name map entry for {}.", index); return nullptr; } } @@ -286,7 +277,7 @@ SpefReader::portDirection(char *spef_dir) else if (stringEq(spef_dir, "B")) direction = PortDirection::bidirect(); else - warn(1646, "unknown port direction %s.", spef_dir); + warn(1646, "unknown port direction {}.", spef_dir); return direction; } @@ -314,16 +305,16 @@ SpefReader::findPin(char *name) if (inst) { pin = network_->findPin(inst, port_name); if (pin == nullptr) - warn(1647, "pin %s not found.", name1); + warn(1647, "pin {} not found.", name1); } else - warn(1648, "instance %s not found.", name1); + warn(1648, "instance {} not found.", name1); } } else { pin = findPortPinRelative(name); if (pin == nullptr) - warn(1649, "pin %s not found.", name); + warn(1649, "pin {} not found.", name); } } return pin; @@ -337,7 +328,7 @@ SpefReader::findNet(const char *name) if (name1) { net = findNetRelative(name1); if (net == nullptr) - warn(1650, "net %s not found.", name1); + warn(1650, "net {} not found.", name1); } return net; } @@ -366,9 +357,7 @@ SpefReader::rspfDrvrBegin(Pin *drvr_pin, float rpi = pi->r1()->value(triple_index_) * res_scale_; float c1 = pi->c1()->value(triple_index_) * cap_scale_; // Only one parasitic, save it under rise transition. - parasitic_ = parasitics_->makePiElmore(drvr_pin, - RiseFall::rise(), - MinMax::max(), + parasitic_ = parasitics_->makePiElmore(drvr_pin, RiseFall::rise(), MinMax::max(), c2, rpi, c1); } delete pi; @@ -412,8 +401,8 @@ SpefReader::dspfBegin(Net *net, delete term_iter; parasitic_ = parasitics_->findParasiticNetwork(parasitic_owner); if (parasitic_ == nullptr) - parasitic_ = parasitics_->makeParasiticNetwork(parasitic_owner, - pin_cap_included_); + parasitic_ = + parasitics_->makeParasiticNetwork(parasitic_owner, pin_cap_included_); } net_ = net; } @@ -451,16 +440,15 @@ SpefReader::findParasiticNode(char *name, // : Pin *pin = network_->findPin(inst, name2); if (pin) { - if (local_only - && !network_->isConnected(net_, pin)) - warn(1651, "%s not connected to net %s.", - name1, sdc_network_->pathName(net_)); + if (local_only && !network_->isConnected(net_, pin)) + warn(1651, "{} not connected to net {}.", name1, + sdc_network_->pathName(net_)); return parasitics_->ensureParasiticNode(parasitic_, pin, network_); } else { // Replace delimiter for error message. *delim = delimiter_; - warn(1652, "pin %s not found.", name1); + warn(1652, "pin {} not found.", name1); } } else { @@ -472,15 +460,13 @@ SpefReader::findParasiticNode(char *name, const char *id_str = delim + 1; if (isDigits(id_str)) { int id = atoi(id_str); - if (local_only - && !network_->isConnected(net, net_)) - warn(1653, "%s not connected to net %s.", - name1, + if (local_only && !network_->isConnected(net, net_)) + warn(1653, "{} not connected to net {}.", name1, network_->pathName(net_)); return parasitics_->ensureParasiticNode(parasitic_, net, id, network_); } else - warn(1654, "node %s not a pin or net:number", name1); + warn(1654, "node {} not a pin or net:number", name1); } } } @@ -491,23 +477,24 @@ SpefReader::findParasiticNode(char *name, if (name1) { Pin *pin = findPortPinRelative(name1); if (pin) { - if (local_only - && !network_->isConnected(net_, pin)) - warn(1655, "%s not connected to net %s.", name1, network_->pathName(net_)); + if (local_only && !network_->isConnected(net_, pin)) + warn(1655, "{} not connected to net {}.", name1, + network_->pathName(net_)); return parasitics_->ensureParasiticNode(parasitic_, pin, network_); } else - warn(1656, "pin %s not found.", name1); + warn(1656, "pin {} not found.", name1); } else - warn(1657, "pin %s not found.", name); + warn(1657, "pin {} not found.", name); } } return nullptr; } void -SpefReader::makeCapacitor(int, char *node_name, +SpefReader::makeCapacitor(int, + char *node_name, SpefTriple *cap) { ParasiticNode *node = findParasiticNode(node_name, true); @@ -622,7 +609,7 @@ SpefScanner::SpefScanner(std::istream *stream, void SpefScanner::error(const char *msg) { - report_->fileError(1867, filename_.c_str(), lineno(), "%s", msg); + report_->fileError(1658, filename_.c_str(), lineno(), "{}", msg); } -} // namespace +} // namespace sta diff --git a/parasitics/SpefReaderPvt.hh b/parasitics/SpefReaderPvt.hh index cf58eb51..7b01fda6 100644 --- a/parasitics/SpefReaderPvt.hh +++ b/parasitics/SpefReaderPvt.hh @@ -25,6 +25,7 @@ #pragma once #include +#include #include "Zlib.hh" #include "StringUtil.hh" @@ -65,10 +66,6 @@ public: const std::string &filename() const { return filename_; } // Translate from spf/spef namespace to sta namespace. char *translated(const char *token); - void warn(int id, - const char *fmt, - ...) - __attribute__((format (printf, 3, 4))); void setBusBrackets(char left, char right); void setTimeScale(float scale, @@ -108,6 +105,15 @@ public: char *node_name2, SpefTriple *res); PortDirection *portDirection(char *spef_dir); + int warnLine() const; + template + void warn(int id, + std::string_view fmt, + Args &&...args) + { + report_->fileWarn(id, filename_, warnLine(), fmt, + std::forward(args)...); + } private: Pin *findPinRelative(const char *name); diff --git a/power/Power.cc b/power/Power.cc index eb8d40cc..d4dd239c 100644 --- a/power/Power.cc +++ b/power/Power.cc @@ -1,31 +1,31 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "Power.hh" -#include // max -#include // abs +#include // max +#include // abs #include "cudd.h" #include "ContainerHelpers.hh" @@ -74,26 +74,28 @@ namespace sta { static bool isPositiveUnate(const LibertyCell *cell, - const LibertyPort *from, - const LibertyPort *to); + const LibertyPort *from, + const LibertyPort *to); -static EnumNameMap pwr_activity_origin_map = - {{PwrActivityOrigin::global, "global"}, - {PwrActivityOrigin::input, "input"}, - {PwrActivityOrigin::user, "user"}, - {PwrActivityOrigin::vcd, "vcd"}, - {PwrActivityOrigin::saif, "saif"}, - {PwrActivityOrigin::propagated, "propagated"}, - {PwrActivityOrigin::clock, "clock"}, - {PwrActivityOrigin::constant, "constant"}, - {PwrActivityOrigin::unknown, "unknown"}}; +static EnumNameMap pwr_activity_origin_map = { + {PwrActivityOrigin::global, "global"}, + {PwrActivityOrigin::input, "input"}, + {PwrActivityOrigin::user, "user"}, + {PwrActivityOrigin::vcd, "vcd"}, + {PwrActivityOrigin::saif, "saif"}, + {PwrActivityOrigin::propagated, "propagated"}, + {PwrActivityOrigin::clock, "clock"}, + {PwrActivityOrigin::constant, "constant"}, + {PwrActivityOrigin::unknown, "unknown"}}; Power::Power(StaState *sta) : StaState(sta), scene_(nullptr), global_activity_(), - input_activity_(), // default set in ensureActivities. - seq_activity_map_(100, SeqPinHash(network_), SeqPinEqual()), + input_activity_(), // default set in ensureActivities. + seq_activity_map_(100, + SeqPinHash(network_), + SeqPinEqual()), activities_valid_(false), bdd_(sta), instance_powers_(InstanceIdLess(network_)), @@ -123,12 +125,12 @@ Power::activitiesInvalid() void Power::setGlobalActivity(float density, - float duty) + float duty) { global_activity_.set(density, duty, PwrActivityOrigin::global); activitiesInvalid(); } - + void Power::unsetGlobalActivity() { @@ -138,7 +140,7 @@ Power::unsetGlobalActivity() void Power::setInputActivity(float density, - float duty) + float duty) { input_activity_.set(density, duty, PwrActivityOrigin::input); activitiesInvalid(); @@ -153,8 +155,8 @@ Power::unsetInputActivity() void Power::setInputPortActivity(const Port *input_port, - float density, - float duty) + float density, + float duty) { Instance *top_inst = network_->topInstance(); const Pin *pin = network_->findPin(top_inst, input_port); @@ -206,12 +208,10 @@ Power::hasUserActivity(const Pin *pin) void Power::setActivity(const Pin *pin, - PwrActivity &activity) + PwrActivity &activity) { - debugPrint(debug_, "power_activity", 3, "set %s %.2e %.2f %s", - network_->pathName(pin), - activity.density(), - activity.duty(), + debugPrint(debug_, "power_activity", 3, "set {} {:.2e} {:.2f} {}", + network_->pathName(pin), activity.density(), activity.duty(), pwr_activity_origin_map.find(activity.origin())); activity_map_[pin] = activity; } @@ -232,8 +232,8 @@ Power::hasActivity(const Pin *pin) // activities are stored by instance/liberty_port pairs. void Power::setSeqActivity(const Instance *reg, - LibertyPort *output, - PwrActivity &activity) + LibertyPort *output, + PwrActivity &activity) { seq_activity_map_[SeqPin(reg, output)] = activity; activitiesInvalid(); @@ -241,14 +241,14 @@ Power::setSeqActivity(const Instance *reg, bool Power::hasSeqActivity(const Instance *reg, - LibertyPort *output) + LibertyPort *output) { return seq_activity_map_.contains(SeqPin(reg, output)); } PwrActivity & Power::seqActivity(const Instance *reg, - LibertyPort *output) + LibertyPort *output) { return seq_activity_map_[SeqPin(reg, output)]; } @@ -261,18 +261,17 @@ SeqPinHash::SeqPinHash(const Network *network) : size_t SeqPinHash::operator()(const SeqPin &pin) const { - const auto& [inst, port] = pin; + const auto &[inst, port] = pin; return hashSum(network_->id(inst), port->id()); } bool SeqPinEqual::operator()(const SeqPin &pin1, - const SeqPin &pin2) const + const SeqPin &pin2) const { - const auto& [inst1, port1] = pin1; - const auto& [inst2, port2] = pin2; - return inst1 == inst2 - && port1 == port2; + const auto &[inst1, port1] = pin1; + const auto &[inst2, port2] = pin2; + return inst1 == inst2 && port1 == port2; } //////////////////////////////////////////////////////////////// @@ -284,7 +283,8 @@ Power::reportDesign(const Scene *scene, PowerResult total, sequential, combinational, clock, macro, pad; power(scene, total, sequential, combinational, clock, macro, pad); ReportPower report_power(this); - report_power.reportDesign(total, sequential, combinational, clock, macro, pad, digits); + report_power.reportDesign(total, sequential, combinational, clock, macro, pad, + digits); } void @@ -313,15 +313,15 @@ Power::reportDesignJson(const Scene *scene, { PowerResult total, sequential, combinational, clock, macro, pad; power(scene, total, sequential, combinational, clock, macro, pad); - - report_->reportLine("{"); + + report_->report("{{"); reportPowerRowJson("Sequential", sequential, digits, ","); reportPowerRowJson("Combinational", combinational, digits, ","); reportPowerRowJson("Clock", clock, digits, ","); reportPowerRowJson("Macro", macro, digits, ","); reportPowerRowJson("Pad", pad, digits, ","); reportPowerRowJson("Total", total, digits, ""); - report_->reportLine("}"); + report_->report("}}"); } void @@ -330,17 +330,17 @@ Power::reportInstsJson(const InstanceSeq &insts, int digits) { InstPowers inst_pwrs = sortInstsByPower(insts, scene); - - report_->reportLine("["); + + report_->report("["); bool first = true; for (const InstPower &inst_pwr : inst_pwrs) { if (!first) { - report_->reportLine(","); + report_->report(","); } first = false; reportPowerInstJson(inst_pwr.first, inst_pwr.second, digits); } - report_->reportLine("]"); + report_->report("]"); } void @@ -353,16 +353,16 @@ Power::reportPowerRowJson(const char *name, float switching = power.switching(); float leakage = power.leakage(); float total = power.total(); - - report_->reportLine(" \"%s\": {", name); - report_->reportLine(" \"internal\": %.*e,", digits, internal); - report_->reportLine(" \"switching\": %.*e,", digits, switching); - report_->reportLine(" \"leakage\": %.*e,", digits, leakage); - report_->reportLine(" \"total\": %.*e", digits, total); + + report_->report(" \"{}\": {{", name); + report_->report(" \"internal\": {:.{}e},", internal, digits); + report_->report(" \"switching\": {:.{}e},", switching, digits); + report_->report(" \"leakage\": {:.{}e},", leakage, digits); + report_->report(" \"total\": {:.{}e}", total, digits); std::string line = " }"; if (separator && separator[0] != '\0') line += separator; - report_->reportLineString(line); + report_->reportLine(line); } void @@ -374,15 +374,15 @@ Power::reportPowerInstJson(const Instance *inst, float switching = power.switching(); float leakage = power.leakage(); float total = power.total(); - + const char *inst_name = network_->pathName(inst); - report_->reportLine("{"); - report_->reportLine(" \"name\": \"%s\",", inst_name); - report_->reportLine(" \"internal\": %.*e,", digits, internal); - report_->reportLine(" \"switching\": %.*e,", digits, switching); - report_->reportLine(" \"leakage\": %.*e,", digits, leakage); - report_->reportLine(" \"total\": %.*e", digits, total); - report_->reportLine("}"); + report_->report("{{"); + report_->report(" \"name\": \"{}\",", inst_name); + report_->report(" \"internal\": {:.{}e},", internal, digits); + report_->report(" \"switching\": {:.{}e},", switching, digits); + report_->report(" \"leakage\": {:.{}e},", leakage, digits); + report_->report(" \"total\": {:.{}e}", total, digits); + report_->report("}}"); } static bool @@ -402,7 +402,7 @@ Power::sortInstsByPower(const InstanceSeq &insts, PowerResult inst_power = power(inst, scene); inst_pwrs.push_back(std::make_pair(inst, inst_power)); } - + // Sort by total power (descending) sort(inst_pwrs, instPowerGreater); return inst_pwrs; @@ -412,13 +412,13 @@ Power::sortInstsByPower(const InstanceSeq &insts, void Power::power(const Scene *scene, - // Return values. - PowerResult &total, - PowerResult &sequential, - PowerResult &combinational, + // Return values. + PowerResult &total, + PowerResult &sequential, + PowerResult &combinational, PowerResult &clock, - PowerResult ¯o, - PowerResult &pad) + PowerResult ¯o, + PowerResult &pad) { total.clear(); sequential.clear(); @@ -433,18 +433,16 @@ Power::power(const Scene *scene, for (auto [inst, inst_power] : instance_powers_) { LibertyCell *cell = network_->libertyCell(inst); if (cell) { - if (cell->isMacro() - || cell->isMemory() - || cell->interfaceTiming()) - macro.incr(inst_power); + if (cell->isMacro() || cell->isMemory() || cell->interfaceTiming()) + macro.incr(inst_power); else if (cell->isPad()) - pad.incr(inst_power); + pad.incr(inst_power); else if (inClockNetwork(inst, clk_network)) - clock.incr(inst_power); + clock.incr(inst_power); else if (cell->hasSequentials()) - sequential.incr(inst_power); + sequential.incr(inst_power); else - combinational.incr(inst_power); + combinational.incr(inst_power); total.incr(inst_power); } } @@ -457,8 +455,7 @@ Power::inClockNetwork(const Instance *inst, InstancePinIterator *pin_iter = network_->pinIterator(inst); while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); - if (network_->direction(pin)->isAnyOutput() - && !clk_network->isClock(pin)) { + if (network_->direction(pin)->isAnyOutput() && !clk_network->isClock(pin)) { delete pin_iter; return false; } @@ -553,12 +550,9 @@ ActivitySrchPred::searchThru(Edge *edge, { const Sdc *sdc = mode->sdc(); const TimingRole *role = edge->role(); - return !(edge->role()->isTimingCheck() - || sdc->isDisabledConstraint(edge) - || sdc->isDisabledCondDefault(edge) - || edge->isBidirectInstPath() - || edge->isDisabledLoop() - || role == TimingRole::regClkToQ() + return !(edge->role()->isTimingCheck() || sdc->isDisabledConstraint(edge) + || sdc->isDisabledCondDefault(edge) || edge->isBidirectInstPath() + || edge->isDisabledLoop() || role == TimingRole::regClkToQ() || role->isLatchDtoQ()); } @@ -576,7 +570,7 @@ class PropActivityVisitor : public VertexVisitor, StaState public: PropActivityVisitor(Power *power, const Mode *mode, - BfsFwdIterator *bfs); + BfsFwdIterator *bfs); virtual VertexVisitor *copy() const; virtual void visit(Vertex *vertex); InstanceSet &visitedRegs() { return visited_regs_; } @@ -599,7 +593,7 @@ private: PropActivityVisitor::PropActivityVisitor(Power *power, const Mode *mode, - BfsFwdIterator *bfs) : + BfsFwdIterator *bfs) : StaState(power), visited_regs_(network_), max_change_(0.0), @@ -628,8 +622,8 @@ PropActivityVisitor::visit(Vertex *vertex) { Pin *pin = vertex->pin(); Instance *inst = network_->instance(pin); - debugPrint(debug_, "power_activity", 3, "visit %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "power_activity", 3, "visit {}", + vertex->to_string(this)); bool changed = false; if (power_->hasUserActivity(pin)) { PwrActivity &activity = power_->userActivity(pin); @@ -639,22 +633,21 @@ PropActivityVisitor::visit(Vertex *vertex) if (network_->isLoad(pin)) { VertexInEdgeIterator edge_iter(vertex, graph_); if (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->isWire()) { - Vertex *from_vertex = edge->from(graph_); + Edge *edge = edge_iter.next(); + if (edge->isWire()) { + Vertex *from_vertex = edge->from(graph_); const Pin *from_pin = from_vertex->pin(); - PwrActivity &from_activity = power_->activity(from_pin); - PwrActivity to_activity(from_activity.density(), - from_activity.duty(), - PwrActivityOrigin::propagated); - changed = setActivityCheck(pin, to_activity); - } + PwrActivity &from_activity = power_->activity(from_pin); + PwrActivity to_activity(from_activity.density(), from_activity.duty(), + PwrActivityOrigin::propagated); + changed = setActivityCheck(pin, to_activity); + } } } if (network_->isDriver(pin)) { LibertyPort *port = network_->libertyPort(pin); if (port) { - FuncExpr *func = port->function(); + FuncExpr *func = port->function(); if (func == nullptr) { LibertyCell *test_cell = port->libertyCell()->testCell(); if (test_cell) { @@ -663,10 +656,10 @@ PropActivityVisitor::visit(Vertex *vertex) func = port->function(); } } - if (func) { + if (func) { PwrActivity activity = power_->evalActivity(func, inst); - changed = setActivityCheck(pin, activity); - } + changed = setActivityCheck(pin, activity); + } if (port->isClockGateOut()) { const Pin *enable, *clk, *gclk; power_->clockGatePins(inst, enable, clk, gclk); @@ -676,12 +669,10 @@ PropActivityVisitor::visit(Vertex *vertex) float p1 = activity1.duty(); float p2 = activity2.duty(); PwrActivity activity(activity1.density() * p2 + activity2.density() * p1, - p1 * p2, - PwrActivityOrigin::propagated); + p1 * p2, PwrActivityOrigin::propagated); changed = setActivityCheck(gclk, activity); - debugPrint(debug_, "power_activity", 3, "gated_clk %s %.2e %.2f", - network_->pathName(gclk), - activity.density(), + debugPrint(debug_, "power_activity", 3, "gated_clk {} {:.2e} {:.2f}", + network_->pathName(gclk), activity.density(), activity.duty()); } } @@ -693,22 +684,20 @@ PropActivityVisitor::visit(Vertex *vertex) if (cell) { LibertyCell *test_cell = cell->libertyCell()->testCell(); if (network_->isLoad(pin)) { - if (cell->hasSequentials() - || (test_cell - && test_cell->hasSequentials())) { - debugPrint(debug_, "power_activity", 3, "pending seq %s", - network_->pathName(inst)); - visited_regs_.insert(inst); - } - // Gated clock cells latch the enable so there is no EN->GCLK timing arc. - if (cell->isClockGate()) { - const Pin *enable, *clk, *gclk; - power_->clockGatePins(inst, enable, clk, gclk); - if (gclk) { - Vertex *gclk_vertex = graph_->pinDrvrVertex(gclk); - bfs_->enqueue(gclk_vertex); - } - } + if (cell->hasSequentials() || (test_cell && test_cell->hasSequentials())) { + debugPrint(debug_, "power_activity", 3, "pending seq {}", + network_->pathName(inst)); + visited_regs_.insert(inst); + } + // Gated clock cells latch the enable so there is no EN->GCLK timing arc. + if (cell->isClockGate()) { + const Pin *enable, *clk, *gclk; + power_->clockGatePins(inst, enable, clk, gclk); + if (gclk) { + Vertex *gclk_vertex = graph_->pinDrvrVertex(gclk); + bfs_->enqueue(gclk_vertex); + } + } } bfs_->enqueueAdjacentVertices(vertex, mode_); } @@ -739,8 +728,7 @@ PropActivityVisitor::setActivityCheck(const Pin *pin, if (activity.density() > max_density) activity.setDensity(max_density); PwrActivity &prev_activity = power_->activity(pin); - float density_delta = percentChange(activity.density(), - prev_activity.density()); + float density_delta = percentChange(activity.density(), prev_activity.density()); float duty_delta = percentChange(activity.duty(), prev_activity.duty()); if (density_delta > max_change_) { max_change_ = density_delta; @@ -750,9 +738,9 @@ PropActivityVisitor::setActivityCheck(const Pin *pin, max_change_ = duty_delta; max_change_pin_ = pin; } - bool changed = density_delta > change_tolerance_ - || duty_delta > change_tolerance_ - || activity.origin() != prev_activity.origin();; + bool changed = density_delta > change_tolerance_ || duty_delta > change_tolerance_ + || activity.origin() != prev_activity.origin(); + ; power_->setActivity(pin, activity); return changed; } @@ -787,10 +775,10 @@ Power::clockGatePins(const Instance *inst, PwrActivity Power::evalActivity(FuncExpr *expr, - const Instance *inst) + const Instance *inst) { LibertyPort *func_port = expr->port(); - if (func_port && func_port->direction()->isInternal()) + if (func_port && func_port->direction()->isInternal()) return findSeqActivity(inst, func_port); else { DdNode *bdd = bdd_.funcBdd(expr); @@ -843,7 +831,7 @@ Power::evalBddDuty(DdNode *bdd, int var_index = Cudd_ReadPerm(bdd_.cuddMgr(), index); const LibertyPort *port = bdd_.varIndexPort(var_index); if (port->direction()->isInternal()) - return findSeqActivity(inst, const_cast(port)).duty(); + return findSeqActivity(inst, const_cast(port)).duty(); else { const Pin *pin = findLinkPin(inst, port); if (pin) { @@ -878,10 +866,8 @@ Power::evalBddActivity(DdNode *bdd, Cudd_RecursiveDeref(bdd_.cuddMgr(), diff); float var_density = var_activity.density() * diff_duty; density += var_density; - debugPrint(debug_, "power_activity", 3, "%s %.3e * %.3f = %.3e", - network_->pathName(pin), - var_activity.density(), - diff_duty, + debugPrint(debug_, "power_activity", 3, "{} {:.3e} * {:.3f} = {:.3e}", + network_->pathName(pin), var_activity.density(), diff_duty, var_density); } } @@ -911,9 +897,8 @@ Power::ensureActivities(const Scene *scene) // unless it has been set by command. if (input_activity_.origin() == PwrActivityOrigin::unknown) { float min_period = clockMinPeriod(scene_->mode()->sdc()); - float density = 0.1 / (min_period != 0.0 - ? min_period - : units_->timeUnit()->scale()); + float density = + 0.1 / (min_period != 0.0 ? min_period : units_->timeUnit()->scale()); input_activity_.set(density, 0.5, PwrActivityOrigin::input); } ActivitySrchPred activity_srch_pred(this); @@ -927,17 +912,15 @@ Power::ensureActivities(const Scene *scene) int pass = 1; while (!regs.empty() && pass < max_activity_passes_) { visitor.init(); - for (const Instance *reg : regs) - // Propagate activiities across register D->Q. - seedRegOutputActivities(reg, bfs); - // Propagate register output activities through - // combinational logic. - bfs.visit(levelize_->maxLevel(), &visitor); + for (const Instance *reg : regs) + // Propagate activiities across register D->Q. + seedRegOutputActivities(reg, bfs); + // Propagate register output activities through + // combinational logic. + bfs.visit(levelize_->maxLevel(), &visitor); regs = std::move(visitor.visitedRegs()); - debugPrint(debug_, "power_activity", 1, "Pass %d change %.2f %s", - pass, - visitor.maxChange(), - network_->pathName(visitor.maxChangePin())); + debugPrint(debug_, "power_activity", 1, "Pass {} change {:.2f} {}", pass, + visitor.maxChange(), network_->pathName(visitor.maxChangePin())); pass++; } } @@ -953,14 +936,14 @@ Power::seedActivities(BfsFwdIterator &bfs) const Pin *pin = vertex->pin(); // Clock activities are baked in. if (!scene_->mode()->sdc()->isLeafPinClock(pin) - && !network_->direction(pin)->isInternal()) { - debugPrint(debug_, "power_activity", 3, "seed %s", - vertex->to_string(this).c_str()); + && !network_->direction(pin)->isInternal()) { + debugPrint(debug_, "power_activity", 3, "seed {}", + vertex->to_string(this)); if (hasUserActivity(pin)) - setActivity(pin, userActivity(pin)); + setActivity(pin, userActivity(pin)); else - // Default inputs without explicit activities to the input default. - setActivity(pin, input_activity_); + // Default inputs without explicit activities to the input default. + setActivity(pin, input_activity_); Vertex *vertex = graph_->pinDrvrVertex(pin); bfs.enqueueAdjacentVertices(vertex, scene_->mode()); } @@ -969,7 +952,7 @@ Power::seedActivities(BfsFwdIterator &bfs) void Power::seedRegOutputActivities(const Instance *inst, - BfsFwdIterator &bfs) + BfsFwdIterator &bfs) { LibertyCell *cell = network_->libertyCell(inst); const SequentialSeq &seqs = cell->sequentials(); @@ -1004,12 +987,10 @@ Power::seedRegOutputActivities(const Instance *inst, if (port) { FuncExpr *func = port->function(); Vertex *vertex = graph_->pinDrvrVertex(pin); - if (vertex - && func - && (func->port() == seq.output() - || func->port() == seq.outputInv())) { - debugPrint(debug_, "power_reg", 1, "enqueue reg output %s", - vertex->to_string(this).c_str()); + if (vertex && func + && (func->port() == seq.output() || func->port() == seq.outputInv())) { + debugPrint(debug_, "power_reg", 1, "enqueue reg output {}", + vertex->to_string(this)); bfs.enqueue(vertex); } } @@ -1020,9 +1001,9 @@ Power::seedRegOutputActivities(const Instance *inst, void Power::seedRegOutputActivities(const Instance *reg, - const Sequential &seq, - LibertyPort *output, - bool invert) + const Sequential &seq, + LibertyPort *output, + bool invert) { const Pin *out_pin = network_->findPin(reg, output); if (!hasUserActivity(out_pin)) { @@ -1041,9 +1022,8 @@ Power::seedRegOutputActivities(const Instance *reg, PwrActivity clk_activity = evalActivity(seq.clock(), reg); float clk_duty = clk_activity.duty(); FuncExpr *clk_func = seq.clock(); - bool clk_invert = clk_func - && clk_func->op() == FuncExpr::Op::not_ - && clk_func->left()->op() == FuncExpr::Op::port; + bool clk_invert = clk_func && clk_func->op() == FuncExpr::Op::not_ + && clk_func->left()->op() == FuncExpr::Op::port; if (clk_invert) out_density = in_density * (1 - clk_duty); else @@ -1087,10 +1067,10 @@ Power::findInstPowers() PowerResult Power::power(const Instance *inst, - LibertyCell *cell, + LibertyCell *cell, const Scene *scene) { - debugPrint(debug_, "power", 2, "find power %s", sdc_network_->pathName(inst)); + debugPrint(debug_, "power", 2, "find power {}", sdc_network_->pathName(inst)); PowerResult result; findInternalPower(inst, cell, scene, result); findSwitchingPower(inst, cell, scene, result); @@ -1128,15 +1108,15 @@ Power::findInternalPower(const Instance *inst, LibertyPort *to_port = network_->libertyPort(to_pin); if (to_port) { float load_cap = to_port->direction()->isAnyOutput() - ? graph_delay_calc_->loadCap(to_pin, scene, MinMax::max()) - : 0.0; + ? graph_delay_calc_->loadCap(to_pin, scene, MinMax::max()) + : 0.0; PwrActivity activity = findActivity(to_pin); if (to_port->direction()->isAnyOutput()) - findOutputInternalPower(to_port, inst, cell, activity, - load_cap, scene, result); + findOutputInternalPower(to_port, inst, cell, activity, load_cap, scene, + result); if (to_port->direction()->isAnyInput()) - findInputInternalPower(to_pin, to_port, inst, cell, activity, - load_cap, scene, result); + findInputInternalPower(to_pin, to_port, inst, cell, activity, load_cap, + scene, result); } } delete pin_iter; @@ -1144,24 +1124,24 @@ Power::findInternalPower(const Instance *inst, void Power::findInputInternalPower(const Pin *pin, - LibertyPort *port, - const Instance *inst, - LibertyCell *cell, - PwrActivity &activity, - float load_cap, + LibertyPort *port, + const Instance *inst, + LibertyCell *cell, + PwrActivity &activity, + float load_cap, const Scene *scene, - // Return values. - PowerResult &result) + // Return values. + PowerResult &result) { const MinMax *min_max = MinMax::max(); LibertyCell *scene_cell = cell->sceneCell(scene, min_max); const LibertyPort *scene_port = port->scenePort(scene, min_max); if (scene_cell && scene_port) { - const InternalPowerPtrSeq &internal_pwrs = scene_cell->internalPowers(scene_port); + const InternalPowerPtrSeq &internal_pwrs = + scene_cell->internalPowers(scene_port); if (!internal_pwrs.empty()) { - debugPrint(debug_, "power", 2, "internal input %s/%s cap %s", - network_->pathName(inst), - port->name(), + debugPrint(debug_, "power", 2, "internal input {}/{} cap {}", + network_->pathName(inst), port->name(), units_->capacitanceUnit()->asString(load_cap)); debugPrint(debug_, "power", 2, " when act/ns duty energy power"); const Pvt *pvt = scene->sdc()->operatingConditions(MinMax::max()); @@ -1173,15 +1153,15 @@ Power::findInputInternalPower(const Pin *pin, int rf_count = 0; for (const RiseFall *rf : RiseFall::range()) { float slew = getSlew(vertex, rf, scene); - if (!delayInf(slew)) { + if (!delayInf(slew, this)) { float table_energy = pwr->power(rf, pvt, slew, load_cap); energy += table_energy; rf_count++; } } if (rf_count) - energy /= rf_count; // average non-inf energies - float duty = 1.0; // fallback default + energy /= rf_count; // average non-inf energies + float duty = 1.0; // fallback default FuncExpr *when = pwr->when(); if (when) { const LibertyPort *out_scene_port = findExprOutPort(when); @@ -1199,13 +1179,9 @@ Power::findInputInternalPower(const Pin *pin, duty = evalActivity(when, inst).duty(); } float port_internal = energy * duty * activity.density(); - debugPrint(debug_, "power", 2, " %3s %6s %.2f %.2f %9.2e %9.2e %s", - port->name(), - when ? when->to_string().c_str() : "", - activity.density() * 1e-9, - duty, - energy, - port_internal, + debugPrint(debug_, "power", 2, " {} {} {:.2f} {:.2f} {:9.2e} {:9.2e} {}", + port->name(), when ? when->to_string() : "", + activity.density() * 1e-9, duty, energy, port_internal, related_pg_pin ? related_pg_pin->name() : "no pg_pin"); internal += port_internal; } @@ -1219,7 +1195,6 @@ Power::getSlew(Vertex *vertex, const RiseFall *rf, const Scene *scene) { - const MinMax *min_max = MinMax::max(); const Pin *pin = vertex->pin(); const ClkNetwork *clk_network = scene->mode()->clkNetwork(); @@ -1238,17 +1213,18 @@ Power::getMinRfSlew(const Pin *pin) graph_->pinVertices(pin, vertex, bidir_vertex); if (vertex) { const MinMax *min_max = MinMax::min(); - Slew mm_slew = min_max->initValue(); + float mm_slew = min_max->initValue(); for (DcalcAPIndex ap_index = 0; ap_index < dcalcAnalysisPtCount(); ap_index++) { const Slew &slew1 = graph_->slew(vertex, RiseFall::rise(), ap_index); const Slew &slew2 = graph_->slew(vertex, RiseFall::fall(), ap_index); - Slew slew = delayAsFloat(slew1 + slew2) / 2.0; - if (delayGreater(slew, mm_slew, min_max, this)) - mm_slew = slew; + float slew_avg = (delayAsFloat(slew1, min_max, this) + + delayAsFloat(slew2, min_max, this)) / 2.0; + if (delayGreater(slew_avg, mm_slew, min_max, this)) + mm_slew = slew_avg; } - return delayAsFloat(mm_slew); + return mm_slew; } return 0.0; } @@ -1258,46 +1234,45 @@ Power::findExprOutPort(FuncExpr *expr) { LibertyPort *port; switch (expr->op()) { - case FuncExpr::Op::port: - port = expr->port(); - if (port && port->direction()->isAnyOutput()) - return expr->port(); - return nullptr; - case FuncExpr::Op::not_: - port = findExprOutPort(expr->left()); - if (port) - return port; - return nullptr; - case FuncExpr::Op::or_: - case FuncExpr::Op::and_: - case FuncExpr::Op::xor_: - port = findExprOutPort(expr->left()); - if (port) - return port; - port = findExprOutPort(expr->right()); - if (port) - return port; - return nullptr; - case FuncExpr::Op::one: - case FuncExpr::Op::zero: - return nullptr; + case FuncExpr::Op::port: + port = expr->port(); + if (port && port->direction()->isAnyOutput()) + return expr->port(); + return nullptr; + case FuncExpr::Op::not_: + port = findExprOutPort(expr->left()); + if (port) + return port; + return nullptr; + case FuncExpr::Op::or_: + case FuncExpr::Op::and_: + case FuncExpr::Op::xor_: + port = findExprOutPort(expr->left()); + if (port) + return port; + port = findExprOutPort(expr->right()); + if (port) + return port; + return nullptr; + case FuncExpr::Op::one: + case FuncExpr::Op::zero: + return nullptr; } return nullptr; } void Power::findOutputInternalPower(const LibertyPort *to_port, - const Instance *inst, - LibertyCell *cell, - PwrActivity &to_activity, - float load_cap, + const Instance *inst, + LibertyCell *cell, + PwrActivity &to_activity, + float load_cap, const Scene *scene, - // Return values. - PowerResult &result) + // Return values. + PowerResult &result) { - debugPrint(debug_, "power", 2, "internal output %s/%s cap %s", - network_->pathName(inst), - to_port->name(), + debugPrint(debug_, "power", 2, "internal output {}/{} cap {}", + network_->pathName(inst), to_port->name(), units_->capacitanceUnit()->asString(load_cap)); const MinMax *min_max = MinMax::max(); const Pvt *pvt = scene->sdc()->operatingConditions(min_max); @@ -1305,7 +1280,7 @@ Power::findOutputInternalPower(const LibertyPort *to_port, const LibertyPort *to_scene_port = to_port->scenePort(scene, min_max); FuncExpr *func = to_port->function(); - std::map pg_duty_sum; + std::map pg_duty_sum; for (const InternalPower *pwr : scene_cell->internalPowers(to_scene_port)) { const LibertyPort *from_scene_port = pwr->relatedPort(); if (from_scene_port) { @@ -1333,7 +1308,7 @@ Power::findOutputInternalPower(const LibertyPort *to_port, positive_unate = isPositiveUnate(scene_cell, from_scene_port, to_scene_port); from_pin = findLinkPin(inst, from_scene_port); if (from_pin) - from_vertex = graph_->pinLoadVertex(from_pin); + from_vertex = graph_->pinLoadVertex(from_pin); } float energy = 0.0; int rf_count = 0; @@ -1343,33 +1318,28 @@ Power::findOutputInternalPower(const LibertyPort *to_port, float slew = from_vertex ? getSlew(from_vertex, from_rf, scene) : 0.0; - if (!delayInf(slew)) { + if (!delayInf(slew, this)) { float table_energy = pwr->power(to_rf, pvt, slew, load_cap); energy += table_energy; rf_count++; } } if (rf_count) - energy /= rf_count; // average non-inf energies + energy /= rf_count; // average non-inf energies auto duty_sum_iter = pg_duty_sum.find(related_pg_pin); float weight = 0.0; if (duty_sum_iter != pg_duty_sum.end()) { float duty_sum = duty_sum_iter->second; if (duty_sum != 0.0 && from_pin) { float from_density = findActivity(from_pin).density(); - weight = from_density * duty / duty_sum; + weight = from_density * duty / duty_sum; } } float port_internal = weight * energy * to_activity.density(); - debugPrint(debug_, "power", 2, "%3s -> %-3s %6s %.3f %.3f %.3f %9.2e %9.2e %s", - from_scene_port ? from_scene_port->name() : "-" , - to_port->name(), - when ? when->to_string().c_str() : "", - to_activity.density() * 1e-9, - duty, - weight, - energy, - port_internal, + debugPrint(debug_, "power", 2, "{} -> {} {} {:.3f} {:.3f} {:.3f} {:9.2e} {:9.2e} {}", + from_scene_port ? from_scene_port->name() : "-", to_port->name(), + when ? when->to_string() : "", to_activity.density() * 1e-9, + duty, weight, energy, port_internal, related_pg_pin ? related_pg_pin->name() : "no pg_pin"); internal += port_internal; } @@ -1383,20 +1353,20 @@ Power::findInputDuty(const Instance *inst, { const LibertyPort *from_scene_port = pwr->relatedPort(); if (from_scene_port) { - LibertyPort *from_port = findLinkPort(network_->libertyCell(inst), - from_scene_port); + LibertyPort *from_port = + findLinkPort(network_->libertyCell(inst), from_scene_port); const Pin *from_pin = network_->findPin(inst, from_port); if (from_pin) { FuncExpr *when = pwr->when(); Vertex *from_vertex = graph_->pinLoadVertex(from_pin); if (func && func->hasPort(from_port)) { - float duty = evalDiffDuty(func, from_port, inst); - return duty; + float duty = evalDiffDuty(func, from_port, inst); + return duty; } else if (when) - return evalActivity(when, inst).duty(); + return evalActivity(when, inst).duty(); else if (scene_->mode()->clkNetwork()->isClock(from_vertex->pin())) - return 0.5; + return 0.5; return 0.5; } } @@ -1422,14 +1392,13 @@ Power::findLinkPin(const Instance *inst, static bool isPositiveUnate(const LibertyCell *cell, - const LibertyPort *from, - const LibertyPort *to) + const LibertyPort *from, + const LibertyPort *to) { const TimingArcSetSeq &arc_sets = cell->timingArcSets(from, to); if (!arc_sets.empty()) { TimingSense sense = arc_sets[0]->sense(); - return sense == TimingSense::positive_unate - || sense == TimingSense::non_unate; + return sense == TimingSense::positive_unate || sense == TimingSense::non_unate; } // default return true; @@ -1451,18 +1420,15 @@ Power::findSwitchingPower(const Instance *inst, const LibertyPort *to_port = network_->libertyPort(to_pin); if (to_port) { float load_cap = to_port->direction()->isAnyOutput() - ? graph_delay_calc_->loadCap(to_pin, scene, MinMax::max()) - : 0.0; + ? graph_delay_calc_->loadCap(to_pin, scene, MinMax::max()) + : 0.0; PwrActivity activity = findActivity(to_pin); if (to_port->direction()->isAnyOutput()) { float volt = portVoltage(scene_cell, to_port, scene, MinMax::max()); float switching = .5 * load_cap * volt * volt * activity.density(); - debugPrint(debug_, "power", 2, "switching %s/%s activity = %.2e volt = %.2f %.3e", - cell->name(), - to_port->name(), - activity.density(), - volt, - switching); + debugPrint(debug_, "power", 2, + "switching {}/{} activity = {:.2e} volt = {:.2f} {:.3e}", cell->name(), + to_port->name(), activity.density(), volt, switching); result.incrSwitching(switching); } } @@ -1472,7 +1438,6 @@ Power::findSwitchingPower(const Instance *inst, //////////////////////////////////////////////////////////////// - // Leakage totals for one power/gnd pin. class LeakageSummary { @@ -1501,41 +1466,34 @@ LeakageSummary::LeakageSummary() : void Power::findLeakagePower(const Instance *inst, - LibertyCell *cell, + LibertyCell *cell, const Scene *scene, - // Return values. - PowerResult &result) + // Return values. + PowerResult &result) { LibertyCell *scene_cell = cell->sceneCell(scene, MinMax::max()); - std::map leakage_summaries; + std::map leakage_summaries; Sim *sim = scene->mode()->sim(); for (const LeakagePower &pwr : scene_cell->leakagePowers()) { LibertyPort *pg_port = pwr.relatedPgPort(); - if (pg_port == nullptr - || pg_port->pwrGndType() == PwrGndType::primary_power) { + if (pg_port == nullptr || pg_port->pwrGndType() == PwrGndType::primary_power) { LeakageSummary &sum = leakage_summaries[pg_port]; float leakage = pwr.power(); FuncExpr *when = pwr.when(); if (when) { LogicValue when_value = sim->evalExpr(when, inst); if (when_value == LogicValue::one) { - debugPrint(debug_, "power", 2, "leakage %s/%s %s=1 %.3e", - cell->name(), - pg_port->name(), - when->to_string().c_str(), - leakage); + debugPrint(debug_, "power", 2, "leakage {}/{} {}=1 {:.3e}", cell->name(), + pg_port->name(), when->to_string(), leakage); sum.cond_true_leakage = leakage; sum.cond_true_exists = true; } else { PwrActivity cond_activity = evalActivity(when, inst); float cond_duty = cond_activity.duty(); - debugPrint(debug_, "power", 2, "leakage %s %s %s %.3e * %.2f", - cell->name(), - pg_port->name(), - when->to_string().c_str(), - leakage, - cond_duty); + debugPrint(debug_, "power", 2, "leakage {} {} {} {:.3e} * {:.2f}", + cell->name(), pg_port->name(), when->to_string(), + leakage, cond_duty); // Leakage power average weighted by duty. sum.cond_leakage += leakage * cond_duty; if (leakage > 0.0) @@ -1544,10 +1502,8 @@ Power::findLeakagePower(const Instance *inst, } } else { - debugPrint(debug_, "power", 2, "leakage %s %s -- %.3e", - cell->name(), - pg_port->name(), - leakage); + debugPrint(debug_, "power", 2, "leakage {} {} -- {:.3e}", cell->name(), + pg_port->name(), leakage); sum.uncond_leakage = leakage; sum.uncond_exists = true; } @@ -1573,10 +1529,8 @@ Power::findLeakagePower(const Instance *inst, // Ignore unconditional leakage unless there are no conditional leakage groups. else if (sum.uncond_exists) leakage = sum.uncond_leakage; - debugPrint(debug_, "power", 2, "leakage %s/%s %.3e", - cell->name(), - pg_port->name(), - leakage); + debugPrint(debug_, "power", 2, "leakage {}/{} {:.3e}", cell->name(), + pg_port->name(), leakage); result.incrLeakage(leakage); } } @@ -1600,8 +1554,7 @@ Power::findActivity(const Pin *pin) Vertex *vertex = graph_->pinLoadVertex(pin); if (vertex && mode->clkNetwork()->isClock(pin)) { PwrActivity *activity = findKeyValuePtr(activity_map_, pin); - if (activity - && activity->origin() != PwrActivityOrigin::unknown) + if (activity && activity->origin() != PwrActivityOrigin::unknown) return *activity; const Clock *clk = findClk(pin); float duty = clockDuty(clk); @@ -1611,8 +1564,7 @@ Power::findActivity(const Pin *pin) return global_activity_; else { PwrActivity *activity = findKeyValuePtr(activity_map_, pin); - if (activity - && activity->origin() != PwrActivityOrigin::unknown) + if (activity && activity->origin() != PwrActivityOrigin::unknown) return *activity; } return PwrActivity(0.0, 0.0, PwrActivityOrigin::unknown); @@ -1624,7 +1576,7 @@ Power::clockDuty(const Clock *clk) if (clk->isGenerated()) { const Clock *master = clk->masterClk(); if (master == nullptr) - return 0.5; // punt + return 0.5; // punt else return clockDuty(master); } @@ -1639,7 +1591,7 @@ Power::clockDuty(const Clock *clk) PwrActivity Power::findSeqActivity(const Instance *inst, - LibertyPort *port) + LibertyPort *port) { if (global_activity_.isSet()) return global_activity_; @@ -1652,7 +1604,7 @@ Power::findSeqActivity(const Instance *inst, float Power::portVoltage(LibertyCell *cell, - const LibertyPort *port, + const LibertyPort *port, const Scene *scene, const MinMax *min_max) { @@ -1661,7 +1613,7 @@ Power::portVoltage(LibertyCell *cell, float Power::pgNameVoltage(LibertyCell *cell, - const char *pg_port_name, + const char *pg_port_name, const Scene *scene, const MinMax *min_max) { @@ -1674,7 +1626,7 @@ Power::pgNameVoltage(LibertyCell *cell, bool exists; library->supplyVoltage(volt_name, voltage, exists); if (exists) - return voltage; + return voltage; } } @@ -1697,10 +1649,8 @@ Power::findClk(const Pin *to_pin) while (path_iter.hasNext()) { Path *path = path_iter.next(); const Clock *path_clk = path->clock(this); - if (path_clk - && (clk == nullptr - || path_clk->period() < clk->period())) - clk = path_clk; + if (path_clk && (clk == nullptr || path_clk->period() < clk->period())) + clk = path_clk; } } return clk; @@ -1715,45 +1665,43 @@ Power::reportActivityAnnotation(bool report_unannotated, size_t vcd_count = 0; size_t saif_count = 0; size_t input_count = 0; - for (auto const& [pin, activity] : user_activity_map_) { + for (auto const &[pin, activity] : user_activity_map_) { PwrActivityOrigin origin = activity.origin(); switch (origin) { - case PwrActivityOrigin::vcd: - vcd_count++; - break; - case PwrActivityOrigin::saif: - saif_count++; - break; - case PwrActivityOrigin::user: - input_count++; - break; - default: - break; + case PwrActivityOrigin::vcd: + vcd_count++; + break; + case PwrActivityOrigin::saif: + saif_count++; + break; + case PwrActivityOrigin::user: + input_count++; + break; + default: + break; } } if (vcd_count > 0) - report_->reportLine("vcd %5zu", vcd_count); + report_->report("vcd {:>5}", vcd_count); if (saif_count > 0) - report_->reportLine("saif %5zu", saif_count); + report_->report("saif {:>5}", saif_count); if (input_count > 0) - report_->reportLine("input %5zu", input_count); + report_->report("input {:>5}", input_count); size_t pin_count = pinCount(); size_t unannotated_count = pin_count - vcd_count - saif_count - input_count; - report_->reportLine("unannotated %5zu", unannotated_count); + report_->report("unannotated {:>5}", unannotated_count); if (report_annotated) { PinSeq annotated_pins; - for (auto const& [pin, activity] : user_activity_map_) + for (auto const &[pin, activity] : user_activity_map_) annotated_pins.push_back(pin); sort(annotated_pins, PinPathNameLess(sdc_network_)); - report_->reportLine("Annotated pins:"); + report_->report("Annotated pins:"); for (const Pin *pin : annotated_pins) { const PwrActivity &activity = user_activity_map_[pin]; PwrActivityOrigin origin = activity.origin(); const char *origin_name = pwr_activity_origin_map.find(origin); - report_->reportLine("%5s %s", - origin_name, - sdc_network_->pathName(pin)); + report_->report("{:>5} {}", origin_name, sdc_network_->pathName(pin)); } } if (report_unannotated) { @@ -1767,9 +1715,9 @@ Power::reportActivityAnnotation(bool report_unannotated, delete inst_iter; sort(unannotated_pins, PinPathNameLess(sdc_network_)); - report_->reportLine("Unannotated pins:"); + report_->report("Unannotated pins:"); for (const Pin *pin : unannotated_pins) { - report_->reportLine(" %s", sdc_network_->pathName(pin)); + report_->report(" {}", sdc_network_->pathName(pin)); } } } @@ -1783,8 +1731,8 @@ Power::findUnannotatedPins(const Instance *inst, const Pin *pin = pin_iter->next(); LibertyPort *liberty_port = sdc_network_->libertyPort(pin); if (!network_->direction(pin)->isInternal() - && !network_->direction(pin)->isPowerGround() - && !(liberty_port && liberty_port->isPwrGnd()) + && !network_->direction(pin)->isPowerGround() + && !(liberty_port && liberty_port->isPwrGnd()) && !user_activity_map_.contains(pin)) unannotated_pins.push_back(pin); } @@ -1804,8 +1752,8 @@ Power::pinCount() const Pin *pin = pin_iter->next(); LibertyPort *liberty_port = sdc_network_->libertyPort(pin); if (!network_->direction(pin)->isInternal() - && !network_->direction(pin)->isPowerGround() - && !(liberty_port && liberty_port->isPwrGnd())) + && !network_->direction(pin)->isPowerGround() + && !(liberty_port && liberty_port->isPwrGnd())) count++; } delete pin_iter; @@ -1854,7 +1802,7 @@ PowerResult::PowerResult() : } void -PowerResult::clear() +PowerResult::clear() { internal_ = 0.0; switching_ = 0.0; @@ -1896,8 +1844,8 @@ PowerResult::incr(PowerResult &result) //////////////////////////////////////////////////////////////// PwrActivity::PwrActivity(float density, - float duty, - PwrActivityOrigin origin) : + float duty, + PwrActivityOrigin origin) : density_(density), duty_(duty), origin_(origin) @@ -1940,8 +1888,8 @@ PwrActivity::init() void PwrActivity::set(float density, - float duty, - PwrActivityOrigin origin) + float duty, + PwrActivityOrigin origin) { density_ = density; duty_ = duty; @@ -1971,4 +1919,4 @@ PwrActivity::originName() const return pwr_activity_origin_map.find(origin_); } -} // namespace +} // namespace sta diff --git a/power/ReportPower.cc b/power/ReportPower.cc index 3f0d0d76..cf4803b7 100644 --- a/power/ReportPower.cc +++ b/power/ReportPower.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "ReportPower.hh" @@ -29,7 +29,7 @@ #include "Report.hh" #include "Network.hh" -#include "StringUtil.hh" +#include "Format.hh" namespace sta { @@ -51,32 +51,31 @@ ReportPower::reportDesign(PowerResult &total, float design_switching = total.switching(); float design_leakage = total.leakage(); float design_total = total.total(); - + int field_width = std::max(digits + 6, 10); - - reportTitle5("Group", "Internal", "Switching", "Leakage", "Total", - field_width); + + reportTitle5("Group", "Internal", "Switching", "Leakage", "Total", field_width); reportTitle5Units(" ", "Power", "Power", "Power", "Power", "(Watts)", field_width); reportTitleDashes5(field_width); - + reportRow("Sequential", sequential, design_total, field_width, digits); reportRow("Combinational", combinational, design_total, field_width, digits); reportRow("Clock", clock, design_total, field_width, digits); reportRow("Macro", macro, design_total, field_width, digits); reportRow("Pad", pad, design_total, field_width, digits); - + reportTitleDashes5(field_width); - + // Report total row using the totals PowerResult reportRow("Total", total, design_total, field_width, digits); - + // Report percentage line - std::string percent_line = stdstrPrint("%-20s", ""); + std::string percent_line = sta::format("{:<20}", ""); percent_line += powerColPercent(design_internal, design_total, field_width); percent_line += powerColPercent(design_switching, design_total, field_width); percent_line += powerColPercent(design_leakage, design_total, field_width); - report_->reportLineString(percent_line); + report_->reportLine(percent_line); } void @@ -84,13 +83,11 @@ ReportPower::reportInsts(const InstPowers &inst_pwrs, int digits) { int field_width = std::max(digits + 6, 10); - - reportTitle4("Internal", "Switching", "Leakage", "Total", - field_width); - reportTitle4Units("Power", "Power", "Power", "Power", "(Watts)", - field_width); + + reportTitle4("Internal", "Switching", "Leakage", "Total", field_width); + reportTitle4Units("Power", "Power", "Power", "Power", "(Watts)", field_width); reportTitleDashes4(field_width); - + for (const InstPower &inst_pwr : inst_pwrs) { reportInst(inst_pwr.first, inst_pwr.second, field_width, digits); } @@ -106,14 +103,14 @@ ReportPower::reportInst(const Instance *inst, float switching = power.switching(); float leakage = power.leakage(); float total = power.total(); - + std::string line = powerCol(internal, field_width, digits); line += powerCol(switching, field_width, digits); line += powerCol(leakage, field_width, digits); line += powerCol(total, field_width, digits); line += " "; line += network_->pathName(inst); - report_->reportLineString(line); + report_->reportLine(line); } std::string @@ -122,9 +119,9 @@ ReportPower::powerCol(float pwr, int digits) { if (std::isnan(pwr)) - return stdstrPrint(" %*s", field_width, "NaN"); + return sta::format(" {:>{}}", "NaN", field_width); else - return stdstrPrint(" %*.*e", field_width, digits, pwr); + return sta::format(" {:{}.{}e}", pwr, field_width, digits); } std::string @@ -136,41 +133,33 @@ ReportPower::powerColPercent(float col_total, if (total != 0.0 && !std::isnan(total)) { percent = col_total / total * 100.0; } - return stdstrPrint("%*.*f%%", field_width, 1, percent); + return sta::format("{:{}.1f}%", percent, field_width); } void ReportPower::reportTitle5(const char *title1, - const char *title2, - const char *title3, - const char *title4, - const char *title5, - int field_width) + const char *title2, + const char *title3, + const char *title4, + const char *title5, + int field_width) { - report_->reportLine("%-20s %*s %*s %*s %*s", - title1, - field_width, title2, - field_width, title3, - field_width, title4, - field_width, title5); + report_->report("{:<20} {:>{}} {:>{}} {:>{}} {:>{}}", title1, title2, field_width, + title3, field_width, title4, field_width, title5, field_width); } void ReportPower::reportTitle5Units(const char *title1, - const char *title2, - const char *title3, - const char *title4, - const char *title5, - const char *units, - int field_width) + const char *title2, + const char *title3, + const char *title4, + const char *title5, + const char *units, + int field_width) { - report_->reportLine("%-20s %*s %*s %*s %*s %s", - title1, - field_width, title2, - field_width, title3, - field_width, title4, - field_width, title5, - units); + report_->report("{:<20} {:>{}} {:>{}} {:>{}} {:>{}} {}", title1, title2, + field_width, title3, field_width, title4, field_width, title5, + field_width, units); } void @@ -178,7 +167,7 @@ ReportPower::reportTitleDashes5(int field_width) { int count = 20 + (field_width + 1) * 4; std::string dashes(count, '-'); - report_->reportLineString(dashes); + report_->reportLine(dashes); } void @@ -192,18 +181,18 @@ ReportPower::reportRow(const char *type, float switching = power.switching(); float leakage = power.leakage(); float total = power.total(); - + float percent = 0.0; if (design_total != 0.0 && !std::isnan(design_total)) percent = total / design_total * 100.0; - - std::string line = stdstrPrint("%-20s", type); + + std::string line = sta::format("{:<20}", type); line += powerCol(internal, field_width, digits); line += powerCol(switching, field_width, digits); line += powerCol(leakage, field_width, digits); line += powerCol(total, field_width, digits); - line += stdstrPrint(" %5.1f%%", percent); - report_->reportLineString(line); + line += sta::format(" {:5.1f}%", percent); + report_->reportLine(line); } void @@ -213,11 +202,8 @@ ReportPower::reportTitle4(const char *title1, const char *title4, int field_width) { - report_->reportLine(" %*s %*s %*s %*s", - field_width, title1, - field_width, title2, - field_width, title3, - field_width, title4); + report_->report(" {:>{}} {:>{}} {:>{}} {:>{}}", title1, field_width, title2, + field_width, title3, field_width, title4, field_width); } void @@ -228,12 +214,8 @@ ReportPower::reportTitle4Units(const char *title1, const char *units, int field_width) { - report_->reportLine(" %*s %*s %*s %*s %s", - field_width, title1, - field_width, title2, - field_width, title3, - field_width, title4, - units); + report_->report(" {:>{}} {:>{}} {:>{}} {:>{}} {}", title1, field_width, title2, + field_width, title3, field_width, title4, field_width, units); } void @@ -241,7 +223,7 @@ ReportPower::reportTitleDashes4(int field_width) { int count = (field_width + 1) * 4; std::string dashes(count, '-'); - report_->reportLineString(dashes); + report_->reportLine(dashes); } -} // namespace +} // namespace sta diff --git a/power/SaifParse.yy b/power/SaifParse.yy index be4f723f..6012d59a 100644 --- a/power/SaifParse.yy +++ b/power/SaifParse.yy @@ -42,7 +42,7 @@ void sta::SaifParse::error(const location_type &loc, const std::string &msg) { - reader->report()->fileError(169,reader->filename(),loc.begin.line,"%s",msg.c_str()); + reader->report()->fileError(169,reader->filename(),loc.begin.line,{}, msg); } %} diff --git a/power/SaifReader.cc b/power/SaifReader.cc index 17345229..c06cb512 100644 --- a/power/SaifReader.cc +++ b/power/SaifReader.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "power/SaifReader.hh" @@ -61,7 +61,7 @@ SaifReader::SaifReader(const char *filename, scope_(scope), divider_('/'), escape_('\\'), - timescale_(1.0E-9F), // default units of ns + timescale_(1.0E-9F), // default units of ns duration_(0.0), in_scope_level_(0), power_(sta->power()) @@ -78,7 +78,7 @@ SaifReader::read() SaifParse parser(&scanner, this); // yyparse returns 0 on success. bool success = (parser.parse() == 0); - report_->reportLine("Annotated %zu pin activities.", annotated_pins_.size()); + report_->report("Annotated {} pin activities.", annotated_pins_.size()); return success; } else @@ -95,9 +95,7 @@ void SaifReader::setTimescale(uint64_t multiplier, const char *units) { - if (multiplier == 1 - || multiplier == 10 - || multiplier == 100) { + if (multiplier == 1 || multiplier == 10 || multiplier == 100) { if (stringEq(units, "us")) timescale_ = multiplier * 1E-6; else if (stringEq(units, "ns")) @@ -107,10 +105,10 @@ SaifReader::setTimescale(uint64_t multiplier, else if (stringEq(units, "fs")) timescale_ = multiplier * 1E-15; else - report_->error(180, "SAIF TIMESCALE units not us, ns, or ps."); + report_->error(1861, "SAIF TIMESCALE units not us, ns, or ps."); } else - report_->error(181, "SAIF TIMESCALE multiplier not 1, 10, or 100."); + report_->error(1862, "SAIF TIMESCALE multiplier not 1, 10, or 100."); stringDelete(units); } @@ -168,8 +166,7 @@ SaifReader::setNetDurations(const char *net_name, std::string unescaped_name = unescaped(net_name); const Pin *pin = sdc_network_->findPin(parent, unescaped_name.c_str()); LibertyPort *liberty_port = pin ? sdc_network_->libertyPort(pin) : nullptr; - if (pin - && !sdc_network_->isHierarchical(pin) + if (pin && !sdc_network_->isHierarchical(pin) && !sdc_network_->direction(pin)->isInternal() && !(liberty_port && liberty_port->isPwrGnd())) { double t1 = durations[static_cast(SaifState::T1)]; @@ -177,13 +174,8 @@ SaifReader::setNetDurations(const char *net_name, double tc = durations[static_cast(SaifState::TC)]; float density = tc / (duration_ * timescale_); debugPrint(debug_, "read_saif", 2, - "%s duty %.0f / %" PRIu64 " = %.2f tc %.0f density %.2f", - sdc_network_->pathName(pin), - t1, - duration_, - duty, - tc, - density); + "{} duty {:.0f} / {} = {:.2f} tc {:.0f} density {:.2f}", + sdc_network_->pathName(pin), t1, duration_, duty, tc, density); power_->setUserActivity(pin, density, duty, PwrActivityOrigin::saif); annotated_pins_.insert(pin); } @@ -202,7 +194,7 @@ SaifReader::unescaped(const char *token) // Just the normal noises. unescaped += ch; } - debugPrint(debug_, "saif_name", 1, "token %s -> %s", token, unescaped.c_str()); + debugPrint(debug_, "saif_name", 1, "token {} -> {}", token, unescaped); return unescaped; } @@ -222,7 +214,7 @@ SaifScanner::SaifScanner(std::istream *stream, void SaifScanner::error(const char *msg) { - report_->fileError(1868, filename_.c_str(), lineno(), "%s", msg); + report_->fileError(1860, filename_.c_str(), lineno(), "{}", msg); } -} // namespace +} // namespace sta diff --git a/power/VcdParse.cc b/power/VcdParse.cc index 1227e1b2..c82423cf 100644 --- a/power/VcdParse.cc +++ b/power/VcdParse.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "VcdParse.hh" @@ -80,16 +80,14 @@ VcdParse::read(const char *filename, else if (token[0] == '#') { try { time_ = stoll(token.substr(1)); + } catch (std::invalid_argument &error) { + report_->fileError(805, filename_, file_line_, "invalid time {}", + token.substr(1)); + } catch (std::out_of_range &error) { + report_->fileError(806, filename_, file_line_, "time out of range {}", + token.substr(1)); } - catch (std::invalid_argument &error) { - report_->fileError(805, filename_, file_line_, "invalid time %s", - token.substr(1).c_str()); - } - catch (std::out_of_range &error) { - report_->fileError(806, filename_, file_line_, "time out of range %s", - token.substr(1).c_str()); - } - reader_->setTimeMin(time_); + reader_->setTimeMin(time_); prev_time_ = time_; } else if (token[0] == '$') @@ -151,37 +149,34 @@ VcdParse::setTimeUnit(const std::string &time_unit, reader_->setTimeUnit(time_unit, time_unit_scale, time_scale); } -static EnumNameMap vcd_var_type_map = - {{VcdVarType::wire, "wire"}, - {VcdVarType::reg, "reg"}, - {VcdVarType::parameter, "parameter"}, - {VcdVarType::integer, "integer"}, - {VcdVarType::real, "real"}, - {VcdVarType::supply0, "supply0"}, - {VcdVarType::supply1, "supply1"}, - {VcdVarType::time, "time"}, - {VcdVarType::tri, "tri"}, - {VcdVarType::triand, "triand"}, - {VcdVarType::trior, "trior"}, - {VcdVarType::trireg, "trireg"}, - {VcdVarType::tri0, "tri0"}, - {VcdVarType::tri1, "tri1"}, - {VcdVarType::wand, "wand"}, - {VcdVarType::wor, "wor"} - }; +static EnumNameMap vcd_var_type_map = { + {VcdVarType::wire, "wire"}, + {VcdVarType::reg, "reg"}, + {VcdVarType::parameter, "parameter"}, + {VcdVarType::integer, "integer"}, + {VcdVarType::real, "real"}, + {VcdVarType::supply0, "supply0"}, + {VcdVarType::supply1, "supply1"}, + {VcdVarType::time, "time"}, + {VcdVarType::tri, "tri"}, + {VcdVarType::triand, "triand"}, + {VcdVarType::trior, "trior"}, + {VcdVarType::trireg, "trireg"}, + {VcdVarType::tri0, "tri0"}, + {VcdVarType::tri1, "tri1"}, + {VcdVarType::wand, "wand"}, + {VcdVarType::wor, "wor"}}; void VcdParse::parseVar() { std::vector tokens = readStmtTokens(); - if (tokens.size() == 4 - || tokens.size() == 5) { + if (tokens.size() == 4 || tokens.size() == 5) { std::string type_name = tokens[0]; VcdVarType type = vcd_var_type_map.find(type_name, VcdVarType::unknown); if (type == VcdVarType::unknown) - report_->fileWarn(1370, filename_, file_line_, - "Unknown variable type %s.", - type_name.c_str()); + report_->fileWarn(809, filename_, file_line_, "Unknown variable type {}.", + type_name); else { size_t width = std::stoi(tokens[1]); std::string &id = tokens[2]; @@ -229,23 +224,18 @@ VcdParse::parseVarValues() if (time_ > prev_time_) reader_->varMinDeltaTime(time_ - prev_time_); } - else if (char0 == '0' - || char0 == '1' - || char0 == 'X' - || char0 == 'U' + else if (char0 == '0' || char0 == '1' || char0 == 'X' || char0 == 'U' || char0 == 'Z') { std::string id = token.substr(1); if (!reader_->varIdValid(id)) - report_->fileError(805, filename_, file_line_, - "unknown variable %s", id.c_str()); + report_->fileError(808, filename_, file_line_, "unknown variable {}", id); reader_->varAppendValue(id, time_, char0); } else if (char0 == 'B') { std::string bus_value = token.substr(1); std::string id = getToken(); if (!reader_->varIdValid(id)) - report_->fileError(807, filename_, file_line_, - "unknown variable %s", id.c_str()); + report_->fileError(807, filename_, file_line_, "unknown variable {}", id); else { // Reverse the bus value to match the bit order in the VCD file. std::reverse(bus_value.begin(), bus_value.end()); @@ -327,4 +317,4 @@ VcdValue::setValue(VcdTime time, value_ = value; } -} // namespace +} // namespace sta diff --git a/power/VcdReader.cc b/power/VcdReader.cc index 7a1b312a..fd5ed1cd 100644 --- a/power/VcdReader.cc +++ b/power/VcdReader.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "VcdReader.hh" @@ -89,12 +89,10 @@ VcdCount::incrCounts(VcdTime time, if (prev_value_ == '1') high_time_ += time - prev_time_; if (value != prev_value_) - transition_count_ += (value == 'X' - || value == 'Z' - || prev_value_ == 'X' - || prev_value_ == 'Z') - ? .5 - : 1.0; + transition_count_ += + (value == 'X' || value == 'Z' || prev_value_ == 'X' || prev_value_ == 'Z') + ? .5 + : 1.0; } prev_time_ = time; prev_value_ = value; @@ -216,8 +214,7 @@ VcdCountReader::makeVar(const VcdScope &scope, size_t width, const std::string &id) { - if (type == VcdVarType::wire - || type == VcdVarType::reg) { + if (type == VcdVarType::wire || type == VcdVarType::reg) { std::string path_name; bool first = true; for (const std::string &context : scope) { @@ -228,24 +225,23 @@ VcdCountReader::makeVar(const VcdScope &scope, } size_t scope_length = scope_.size(); // string::starts_with in c++20 - if (scope_length == 0 - || path_name.substr(0, scope_length) == scope_) { + if (scope_length == 0 || path_name.substr(0, scope_length) == scope_) { path_name += '/'; path_name += name; // Strip the scope from the name. std::string var_scoped = path_name.substr(scope_length + 1); if (width == 1) { - std::string pin_name = netVerilogToSta(&var_scoped); + std::string pin_name = netVerilogToSta(var_scoped); addVarPin(pin_name, id, width, 0); } else { bool is_bus, is_range, subscript_wild; std::string bus_name; int from, to; - parseBusName(var_scoped.c_str(), '[', ']', '\\', - is_bus, is_range, bus_name, from, to, subscript_wild); + parseBusName(var_scoped.c_str(), '[', ']', '\\', is_bus, is_range, bus_name, + from, to, subscript_wild); if (is_bus) { - std::string sta_bus_name = netVerilogToSta(&bus_name); + std::string sta_bus_name = netVerilogToSta(bus_name); int bit_idx = 0; if (to < from) { for (int bus_bit = to; bus_bit <= from; bus_bit++) { @@ -269,7 +265,7 @@ VcdCountReader::makeVar(const VcdScope &scope, } } else - report_->warn(1451, "problem parsing bus %s.", var_scoped.c_str()); + report_->warn(1451, "problem parsing bus {}.", var_scoped); } } } @@ -283,17 +279,14 @@ VcdCountReader::addVarPin(const std::string &pin_name, { const Pin *pin = sdc_network_->findPin(pin_name.c_str()); LibertyPort *liberty_port = pin ? sdc_network_->libertyPort(pin) : nullptr; - if (pin - && !sdc_network_->isHierarchical(pin) + if (pin && !sdc_network_->isHierarchical(pin) && !sdc_network_->direction(pin)->isInternal() && !sdc_network_->direction(pin)->isPowerGround() && !(liberty_port && liberty_port->isPwrGnd())) { VcdCounts &vcd_counts = vcd_count_map_[id]; vcd_counts.resize(width); vcd_counts[bit_idx].addPin(pin); - debugPrint(debug_, "read_vcd", 2, "id %s pin %s", - id.c_str(), - pin_name.c_str()); + debugPrint(debug_, "read_vcd", 2, "id {} pin {}", id, pin_name); } } @@ -309,10 +302,8 @@ VcdCountReader::varAppendValue(const std::string &id, for (size_t bit_idx = 0; bit_idx < vcd_counts.size(); bit_idx++) { VcdCount &vcd_count = vcd_counts[bit_idx]; for (const Pin *pin : vcd_count.pins()) { - debugPrint(debug_, "read_vcd", 3, "%s time %" PRIu64 " value %c", - sdc_network_->pathName(pin), - time, - value); + debugPrint(debug_, "read_vcd", 3, "{} time {} value {}", + sdc_network_->pathName(pin), time, value); } } } @@ -335,7 +326,7 @@ VcdCountReader::varAppendBusValue(const std::string &id, char bit_value; if (bus_value.size() == 1) bit_value = bus_value[0]; - else if (bit_idx < bus_value.size()) + else if (bit_idx < bus_value.size()) bit_value = bus_value[bit_idx]; else bit_value = '0'; @@ -343,10 +334,8 @@ VcdCountReader::varAppendBusValue(const std::string &id, vcd_count.incrCounts(time, bit_value); if (debug_->check("read_vcd", 3)) { for (const Pin *pin : vcd_count.pins()) { - debugPrint(debug_, "read_vcd", 3, "%s time %" PRIu64 " value %c", - sdc_network_->pathName(pin), - time, - bit_value); + debugPrint(debug_, "read_vcd", 3, "{} time {} value {}", + sdc_network_->pathName(pin), time, bit_value); } } } @@ -371,7 +360,7 @@ private: const std::string filename_; - std::set annotated_pins_; + std::set annotated_pins_; VcdCountReader vcd_reader_; VcdParse vcd_parse_; const Sdc *sdc_; @@ -398,8 +387,12 @@ ReadVcdActivities::ReadVcdActivities(const std::string &filename, Sta *sta) : StaState(sta), filename_(filename), - vcd_reader_(scope, sdc_network_, report_, debug_), - vcd_parse_(report_, debug_), + vcd_reader_(scope, + sdc_network_, + report_, + debug_), + vcd_parse_(report_, + debug_), sdc_(sdc), power_(sta->power()) { @@ -418,7 +411,7 @@ ReadVcdActivities::readActivities() setActivities(); else report_->warn(1450, "VCD max time is zero."); - report_->reportLine("Annotated %zu pin activities.", annotated_pins_.size()); + report_->report("Annotated {} pin activities.", annotated_pins_.size()); } void @@ -428,7 +421,7 @@ ReadVcdActivities::setActivities() VcdTime time_max = vcd_reader_.timeMax(); VcdTime time_delta = time_max - time_min; double time_scale = vcd_reader_.timeScale(); - for (auto& [id, vcd_counts] : vcd_reader_.countMap()) { + for (auto &[id, vcd_counts] : vcd_reader_.countMap()) { for (const VcdCount &vcd_count : vcd_counts) { double transition_count = vcd_count.transitionCount(); VcdTime high_time = vcd_count.highTime(time_max); @@ -437,11 +430,8 @@ ReadVcdActivities::setActivities() if (debug_->check("read_vcd", 1)) { for (const Pin *pin : vcd_count.pins()) { debugPrint(debug_, "read_vcd", 1, - "%s transitions %.1f activity %.2f duty %.2f", - sdc_network_->pathName(pin), - transition_count, - density, - duty); + "{} transitions {:.1f} activity {:.2f} duty {:.2f}", + sdc_network_->pathName(pin), transition_count, density, duty); } } for (const Pin *pin : vcd_count.pins()) { @@ -463,23 +453,24 @@ ReadVcdActivities::checkClkPeriod(const Pin *pin, VcdTime time_max = vcd_reader_.timeMax(); VcdTime time_min = vcd_reader_.timeMin(); double time_scale = vcd_reader_.timeScale(); - double sim_period = (time_max - time_min) * time_scale / (transition_count / 2.0); + double sim_period = + (time_max - time_min) * time_scale / (transition_count / 2.0); for (Clock *clk : *clks) { if (transition_count == 0) - report_->warn(1453, "clock %s pin %s has no vcd transitions.", - clk->name(), + report_->warn(1453, "clock {} pin {} has no vcd transitions.", clk->name(), sdc_network_->pathName(pin)); else { double clk_period = clk->period(); - if (std::abs((clk_period - sim_period) / clk_period) > sim_clk_period_tolerance_) + if (std::abs((clk_period - sim_period) / clk_period) + > sim_clk_period_tolerance_) // Warn if sim clock period differs from SDC by more than 10%. - report_->warn(1452, "clock %s vcd period %s differs from SDC clock period %s", - clk->name(), - delayAsString(sim_period, this), + report_->warn(1452, + "clock {} vcd period {} differs from SDC clock period {}", + clk->name(), delayAsString(sim_period, this), delayAsString(clk_period, this)); } } } } -} // namespace +} // namespace sta diff --git a/sdc/Clock.cc b/sdc/Clock.cc index b54f4302..df161fc2 100644 --- a/sdc/Clock.cc +++ b/sdc/Clock.cc @@ -28,6 +28,7 @@ #include "ContainerHelpers.hh" #include "Error.hh" +#include "Format.hh" #include "StringUtil.hh" #include "MinMax.hh" #include "Transition.hh" @@ -531,7 +532,7 @@ ClockEdge::ClockEdge(Clock *clock, const RiseFall *rf) : clock_(clock), rf_(rf), - name_(stringPrint("%s %s", clock_->name(), rf_->shortName())), + name_(sta::format("{} {}", clock_->name(), rf_->shortName())), time_(0.0), index_(clock_->index() * RiseFall::index_count + rf_->index()) { @@ -539,7 +540,6 @@ ClockEdge::ClockEdge(Clock *clock, ClockEdge::~ClockEdge() { - stringDelete(name_); } void diff --git a/sdc/ClockGroups.cc b/sdc/ClockGroups.cc index 9729a15c..0bf76c38 100644 --- a/sdc/ClockGroups.cc +++ b/sdc/ClockGroups.cc @@ -29,14 +29,14 @@ namespace sta { -ClockGroups::ClockGroups(const char *name, +ClockGroups::ClockGroups(const std::string &name, bool logically_exclusive, bool physically_exclusive, bool asynchronous, bool allow_paths, const char *comment) : SdcCmdComment(comment), - name_(stringCopy(name)), + name_(name), logically_exclusive_(logically_exclusive), physically_exclusive_(physically_exclusive), asynchronous_(asynchronous), @@ -46,7 +46,6 @@ ClockGroups::ClockGroups(const char *name, ClockGroups::~ClockGroups() { - stringDelete(name_); deleteContents(groups_); } diff --git a/sdc/CycleAccting.cc b/sdc/CycleAccting.cc index 3c674e05..a3baf716 100644 --- a/sdc/CycleAccting.cc +++ b/sdc/CycleAccting.cc @@ -93,7 +93,7 @@ CycleAcctings::reportClkToClkMaxCycleWarnings(Report *report) ClockPair clk_pair2(tgt_clk, src_clk); if (!clk_warnings.contains(clk_pair1) && !clk_warnings.contains(clk_pair2)) { - report->warn(1010, "No common period was found between clocks %s and %s.", + report->warn(1010, "No common period was found between clocks {} and {}.", src_clk->name(), tgt_clk->name()); clk_warnings.insert(clk_pair1); @@ -126,7 +126,7 @@ CycleAccting::findDelays(StaState *sta) { Debug *debug = sta->debug(); const Unit *time_unit = sta->units()->timeUnit(); - debugPrint(debug, "cycle_acct", 1, "%s -> %s", + debugPrint(debug, "cycle_acct", 1, "{} -> {}", src_->name(), tgt_->name()); const int setup_index = TimingRole::setup()->index(); @@ -167,14 +167,14 @@ CycleAccting::findDelays(StaState *sta) if (tgt_past_src && src_past_tgt // Synchronicity achieved. && fuzzyEqual(src_cycle_start, tgt_cycle_start)) { - debugPrint(debug, "cycle_acct", 1, " setup = %s, required = %s", + debugPrint(debug, "cycle_acct", 1, " setup = {}, required = {}", time_unit->asString(delay_[setup_index]), time_unit->asString(required_[setup_index])); - debugPrint(debug, "cycle_acct", 1, " hold = %s, required = %s", + debugPrint(debug, "cycle_acct", 1, " hold = {}, required = {}", time_unit->asString(delay_[hold_index]), time_unit->asString(required_[hold_index])); debugPrint(debug, "cycle_acct", 1, - " converged at src cycles = %d tgt cycles = %d", + " converged at src cycles = {} tgt cycles = {}", src_cycle, tgt_cycle); return; } @@ -182,13 +182,13 @@ CycleAccting::findDelays(StaState *sta) if (fuzzyGreater(src_cycle_start, tgt_cycle_start + tgt_period) && src_past_tgt) break; - debugPrint(debug, "cycle_acct", 2, " %s src cycle %d %s + %s = %s", + debugPrint(debug, "cycle_acct", 2, " {} src cycle {} {} + {} = {}", src_->name(), src_cycle, time_unit->asString(src_cycle_start), time_unit->asString(src_->time()), time_unit->asString(src_time)); - debugPrint(debug, "cycle_acct", 2, " %s tgt cycle %d %s + %s = %s", + debugPrint(debug, "cycle_acct", 2, " {} tgt cycle {} {} + {} = {}", tgt_->name(), tgt_cycle, time_unit->asString(tgt_cycle_start), @@ -203,7 +203,7 @@ CycleAccting::findDelays(StaState *sta) double required = tgt_time - src_cycle_start; setSetupAccting(src_cycle, tgt_cycle, delay, required); debugPrint(debug, "cycle_acct", 2, - " setup min delay = %s, required = %s", + " setup min delay = {}, required = {}", time_unit->asString(delay_[setup_index]), time_unit->asString(required_[setup_index])); } @@ -239,7 +239,7 @@ CycleAccting::findDelays(StaState *sta) setAccting(TimingRole::latchSetup(), src_cycle, latch_tgt_cycle, delay, required); debugPrint(debug, "cycle_acct", 2, - " latch setup min delay = %s, required = %s", + " latch setup min delay = {}, required = {}", time_unit->asString(delay_[latch_setup_index]), time_unit->asString(required_[latch_setup_index])); } @@ -253,7 +253,7 @@ CycleAccting::findDelays(StaState *sta) double required = tgt_time - src_cycle_start; setHoldAccting(src_cycle, tgt_cycle, delay, required); debugPrint(debug, "cycle_acct", 2, - " hold min delay = %s, required = %s", + " hold min delay = {}, required = {}", time_unit->asString(delay_[hold_index]), time_unit->asString(required_[hold_index])); } @@ -268,7 +268,7 @@ CycleAccting::findDelays(StaState *sta) setAccting(TimingRole::gatedClockHold(), src_cycle, tgt_cycle, delay, required); debugPrint(debug, "cycle_acct", 2, - " gated clk hold min delay = %s, required = %s", + " gated clk hold min delay = {}, required = {}", time_unit->asString(delay_[gclk_hold_index]), time_unit->asString(required_[gclk_hold_index])); } @@ -278,7 +278,7 @@ CycleAccting::findDelays(StaState *sta) } max_cycles_exceeded_ = true; debugPrint(debug, "cycle_acct", 1, - " max cycles exceeded after %d src cycles, %d tgt_cycles", + " max cycles exceeded after {} src cycles, {} tgt_cycles", src_cycle, tgt_cycle); } else if (tgt_period > 0.0) diff --git a/sdc/ExceptionPath.cc b/sdc/ExceptionPath.cc index 4ca26e4e..83bb6055 100644 --- a/sdc/ExceptionPath.cc +++ b/sdc/ExceptionPath.cc @@ -26,6 +26,7 @@ #include +#include "Format.hh" #include "ContainerHelpers.hh" #include "MinMax.hh" #include "TimingRole.hh" @@ -121,17 +122,10 @@ ExceptionPath::~ExceptionPath() } } -const char * -ExceptionPath::asString(const Network *network) const +std::string +ExceptionPath::to_string(const Network *network) const { - const char *from_thru_to = fromThruToString(network); - const char *type = typeString(); - size_t length = strlen(type) + strlen(from_thru_to) + 1; - char *result = makeTmpString(length); - char *r = result; - stringAppend(r, type); - stringAppend(r, from_thru_to); - return result; + return sta::format("{}{}", typeString(), fromThruToString(network)); } void @@ -321,7 +315,7 @@ ExceptionPath::intersectsPts(ExceptionPath *exception, return false; } -const char * +std::string ExceptionPath::fromThruToString(const Network *network) const { std::string str; @@ -331,7 +325,7 @@ ExceptionPath::fromThruToString(const Network *network) const } if (from_) - str += from_->asString(network); + str += from_->to_string(network); if (thrus_) { str += " -thru"; @@ -341,7 +335,7 @@ ExceptionPath::fromThruToString(const Network *network) const if (!first_thru) str += " &&"; str += " {"; - str += thru->asString(network); + str += thru->to_string(network); str += "}"; first_thru = false; } @@ -349,11 +343,9 @@ ExceptionPath::fromThruToString(const Network *network) const } if (to_) - str += to_->asString(network); + str += to_->to_string(network); - char *result = makeTmpString(str.size() + 1); - strcpy(result, str.c_str()); - return result; + return str; } ExceptionState * @@ -524,14 +516,12 @@ PathDelay::tighterThan(ExceptionPath *exception) const return delay_ < exception->delay(); } -const char * -PathDelay::asString(const Network *network) const +std::string +PathDelay::to_string(const Network *network) const { - const char *from_thru_to = fromThruToString(network); - const char *result = stringPrintTmp("PathDelay %.3fns%s", - delay_ * 1E+9F, - from_thru_to); - return result; + return sta::format("PathDelay {:.3f}ns{}", + delay_ * 1E+9F, + fromThruToString(network)); } const char * @@ -728,15 +718,13 @@ MultiCyclePath::matches(const MinMax *min_max, || (!exactly && min_max == MinMax::min()); } -const char * -MultiCyclePath::asString(const Network *network) const +std::string +MultiCyclePath::to_string(const Network *network) const { - const char *from_thru_to = fromThruToString(network); - const char *result = stringPrintTmp("Multicycle %s %d%s", - (use_end_clk_) ? "-end" : "-start", - path_multiplier_, - from_thru_to); - return result; + return sta::format("Multicycle {} {}{}", + (use_end_clk_) ? "-end" : "-start", + path_multiplier_, + fromThruToString(network)); } const char * @@ -826,7 +814,7 @@ FilterPath::resetMatch(ExceptionFrom *, //////////////////////////////////////////////////////////////// -GroupPath::GroupPath(const char *name, +GroupPath::GroupPath(const std::string &name, bool is_default, ExceptionFrom *from, ExceptionThruSeq *thrus, @@ -836,14 +824,13 @@ GroupPath::GroupPath(const char *name, ExceptionPath(from, thrus, to, MinMaxAll::all(), own_pts, groupPathPriority() + fromThruToPriority(from, thrus, to), comment), - name_(stringCopy(name)), + name_(name), is_default_(is_default) { } GroupPath::~GroupPath() { - stringDelete(name_); } const char * @@ -877,7 +864,7 @@ GroupPath::tighterThan(ExceptionPath *) const bool GroupPath::mergeable(ExceptionPath *exception) const { - return stringEqIf(name_, exception->name()) + return name_ == exception->name() && ExceptionPath::mergeable(exception) && overrides(exception); } @@ -887,12 +874,12 @@ GroupPath::overrides(ExceptionPath *exception) const { return exception->isGroupPath() && is_default_ == exception->isDefault() - && stringEqIf(name_, exception->name()); + && name_ == exception->name(); } //////////////////////////////////////////////////////////////// -const int ExceptionPt::as_string_max_objects_ = 20; +const int ExceptionPt::to_string_max_objects_ = 20; ExceptionPt::ExceptionPt(const RiseFallBoth *rf, bool own_pts) : @@ -1181,8 +1168,8 @@ ExceptionFromTo::deletePinBefore(const Pin *pin, deletePin(pin, network); } -const char * -ExceptionFromTo::asString(const Network *network) const +std::string +ExceptionFromTo::to_string(const Network *network) const { std::string str; str += " "; @@ -1199,7 +1186,7 @@ ExceptionFromTo::asString(const Network *network) const str += network->pathName(pin); first = false; obj_count++; - if (obj_count > as_string_max_objects_) + if (obj_count > to_string_max_objects_) break; } } @@ -1211,7 +1198,7 @@ ExceptionFromTo::asString(const Network *network) const str += clk->name(); first = false; obj_count++; - if (obj_count > as_string_max_objects_) + if (obj_count > to_string_max_objects_) break; } } @@ -1223,18 +1210,16 @@ ExceptionFromTo::asString(const Network *network) const str += network->pathName(inst); first = false; obj_count++; - if (obj_count > as_string_max_objects_) + if (obj_count > to_string_max_objects_) break; } } - if (obj_count == as_string_max_objects_) + if (obj_count == to_string_max_objects_) str += ", ..."; str += "}"; - char *result = makeTmpString(str.size() + 1); - strcpy(result, str.c_str()); - return result; + return str; } size_t @@ -1355,19 +1340,17 @@ ExceptionTo::clone(const Network *network) return new ExceptionTo(pins, clks, insts, rf_, end_rf_, true, network); } -const char * -ExceptionTo::asString(const Network *network) const +std::string +ExceptionTo::to_string(const Network *network) const { std::string str; if (hasObjects()) - str += ExceptionFromTo::asString(network); + str += ExceptionFromTo::to_string(network); if (end_rf_ != RiseFallBoth::riseFall()) str += (end_rf_ == RiseFallBoth::rise()) ? " -rise" : " -fall"; - char *result = makeTmpString(str.size() + 1); - strcpy(result, str.c_str()); - return result; + return str; } bool @@ -1674,8 +1657,8 @@ ExceptionThru::~ExceptionThru() } } -const char * -ExceptionThru::asString(const Network *network) const +std::string +ExceptionThru::to_string(const Network *network) const { std::string str; bool first = true; @@ -1688,7 +1671,7 @@ ExceptionThru::asString(const Network *network) const str += network->pathName(pin); first = false; obj_count++; - if (obj_count > as_string_max_objects_) + if (obj_count > to_string_max_objects_) break; } } @@ -1700,7 +1683,7 @@ ExceptionThru::asString(const Network *network) const str += network->pathName(net); first = false; obj_count++; - if (obj_count > as_string_max_objects_) + if (obj_count > to_string_max_objects_) break; } } @@ -1712,20 +1695,18 @@ ExceptionThru::asString(const Network *network) const str += network->pathName(inst); first = false; obj_count++; - if (obj_count > as_string_max_objects_) + if (obj_count > to_string_max_objects_) break; } } - if (obj_count == as_string_max_objects_) + if (obj_count == to_string_max_objects_) str += ", ..."; if (rf_ == RiseFallBoth::rise()) str += " rise"; else if (rf_ == RiseFallBoth::fall()) str += " fall"; - char *result = makeTmpString(str.size() + 1); - strcpy(result, str.c_str()); - return result; + return str; } ExceptionThruSeq * diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 6d035b05..8889f177 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -1941,40 +1941,38 @@ ClockInsertionkLess::operator()(const ClockInsertion *insert1, //////////////////////////////////////////////////////////////// ClockGroups * -Sdc::makeClockGroups(const char *name, +Sdc::makeClockGroups(const std::string &name, bool logically_exclusive, bool physically_exclusive, bool asynchronous, bool allow_paths, const char *comment) { - char *gen_name = nullptr; - if (name == nullptr - || name[0] == '\0') - name = gen_name = makeClockGroupsName(); + std::string group_name; + if (name.empty()) + group_name = makeClockGroupsName(); else { - ClockGroups *groups = findKey(clk_groups_name_map_, name); + group_name = name; + ClockGroups *groups = findKey(clk_groups_name_map_, group_name); if (groups) removeClockGroups(groups); } - ClockGroups *groups = new ClockGroups(name, logically_exclusive, + ClockGroups *groups = new ClockGroups(group_name, logically_exclusive, physically_exclusive, asynchronous, allow_paths, comment); clk_groups_name_map_[groups->name()] = groups; - stringDelete(gen_name); return groups; } // Generate a name for the clock group. -char * +std::string Sdc::makeClockGroupsName() { - char *name = nullptr; + std::string name; int i = 0; do { i++; - stringDelete(name); - name = stringPrint("group%d", i); + name = sta::format("group{}", i); } while (clk_groups_name_map_.contains(name)); return name; } @@ -1990,7 +1988,7 @@ void Sdc::ensureClkGroupExclusions() { if (clk_group_exclusions_.empty()) { - for (const auto [name, clk_groups] : clk_groups_name_map_) + for (const auto &[name, clk_groups] : clk_groups_name_map_) makeClkGroupExclusions(clk_groups); } } @@ -2087,7 +2085,7 @@ Sdc::sameClockGroupExplicit(const Clock *clk1, } void -Sdc::removeClockGroups(const char *name) +Sdc::removeClockGroups(const std::string &name) { ClockGroups *clk_groups = findKey(clk_groups_name_map_, name); if (clk_groups) @@ -2095,51 +2093,55 @@ Sdc::removeClockGroups(const char *name) } void -Sdc::removeClockGroupsLogicallyExclusive(const char *name) +Sdc::removeClockGroupsLogicallyExclusive() { - if (name) { - ClockGroups *groups = findKey(clk_groups_name_map_, name); - if (groups && groups->logicallyExclusive()) + + for (const auto &[name, groups] : clk_groups_name_map_) { + if (groups->logicallyExclusive()) removeClockGroups(groups); } - else { - for (const auto [name, groups] : clk_groups_name_map_) { - if (groups->logicallyExclusive()) - removeClockGroups(groups); - } - } } void -Sdc::removeClockGroupsPhysicallyExclusive(const char *name) +Sdc::removeClockGroupsLogicallyExclusive(const std::string &name) { - if (name) { - ClockGroups *groups = findKey(clk_groups_name_map_, name); - if (groups && groups->physicallyExclusive()) + ClockGroups *groups = findKey(clk_groups_name_map_, name); + if (groups && groups->logicallyExclusive()) + removeClockGroups(groups); +} + +void +Sdc::removeClockGroupsPhysicallyExclusive() +{ + for (const auto &[name, groups] : clk_groups_name_map_) { + if (groups->physicallyExclusive()) removeClockGroups(groups); } - else { - for (const auto [name, groups] : clk_groups_name_map_) { - if (groups->physicallyExclusive()) - removeClockGroups(groups); - } - } } void -Sdc::removeClockGroupsAsynchronous(const char *name) +Sdc::removeClockGroupsPhysicallyExclusive(const std::string &name) { - if (name) { - ClockGroups *groups = findKey(clk_groups_name_map_, name); - if (groups && groups->asynchronous()) + ClockGroups *groups = findKey(clk_groups_name_map_, name); + if (groups && groups->physicallyExclusive()) + removeClockGroups(groups); +} + +void +Sdc::removeClockGroupsAsynchronous() +{ + for (const auto &[name, groups] : clk_groups_name_map_) { + if (groups->asynchronous()) removeClockGroups(groups); } - else { - for (const auto [name, groups] : clk_groups_name_map_) { - if (groups->asynchronous()) - removeClockGroups(groups); - } - } +} + +void +Sdc::removeClockGroupsAsynchronous(const std::string &name) +{ + ClockGroups *groups = findKey(clk_groups_name_map_, name); + if (groups && groups->asynchronous()) + removeClockGroups(groups); } void @@ -2155,7 +2157,7 @@ Sdc::removeClockGroups(ClockGroups *groups) void Sdc::clockGroupsDeleteClkRefs(Clock *clk) { - for (const auto [name, groups] : clk_groups_name_map_) + for (const auto &[name, groups] : clk_groups_name_map_) groups->removeClock(clk); clearClkGroupExclusions(); } @@ -4080,9 +4082,7 @@ void Sdc::clearGroupPathMap() { // GroupPath exceptions are deleted with other exceptions. - // Delete group_path name strings. for (auto [name, groups] : group_path_map_) { - stringDelete(name); deleteContents(*groups); delete groups; } @@ -4090,7 +4090,7 @@ Sdc::clearGroupPathMap() } void -Sdc::makeGroupPath(const char *name, +Sdc::makeGroupPath(const std::string &name, bool is_default, ExceptionFrom *from, ExceptionThruSeq *thrus, @@ -4098,9 +4098,9 @@ Sdc::makeGroupPath(const char *name, const char *comment) { checkFromThrusTo(from, thrus, to); - if (name && is_default) + if (!name.empty() && is_default) report_->critical(1490, "group path name and is_default are mutually exclusive."); - else if (name) { + else if (!name.empty()) { GroupPath *group_path = new GroupPath(name, is_default, from, thrus, to, true, comment); // Clone the group_path because it may get merged and hence deleted @@ -4115,7 +4115,7 @@ Sdc::makeGroupPath(const char *name, GroupPathSet *groups = findKey(group_path_map_, name); if (groups == nullptr) { groups = new GroupPathSet(network_); - group_path_map_[stringCopy(name)] = groups; + group_path_map_[name] = groups; } if (groups->contains(group_path)) // Exact copy of existing group path. @@ -4226,7 +4226,7 @@ void Sdc::makeLoopExceptionThru(const Pin *pin, ExceptionThruSeq *thrus) { - debugPrint(debug_, "levelize", 2, " %s", network_->pathName(pin)); + debugPrint(debug_, "levelize", 2, " {}", network_->pathName(pin)); PinSet *pins = new PinSet(network_); pins->insert(pin); ExceptionThru *thru = makeExceptionThru(pins, nullptr, nullptr, @@ -4254,8 +4254,8 @@ Sdc::deleteLoopExceptions() void Sdc::addException(ExceptionPath *exception) { - debugPrint(debug_, "exception_merge", 1, "add exception for %s", - exception->asString(network_)); + debugPrint(debug_, "exception_merge", 1, "add exception for {}", + exception->to_string(network_)); if (exception->isPathDelay()) { recordPathDelayInternalFrom(exception); @@ -4282,8 +4282,8 @@ Sdc::addException(ExceptionPath *exception) ExceptionTo *to = exception->to(); ExceptionTo *to1 = to ? to->clone(network_) : nullptr; ExceptionPath *exception1 = exception->clone(from1, thrus1, to1, true); - debugPrint(debug_, "exception_merge", 1, " split exception for %s", - exception1->asString(network_)); + debugPrint(debug_, "exception_merge", 1, " split exception for {}", + exception1->to_string(network_)); addException1(exception1); ClockSet *clks2 = new ClockSet(*from->clks()); @@ -4292,8 +4292,8 @@ Sdc::addException(ExceptionPath *exception) ExceptionThruSeq *thrus2 = exceptionThrusClone(exception->thrus(), network_); ExceptionTo *to2 = to ? to->clone(network_) : nullptr; ExceptionPath *exception2 = exception->clone(from2, thrus2, to2, true); - debugPrint(debug_, "exception_merge", 1, " split exception for %s", - exception2->asString(network_)); + debugPrint(debug_, "exception_merge", 1, " split exception for {}", + exception2->to_string(network_)); addException1(exception2); delete exception; @@ -4316,8 +4316,8 @@ Sdc::addException1(ExceptionPath *exception) ExceptionTo *to1 = new ExceptionTo(pins1, nullptr, insts1, to->transition(), to->endTransition(), true, network_); ExceptionPath *exception1 = exception->clone(from1, thrus1, to1, true); - debugPrint(debug_, "exception_merge", 1, " split exception for %s", - exception1->asString(network_)); + debugPrint(debug_, "exception_merge", 1, " split exception for {}", + exception1->to_string(network_)); addException2(exception1); ExceptionFrom *from2 = exception->from() ? exception->from()->clone(network_):nullptr; @@ -4326,8 +4326,8 @@ Sdc::addException1(ExceptionPath *exception) ExceptionTo *to2 = new ExceptionTo(nullptr, clks2, nullptr, to->transition(), to->endTransition(), true, network_); ExceptionPath *exception2 = exception->clone(from2, thrus2, to2, true); - debugPrint(debug_, "exception_merge", 1, " split exception for %s", - exception2->asString(network_)); + debugPrint(debug_, "exception_merge", 1, " split exception for {}", + exception2->to_string(network_)); addException2(exception2); delete exception; @@ -4389,8 +4389,8 @@ Sdc::addException2(ExceptionPath *exception) void Sdc::deleteMatchingExceptions(ExceptionPath *exception) { - debugPrint(debug_, "exception_merge", 1, "find matches for %s", - exception->asString(network_)); + debugPrint(debug_, "exception_merge", 1, "find matches for {}", + exception->to_string(network_)); ExceptionPathSet matches; findMatchingExceptions(exception, matches); @@ -4676,10 +4676,10 @@ Sdc::recordMergeHash(ExceptionPath *exception, { size_t hash = exception->hash(missing_pt); debugPrint(debug_, "exception_merge", 3, - "record merge hash %zu %s missing %s", + "record merge hash {} {} missing {}", hash, - exception->asString(network_), - missing_pt->asString(network_)); + exception->to_string(network_), + missing_pt->to_string(network_)); ExceptionPathSet &set = exception_merge_hash_[hash]; set.insert(exception); } @@ -4860,10 +4860,10 @@ Sdc::findMergeMatch(ExceptionPath *exception) // search at the endpoint. && exception->mergeable(match) && match->mergeablePts(exception, missing_pt, match_missing_pt)) { - debugPrint(debug_, "exception_merge", 1, "merge %s", - exception->asString(network_)); - debugPrint(debug_, "exception_merge", 1, " with %s", - match->asString(network_)); + debugPrint(debug_, "exception_merge", 1, "merge {}", + exception->to_string(network_)); + debugPrint(debug_, "exception_merge", 1, " with {}", + match->to_string(network_)); // Unrecord the exception that is being merged away. unrecordException(exception); unrecordMergeHashes(match); @@ -4965,8 +4965,8 @@ Sdc::deleteExceptionsReferencing(Clock *clk) void Sdc::deleteException(ExceptionPath *exception) { - debugPrint(debug_, "exception_merge", 2, "delete %s", - exception->asString(network_)); + debugPrint(debug_, "exception_merge", 2, "delete {}", + exception->to_string(network_)); unrecordException(exception); delete exception; } @@ -4996,10 +4996,10 @@ Sdc::unrecordMergeHash(ExceptionPath *exception, { size_t hash = exception->hash(missing_pt); debugPrint(debug_, "exception_merge", 3, - "unrecord merge hash %zu %s missing %s", + "unrecord merge hash {} {} missing {}", hash, - exception->asString(network_), - missing_pt->asString(network_)); + exception->to_string(network_), + missing_pt->to_string(network_)); auto itr = exception_merge_hash_.find(hash); if (itr != exception_merge_hash_.end()) { ExceptionPathSet &matches = itr->second; @@ -5214,8 +5214,8 @@ Sdc::resetPath(ExceptionFrom *from, for (auto itr = exceptions_.begin(); itr != exceptions_.end(); ) { ExceptionPath *match = *itr; if (match->resetMatch(from, thrus, to, min_max, network_)) { - debugPrint(debug_, "exception_match", 3, "reset match %s", - match->asString(network_)); + debugPrint(debug_, "exception_match", 3, "reset match {}", + match->to_string(network_)); ExceptionPathSet expansions; expandException(match, expansions); itr = exceptions_.erase(itr); diff --git a/sdc/Sdc.i b/sdc/Sdc.i index 1347ac25..0b0251f1 100644 --- a/sdc/Sdc.i +++ b/sdc/Sdc.i @@ -860,8 +860,6 @@ make_group_path(const char *name, { Sta *sta = Sta::sta(); Sdc *sdc = sta->cmdSdc(); - if (name[0] == '\0') - name = nullptr; sta->makeGroupPath(name, is_default, from, thrus, to, comment, sdc); } @@ -975,6 +973,14 @@ clock_groups_make_group(ClockGroups *clk_groups, sta->makeClockGroup(clk_groups, clks, sdc); } +void +unset_clock_groups_logically_exclusive() +{ + Sta *sta = Sta::sta(); + Sdc *sdc = sta->cmdSdc(); + sta->removeClockGroupsLogicallyExclusive(sdc); +} + void unset_clock_groups_logically_exclusive(const char *name) { @@ -983,6 +989,14 @@ unset_clock_groups_logically_exclusive(const char *name) sta->removeClockGroupsLogicallyExclusive(name, sdc); } +void +unset_clock_groups_physically_exclusive() +{ + Sta *sta = Sta::sta(); + Sdc *sdc = sta->cmdSdc(); + sta->removeClockGroupsPhysicallyExclusive(sdc); +} + void unset_clock_groups_physically_exclusive(const char *name) { @@ -991,6 +1005,14 @@ unset_clock_groups_physically_exclusive(const char *name) sta->removeClockGroupsPhysicallyExclusive(name, sdc); } +void +unset_clock_groups_asynchronous() +{ + Sta *sta = Sta::sta(); + Sdc *sdc = sta->cmdSdc(); + sta->removeClockGroupsAsynchronous(sdc); +} + void unset_clock_groups_asynchronous(const char *name) { diff --git a/sdc/Sdc.tcl b/sdc/Sdc.tcl index 50f49e95..26196d2f 100644 --- a/sdc/Sdc.tcl +++ b/sdc/Sdc.tcl @@ -1435,11 +1435,11 @@ proc unset_clk_groups_cmd { cmd cmd_args } { if { $all } { if { $logically_exclusive } { - unset_clock_groups_logically_exclusive "NULL" + unset_clock_groups_logically_exclusive_all } elseif { $physically_exclusive } { - unset_clock_groups_physically_exclusive "NULL" + unset_clock_groups_physically_exclusive_all } elseif { $asynchronous } { - unset_clock_groups_asynchronous "NULL" + unset_clock_groups_asynchronous_all } } else { foreach name $names { diff --git a/sdc/Variables.cc b/sdc/Variables.cc index 6aae9894..f877fc45 100644 --- a/sdc/Variables.cc +++ b/sdc/Variables.cc @@ -39,7 +39,8 @@ Variables::Variables() : dynamic_loop_breaking_(false), propagate_all_clks_(false), use_default_arrival_clock_(false), - pocv_enabled_(false) + pocv_mode_(PocvMode::scalar), + pocv_quantile_(3.0) { } @@ -115,10 +116,24 @@ Variables::setUseDefaultArrivalClock(bool enable) use_default_arrival_clock_ = enable; } -void -Variables::setPocvEnabled(bool enabled) +//////////////////////////////////////////////////////////////// + +bool +Variables::pocvEnabled() const { - pocv_enabled_ = enabled; + return pocv_mode_ != PocvMode::scalar; } - + +void +Variables::setPocvMode(PocvMode mode) +{ + pocv_mode_ = mode; +} + +void +Variables::setPocvQuantile(float quantile) +{ + pocv_quantile_ = quantile; +} + } // namespace diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index cd58f136..7688fc68 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -32,6 +32,7 @@ #include #include "ContainerHelpers.hh" +#include "Format.hh" #include "Zlib.hh" #include "Report.hh" #include "Error.hh" @@ -148,7 +149,7 @@ void WriteGetPinAndClkKey::write() const { writer_->writeClockKey(clk_); - gzprintf(writer_->stream(), " "); + sta::print(writer_->stream(), " "); writer_->writeGetPin(pin_, map_hpin_to_drvr_); } @@ -356,18 +357,18 @@ void WriteSdc::writeHeader() const { writeCommentSeparator(); - gzprintf(stream_, "# Created by %s\n", creator_); + sta::print(stream_, "# Created by {}\n", creator_); if (!no_timestamp_) { time_t now; time(&now); char *time_str = ctime(&now); // Remove trailing \n. time_str[strlen(time_str) - 1] = '\0'; - gzprintf(stream_, "# %s\n", time_str); + sta::print(stream_, "# {}\n", time_str); } writeCommentSeparator(); - gzprintf(stream_, "current_design %s\n", sdc_network_->name(cell_)); + sta::print(stream_, "current_design {}\n", sdc_network_->name(cell_)); } //////////////////////////////////////////////////////////////// @@ -404,9 +405,9 @@ WriteSdc::writeClocks() const writeClockSlews(clk); writeClockUncertainty(clk); if (clk->isPropagated()) { - gzprintf(stream_, "set_propagated_clock "); + sta::print(stream_, "set_propagated_clock "); writeGetClock(clk); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } } @@ -414,69 +415,69 @@ WriteSdc::writeClocks() const void WriteSdc::writeClock(Clock *clk) const { - gzprintf(stream_, "create_clock -name %s", - clk->name()); + sta::print(stream_, "create_clock -name {}", + clk->name()); if (clk->addToPins()) - gzprintf(stream_, " -add"); - gzprintf(stream_, " -period "); + sta::print(stream_, " -add"); + sta::print(stream_, " -period "); float period = clk->period(); writeTime(period); FloatSeq *waveform = clk->waveform(); if (!(waveform->size() == 2 && (*waveform)[0] == 0.0 && fuzzyEqual((*waveform)[1], period / 2.0))) { - gzprintf(stream_, " -waveform "); + sta::print(stream_, " -waveform "); writeFloatSeq(waveform, scaleTime(1.0)); } writeCmdComment(clk); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeClockPins(clk); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } void WriteSdc::writeGeneratedClock(Clock *clk) const { - gzprintf(stream_, "create_generated_clock -name %s", - clk->name()); + sta::print(stream_, "create_generated_clock -name {}", + clk->name()); if (clk->addToPins()) - gzprintf(stream_, " -add"); - gzprintf(stream_, " -source "); + sta::print(stream_, " -add"); + sta::print(stream_, " -source "); writeGetPin(clk->srcPin(), true); Clock *master = clk->masterClk(); if (master && !clk->masterClkInfered()) { - gzprintf(stream_, " -master_clock "); + sta::print(stream_, " -master_clock "); writeGetClock(master); } if (clk->combinational()) - gzprintf(stream_, " -combinational"); + sta::print(stream_, " -combinational"); int divide_by = clk->divideBy(); if (divide_by != 0) - gzprintf(stream_, " -divide_by %d", divide_by); + sta::print(stream_, " -divide_by {}", divide_by); int multiply_by = clk->multiplyBy(); if (multiply_by != 0) - gzprintf(stream_, " -multiply_by %d", multiply_by); + sta::print(stream_, " -multiply_by {}", multiply_by); float duty_cycle = clk->dutyCycle(); if (duty_cycle != 0.0) { - gzprintf(stream_, " -duty_cycle "); + sta::print(stream_, " -duty_cycle "); writeFloat(duty_cycle); } if (clk->invert()) - gzprintf(stream_, " -invert"); + sta::print(stream_, " -invert"); IntSeq *edges = clk->edges(); if (edges && !edges->empty()) { - gzprintf(stream_, " -edges "); + sta::print(stream_, " -edges "); writeIntSeq(edges); FloatSeq *edge_shifts = clk->edgeShifts(); if (edge_shifts && !edge_shifts->empty()) { - gzprintf(stream_, " -edge_shift "); + sta::print(stream_, " -edge_shift "); writeFloatSeq(edge_shifts, scaleTime(1.0)); } } writeCmdComment(clk); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeClockPins(clk); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } void @@ -485,7 +486,7 @@ WriteSdc::writeClockPins(const Clock *clk) const const PinSet &pins = clk->pins(); if (!pins.empty()) { if (pins.size() > 1) - gzprintf(stream_, "\\\n "); + sta::print(stream_, "\\\n "); writeGetPins(&pins, true); } } @@ -523,9 +524,9 @@ WriteSdc::writeClockUncertainty(const Clock *clk, const char *setup_hold, float value) const { - gzprintf(stream_, "set_clock_uncertainty %s", setup_hold); + sta::print(stream_, "set_clock_uncertainty {}", setup_hold); writeTime(value); - gzprintf(stream_, " %s\n", clk->name()); + sta::print(stream_, " {}\n", clk->name()); } void @@ -560,11 +561,11 @@ WriteSdc::writeClockUncertaintyPin(const Pin *pin, const char *setup_hold, float value) const { - gzprintf(stream_, "set_clock_uncertainty %s", setup_hold); + sta::print(stream_, "set_clock_uncertainty {}", setup_hold); writeTime(value); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetPin(pin, true); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } void @@ -633,9 +634,9 @@ void WriteSdc::writePropagatedClkPins() const { for (const Pin *pin : sdc_->propagated_clk_pins_) { - gzprintf(stream_, "set_propagated_clock "); + sta::print(stream_, "set_propagated_clock "); writeGetPin(pin, true); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } @@ -659,13 +660,13 @@ writeInterClockUncertainty(InterClockUncertainty *uncertainty) const float value; if (src_rise->equal(src_fall) && src_rise->isOneValue(value)) { - gzprintf(stream_, "set_clock_uncertainty -from "); + sta::print(stream_, "set_clock_uncertainty -from "); writeGetClock(src_clk); - gzprintf(stream_, " -to "); + sta::print(stream_, " -to "); writeGetClock(tgt_clk); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeTime(value); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } else { for (auto src_rf : RiseFall::range()) { @@ -676,16 +677,16 @@ writeInterClockUncertainty(InterClockUncertainty *uncertainty) const sdc_->clockUncertainty(src_clk, src_rf, tgt_clk, tgt_rf, setup_hold, value, exists); if (exists) { - gzprintf(stream_, "set_clock_uncertainty -%s_from ", - src_rf == RiseFall::rise() ? "rise" : "fall"); + sta::print(stream_, "set_clock_uncertainty -{}_from ", + src_rf == RiseFall::rise() ? "rise" : "fall"); writeGetClock(uncertainty->src()); - gzprintf(stream_, " -%s_to ", - tgt_rf == RiseFall::rise() ? "rise" : "fall"); + sta::print(stream_, " -{}_to ", + tgt_rf == RiseFall::rise() ? "rise" : "fall"); writeGetClock(uncertainty->target()); - gzprintf(stream_, " %s ", - setupHoldFlag(setup_hold)); + sta::print(stream_, " {} ", + setupHoldFlag(setup_hold)); writeTime(value); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } } @@ -794,25 +795,25 @@ WriteSdc::writePortDelay(PortDelay *port_delay, const MinMaxAll *min_max, const char *sdc_cmd) const { - gzprintf(stream_, "%s ", sdc_cmd); + sta::print(stream_, "{} ", sdc_cmd); writeTime(delay); const ClockEdge *clk_edge = port_delay->clkEdge(); if (clk_edge) { writeClockKey(clk_edge->clock()); if (clk_edge->transition() == RiseFall::fall()) - gzprintf(stream_, " -clock_fall"); + sta::print(stream_, " -clock_fall"); } - gzprintf(stream_, "%s%s -add_delay ", - transRiseFallFlag(rf), - minMaxFlag(min_max)); + sta::print(stream_, "{}{} -add_delay ", + transRiseFallFlag(rf), + minMaxFlag(min_max)); const Pin *ref_pin = port_delay->refPin(); if (ref_pin) { - gzprintf(stream_, "-reference_pin "); + sta::print(stream_, "-reference_pin "); writeGetPin(ref_pin, true); - gzprintf(stream_, " "); + sta::print(stream_, " "); } writeGetPin(port_delay->pin(), is_input_delay); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } class PinClockPairNameLess @@ -876,15 +877,15 @@ WriteSdc::writeClockSense(PinClockPair &pin_clk, flag = "-negative"; else if (sense == ClockSense::stop) flag = "-stop_propagation"; - gzprintf(stream_, "set_sense -type clock %s ", flag); + sta::print(stream_, "set_sense -type clock {} ", flag); const Clock *clk = pin_clk.second; if (clk) { - gzprintf(stream_, "-clock "); + sta::print(stream_, "-clock "); writeGetClock(clk); - gzprintf(stream_, " "); + sta::print(stream_, " "); } writeGetPin(pin_clk.first, true); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } class ClockGroupLess @@ -935,22 +936,22 @@ ClockGroupLess::operator()(const ClockGroup *clk_group1, void WriteSdc::writeClockGroups() const { - for (const auto [name, clk_groups] : sdc_->clk_groups_name_map_) + for (const auto &[name, clk_groups] : sdc_->clk_groups_name_map_) writeClockGroups(clk_groups); } void WriteSdc::writeClockGroups(ClockGroups *clk_groups) const { - gzprintf(stream_, "set_clock_groups -name %s ", clk_groups->name()); + sta::print(stream_, "set_clock_groups -name {} ", clk_groups->name()); if (clk_groups->logicallyExclusive()) - gzprintf(stream_, "-logically_exclusive \\\n"); + sta::print(stream_, "-logically_exclusive \\\n"); else if (clk_groups->physicallyExclusive()) - gzprintf(stream_, "-physically_exclusive \\\n"); + sta::print(stream_, "-physically_exclusive \\\n"); else if (clk_groups->asynchronous()) - gzprintf(stream_, "-asynchronous \\\n"); + sta::print(stream_, "-asynchronous \\\n"); if (clk_groups->allowPaths()) - gzprintf(stream_, "-allow_paths \\\n"); + sta::print(stream_, "-allow_paths \\\n"); std::vector groups; for (ClockGroup *clk_group : *clk_groups->groups()) groups.push_back(clk_group); @@ -958,13 +959,13 @@ WriteSdc::writeClockGroups(ClockGroups *clk_groups) const bool first = true; for (ClockGroup *clk_group : groups) { if (!first) - gzprintf(stream_, "\\\n"); - gzprintf(stream_, " -group "); + sta::print(stream_, "\\\n"); + sta::print(stream_, " -group "); writeGetClocks(clk_group); first = false; } writeCmdComment(clk_groups); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } //////////////////////////////////////////////////////////////// @@ -987,46 +988,46 @@ WriteSdc::writeDisabledCells() const for (const DisabledCellPorts *disable : disables) { const LibertyCell *cell = disable->cell(); if (disable->all()) { - gzprintf(stream_, "set_disable_timing "); + sta::print(stream_, "set_disable_timing "); writeGetLibCell(cell); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } if (disable->fromTo()) { LibertyPortPairSeq from_tos = sortByName(disable->fromTo()); for (const LibertyPortPair &from_to : from_tos) { const LibertyPort *from = from_to.first; const LibertyPort *to = from_to.second; - gzprintf(stream_, "set_disable_timing -from {%s} -to {%s} ", - from->name(), - to->name()); + sta::print(stream_, "set_disable_timing -from {{{}}} -to {{{}}} ", + from->name(), + to->name()); writeGetLibCell(cell); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } if (disable->from()) { LibertyPortSeq from = sortByName(disable->from()); for (const LibertyPort *from_port : from) { - gzprintf(stream_, "set_disable_timing -from {%s} ", - from_port->name()); + sta::print(stream_, "set_disable_timing -from {{{}}} ", + from_port->name()); writeGetLibCell(cell); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } if (disable->to()) { LibertyPortSeq to = sortByName(disable->to()); for (const LibertyPort *to_port : to) { - gzprintf(stream_, "set_disable_timing -to {%s} ", - to_port->name()); + sta::print(stream_, "set_disable_timing -to {{{}}} ", + to_port->name()); writeGetLibCell(cell); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } if (disable->timingArcSets()) { // The only syntax to disable timing arc sets disables all of the // cell's timing arc sets. - gzprintf(stream_, "set_disable_timing "); + sta::print(stream_, "set_disable_timing "); writeGetTimingArcsOfOjbects(cell); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } } @@ -1036,9 +1037,9 @@ WriteSdc::writeDisabledPorts() const { const PortSeq ports = sortByName(sdc_->disabledPorts(), sdc_network_); for (const Port *port : ports) { - gzprintf(stream_, "set_disable_timing "); + sta::print(stream_, "set_disable_timing "); writeGetPort(port); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } @@ -1047,9 +1048,9 @@ WriteSdc::writeDisabledLibPorts() const { LibertyPortSeq ports = sortByName(sdc_->disabledLibPorts()); for (LibertyPort *port : ports) { - gzprintf(stream_, "set_disable_timing "); + sta::print(stream_, "set_disable_timing "); writeGetLibPin(port); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } @@ -1061,38 +1062,38 @@ WriteSdc::writeDisabledInstances() const for (DisabledInstancePorts *disable : disables) { Instance *inst = disable->instance(); if (disable->all()) { - gzprintf(stream_, "set_disable_timing "); + sta::print(stream_, "set_disable_timing "); writeGetInstance(inst); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } else if (disable->fromTo()) { LibertyPortPairSeq from_tos = sortByName(disable->fromTo()); for (LibertyPortPair &from_to : from_tos) { const LibertyPort *from_port = from_to.first; const LibertyPort *to_port = from_to.second; - gzprintf(stream_, "set_disable_timing -from {%s} -to {%s} ", - from_port->name(), - to_port->name()); + sta::print(stream_, "set_disable_timing -from {{{}}} -to {{{}}} ", + from_port->name(), + to_port->name()); writeGetInstance(inst); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } if (disable->from()) { LibertyPortSeq from = sortByName(disable->from()); for (const LibertyPort *from_port : from) { - gzprintf(stream_, "set_disable_timing -from {%s} ", - from_port->name()); + sta::print(stream_, "set_disable_timing -from {{{}}} ", + from_port->name()); writeGetInstance(inst); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } if (disable->to()) { LibertyPortSeq to = sortByName(disable->to()); for (const LibertyPort *to_port : to) { - gzprintf(stream_, "set_disable_timing -to {%s} ", - to_port->name()); + sta::print(stream_, "set_disable_timing -to {{{}}} ", + to_port->name()); writeGetInstance(inst); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } } @@ -1103,9 +1104,9 @@ WriteSdc::writeDisabledPins() const { PinSeq pins = sortByPathName(sdc_->disabledPins(), sdc_network_); for (const Pin *pin : pins) { - gzprintf(stream_, "set_disable_timing "); + sta::print(stream_, "set_disable_timing "); writeGetPin(pin, false); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } @@ -1156,20 +1157,19 @@ WriteSdc::edgeSenseIsUnique(Edge *edge, void WriteSdc::writeDisabledEdge(Edge *edge) const { - gzprintf(stream_, "set_disable_timing "); + sta::print(stream_, "set_disable_timing "); writeGetTimingArcs(edge); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } void WriteSdc::writeDisabledEdgeSense(Edge *edge) const { - gzprintf(stream_, "set_disable_timing "); + sta::print(stream_, "set_disable_timing "); const char *sense = to_string(edge->sense()); - std::string filter; - stringPrint(filter, "sense == %s", sense); + std::string filter = sta::format("sense == {}", sense); writeGetTimingArcs(edge, filter.c_str()); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } //////////////////////////////////////////////////////////////// @@ -1202,44 +1202,44 @@ WriteSdc::writeException(ExceptionPath *exception) const writeExceptionTo(exception->to()); writeExceptionValue(exception); writeCmdComment(exception); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } void WriteSdc::writeExceptionCmd(ExceptionPath *exception) const { if (exception->isFalse()) { - gzprintf(stream_, "set_false_path"); + sta::print(stream_, "set_false_path"); writeSetupHoldFlag(exception->minMax()); } else if (exception->isMultiCycle()) { - gzprintf(stream_, "set_multicycle_path"); + sta::print(stream_, "set_multicycle_path"); const MinMaxAll *min_max = exception->minMax(); writeSetupHoldFlag(min_max); if (min_max == MinMaxAll::min()) { // For hold MCPs default is -start. if (exception->useEndClk()) - gzprintf(stream_, " -end"); + sta::print(stream_, " -end"); } else { // For setup MCPs default is -end. if (!exception->useEndClk()) - gzprintf(stream_, " -start"); + sta::print(stream_, " -start"); } } else if (exception->isPathDelay()) { if (exception->minMax() == MinMaxAll::max()) - gzprintf(stream_, "set_max_delay"); + sta::print(stream_, "set_max_delay"); else - gzprintf(stream_, "set_min_delay"); + sta::print(stream_, "set_min_delay"); if (exception->ignoreClkLatency()) - gzprintf(stream_, " -ignore_clock_latency"); + sta::print(stream_, " -ignore_clock_latency"); } else if (exception->isGroupPath()) { if (exception->isDefault()) - gzprintf(stream_, "group_path -default"); + sta::print(stream_, "group_path -default"); else - gzprintf(stream_, "group_path -name %s", exception->name()); + sta::print(stream_, "group_path -name {}", exception->name()); } else report_->critical(1620, "unknown exception type"); @@ -1249,10 +1249,10 @@ void WriteSdc::writeExceptionValue(ExceptionPath *exception) const { if (exception->isMultiCycle()) - gzprintf(stream_, " %d", - exception->pathMultiplier()); + sta::print(stream_, " {}", + exception->pathMultiplier()); else if (exception->isPathDelay()) { - gzprintf(stream_, " "); + sta::print(stream_, " "); writeTime(exception->delay()); } } @@ -1268,7 +1268,7 @@ WriteSdc::writeExceptionTo(ExceptionTo *to) const { const RiseFallBoth *end_rf = to->endTransition(); if (end_rf != RiseFallBoth::riseFall()) - gzprintf(stream_, "%s ", transRiseFallFlag(end_rf)); + sta::print(stream_, "{} ", transRiseFallFlag(end_rf)); if (to->hasObjects()) writeExceptionFromTo(to, "to", false); } @@ -1284,19 +1284,19 @@ WriteSdc::writeExceptionFromTo(ExceptionFromTo *from_to, rf_prefix = "-rise_"; else if (rf == RiseFallBoth::fall()) rf_prefix = "-fall_"; - gzprintf(stream_, "\\\n %s%s ", rf_prefix, from_to_key); + sta::print(stream_, "\\\n {}{} ", rf_prefix, from_to_key); bool multi_objs = ((from_to->pins() ? from_to->pins()->size() : 0) + (from_to->clks() ? from_to->clks()->size() : 0) + (from_to->instances() ? from_to->instances()->size() : 0)) > 1; if (multi_objs) - gzprintf(stream_, "[list "); + sta::print(stream_, "[list "); bool first = true; if (from_to->pins()) { PinSeq pins = sortByPathName(from_to->pins(), sdc_network_); for (const Pin *pin : pins) { if (multi_objs && !first) - gzprintf(stream_, "\\\n "); + sta::print(stream_, "\\\n "); writeGetPin(pin, map_hpin_to_drvr); first = false; } @@ -1307,13 +1307,13 @@ WriteSdc::writeExceptionFromTo(ExceptionFromTo *from_to, InstanceSeq insts = sortByPathName(from_to->instances(), sdc_network_); for (const Instance *inst : insts) { if (multi_objs && !first) - gzprintf(stream_, "\\\n "); + sta::print(stream_, "\\\n "); writeGetInstance(inst); first = false; } } if (multi_objs) - gzprintf(stream_, "]"); + sta::print(stream_, "]"); } void @@ -1325,7 +1325,7 @@ WriteSdc::writeExceptionThru(ExceptionThru *thru) const rf_prefix = "-rise_"; else if (rf == RiseFallBoth::fall()) rf_prefix = "-fall_"; - gzprintf(stream_, "\\\n %sthrough ", rf_prefix); + sta::print(stream_, "\\\n {}through ", rf_prefix); PinSeq pins; mapThruHpins(thru, pins); bool multi_objs = @@ -1333,12 +1333,12 @@ WriteSdc::writeExceptionThru(ExceptionThru *thru) const + (thru->nets() ? thru->nets()->size() : 0) + (thru->instances() ? thru->instances()->size() : 0)) > 1; if (multi_objs) - gzprintf(stream_, "[list "); + sta::print(stream_, "[list "); bool first = true; sort(pins, PinPathNameLess(network_)); for (const Pin *pin : pins) { if (multi_objs && !first) - gzprintf(stream_, "\\\n "); + sta::print(stream_, "\\\n "); writeGetPin(pin); first = false; } @@ -1347,7 +1347,7 @@ WriteSdc::writeExceptionThru(ExceptionThru *thru) const NetSeq nets = sortByPathName(thru->nets(), sdc_network_); for (const Net *net : nets) { if (multi_objs && !first) - gzprintf(stream_, "\\\n "); + sta::print(stream_, "\\\n "); writeGetNet(net); first = false; } @@ -1356,13 +1356,13 @@ WriteSdc::writeExceptionThru(ExceptionThru *thru) const InstanceSeq insts = sortByPathName(thru->instances(), sdc_network_); for (const Instance *inst : insts) { if (multi_objs && !first) - gzprintf(stream_, "\\\n "); + sta::print(stream_, "\\\n "); writeGetInstance(inst); first = false; } } if (multi_objs) - gzprintf(stream_, "]"); + sta::print(stream_, "]"); } void @@ -1446,19 +1446,19 @@ WriteSdc::writeDataCheck(DataCheck *check, from_key = "-rise_from"; else if (from_rf == RiseFallBoth::fall()) from_key = "-fall_from"; - gzprintf(stream_, "set_data_check %s ", from_key); + sta::print(stream_, "set_data_check {} ", from_key); writeGetPin(check->from(), true); const char *to_key = "-to"; if (to_rf == RiseFallBoth::rise()) to_key = "-rise_to"; else if (to_rf == RiseFallBoth::fall()) to_key = "-fall_to"; - gzprintf(stream_, " %s ", to_key); + sta::print(stream_, " {} ", to_key); writeGetPin(check->to(), false); - gzprintf(stream_, "%s ", - setupHoldFlag(setup_hold)); + sta::print(stream_, "{} ", + setupHoldFlag(setup_hold)); writeTime(margin); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } //////////////////////////////////////////////////////////////// @@ -1486,7 +1486,7 @@ WriteSdc::writeOperatingConditions() const { OperatingConditions *cond = sdc_->operatingConditions(MinMax::max()); if (cond) - gzprintf(stream_, "set_operating_conditions %s\n", cond->name()); + sta::print(stream_, "set_operating_conditions {}\n", cond->name()); } void @@ -1494,8 +1494,8 @@ WriteSdc::writeWireload() const { WireloadMode wireload_mode = sdc_->wireloadMode(); if (wireload_mode != WireloadMode::unknown) - gzprintf(stream_, "set_wire_load_mode \"%s\"\n", - wireloadModeString(wireload_mode)); + sta::print(stream_, "set_wire_load_mode \"{}\"\n", + wireloadModeString(wireload_mode)); } void @@ -1523,12 +1523,12 @@ WriteSdc::writeNetLoad(const Net *net, const MinMaxAll *min_max, float cap) const { - gzprintf(stream_, "set_load "); - gzprintf(stream_, "%s ", minMaxFlag(min_max)); + sta::print(stream_, "set_load "); + sta::print(stream_, "{} ", minMaxFlag(min_max)); writeCapacitance(cap); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetNet(net); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } void @@ -1572,12 +1572,12 @@ WriteSdc::writeDriveResistances() const float res; bool exists; drive->driveResistance(rf, MinMax::max(), res, exists); - gzprintf(stream_, "set_drive %s ", - transRiseFallFlag(rf)); + sta::print(stream_, "set_drive {} ", + transRiseFallFlag(rf)); writeResistance(res); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetPort(port); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } else { for (auto min_max : MinMax::range()) { @@ -1585,13 +1585,13 @@ WriteSdc::writeDriveResistances() const bool exists; drive->driveResistance(rf, min_max, res, exists); if (exists) { - gzprintf(stream_, "set_drive %s %s ", - transRiseFallFlag(rf), - minMaxFlag(min_max)); + sta::print(stream_, "set_drive {} {} ", + transRiseFallFlag(rf), + minMaxFlag(min_max)); writeResistance(res); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetPort(port); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } } @@ -1668,27 +1668,27 @@ WriteSdc::writeDrivingCell(Port *port, const LibertyPort *to_port = drive_cell->toPort(); float *from_slews = drive_cell->fromSlews(); const LibertyLibrary *lib = drive_cell->library(); - gzprintf(stream_, "set_driving_cell"); + sta::print(stream_, "set_driving_cell"); if (rf) - gzprintf(stream_, " %s", transRiseFallFlag(rf)); + sta::print(stream_, " {}", transRiseFallFlag(rf)); if (min_max) - gzprintf(stream_, " %s", minMaxFlag(min_max)); + sta::print(stream_, " {}", minMaxFlag(min_max)); // Only write -library if it was specified in the sdc. if (lib) - gzprintf(stream_, " -library %s", lib->name()); - gzprintf(stream_, " -lib_cell %s", cell->name()); + sta::print(stream_, " -library {}", lib->name()); + sta::print(stream_, " -lib_cell {}", cell->name()); if (from_port) - gzprintf(stream_, " -from_pin {%s}", - from_port->name()); - gzprintf(stream_, - " -pin {%s} -input_transition_rise ", - to_port->name()); + sta::print(stream_, " -from_pin {{{}}}", + from_port->name()); + sta::print(stream_, + " -pin {{{}}} -input_transition_rise ", + to_port->name()); writeTime(from_slews[RiseFall::riseIndex()]); - gzprintf(stream_, " -input_transition_fall "); + sta::print(stream_, " -input_transition_fall "); writeTime(from_slews[RiseFall::fallIndex()]); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetPort(port); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } void @@ -1736,11 +1736,11 @@ WriteSdc::writeNetResistance(const Net *net, const MinMaxAll *min_max, float res) const { - gzprintf(stream_, "set_resistance "); + sta::print(stream_, "set_resistance "); writeResistance(res); - gzprintf(stream_, "%s ", minMaxFlag(min_max)); + sta::print(stream_, "{} ", minMaxFlag(min_max)); writeGetNet(net); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } void @@ -1756,9 +1756,9 @@ void WriteSdc::writeConstant(const Pin *pin) const { const char *cmd = setConstantCmd(pin); - gzprintf(stream_, "%s ", cmd); + sta::print(stream_, "{} ", cmd); writeGetPin(pin, false); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } const char * @@ -1796,9 +1796,9 @@ void WriteSdc::writeCaseAnalysis(const Pin *pin) const { const char *value_str = caseAnalysisValueStr(pin); - gzprintf(stream_, "set_case_analysis %s ", value_str); + sta::print(stream_, "set_case_analysis {} ", value_str); writeGetPin(pin, false); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } const char * @@ -1882,9 +1882,9 @@ WriteSdc::writeDerating(DeratingFactorsGlobal *factors) const && (!cell_check_factors->hasValue() || (check_is_one_value && check_value == 1.0))) { if (delay_value != 1.0) { - gzprintf(stream_, "set_timing_derate %s ", earlyLateFlag(early_late)); + sta::print(stream_, "set_timing_derate {} ", earlyLateFlag(early_late)); writeFloat(delay_value); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } else { @@ -1923,15 +1923,15 @@ WriteSdc::writeDerating(DeratingFactors *factors, factors->isOneValue(early_late, is_one_value, value); if (is_one_value) { if (value != 1.0) { - gzprintf(stream_, "set_timing_derate %s %s ", - type_key, - earlyLateFlag(early_late)); + sta::print(stream_, "set_timing_derate {} {} ", + type_key, + earlyLateFlag(early_late)); writeFloat(value); if (write_obj) { - gzprintf(stream_, " "); + sta::print(stream_, " "); write_obj->write(); } - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } else { @@ -1944,16 +1944,16 @@ WriteSdc::writeDerating(DeratingFactors *factors, factors->isOneValue(clk_data, early_late, is_one_value, value); if (is_one_value) { if (value != 1.0) { - gzprintf(stream_, "set_timing_derate %s %s %s ", - type_key, - earlyLateFlag(early_late), - clk_data_key); + sta::print(stream_, "set_timing_derate {} {} {} ", + type_key, + earlyLateFlag(early_late), + clk_data_key); writeFloat(value); if (write_obj) { - gzprintf(stream_, " "); + sta::print(stream_, " "); write_obj->write(); } - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } else { @@ -1962,17 +1962,17 @@ WriteSdc::writeDerating(DeratingFactors *factors, bool exists; factors->factor(clk_data, rf, early_late, factor, exists); if (exists) { - gzprintf(stream_, "set_timing_derate %s %s %s %s ", - type_key, - clk_data_key, - transRiseFallFlag(rf), - earlyLateFlag(early_late)); + sta::print(stream_, "set_timing_derate {} {} {} {} ", + type_key, + clk_data_key, + transRiseFallFlag(rf), + earlyLateFlag(early_late)); writeFloat(factor); if (write_obj) { - gzprintf(stream_, " "); + sta::print(stream_, " "); write_obj->write(); } - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } } @@ -1998,11 +1998,11 @@ WriteSdc::writeVoltages() const if (exists_max) { sdc_->voltage(MinMax::min(), voltage_min, exists_min); if (exists_min) - gzprintf(stream_, "set_voltage -min %.3f %.3f\n", - voltage_min, - voltage_max); + sta::print(stream_, "set_voltage -min {:.3f} {:.3f}\n", + voltage_min, + voltage_max); else - gzprintf(stream_, "set_voltage %.3f\n", voltage_max); + sta::print(stream_, "set_voltage {:.3f}\n", voltage_max); } for (const auto& [net, volts] : sdc_->net_voltage_map_) { @@ -2010,14 +2010,14 @@ WriteSdc::writeVoltages() const if (exists_max) { volts.value(MinMax::min(), voltage_min, exists_min); if (exists_min) - gzprintf(stream_, "set_voltage -object_list %s -min %.3f %.3f\n", - sdc_network_->pathName(net), - voltage_min, - voltage_max); + sta::print(stream_, "set_voltage -object_list {} -min {:.3f} {:.3f}\n", + sdc_network_->pathName(net), + voltage_min, + voltage_max); else - gzprintf(stream_, "set_voltage -object_list %s %.3f\n", - sdc_network_->pathName(net), - voltage_max); + sta::print(stream_, "set_voltage -object_list {} {:.3f}\n", + sdc_network_->pathName(net), + voltage_max); } } } @@ -2079,11 +2079,11 @@ WriteSdc::writeMinPulseWidth(const char *hi_low, float value, WriteSdcObject &write_obj) const { - gzprintf(stream_, "set_min_pulse_width %s", hi_low); + sta::print(stream_, "set_min_pulse_width {}", hi_low); writeTime(value); - gzprintf(stream_, " "); + sta::print(stream_, " "); write_obj.write(); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } //////////////////////////////////////////////////////////////// @@ -2092,27 +2092,27 @@ void WriteSdc::writeLatchBorowLimits() const { for (const auto [pin, limit] : sdc_->pin_latch_borrow_limit_map_) { - gzprintf(stream_, "set_max_time_borrow "); + sta::print(stream_, "set_max_time_borrow "); writeTime(limit); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetPin(pin, false); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } for (const auto [inst, limit] : sdc_->inst_latch_borrow_limit_map_) { - gzprintf(stream_, "set_max_time_borrow "); + sta::print(stream_, "set_max_time_borrow "); writeTime(limit); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetInstance(inst); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } for (const auto [clk, limit] : sdc_->clk_latch_borrow_limit_map_) { - gzprintf(stream_, "set_max_time_borrow "); + sta::print(stream_, "set_max_time_borrow "); writeTime(limit); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetClock(clk); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } @@ -2126,9 +2126,9 @@ WriteSdc::writeSlewLimits() const bool exists; sdc_->slewLimit(cell_, min_max, slew, exists); if (exists) { - gzprintf(stream_, "set_max_transition "); + sta::print(stream_, "set_max_transition "); writeTime(slew); - gzprintf(stream_, " [current_design]\n"); + sta::print(stream_, " [current_design]\n"); } CellPortBitIterator *port_iter = sdc_network_->portBitIterator(cell_); @@ -2136,11 +2136,11 @@ WriteSdc::writeSlewLimits() const Port *port = port_iter->next(); sdc_->slewLimit(port, min_max, slew, exists); if (exists) { - gzprintf(stream_, "set_max_transition "); + sta::print(stream_, "set_max_transition "); writeTime(slew); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetPort(port); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } delete port_iter; @@ -2200,11 +2200,11 @@ WriteSdc::writeClkSlewLimit(const char *clk_data, const Clock *clk, float limit) const { - gzprintf(stream_, "set_max_transition %s%s", clk_data, rise_fall); + sta::print(stream_, "set_max_transition {}{}", clk_data, rise_fall); writeTime(limit); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetClock(clk); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } void @@ -2222,9 +2222,9 @@ WriteSdc::writeCapLimits(const MinMax *min_max, bool exists; sdc_->capacitanceLimit(cell_, min_max, cap, exists); if (exists) { - gzprintf(stream_, "%s ", cmd); + sta::print(stream_, "{} ", cmd); writeCapacitance(cap); - gzprintf(stream_, " [current_design]\n"); + sta::print(stream_, " [current_design]\n"); } for (const auto [port, limits] : sdc_->port_cap_limit_map_) { @@ -2232,11 +2232,11 @@ WriteSdc::writeCapLimits(const MinMax *min_max, bool exists; limits.value(min_max, cap, exists); if (exists) { - gzprintf(stream_, "%s ", cmd); + sta::print(stream_, "{} ", cmd); writeCapacitance(cap); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetPort(port); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } @@ -2245,11 +2245,11 @@ WriteSdc::writeCapLimits(const MinMax *min_max, bool exists; limits.value(min_max, cap, exists); if (exists) { - gzprintf(stream_, "%s ", cmd); + sta::print(stream_, "{} ", cmd); writeCapacitance(cap); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetPin(pin, false); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } } @@ -2259,9 +2259,9 @@ WriteSdc::writeMaxArea() const { float max_area = sdc_->maxArea(); if (max_area > 0.0) { - gzprintf(stream_, "set_max_area "); + sta::print(stream_, "set_max_area "); writeFloat(max_area); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } @@ -2280,9 +2280,9 @@ WriteSdc::writeFanoutLimits(const MinMax *min_max, bool exists; sdc_->fanoutLimit(cell_, min_max, fanout, exists); if (exists) { - gzprintf(stream_, "%s ", cmd); + sta::print(stream_, "{} ", cmd); writeFloat(fanout); - gzprintf(stream_, " [current_design]\n"); + sta::print(stream_, " [current_design]\n"); } else { CellPortBitIterator *port_iter = sdc_network_->portBitIterator(cell_); @@ -2290,11 +2290,11 @@ WriteSdc::writeFanoutLimits(const MinMax *min_max, Port *port = port_iter->next(); sdc_->fanoutLimit(port, min_max, fanout, exists); if (exists) { - gzprintf(stream_, "%s ", cmd); + sta::print(stream_, "{} ", cmd); writeFloat(fanout); - gzprintf(stream_, " "); + sta::print(stream_, " "); writeGetPort(port); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } } delete port_iter; @@ -2308,15 +2308,15 @@ WriteSdc::writeVariables() const { if (variables_->propagateAllClocks()) { if (native_) - gzprintf(stream_, "set sta_propagate_all_clocks 1\n"); + sta::print(stream_, "set sta_propagate_all_clocks 1\n"); else - gzprintf(stream_, "set timing_all_clocks_propagated true\n"); + sta::print(stream_, "set timing_all_clocks_propagated true\n"); } if (variables_->presetClrArcsEnabled()) { if (native_) - gzprintf(stream_, "set sta_preset_clear_arcs_enabled 1\n"); + sta::print(stream_, "set sta_preset_clear_arcs_enabled 1\n"); else - gzprintf(stream_, "set timing_enable_preset_clear_arcs true\n"); + sta::print(stream_, "set timing_enable_preset_clear_arcs true\n"); } } @@ -2325,9 +2325,9 @@ WriteSdc::writeVariables() const void WriteSdc::writeGetTimingArcsOfOjbects(const LibertyCell *cell) const { - gzprintf(stream_, "[%s -of_objects ", getTimingArcsCmd()); + sta::print(stream_, "[{} -of_objects ", getTimingArcsCmd()); writeGetLibCell(cell); - gzprintf(stream_, "]"); + sta::print(stream_, "]"); } void @@ -2340,15 +2340,15 @@ void WriteSdc::writeGetTimingArcs(Edge *edge, const char *filter) const { - gzprintf(stream_, "[%s -from ", getTimingArcsCmd()); + sta::print(stream_, "[{} -from ", getTimingArcsCmd()); Vertex *from_vertex = edge->from(graph_); writeGetPin(from_vertex->pin(), true); - gzprintf(stream_, " -to "); + sta::print(stream_, " -to "); Vertex *to_vertex = edge->to(graph_); writeGetPin(to_vertex->pin(), false); if (filter) - gzprintf(stream_, " -filter {%s}", filter); - gzprintf(stream_, "]"); + sta::print(stream_, " -filter {{{}}}", filter); + sta::print(stream_, "]"); } const char * @@ -2362,7 +2362,7 @@ WriteSdc::getTimingArcsCmd() const void WriteSdc::writeGetLibCell(const LibertyCell *cell) const { - gzprintf(stream_, "[get_lib_cells {%s/%s}]", + sta::print(stream_, "[get_lib_cells {{{}/{}}}]", cell->libertyLibrary()->name(), cell->name()); } @@ -2372,10 +2372,10 @@ WriteSdc::writeGetLibPin(const LibertyPort *port) const { LibertyCell *cell = port->libertyCell(); LibertyLibrary *lib = cell->libertyLibrary(); - gzprintf(stream_, "[get_lib_pins {%s/%s/%s}]", - lib->name(), - cell->name(), - port->name()); + sta::print(stream_, "[get_lib_pins {{{}/{}/{}}}]", + lib->name(), + cell->name(), + port->name()); } void @@ -2384,10 +2384,10 @@ WriteSdc::writeGetClocks(ClockSet *clks) const bool first = true; bool multiple = clks->size() > 1; if (multiple) - gzprintf(stream_, "[list "); + sta::print(stream_, "[list "); writeGetClocks(clks, multiple, first); if (multiple) - gzprintf(stream_, "]"); + sta::print(stream_, "]"); } void @@ -2398,7 +2398,7 @@ WriteSdc::writeGetClocks(ClockSet *clks, ClockSeq clks1 = sortByName(clks); for (const Clock *clk : clks1) { if (multiple && !first) - gzprintf(stream_, "\\\n "); + sta::print(stream_, "\\\n "); writeGetClock(clk); first = false; } @@ -2407,14 +2407,14 @@ WriteSdc::writeGetClocks(ClockSet *clks, void WriteSdc::writeGetClock(const Clock *clk) const { - gzprintf(stream_, "[get_clocks {%s}]", - clk->name()); + sta::print(stream_, "[get_clocks {{{}}}]", + clk->name()); } void WriteSdc::writeGetPort(const Port *port) const { - gzprintf(stream_, "[get_ports {%s}]", sdc_network_->name(port)); + sta::print(stream_, "[get_ports {{{}}}]", sdc_network_->name(port)); } void @@ -2447,25 +2447,25 @@ WriteSdc::writeGetPins1(PinSeq *pins) const { bool multiple = pins->size() > 1; if (multiple) - gzprintf(stream_, "[list "); + sta::print(stream_, "[list "); bool first = true; for (const Pin *pin : *pins) { if (multiple && !first) - gzprintf(stream_, "\\\n "); + sta::print(stream_, "\\\n "); writeGetPin(pin); first = false; } if (multiple) - gzprintf(stream_, "]"); + sta::print(stream_, "]"); } void WriteSdc::writeGetPin(const Pin *pin) const { if (sdc_network_->instance(pin) == instance_) - gzprintf(stream_, "[get_ports {%s}]", sdc_network_->portName(pin)); + sta::print(stream_, "[get_ports {{{}}}]", sdc_network_->portName(pin)); else - gzprintf(stream_, "[get_pins {%s}]", pathName(pin)); + sta::print(stream_, "[get_pins {{{}}}]", pathName(pin)); } void @@ -2484,13 +2484,13 @@ WriteSdc::writeGetPin(const Pin *pin, void WriteSdc::writeGetNet(const Net *net) const { - gzprintf(stream_, "[get_nets {%s}]", pathName(net)); + sta::print(stream_, "[get_nets {{{}}}]", pathName(net)); } void WriteSdc::writeGetInstance(const Instance *inst) const { - gzprintf(stream_, "[get_cells {%s}]", pathName(inst)); + sta::print(stream_, "[get_cells {{{}}}]", pathName(inst)); } const char * @@ -2527,14 +2527,14 @@ void WriteSdc::writeCommentSection(const char *line) const { writeCommentSeparator(); - gzprintf(stream_, "# %s\n", line); + sta::print(stream_, "# {}\n", line); writeCommentSeparator(); } void WriteSdc::writeCommentSeparator() const { - gzprintf(stream_, "###############################################################################\n"); + sta::print(stream_, "###############################################################################\n"); } //////////////////////////////////////////////////////////////// @@ -2632,20 +2632,20 @@ WriteSdc::writeRiseFallMinMaxCmd(const char *sdc_cmd, const MinMaxAll *min_max, WriteSdcObject &write_object) const { - gzprintf(stream_, "%s%s%s ", - sdc_cmd, - transRiseFallFlag(rf), - minMaxFlag(min_max)); + sta::print(stream_, "{}{}{} ", + sdc_cmd, + transRiseFallFlag(rf), + minMaxFlag(min_max)); writeFloat(value / scale); - gzprintf(stream_, " "); + sta::print(stream_, " "); write_object.write(); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } void WriteSdc::writeClockKey(const Clock *clk) const { - gzprintf(stream_, " -clock "); + sta::print(stream_, " -clock "); writeGetClock(clk); } @@ -2681,13 +2681,13 @@ WriteSdc::writeMinMaxFloatCmd(const char *sdc_cmd, const MinMaxAll *min_max, WriteSdcObject &write_object) const { - gzprintf(stream_, "%s%s ", - sdc_cmd, - minMaxFlag(min_max)); + sta::print(stream_, "{}{} ", + sdc_cmd, + minMaxFlag(min_max)); writeFloat(value / scale); - gzprintf(stream_, " "); + sta::print(stream_, " "); write_object.write(); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } void @@ -2718,12 +2718,12 @@ WriteSdc::writeMinMaxIntCmd(const char *sdc_cmd, const MinMaxAll *min_max, WriteSdcObject &write_object) const { - gzprintf(stream_, "%s%s ", - sdc_cmd, - minMaxFlag(min_max)); - gzprintf(stream_, "%d ", value); + sta::print(stream_, "{}{} ", + sdc_cmd, + minMaxFlag(min_max)); + sta::print(stream_, "{} ", value); write_object.write(); - gzprintf(stream_, "\n"); + sta::print(stream_, "\n"); } //////////////////////////////////////////////////////////////// @@ -2749,54 +2749,54 @@ WriteSdc::scaleResistance(float res) const void WriteSdc::writeFloat(float value) const { - gzprintf(stream_, "%.*f", digits_, value); + sta::print(stream_, "{}", sta::formatRuntime("{:.{}f}", value, digits_)); } void WriteSdc::writeTime(float time) const { - gzprintf(stream_, "%.*f", digits_, scaleTime(time)); + sta::print(stream_, "{}", sta::formatRuntime("{:.{}f}", scaleTime(time), digits_)); } void WriteSdc::writeCapacitance(float cap) const { - gzprintf(stream_, "%.*f", digits_, scaleCapacitance(cap)); + sta::print(stream_, "{}", sta::formatRuntime("{:.{}f}", scaleCapacitance(cap), digits_)); } void WriteSdc::writeResistance(float res) const { - gzprintf(stream_, "%.*f", digits_, scaleResistance(res)); + sta::print(stream_, "{}", sta::formatRuntime("{:.{}f}", scaleResistance(res), digits_)); } void WriteSdc::writeFloatSeq(FloatSeq *floats, float scale) const { - gzprintf(stream_, "{"); + sta::print(stream_, "{{"); bool first = true; for (float flt : *floats) { if (!first) - gzprintf(stream_, " "); + sta::print(stream_, " "); writeFloat(flt * scale); first = false; } - gzprintf(stream_, "}"); + sta::print(stream_, "}}"); } void WriteSdc::writeIntSeq(IntSeq *ints) const { - gzprintf(stream_, "{"); + sta::print(stream_, "{{"); bool first = true; for (int i : *ints) { if (!first) - gzprintf(stream_, " "); - gzprintf(stream_, "%d", i); + sta::print(stream_, " "); + sta::print(stream_, "{}", i); first = false; } - gzprintf(stream_, "}"); + sta::print(stream_, "}}"); } @@ -2846,9 +2846,9 @@ void WriteSdc::writeSetupHoldFlag(const MinMaxAll *min_max) const { if (min_max == MinMaxAll::min()) - gzprintf(stream_, " -hold"); + sta::print(stream_, " -hold"); else if (min_max == MinMaxAll::max()) - gzprintf(stream_, " -setup"); + sta::print(stream_, " -setup"); } static const char * @@ -2862,7 +2862,7 @@ WriteSdc::writeCmdComment(SdcCmdComment *cmd) const { const char *comment = cmd->comment(); if (comment) { - gzprintf(stream_, " -comment {%s}", comment); + sta::print(stream_, " -comment {{{}}}", comment); } } diff --git a/sdf/ReportAnnotation.cc b/sdf/ReportAnnotation.cc index 0e516e0e..8f667b71 100644 --- a/sdf/ReportAnnotation.cc +++ b/sdf/ReportAnnotation.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "sdf/ReportAnnotation.hh" @@ -72,7 +72,8 @@ protected: count_input_net, count_output_net, }; - static const int count_index_max = static_cast(CountIndex::count_output_net) + 1; + static const int count_index_max = + static_cast(CountIndex::count_output_net) + 1; static int count_delay; void init(); @@ -81,7 +82,7 @@ protected: void reportDelayCounts(); void reportCheckCounts(); void reportArcs(); - void reportArcs(const char *header, + void reportArcs(const std::string &header, bool report_annotated, PinSet &pins); void reportArcs(Vertex *vertex, @@ -117,7 +118,6 @@ protected: PinSet annotated_pins_; }; - int ReportAnnotated::count_delay; void @@ -132,10 +132,9 @@ reportAnnotatedDelay(const Scene *scene, bool report_constant_arcs, StaState *sta) { - ReportAnnotated report(scene, report_cells, report_nets, - from_in_ports, to_out_ports, - max_lines, report_annotated, report_unannotated, - report_constant_arcs, sta); + ReportAnnotated report(scene, report_cells, report_nets, from_in_ports, + to_out_ports, max_lines, report_annotated, + report_unannotated, report_constant_arcs, sta); report.reportDelayAnnotation(); } @@ -176,24 +175,27 @@ ReportAnnotated::reportDelayAnnotation() void ReportAnnotated::reportDelayCounts() { - report_->reportLine(" Not "); - report_->reportLine("Delay type Total Annotated Annotated"); - report_->reportLine("----------------------------------------------------------------"); + report_->report( + " Not "); + report_->report( + "Delay type Total Annotated Annotated"); + report_->report( + "----------------------------------------------------------------"); int total = 0; int annotated_total = 0; reportCount("cell arcs", count_delay, total, annotated_total); - reportCount("internal net arcs", static_cast(CountIndex::count_internal_net), total, annotated_total); - reportCount("net arcs from primary inputs", static_cast(CountIndex::count_input_net), - total, annotated_total); - reportCount("net arcs to primary outputs", static_cast(CountIndex::count_output_net), + reportCount("internal net arcs", static_cast(CountIndex::count_internal_net), total, annotated_total); - report_->reportLine("----------------------------------------------------------------"); - report_->reportLine("%-28s %10u %10u %10u", - " ", - total, - annotated_total, - total - annotated_total); + reportCount("net arcs from primary inputs", + static_cast(CountIndex::count_input_net), total, annotated_total); + reportCount("net arcs to primary outputs", + static_cast(CountIndex::count_output_net), total, + annotated_total); + report_->report( + "----------------------------------------------------------------"); + report_->report("{:<28} {:10} {:10} {:10}", " ", total, annotated_total, + total - annotated_total); } //////////////////////////////////////////////////////////////// @@ -215,12 +217,10 @@ reportAnnotatedCheck(const Scene *scene, StaState *sta) { - ReportAnnotated report(scene, report_setup, report_hold, - report_recovery, report_removal, - report_nochange, report_width, - report_period, report_max_skew, - max_lines, report_annotated, report_unannotated, - report_constant_arcs, sta); + ReportAnnotated report(scene, report_setup, report_hold, report_recovery, + report_removal, report_nochange, report_width, + report_period, report_max_skew, max_lines, report_annotated, + report_unannotated, report_constant_arcs, sta); report.reportCheckAnnotation(); } @@ -269,9 +269,12 @@ ReportAnnotated::reportCheckAnnotation() void ReportAnnotated::reportCheckCounts() { - report_->reportLine(" Not "); - report_->reportLine("Check type Total Annotated Annotated"); - report_->reportLine("----------------------------------------------------------------"); + report_->report( + " Not "); + report_->report( + "Check type Total Annotated Annotated"); + report_->report( + "----------------------------------------------------------------"); int total = 0; int annotated_total = 0; @@ -284,12 +287,10 @@ ReportAnnotated::reportCheckCounts() reportCheckCount(TimingRole::period(), total, annotated_total); reportCheckCount(TimingRole::skew(), total, annotated_total); - report_->reportLine("----------------------------------------------------------------"); - report_->reportLine("%-28s %10u %10u %10u", - " ", - total, - annotated_total, - total - annotated_total); + report_->report( + "----------------------------------------------------------------"); + report_->report("{:<28} {:10} {:10} {:10}", " ", total, annotated_total, + total - annotated_total); } void @@ -299,8 +300,7 @@ ReportAnnotated::reportCheckCount(const TimingRole *role, { int index = role->index(); if (edge_count_[index] > 0) { - std::string title; - stringPrint(title, "cell %s arcs", role->to_string().c_str()); + std::string title = sta::format("cell {} arcs", role->to_string()); reportCount(title.c_str(), index, total, annotated_total); } } @@ -330,8 +330,7 @@ ReportAnnotated::findCounts() Pin *from_pin = from_vertex->pin(); LogicValue from_logic_value; bool from_logic_value_exists; - sdc->logicValue(from_pin, from_logic_value, - from_logic_value_exists); + sdc->logicValue(from_pin, from_logic_value, from_logic_value_exists); VertexOutEdgeIterator edge_iter(from_vertex, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); @@ -341,8 +340,7 @@ ReportAnnotated::findCounts() int index = roleIndex(role, from_pin, to_pin); LogicValue to_logic_value; bool to_logic_value_exists; - sdc->logicValue(to_pin, to_logic_value, - to_logic_value_exists); + sdc->logicValue(to_pin, to_logic_value, to_logic_value_exists); edge_count_[index]++; @@ -374,7 +372,7 @@ ReportAnnotated::delayAnnotated(Edge *edge) for (const MinMax *min_max : MinMax::range()) { DcalcAPIndex ap_index = scene_->dcalcAnalysisPtIndex(min_max); if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) - return false; + return false; } } return true; @@ -397,8 +395,7 @@ ReportAnnotated::roleIndex(const TimingRole *role, return count_delay; else { if (role->isTimingCheck() - && (role == TimingRole::latchSetup() - || role == TimingRole::latchHold())) + && (role == TimingRole::latchSetup() || role == TimingRole::latchHold())) role = role->genericRole(); return role->index(); } @@ -443,19 +440,13 @@ ReportAnnotated::reportCount(const char *title, if (report_role_[index]) { int count = edge_count_[index]; int annotated_count = edge_annotated_count_[index]; - report_->reportLine("%-28s %10u %10u %10u", - title, - count, - annotated_count, - count - annotated_count); + report_->report("{:<28} {:10} {:10} {:10}", title, count, annotated_count, + count - annotated_count); if (report_constant_arcs_) { int const_count = edge_constant_count_[index]; int const_annotated_count = edge_constant_annotated_count_[index]; - report_->reportLine("%-28s %10s %10u %10u", - "constant arcs", - "", - const_annotated_count, - const_count - const_annotated_count); + report_->report("{:<28} {:10} {:10} {:10}", "constant arcs", "", + const_annotated_count, const_count - const_annotated_count); } total += count; annotated_total += annotated_count; @@ -472,12 +463,12 @@ ReportAnnotated::reportArcs() } void -ReportAnnotated::reportArcs(const char *header, +ReportAnnotated::reportArcs(const std::string &header, bool report_annotated, PinSet &pins) { report_->reportBlankLine(); - report_->reportLineString(header); + report_->reportLine(header); PinSeq pins1 = sortByPathName(&pins, network_); int i = 0; for (const Pin *pin : pins1) { @@ -499,8 +490,7 @@ ReportAnnotated::reportArcs(Vertex *vertex, { const Pin *from_pin = vertex->pin(); VertexOutEdgeIterator edge_iter(vertex, graph_); - while (edge_iter.hasNext() - && (max_lines_ == 0 || i < max_lines_)) { + while (edge_iter.hasNext() && (max_lines_ == 0 || i < max_lines_)) { Edge *edge = edge_iter.next(); const TimingRole *role = edge->role(); const Pin *to_pin = edge->to(graph_)->pin(); @@ -520,11 +510,8 @@ ReportAnnotated::reportArcs(Vertex *vertex, else role_name = "delay"; const std::string &cond = edge->timingArcSet()->sdfCond(); - report_->reportLine(" %-18s %s -> %s %s", - role_name, - network_->pathName(from_pin), - network_->pathName(to_pin), - cond.c_str()); + report_->report(" {:<18} {} -> {} {}", role_name, network_->pathName(from_pin), + network_->pathName(to_pin), cond); i++; } } @@ -539,8 +526,7 @@ ReportAnnotated::reportPeriodArcs(const Pin *pin, if (port) { DcalcAPIndex ap_index = 0; int period_index = TimingRole::period()->index(); - if (report_role_[period_index] - && (max_lines_ == 0 || i < max_lines_)) { + if (report_role_[period_index] && (max_lines_ == 0 || i < max_lines_)) { float value; bool exists, annotated; port->minPeriod(value, exists); @@ -548,9 +534,7 @@ ReportAnnotated::reportPeriodArcs(const Pin *pin, edge_count_[period_index]++; graph_->periodCheckAnnotation(pin, ap_index, value, annotated); if (annotated == report_annotated) { - report_->reportLine(" %-18s %s", - "period", - network_->pathName(pin)); + report_->report(" {:<18} {}", "period", network_->pathName(pin)); i++; } } @@ -558,4 +542,4 @@ ReportAnnotated::reportPeriodArcs(const Pin *pin, } } -} // namespace +} // namespace sta diff --git a/sdf/SdfParse.yy b/sdf/SdfParse.yy index 60e8b7ef..6c9c3efb 100644 --- a/sdf/SdfParse.yy +++ b/sdf/SdfParse.yy @@ -38,8 +38,7 @@ void sta::SdfParse::error(const location_type &loc, const std::string &msg) { - reader->report()->fileError(164,reader->filename().c_str(), - loc.begin.line,"%s",msg.c_str()); + reader->report()->fileError(170, reader->filename(), loc.begin.line,"{}",msg); } %} diff --git a/sdf/SdfReader.cc b/sdf/SdfReader.cc index 93804d87..65a2bb8e 100644 --- a/sdf/SdfReader.cc +++ b/sdf/SdfReader.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "sdf/SdfReader.hh" @@ -74,7 +74,7 @@ public: private: const Transition *tr_; const std::string *port_; - const std::string *cond_; // timing checks only + const std::string *cond_; // timing checks only }; bool @@ -88,11 +88,9 @@ readSdf(const char *filename, { int arc_min_index = scene->dcalcAnalysisPtIndex(MinMax::min()); int arc_max_index = scene->dcalcAnalysisPtIndex(MinMax::max()); - SdfReader reader(filename, path, - arc_min_index, arc_max_index, - scene->sdc()->analysisType(), - unescaped_dividers, incremental_only, - cond_use, sta); + SdfReader reader(filename, path, arc_min_index, arc_max_index, + scene->sdc()->analysisType(), unescaped_dividers, + incremental_only, cond_use, sta); bool success = reader.read(); return success; } @@ -123,7 +121,7 @@ SdfReader::SdfReader(const char *filename, cell_name_(nullptr), in_timing_check_(false), in_incremental_(false), - timescale_(1.0E-9F) // default units of ns + timescale_(1.0E-9F) // default units of ns { if (unescaped_dividers) network_ = makeSdcNetwork(network_); @@ -149,7 +147,7 @@ SdfReader::read() return success; } else - throw FileNotReadable(filename_.c_str()); + throw FileNotReadable(filename_); } void @@ -162,9 +160,7 @@ void SdfReader::setTimescale(float multiplier, const std::string *units) { - if (multiplier == 1.0 - || multiplier == 10.0 - || multiplier == 100.0) { + if (multiplier == 1.0 || multiplier == 10.0 || multiplier == 100.0) { if (*units == "us") timescale_ = multiplier * 1E-6F; else if (*units == "ns") @@ -172,10 +168,10 @@ SdfReader::setTimescale(float multiplier, else if (*units == "ps") timescale_ = multiplier * 1E-12F; else - sdfError(180, "TIMESCALE units not us, ns, or ps."); + error(180, "TIMESCALE units not us, ns, or ps."); } else - sdfError(181, "TIMESCALE multiplier not 1, 10, or 100."); + error(181, "TIMESCALE multiplier not 1, 10, or 100."); delete units; } @@ -198,23 +194,20 @@ SdfReader::interconnect(const std::string *from_pin_name, bool to_is_hier = network_->isHierarchical(to_pin); if (from_is_hier || to_is_hier) { if (from_is_hier) - sdfError(182, "pin %s is a hierarchical pin.", - from_pin_name->c_str()); + error(182, "pin {} is a hierarchical pin.", *from_pin_name); if (to_is_hier) - sdfError(183, "pin %s is a hierarchical pin.", - to_pin_name->c_str()); + error(183, "pin {} is a hierarchical pin.", *to_pin_name); } else - sdfWarn(184, "INTERCONNECT from %s to %s not found.", - from_pin_name->c_str(), - to_pin_name->c_str()); + warn(184, "INTERCONNECT from {} to {} not found.", + *from_pin_name, *to_pin_name); } } else { if (from_pin == nullptr) - sdfWarn(185, "pin %s not found.", from_pin_name->c_str()); + warn(185, "pin {} not found.", *from_pin_name); if (to_pin == nullptr) - sdfWarn(186, "pin %s not found.", to_pin_name->c_str()); + warn(186, "pin {} not found.", *to_pin_name); } } delete from_pin_name; @@ -229,10 +222,10 @@ SdfReader::port(const std::string *to_pin_name, // Ignore non-incremental annotations in incremental only mode. if (!(is_incremental_only_ && !in_incremental_)) { Pin *to_pin = (instance_) - ? network_->findPinRelative(instance_, to_pin_name->c_str()) - : network_->findPin(to_pin_name->c_str()); + ? network_->findPinRelative(instance_, to_pin_name->c_str()) + : network_->findPin(to_pin_name->c_str()); if (to_pin == nullptr) - sdfWarn(187, "pin %s not found.", to_pin_name->c_str()); + warn(187, "pin {} not found.", *to_pin_name); else { Vertex *vertex = graph_->pinLoadVertex(to_pin); VertexInEdgeIterator edge_iter(vertex, graph_); @@ -259,8 +252,7 @@ SdfReader::findWireEdge(Pin *from_pin, while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); const TimingRole *edge_role = edge->role(); - if (edge->from(graph_)->pin() == from_pin - && edge_role->sdfRole()->isWire()) + if (edge->from(graph_)->pin() == from_pin && edge_role->sdfRole()->isWire()) return edge; } } @@ -274,8 +266,7 @@ SdfReader::setEdgeDelays(Edge *edge, { // Rise/fall triples. size_t triple_count = triples->size(); - if (triple_count == 1 - || triple_count == 2) { + if (triple_count == 1 || triple_count == 2) { TimingArcSet *arc_set = edge->timingArcSet(); for (TimingArc *arc : arc_set->arcs()) { size_t triple_index; @@ -288,9 +279,9 @@ SdfReader::setEdgeDelays(Edge *edge, } } else if (triple_count == 0) - sdfError(188, "%s with no triples.", sdf_cmd); + error(188, "{} with no triples.", sdf_cmd); else - sdfError(189, "%s with more than 2 triples.", sdf_cmd); + error(189, "{} with more than 2 triples.", sdf_cmd); } void @@ -313,10 +304,8 @@ SdfReader::setInstance(const std::string *instance_name) Cell *inst_cell = network_->cell(instance_); const char *inst_cell_name = network_->name(inst_cell); if (cell_name_ && !stringEq(inst_cell_name, cell_name_->c_str())) - sdfWarn(190, "instance %s cell %s does not match enclosing cell %s.", - instance_name->c_str(), - inst_cell_name, - cell_name_->c_str()); + warn(190, "instance {} cell {} does not match enclosing cell {}.", + *instance_name, inst_cell_name, *cell_name_); } } } @@ -372,7 +361,7 @@ SdfReader::iopath(SdfPortSpec *from_edge, const std::string &lib_cond = arc_set->sdfCond(); const TimingRole *edge_role = arc_set->role(); bool cond_use_flag = cond_use_ && cond && lib_cond.empty() - && !(!is_incremental_only_ && in_incremental_); + && !(!is_incremental_only_ && in_incremental_); if (edge->from(graph_)->pin() == from_pin && edge_role->sdfRole() == TimingRole::sdfIopath() && (cond_use_flag @@ -402,10 +391,9 @@ SdfReader::iopath(SdfPortSpec *from_edge, } } if (!matched) - sdfWarn(191, "cell %s IOPATH %s -> %s not found.", - network_->cellName(instance_), - from_port_name->c_str(), - to_port_name->c_str()); + warn(191, "cell {} IOPATH {} -> {} not found.", + network_->cellName(instance_), *from_port_name, + *to_port_name); } } } @@ -422,9 +410,8 @@ SdfReader::findPort(const Cell *cell, { Port *port = network_->findPort(cell, port_name->c_str()); if (port == nullptr) - sdfWarn(194, "instance %s port %s not found.", - network_->pathName(instance_), - port_name->c_str()); + warn(194, "instance {} port {} not found.", network_->pathName(instance_), + *port_name); return port; } @@ -457,8 +444,7 @@ SdfReader::timingCheck1(const TimingRole *role, SdfTriple *triple) { // Ignore non-incremental annotations in incremental only mode. - if (!(is_incremental_only_ && !in_incremental_) - && instance_) { + if (!(is_incremental_only_ && !in_incremental_) && instance_) { Pin *data_pin = network_->findPin(instance_, data_port); Pin *clk_pin = network_->findPin(instance_, clk_port); if (data_pin && clk_pin) { @@ -468,36 +454,32 @@ SdfReader::timingCheck1(const TimingRole *role, float *value_max = values[triple_max_index_]; if (value_min && value_max) { switch (analysis_type_) { - case AnalysisType::single: - break; - case AnalysisType::bc_wc: - if (role->genericRole() == TimingRole::setup()) + case AnalysisType::single: + break; + case AnalysisType::bc_wc: + if (role->genericRole() == TimingRole::setup()) + *value_min = *value_max; + else + *value_max = *value_min; + break; + case AnalysisType::ocv: *value_min = *value_max; - else - *value_max = *value_min; - break; - case AnalysisType::ocv: - *value_min = *value_max; - break; + break; } } - bool matched = annotateCheckEdges(data_pin, data_edge, - clk_pin, clk_edge, role, + bool matched = annotateCheckEdges(data_pin, data_edge, clk_pin, clk_edge, role, triple, false); // Liberty setup/hold checks on preset/clear pins can be translated // into recovery/removal checks, so be flexible about matching. if (!matched) - matched = annotateCheckEdges(data_pin, data_edge, - clk_pin, clk_edge, role, + matched = annotateCheckEdges(data_pin, data_edge, clk_pin, clk_edge, role, triple, true); if (!matched // Only warn when non-null values are present. && triple->hasValue()) - sdfWarn(192, "cell %s %s -> %s %s check not found.", - network_->cellName(instance_), - network_->name(data_port), - network_->name(clk_port), - role->to_string().c_str()); + warn(192, "cell {} {} -> {} {} check not found.", + network_->cellName(instance_), network_->name(data_port), + network_->name(clk_port), role->to_string()); } } } @@ -526,11 +508,10 @@ SdfReader::annotateCheckEdges(Pin *data_pin, const TimingRole *edge_role = arc_set->role(); const std::string &lib_cond_start = arc_set->sdfCondStart(); const std::string &lib_cond_end = arc_set->sdfCondEnd(); - bool cond_matches = condMatch(cond_start, lib_cond_start) - && condMatch(cond_end, lib_cond_end); + bool cond_matches = + condMatch(cond_start, lib_cond_start) && condMatch(cond_end, lib_cond_end); if (((!match_generic && edge_role->sdfRole() == sdf_role) - || (match_generic - && edge_role->genericRole() == sdf_role->genericRole())) + || (match_generic && edge_role->genericRole() == sdf_role->genericRole())) && cond_matches) { TimingArcSet *arc_set = edge->timingArcSet(); for (TimingArc *arc : arc_set->arcs()) { @@ -553,8 +534,7 @@ SdfReader::timingCheckWidth(SdfPortSpec *edge, SdfTriple *triple) { // Ignore non-incremental annotations in incremental only mode. - if (!(is_incremental_only_ && !in_incremental_) - && instance_) { + if (!(is_incremental_only_ && !in_incremental_) && instance_) { const std::string *port_name = edge->port(); Cell *cell = network_->cell(instance_); Port *port = findPort(cell, port_name); @@ -622,8 +602,7 @@ SdfReader::timingCheckPeriod(SdfPortSpec *edge, SdfTriple *triple) { // Ignore non-incremental annotations in incremental only mode. - if (!(is_incremental_only_ && !in_incremental_) - && instance_) { + if (!(is_incremental_only_ && !in_incremental_) && instance_) { const std::string *port_name = edge->port(); Cell *cell = network_->cell(instance_); Port *port = findPort(cell, port_name); @@ -668,8 +647,7 @@ void SdfReader::device(SdfTripleSeq *triples) { // Ignore non-incremental annotations in incremental only mode. - if (!(is_incremental_only_ && !in_incremental_) - && instance_) { + if (!(is_incremental_only_ && !in_incremental_) && instance_) { InstancePinIterator *pin_iter = network_->pinIterator(instance_); while (pin_iter->hasNext()) { Pin *to_pin = pin_iter->next(); @@ -685,8 +663,7 @@ SdfReader::device(const std::string *to_port_name, SdfTripleSeq *triples) { // Ignore non-incremental annotations in incremental only mode. - if (!(is_incremental_only_ && !in_incremental_) - && instance_) { + if (!(is_incremental_only_ && !in_incremental_) && instance_) { Cell *cell = network_->cell(instance_); Port *to_port = findPort(cell, to_port_name); if (to_port) { @@ -735,7 +712,7 @@ SdfReader::setEdgeArcDelays(Edge *edge, if (value_ptr) { ArcDelay delay; if (in_incremental_) - delay = *value_ptr + graph_->arcDelay(edge, arc, arc_delay_index); + delay = delaySum(graph_->arcDelay(edge, arc, arc_delay_index), *value_ptr, this); else delay = *value_ptr; graph_->setArcDelay(edge, arc, arc_delay_index, delay); @@ -780,11 +757,10 @@ SdfReader::setEdgeArcDelaysCondUse(Edge *edge, int arc_delay_index, const MinMax *min_max) { - if (value - && triple_index != null_index_) { + if (value && triple_index != null_index_) { ArcDelay delay(*value); if (!is_incremental_only_ && in_incremental_) - delay = graph_->arcDelay(edge, arc, arc_delay_index) + *value; + delay = delaySum(graph_->arcDelay(edge, arc, arc_delay_index), *value, this); else if (graph_->arcDelayAnnotated(edge, arc, arc_delay_index)) { ArcDelay prev_value = graph_->arcDelay(edge, arc, arc_delay_index); if (delayGreater(prev_value, delay, min_max, this)) @@ -844,9 +820,7 @@ SdfReader::makeCondPortSpec(const std::string *cond_port) auto cond_end = cond_port1.find_last_not_of(" ", port_idx); if (cond_end != cond_port1.npos) { std::string *cond1 = new std::string(cond_port1.substr(0, cond_end + 1)); - SdfPortSpec *port_spec = new SdfPortSpec(Transition::riseFall(), - port1, - cond1); + SdfPortSpec *port_spec = new SdfPortSpec(Transition::riseFall(), port1, cond1); delete cond_port; return port_spec; } @@ -887,9 +861,12 @@ SdfReader::makeTriple(float *min, float *typ, float *max) { - if (min) *min *= timescale_; - if (typ) *typ *= timescale_; - if (max) *max *= timescale_; + if (min) + *min *= timescale_; + if (typ) + *typ *= timescale_; + if (max) + *max *= timescale_; return new SdfTriple(min, typ, max); } @@ -929,9 +906,7 @@ SdfReader::unescaped(const std::string *token) // Translate sdf divider to network divider. *unescaped += path_divider; } - else if (next_ch == '[' - || next_ch == ']' - || next_ch == escape_) { + else if (next_ch == '[' || next_ch == ']' || next_ch == escape_) { // Escaped bus bracket or escape. // Translate sdf escape to network escape. *unescaped += path_escape; @@ -946,9 +921,8 @@ SdfReader::unescaped(const std::string *token) // Just the normal noises. *unescaped += ch; } - debugPrint(debug_, "sdf_name", 1, "unescape %s -> %s", - token->c_str(), - unescaped->c_str()); + debugPrint(debug_, "sdf_name", 1, "unescape {} -> {}", *token, + *unescaped); delete token; return unescaped; } @@ -980,27 +954,13 @@ SdfReader::makeBusName(std::string *base_name, void SdfReader::notSupported(const char *feature) { - sdfError(193, "%s not supported.", feature); + error(193, "{} not supported.", feature); } -void -SdfReader::sdfWarn(int id, - const char *fmt, ...) +int +SdfReader::sdfLine() const { - va_list args; - va_start(args, fmt); - report_->vfileWarn(id, filename_.c_str(), scanner_->lineno(), fmt, args); - va_end(args); -} - -void -SdfReader::sdfError(int id, - const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - report_->vfileError(id, filename_.c_str(), scanner_->lineno(), fmt, args); - va_end(args); + return scanner_->lineno(); } Pin * @@ -1030,7 +990,7 @@ SdfReader::findInstance(const std::string *name) inst_name = *name; Instance *inst = network_->findInstance(inst_name.c_str()); if (inst == nullptr) - sdfWarn(195, "instance %s not found.", inst_name.c_str()); + warn(195, "instance {} not found.", inst_name); return inst; } @@ -1067,9 +1027,12 @@ SdfTriple::~SdfTriple() if (values_[0] == values_[1] && values_[0] == values_[2]) delete values_[0]; else { - if (values_[0]) delete values_[0]; - if (values_[1]) delete values_[1]; - if (values_[2]) delete values_[2]; + if (values_[0]) + delete values_[0]; + if (values_[1]) + delete values_[1]; + if (values_[2]) + delete values_[2]; } } @@ -1095,7 +1058,7 @@ SdfScanner::SdfScanner(std::istream *stream, void SdfScanner::error(const char *msg) { - report_->fileError(1869, filename_.c_str(), lineno(), "%s", msg); + report_->fileError(196, filename_.c_str(), lineno(), "{}", msg); } -} // namespace +} // namespace sta diff --git a/sdf/SdfReaderPvt.hh b/sdf/SdfReaderPvt.hh index 3b140a4e..4ae883ba 100644 --- a/sdf/SdfReaderPvt.hh +++ b/sdf/SdfReaderPvt.hh @@ -24,6 +24,7 @@ #pragma once +#include #include #include "TimingRole.hh" @@ -31,6 +32,7 @@ #include "LibertyClass.hh" #include "NetworkClass.hh" #include "GraphClass.hh" +#include "Report.hh" #include "SdcClass.hh" #include "StaState.hh" @@ -148,11 +150,23 @@ public: std::string *makeBusName(std::string *bus_name, int index); const std::string &filename() const { return filename_; } - void sdfWarn(int id, - const char *fmt, ...); - void sdfError(int id, - const char *fmt, - ...); + int sdfLine() const; + template + void warn(int id, + std::string_view fmt, + Args &&...args) + { + report_->fileWarn(id, filename_, sdfLine(), fmt, + std::forward(args)...); + } + template + void error(int id, + std::string_view fmt, + Args &&...args) + { + report_->fileError(id, filename_, sdfLine(), fmt, + std::forward(args)...); + } void notSupported(const char *feature); private: diff --git a/sdf/SdfWriter.cc b/sdf/SdfWriter.cc index 6cc3cd1d..fa79139f 100644 --- a/sdf/SdfWriter.cc +++ b/sdf/SdfWriter.cc @@ -27,6 +27,7 @@ #include #include +#include "Format.hh" #include "Zlib.hh" #include "StaConfig.hh" // STA_VERSION #include "Fuzzy.hh" @@ -49,7 +50,6 @@ class SdfWriter : public StaState { public: SdfWriter(StaState *sta); - ~SdfWriter(); void write(const char *filename, const Scene *scene, char sdf_divider, @@ -118,7 +118,7 @@ private: char sdf_escape_; char network_escape_; - char *delay_format_; + int digits_; gzFile stream_; const Scene *scene_; @@ -145,16 +145,10 @@ writeSdf(const char *filename, SdfWriter::SdfWriter(StaState *sta) : StaState(sta), sdf_escape_('\\'), - network_escape_(network_->pathEscape()), - delay_format_(nullptr) + network_escape_(network_->pathEscape()) { } -SdfWriter::~SdfWriter() -{ - stringDelete(delay_format_); -} - void SdfWriter::write(const char *filename, const Scene *scene, @@ -167,8 +161,7 @@ SdfWriter::write(const char *filename, { sdf_divider_ = sdf_divider; include_typ_ = include_typ; - if (delay_format_ == nullptr) - delay_format_ = stringPrint("%%.%df", digits); + digits_ = digits; LibertyLibrary *default_lib = network_->defaultLibertyLibrary(); timescale_ = default_lib->units()->timeUnit()->scale(); @@ -195,25 +188,25 @@ SdfWriter::writeHeader(LibertyLibrary *default_lib, bool no_timestamp, bool no_version) { - gzprintf(stream_, "(DELAYFILE\n"); - gzprintf(stream_, " (SDFVERSION \"3.0\")\n"); - gzprintf(stream_, " (DESIGN \"%s\")\n", - network_->cellName(network_->topInstance())); - + sta::print(stream_, "(DELAYFILE\n"); + sta::print(stream_, " (SDFVERSION \"3.0\")\n"); + sta::print(stream_, " (DESIGN \"{}\")\n", + network_->cellName(network_->topInstance())); + if (!no_timestamp) { time_t now; time(&now); char *time_str = ctime(&now); // Remove trailing \n. time_str[strlen(time_str) - 1] = '\0'; - gzprintf(stream_, " (DATE \"%s\")\n", time_str); + sta::print(stream_, " (DATE \"{}\")\n", time_str); } - gzprintf(stream_, " (VENDOR \"Parallax\")\n"); - gzprintf(stream_, " (PROGRAM \"STA\")\n"); + sta::print(stream_, " (VENDOR \"Parallax\")\n"); + sta::print(stream_, " (PROGRAM \"STA\")\n"); if (!no_version) - gzprintf(stream_, " (VERSION \"%s\")\n", STA_VERSION); - gzprintf(stream_, " (DIVIDER %c)\n", sdf_divider_); + sta::print(stream_, " (VERSION \"{}\")\n", STA_VERSION); + sta::print(stream_, " (DIVIDER {:c})\n", sdf_divider_); LibertyLibrary *lib_min = default_lib; const LibertySeq &libs_min = scene_->libertyLibraries(MinMax::min()); @@ -227,15 +220,15 @@ SdfWriter::writeHeader(LibertyLibrary *default_lib, OperatingConditions *cond_min = lib_min->defaultOperatingConditions(); OperatingConditions *cond_max = lib_max->defaultOperatingConditions(); if (cond_min && cond_max) { - gzprintf(stream_, " (VOLTAGE %.3f::%.3f)\n", - cond_min->voltage(), - cond_max->voltage()); - gzprintf(stream_, " (PROCESS \"%.3f::%.3f\")\n", - cond_min->process(), - cond_max->process()); - gzprintf(stream_, " (TEMPERATURE %.3f::%.3f)\n", - cond_min->temperature(), - cond_max->temperature()); + sta::print(stream_, " (VOLTAGE {:.3f}::{:.3f})\n", + cond_min->voltage(), + cond_max->voltage()); + sta::print(stream_, " (PROCESS \"{:.3f}::{:.3f}\")\n", + cond_min->process(), + cond_max->process()); + sta::print(stream_, " (TEMPERATURE {:.3f}::{:.3f})\n", + cond_min->temperature(), + cond_max->temperature()); } const char *sdf_timescale = nullptr; @@ -258,24 +251,24 @@ SdfWriter::writeHeader(LibertyLibrary *default_lib, else if (fuzzyEqual(timescale_, 100e-12)) sdf_timescale = "100ps"; if (sdf_timescale) - gzprintf(stream_, " (TIMESCALE %s)\n", sdf_timescale); + sta::print(stream_, " (TIMESCALE {})\n", sdf_timescale); } void SdfWriter::writeTrailer() { - gzprintf(stream_, ")\n"); + sta::print(stream_, ")\n"); } void SdfWriter::writeInterconnects() { - gzprintf(stream_, " (CELL\n"); - gzprintf(stream_, " (CELLTYPE \"%s\")\n", - network_->cellName(network_->topInstance())); - gzprintf(stream_, " (INSTANCE)\n"); - gzprintf(stream_, " (DELAY\n"); - gzprintf(stream_, " (ABSOLUTE\n"); + sta::print(stream_, " (CELL\n"); + sta::print(stream_, " (CELLTYPE \"{}\")\n", + network_->cellName(network_->topInstance())); + sta::print(stream_, " (INSTANCE)\n"); + sta::print(stream_, " (DELAY\n"); + sta::print(stream_, " (ABSOLUTE\n"); writeInstInterconnects(network_->topInstance()); @@ -286,9 +279,9 @@ SdfWriter::writeInterconnects() } delete inst_iter; - gzprintf(stream_, " )\n"); - gzprintf(stream_, " )\n"); - gzprintf(stream_, " )\n"); + sta::print(stream_, " )\n"); + sta::print(stream_, " )\n"); + sta::print(stream_, " )\n"); } void @@ -315,11 +308,11 @@ SdfWriter::writeInterconnectFromPin(Pin *drvr_pin) Pin *load_pin = edge->to(graph_)->pin(); std::string drvr_pin_name = sdfPathName(drvr_pin); std::string load_pin_name = sdfPathName(load_pin); - gzprintf(stream_, " (INTERCONNECT %s %s ", - drvr_pin_name.c_str(), - load_pin_name.c_str()); + sta::print(stream_, " (INTERCONNECT {} {} ", + drvr_pin_name, + load_pin_name); writeArcDelays(edge); - gzprintf(stream_, ")\n"); + sta::print(stream_, ")\n"); } } } @@ -343,16 +336,16 @@ SdfWriter::writeInstances() void SdfWriter::writeInstHeader(const Instance *inst) { - gzprintf(stream_, " (CELL\n"); - gzprintf(stream_, " (CELLTYPE \"%s\")\n", network_->cellName(inst)); + sta::print(stream_, " (CELL\n"); + sta::print(stream_, " (CELLTYPE \"{}\")\n", network_->cellName(inst)); std::string inst_name = sdfPathName(inst); - gzprintf(stream_, " (INSTANCE %s)\n", inst_name.c_str()); + sta::print(stream_, " (INSTANCE {})\n", inst_name); } void SdfWriter::writeInstTrailer() { - gzprintf(stream_, " )\n"); + sta::print(stream_, " )\n"); } void @@ -387,18 +380,18 @@ SdfWriter::writeIopaths(const Instance *inst, } const std::string &sdf_cond = edge->timingArcSet()->sdfCond(); if (!sdf_cond.empty()) { - gzprintf(stream_, " (COND %s\n", sdf_cond.c_str()); - gzprintf(stream_, " "); + sta::print(stream_, " (COND {}\n", sdf_cond); + sta::print(stream_, " "); } std::string from_pin_name = sdfPortName(from_pin); std::string to_pin_name = sdfPortName(to_pin); - gzprintf(stream_, " (IOPATH %s %s ", - from_pin_name.c_str(), - to_pin_name.c_str()); + sta::print(stream_, " (IOPATH {} {} ", + from_pin_name, + to_pin_name); writeArcDelays(edge); if (!sdf_cond.empty()) - gzprintf(stream_, ")"); - gzprintf(stream_, ")\n"); + sta::print(stream_, ")"); + sta::print(stream_, ")\n"); } } } @@ -412,15 +405,15 @@ SdfWriter::writeIopaths(const Instance *inst, void SdfWriter::writeIopathHeader() { - gzprintf(stream_, " (DELAY\n"); - gzprintf(stream_, " (ABSOLUTE\n"); + sta::print(stream_, " (DELAY\n"); + sta::print(stream_, " (ABSOLUTE\n"); } void SdfWriter::writeIopathTrailer() { - gzprintf(stream_, " )\n"); - gzprintf(stream_, " )\n"); + sta::print(stream_, " )\n"); + sta::print(stream_, " )\n"); } void @@ -430,11 +423,11 @@ SdfWriter::writeArcDelays(Edge *edge) TimingArcSet *arc_set = edge->timingArcSet(); for (TimingArc *arc : arc_set->arcs()) { const RiseFall *rf = arc->toEdge()->asRiseFall(); - ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_); - delays.setValue(rf, MinMax::min(), delayAsFloat(min_delay)); + const ArcDelay &min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_); + delays.setValue(rf, MinMax::min(), delayAsFloat(min_delay, MinMax::min(), this)); - ArcDelay max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_); - delays.setValue(rf, MinMax::max(), delayAsFloat(max_delay)); + const ArcDelay &max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_); + delays.setValue(rf, MinMax::max(), delayAsFloat(max_delay, MinMax::max(), this)); } if (delays.hasValue(RiseFall::rise(), MinMax::min()) @@ -446,7 +439,7 @@ SdfWriter::writeArcDelays(Edge *edge) delays.value(RiseFall::fall(), MinMax::min())) && fuzzyEqual(delays.value(RiseFall::rise(), MinMax::max()), delays.value(RiseFall::fall(),MinMax::max())))) { - gzprintf(stream_, " "); + sta::print(stream_, " "); writeSdfTriple(delays, RiseFall::fall()); } } @@ -455,7 +448,7 @@ SdfWriter::writeArcDelays(Edge *edge) writeSdfTriple(delays, RiseFall::rise()); else if (delays.hasValue(RiseFall::fall(), MinMax::min())) { // Fall only. - gzprintf(stream_, "() "); + sta::print(stream_, "() "); writeSdfTriple(delays, RiseFall::fall()); } } @@ -473,23 +466,24 @@ void SdfWriter::writeSdfTriple(float min, float max) { - gzprintf(stream_, "("); + sta::print(stream_, "("); writeSdfDelay(min); if (include_typ_) { - gzprintf(stream_, ":"); + sta::print(stream_, ":"); writeSdfDelay((min + max) / 2.0); - gzprintf(stream_, ":"); + sta::print(stream_, ":"); } else - gzprintf(stream_, "::"); + sta::print(stream_, "::"); writeSdfDelay(max); - gzprintf(stream_, ")"); + sta::print(stream_, ")"); } void SdfWriter::writeSdfDelay(double delay) { - gzprintf(stream_, delay_format_, delay / timescale_); + std::string str = sta::formatRuntime("{:.{}f}", delay / timescale_, digits_); + sta::print(stream_, "{}", str); } void @@ -527,8 +521,10 @@ SdfWriter::writeTimingChecks(const Instance *inst, TimingArc *arc; graph_->minPulseWidthArc(vertex, hi_low, edge, arc); if (edge) { - min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_)); - max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_)); + min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_), + MinMax::min(), this); + max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_), + MinMax::max(), this); ensureTimingCheckheaders(check_header, inst, inst_header); writeWidthCheck(pin, hi_low, min_width, max_width); } @@ -566,13 +562,13 @@ SdfWriter::ensureTimingCheckheaders(bool &check_header, void SdfWriter::writeTimingCheckHeader() { - gzprintf(stream_, " (TIMINGCHECK\n"); + sta::print(stream_, " (TIMINGCHECK\n"); } void SdfWriter::writeTimingCheckTrailer() { - gzprintf(stream_, " )\n"); + sta::print(stream_, " )\n"); } void @@ -615,30 +611,37 @@ SdfWriter::writeEdgeCheck(Edge *edge, if (arcs[clk_rf_index][RiseFall::riseIndex()] && arcs[clk_rf_index][RiseFall::fallIndex()] && arcs[clk_rf_index][RiseFall::riseIndex()] - && arcs[clk_rf_index][RiseFall::fallIndex()] - && delayEqual(graph_->arcDelay(edge, - arcs[clk_rf_index][RiseFall::riseIndex()], - arc_delay_min_index_), - graph_->arcDelay(edge, - arcs[clk_rf_index][RiseFall::fallIndex()], - arc_delay_min_index_)) - && delayEqual(graph_->arcDelay(edge, - arcs[clk_rf_index][RiseFall::riseIndex()], - arc_delay_max_index_), - graph_->arcDelay(edge, - arcs[clk_rf_index][RiseFall::fallIndex()], - arc_delay_max_index_))) - // Rise/fall margins are the same, so no data edge specifier is required. - writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()], - sdf_check, false, true); - else { - if (arcs[clk_rf_index][RiseFall::riseIndex()]) - writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()], - sdf_check, true, true); - if (arcs[clk_rf_index][RiseFall::fallIndex()]) - writeCheck(edge, arcs[clk_rf_index][RiseFall::fallIndex()], - sdf_check, true, true); + && arcs[clk_rf_index][RiseFall::fallIndex()]) { + float rise_min=delayAsFloat(graph_->arcDelay(edge, + arcs[clk_rf_index][RiseFall::riseIndex()], + arc_delay_min_index_), + MinMax::min(), this); + float fall_min=delayAsFloat(graph_->arcDelay(edge, + arcs[clk_rf_index][RiseFall::fallIndex()], + arc_delay_min_index_), + MinMax::min(), this); + float rise_max=delayAsFloat(graph_->arcDelay(edge, + arcs[clk_rf_index][RiseFall::riseIndex()], + arc_delay_max_index_), + MinMax::max(), this); + float fall_max=delayAsFloat(graph_->arcDelay(edge, + arcs[clk_rf_index][RiseFall::fallIndex()], + arc_delay_max_index_), + MinMax::max(), this); + if (fuzzyEqual(rise_min, fall_min) + && fuzzyEqual(rise_max, fall_max)) { + // Rise/fall margins are the same, so no data edge specifier is required. + writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()], + sdf_check, false, true); + return; + } } + if (arcs[clk_rf_index][RiseFall::riseIndex()]) + writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()], + sdf_check, true, true); + if (arcs[clk_rf_index][RiseFall::fallIndex()]) + writeCheck(edge, arcs[clk_rf_index][RiseFall::fallIndex()], + sdf_check, true, true); } void @@ -654,46 +657,48 @@ SdfWriter::writeCheck(Edge *edge, const std::string &sdf_cond_start = arc_set->sdfCondStart(); const std::string &sdf_cond_end = arc_set->sdfCondEnd(); - gzprintf(stream_, " (%s ", sdf_check); + sta::print(stream_, " ({} ", sdf_check); if (!sdf_cond_start.empty()) - gzprintf(stream_, "(COND %s ", sdf_cond_start.c_str()); + sta::print(stream_, "(COND {} ", sdf_cond_start); std::string to_pin_name = sdfPortName(to_pin); if (use_data_edge) { - gzprintf(stream_, "(%s %s)", - sdfEdge(arc->toEdge()), - to_pin_name.c_str()); + sta::print(stream_, "({} {})", + sdfEdge(arc->toEdge()), + to_pin_name); } else - gzprintf(stream_, "%s", to_pin_name.c_str()); + sta::print(stream_, "{}", to_pin_name); if (!sdf_cond_start.empty()) - gzprintf(stream_, ")"); + sta::print(stream_, ")"); - gzprintf(stream_, " "); + sta::print(stream_, " "); if (!sdf_cond_end.empty()) - gzprintf(stream_, "(COND %s ", sdf_cond_end.c_str()); + sta::print(stream_, "(COND {} ", sdf_cond_end); std::string from_pin_name = sdfPortName(from_pin); if (use_clk_edge) - gzprintf(stream_, "(%s %s)", - sdfEdge(arc->fromEdge()), - from_pin_name.c_str()); + sta::print(stream_, "({} {})", + sdfEdge(arc->fromEdge()), + from_pin_name); else - gzprintf(stream_, "%s", from_pin_name.c_str()); + sta::print(stream_, "{}", from_pin_name); if (!sdf_cond_end.empty()) - gzprintf(stream_, ")"); + sta::print(stream_, ")"); - gzprintf(stream_, " "); + sta::print(stream_, " "); - ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_); - ArcDelay max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_); - writeSdfTriple(delayAsFloat(min_delay), delayAsFloat(max_delay)); + float min_delay = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_), + MinMax::min(), this); + float max_delay = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_), + MinMax::max(), this); + writeSdfTriple(min_delay, max_delay); - gzprintf(stream_, ")\n"); + sta::print(stream_, ")\n"); } void @@ -703,11 +708,11 @@ SdfWriter::writeWidthCheck(const Pin *pin, float max_width) { std::string pin_name = sdfPortName(pin); - gzprintf(stream_, " (WIDTH (%s %s) ", - sdfEdge(hi_low->asTransition()), - pin_name.c_str()); + sta::print(stream_, " (WIDTH ({} {}) ", + sdfEdge(hi_low->asTransition()), + pin_name); writeSdfTriple(min_width, max_width); - gzprintf(stream_, ")\n"); + sta::print(stream_, ")\n"); } void @@ -715,9 +720,9 @@ SdfWriter::writePeriodCheck(const Pin *pin, float min_period) { std::string pin_name = sdfPortName(pin); - gzprintf(stream_, " (PERIOD %s ", pin_name.c_str()); + sta::print(stream_, " (PERIOD {} ", pin_name); writeSdfTriple(min_period, min_period); - gzprintf(stream_, ")\n"); + sta::print(stream_, ")\n"); } const char * diff --git a/search/Bfs.cc b/search/Bfs.cc index ba73f780..8324d54e 100644 --- a/search/Bfs.cc +++ b/search/Bfs.cc @@ -1,26 +1,26 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "Bfs.hh" @@ -38,10 +38,10 @@ namespace sta { BfsIterator::BfsIterator(BfsIndex bfs_index, - Level level_min, - Level level_max, - SearchPred *search_pred, - StaState *sta) : + Level level_min, + Level level_max, + SearchPred *search_pred, + StaState *sta) : StaState(sta), bfs_index_(bfs_index), level_min_(level_min), @@ -69,9 +69,7 @@ BfsIterator::ensureSize() } } -BfsIterator::~BfsIterator() -{ -} +BfsIterator::~BfsIterator() {} void BfsIterator::clear() @@ -81,7 +79,7 @@ BfsIterator::clear() VertexSeq &level_vertices = queue_[level]; for (Vertex *vertex : level_vertices) { if (vertex) - vertex->setBfsInQueue(bfs_index_, false); + vertex->setBfsInQueue(bfs_index_, false); } level_vertices.clear(); incrLevel(level); @@ -92,18 +90,18 @@ BfsIterator::clear() void BfsIterator::reportEntries() const { - for (Level level=first_level_; levelLessOrEqual(level, last_level_);incrLevel(level)){ + for (Level level = first_level_; levelLessOrEqual(level, last_level_); + incrLevel(level)) { const VertexSeq &level_vertices = queue_[level]; if (!level_vertices.empty()) { - report_->reportLine("Level %d", level); + report_->report("Level {}", level); for (Vertex *vertex : level_vertices) - report_->reportLine(" %s", - vertex ? vertex->to_string(this).c_str() : "NULL"); + report_->report(" {}", vertex ? vertex->to_string(this) : "NULL"); } } } -void +void BfsIterator::deleteEntries(Level level) { VertexSeq &level_vertices = queue_[level]; @@ -135,11 +133,11 @@ BfsIterator::enqueueAdjacentVertices(Vertex *vertex, int BfsIterator::visit(Level to_level, - VertexVisitor *visitor) + VertexVisitor *visitor) { int visit_count = 0; while (levelLessOrEqual(first_level_, last_level_) - && levelLessOrEqual(first_level_, to_level)) { + && levelLessOrEqual(first_level_, to_level)) { Level level = first_level_; VertexSeq &level_vertices = queue_[level]; incrLevel(first_level_); @@ -163,7 +161,7 @@ BfsIterator::visit(Level to_level, int BfsIterator::visitParallel(Level to_level, - VertexVisitor *visitor) + VertexVisitor *visitor) { size_t thread_count = thread_count_; int visit_count = 0; @@ -171,15 +169,15 @@ BfsIterator::visitParallel(Level to_level, if (thread_count == 1) visit_count = visit(to_level, visitor); else { - std::vector visitors; + std::vector visitors; for (int k = 0; k < thread_count_; k++) - visitors.push_back(visitor->copy()); + visitors.push_back(visitor->copy()); while (levelLessOrEqual(first_level_, last_level_) - && levelLessOrEqual(first_level_, to_level)) { - VertexSeq &level_vertices = queue_[first_level_]; + && levelLessOrEqual(first_level_, to_level)) { + VertexSeq &level_vertices = queue_[first_level_]; Level level = first_level_; - incrLevel(first_level_); - if (!level_vertices.empty()) { + incrLevel(first_level_); + if (!level_vertices.empty()) { size_t vertex_count = level_vertices.size(); if (vertex_count < thread_count) { for (Vertex *vertex : level_vertices) { @@ -197,7 +195,7 @@ BfsIterator::visitParallel(Level to_level, for (size_t k = 0; k < thread_count; k++) { // Last thread gets the left overs. size_t to = (k == thread_count - 1) ? vertex_count : from + chunk_size; - dispatch_queue_->dispatch( [=, this](int) { + dispatch_queue_->dispatch([=, this](int) { for (size_t i = from; i < to; i++) { Vertex *vertex = level_vertices[i]; if (vertex) { @@ -211,13 +209,13 @@ BfsIterator::visitParallel(Level to_level, } dispatch_queue_->finishTasks(); } - visitor->levelFinished(); - level_vertices.clear(); + visitor->levelFinished(); + level_vertices.clear(); visit_count += vertex_count; - } + } } for (VertexVisitor *visitor : visitors) - delete visitor; + delete visitor; } } return visit_count; @@ -234,7 +232,7 @@ BfsIterator::hasNext(Level to_level) { findNext(to_level); return levelLessOrEqual(first_level_, last_level_) - && !queue_[first_level_].empty(); + && !queue_[first_level_].empty(); } Vertex * @@ -251,16 +249,16 @@ void BfsIterator::findNext(Level to_level) { while (levelLessOrEqual(first_level_, last_level_) - && levelLessOrEqual(first_level_, to_level)) { + && levelLessOrEqual(first_level_, to_level)) { VertexSeq &level_vertices = queue_[first_level_]; // Skip null entries from deleted vertices. while (!level_vertices.empty()) { Vertex *vertex = level_vertices.back(); if (vertex == nullptr) - level_vertices.pop_back(); + level_vertices.pop_back(); else { checkLevel(vertex, first_level_); - return; + return; } } incrLevel(first_level_); @@ -270,8 +268,7 @@ BfsIterator::findNext(Level to_level) void BfsIterator::enqueue(Vertex *vertex) { - debugPrint(debug_, "bfs", 2, "enqueue %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "bfs", 2, "enqueue {}", vertex->to_string(this)); if (!vertex->bfsInQueue(bfs_index_)) { Level level = vertex->level(); LockGuard lock(queue_lock_); @@ -280,9 +277,9 @@ BfsIterator::enqueue(Vertex *vertex) queue_[level].push_back(vertex); if (levelLess(last_level_, level)) - last_level_ = level; + last_level_ = level; if (levelLess(level, first_level_)) - first_level_ = level; + first_level_ = level; } } } @@ -301,17 +298,15 @@ BfsIterator::checkInQueue(Vertex *vertex) if (static_cast(queue_.size()) > level) { for (Vertex *v : queue_[level]) { if (v == vertex) { - if (vertex->bfsInQueue(bfs_index_)) - return; - else - debugPrint(debug_, "bfs", 1, "extra %s", - vertex->to_string(this).c_str()); + if (vertex->bfsInQueue(bfs_index_)) + return; + else + debugPrint(debug_, "bfs", 1, "extra {}", vertex->to_string(this)); } } } if (vertex->bfsInQueue(bfs_index_)) - debugPrint(debug_, "brs", 1, "missing %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "brs", 1, "missing {}", vertex->to_string(this)); } void @@ -319,10 +314,8 @@ BfsIterator::checkLevel(Vertex *vertex, Level level) { if (vertex->level() != level) - report_->error(2300, "vertex %s level %d != bfs level %d", - vertex->to_string(this).c_str(), - vertex->level(), - level); + report_->error(2300, "vertex {} level {} != bfs level {}", + vertex->to_string(this), vertex->level(), level); } void @@ -337,14 +330,12 @@ BfsIterator::remove(Vertex *vertex) { // If the iterator has not been inited the queue will be empty. Level level = vertex->level(); - if (vertex->bfsInQueue(bfs_index_) - && static_cast(queue_.size()) > level) { - debugPrint(debug_, "bfs", 2, "remove %s", - vertex->to_string(this).c_str()); + if (vertex->bfsInQueue(bfs_index_) && static_cast(queue_.size()) > level) { + debugPrint(debug_, "bfs", 2, "remove {}", vertex->to_string(this)); for (Vertex *&v : queue_[level]) { if (v == vertex) { - v = nullptr; - vertex->setBfsInQueue(bfs_index_, false); + v = nullptr; + vertex->setBfsInQueue(bfs_index_, false); break; } } @@ -354,9 +345,13 @@ BfsIterator::remove(Vertex *vertex) //////////////////////////////////////////////////////////////// BfsFwdIterator::BfsFwdIterator(BfsIndex bfs_index, - SearchPred *search_pred, - StaState *sta) : - BfsIterator(bfs_index, 0, level_max, search_pred, sta) + SearchPred *search_pred, + StaState *sta) : + BfsIterator(bfs_index, + 0, + level_max, + search_pred, + sta) { } @@ -375,14 +370,14 @@ BfsFwdIterator::incrLevel(Level &level) const bool BfsFwdIterator::levelLessOrEqual(Level level1, - Level level2) const + Level level2) const { return level1 <= level2; } bool BfsFwdIterator::levelLess(Level level1, - Level level2) const + Level level2) const { return level1 < level2; } @@ -396,9 +391,8 @@ BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex, while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); Vertex *to_vertex = edge->to(graph_); - if (search_pred->searchThru(edge) - && search_pred->searchTo(to_vertex)) - enqueue(to_vertex); + if (search_pred->searchThru(edge) && search_pred->searchTo(to_vertex)) + enqueue(to_vertex); } } } @@ -423,9 +417,13 @@ BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex, //////////////////////////////////////////////////////////////// BfsBkwdIterator::BfsBkwdIterator(BfsIndex bfs_index, - SearchPred *search_pred, - StaState *sta) : - BfsIterator(bfs_index, level_max, 0, search_pred, sta) + SearchPred *search_pred, + StaState *sta) : + BfsIterator(bfs_index, + level_max, + 0, + search_pred, + sta) { } @@ -444,14 +442,14 @@ BfsBkwdIterator::incrLevel(Level &level) const bool BfsBkwdIterator::levelLessOrEqual(Level level1, - Level level2) const + Level level2) const { return level1 >= level2; } bool BfsBkwdIterator::levelLess(Level level1, - Level level2) const + Level level2) const { return level1 > level2; } @@ -465,9 +463,8 @@ BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex, while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); Vertex *from_vertex = edge->from(graph_); - if (search_pred->searchFrom(from_vertex) - && search_pred->searchThru(edge)) - enqueue(from_vertex); + if (search_pred->searchFrom(from_vertex) && search_pred->searchThru(edge)) + enqueue(from_vertex); } } } @@ -489,4 +486,4 @@ BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex, } } -} // namespace +} // namespace sta diff --git a/search/CheckMaxSkews.cc b/search/CheckMaxSkews.cc index 8682f6f1..20cb5224 100644 --- a/search/CheckMaxSkews.cc +++ b/search/CheckMaxSkews.cc @@ -178,15 +178,15 @@ MaxSkewCheck::maxSkew(const StaState *sta) const } Delay -MaxSkewCheck::skew() const +MaxSkewCheck::skew(const StaState *sta) const { - return Delay(clk_path_->arrival() - ref_path_->arrival()); + return delayDiff(clk_path_->arrival(), ref_path_->arrival(), sta); } Slack MaxSkewCheck::slack(const StaState *sta) const { - return maxSkew(sta) - skew(); + return delayDiff(maxSkew(sta), skew(sta), sta); } //////////////////////////////////////////////////////////////// @@ -203,7 +203,7 @@ MaxSkewSlackLess::operator()(const MaxSkewCheck &check1, Slack slack1 = check1.slack(sta_); Slack slack2 = check2.slack(sta_); return delayLess(slack1, slack2, sta_) - || (delayEqual(slack1, slack2) + || (delayEqual(slack1, slack2, sta_) // Break ties based on constrained pin names. && sta_->network()->pinLess(check1.clkPin(sta_), check2.clkPin(sta_))); } diff --git a/search/CheckMaxSkews.hh b/search/CheckMaxSkews.hh index ac1660cc..dc64f0c0 100644 --- a/search/CheckMaxSkews.hh +++ b/search/CheckMaxSkews.hh @@ -48,7 +48,7 @@ public: Pin *clkPin(const StaState *sta) const; const Path *refPath() const { return ref_path_; } Pin *refPin(const StaState *sta) const; - Delay skew() const; + Delay skew(const StaState *sta) const; ArcDelay maxSkew(const StaState *sta) const; Slack slack(const StaState *sta) const; TimingArc *checkArc() const { return check_arc_; } diff --git a/search/CheckMinPeriods.cc b/search/CheckMinPeriods.cc index bb9b9282..195187c5 100644 --- a/search/CheckMinPeriods.cc +++ b/search/CheckMinPeriods.cc @@ -198,7 +198,7 @@ MinPeriodSlackLess::operator()(const MinPeriodCheck &check1, const Pin *pin2 = check2.pin(); return delayLess(slack1, slack2, sta_) // Break ties based on pin and clock names. - || (delayEqual(slack1, slack2) + || (delayEqual(slack1, slack2, sta_) && (sta_->network()->pinLess(pin1, pin2) || (pin1 == pin2 && ClockNameLess()(check1.clk(), diff --git a/search/CheckMinPulseWidths.cc b/search/CheckMinPulseWidths.cc index 0f7ff320..cad8319e 100644 --- a/search/CheckMinPulseWidths.cc +++ b/search/CheckMinPulseWidths.cc @@ -140,8 +140,8 @@ CheckMinPulseWidths::checkVertex(Vertex *vertex, Path *close_path = check.closePath(sta_); // Don't bother visiting if nobody is home. if (close_path) { - debugPrint(debug, "mpw", 2, "%s %s %s", - path_vertex->to_string(sta_).c_str(), + debugPrint(debug, "mpw", 2, "{} {} {}", + path_vertex->to_string(sta_), path->transition(sta_) == RiseFall::rise() ? "(high)" : "(low)", delayAsString(check.slack(sta_), sta_)); if (violators) { @@ -219,17 +219,17 @@ MinPulseWidthCheck::closePath(const StaState *sta) const open_tag->isSegmentStart(), open_tag->states(), false); - debugPrint(sta->debug(), "mpw", 3, " open %s", - open_tag->to_string(sta).c_str()); - debugPrint(sta->debug(), "mpw", 3, " close %s", - close_tag.to_string(sta).c_str()); + debugPrint(sta->debug(), "mpw", 3, " open {}", + open_tag->to_string(sta)); + debugPrint(sta->debug(), "mpw", 3, " close {}", + close_tag.to_string(sta)); VertexPathIterator close_iter(open_path_->vertex(sta), scene, close_min_max, close_rf, sta); while (close_iter.hasNext()) { Path *close_path = close_iter.next(); if (Tag::matchNoPathAp(close_path->tag(sta), &close_tag)) { - debugPrint(sta->debug(), "mpw", 3, " match %s", - close_path->tag(sta)->to_string(sta).c_str()); + debugPrint(sta->debug(), "mpw", 3, " match {}", + close_path->tag(sta)->to_string(sta)); return close_path; } } @@ -252,13 +252,13 @@ MinPulseWidthCheck::closeArrival(const StaState *sta) const Arrival MinPulseWidthCheck::openDelay(const StaState *sta) const { - return openArrival(sta) - openClkEdge(sta)->time(); + return delayDiff(openArrival(sta), openClkEdge(sta)->time(), sta); } Arrival MinPulseWidthCheck::closeDelay(const StaState *sta) const { - return closeArrival(sta) - closeClkEdge(sta)->time(); + return delayDiff(closeArrival(sta), closeClkEdge(sta)->time(), sta); } const ClockEdge * @@ -289,9 +289,11 @@ MinPulseWidthCheck::closeOffset(const StaState *sta) const Arrival MinPulseWidthCheck::width(const StaState *sta) const { - return closeArrival(sta) + closeOffset(sta) - - open_path_->arrival() - + checkCrpr(sta); + Arrival close_with_offset = delaySum(closeArrival(sta), + closeOffset(sta), + sta); + Arrival minus_open = delayDiff(close_with_offset, open_path_->arrival(), sta); + return delaySum(minus_open, checkCrpr(sta), sta); } float @@ -323,6 +325,7 @@ minPulseWidth(const Path *path, // set_min_pulse_width command. sdc->minPulseWidth(pin, clk, rf, min_width, exists); if (!exists) { + const MinMax *min_max = path->minMax(sta); DcalcAPIndex dcalc_ap = path->dcalcAnalysisPtIndex(sta); Vertex *vertex = path->vertex(sta); Graph *graph = sta->graph(); @@ -330,7 +333,7 @@ minPulseWidth(const Path *path, TimingArc *arc; graph->minPulseWidthArc(vertex, rf, edge, arc); if (edge) { - min_width = delayAsFloat(graph->arcDelay(edge, arc, dcalc_ap)); + min_width = delayAsFloat(graph->arcDelay(edge, arc, dcalc_ap), min_max, sta); exists = true; } } @@ -350,7 +353,7 @@ MinPulseWidthCheck::checkCrpr(const StaState *sta) const Slack MinPulseWidthCheck::slack(const StaState *sta) const { - return width(sta) - minWidth(sta); + return delayDiff(width(sta), minWidth(sta), sta); } Scene * @@ -375,7 +378,7 @@ MinPulseWidthSlackLess::operator()(const MinPulseWidthCheck &check1, const Pin *pin1 = check1.pin(sta_); const Pin *pin2 = check2.pin(sta_); return delayLess(slack1, slack2, sta_) - || (delayEqual(slack1, slack2) + || (delayEqual(slack1, slack2, sta_) // Break ties for the sake of regression stability. && (sta_->network()->pinLess(pin1, pin2) || (pin1 == pin2 diff --git a/search/CheckTiming.cc b/search/CheckTiming.cc index de4ad8b4..9b83593f 100644 --- a/search/CheckTiming.cc +++ b/search/CheckTiming.cc @@ -123,8 +123,7 @@ CheckTiming::checkNoInputDelay() } } delete pin_iter; - pushPinErrors("Warning: There %is %d input port%s missing set_input_delay.", - no_arrival); + pushPinErrors("Warning: There {} {} input port{} missing set_input_delay.",no_arrival); } void @@ -132,7 +131,7 @@ CheckTiming::checkNoOutputDelay() { PinSet no_departure(network_); checkNoOutputDelay(no_departure); - pushPinErrors("Warning: There %is %d output port%s missing set_output_delay.", + pushPinErrors("Warning: There {} {} output port{} missing set_output_delay.", no_departure); } @@ -179,12 +178,24 @@ CheckTiming::checkRegClks(bool reg_multiple_clks, if (reg_multiple_clks && clks && clks->size() > 1) multiple_clk_pins.insert(pin); } - pushPinErrors("Warning: There %is %d unclocked register/latch pin%s.", + pushPinErrors("Warning: There {} {} unclocked register/latch pin{}.", no_clk_pins); - pushPinErrors("Warning: There %is %d register/latch pin%s with multiple clocks.", + pushPinErrors("Warning: There {} {} register/latch pin{} with multiple clocks.", multiple_clk_pins); } +static const char * +plurality(int n) +{ + return n == 1 ? "is" : "are"; +} + +static const char * +pluralSuffix(int n) +{ + return n == 1 ? "" : "s"; +} + void CheckTiming::checkLoops() { @@ -198,11 +209,11 @@ CheckTiming::checkLoops() loop_count++; } if (loop_count > 0) { - std::string error_msg; - errorMsgSubst("Warning: There %is %d combinational loop%s in the design.", - loop_count, error_msg); CheckError *error = new CheckError; - error->push_back(error_msg); + error->push_back(sta::format("Warning: There {} {} combinational loop{} in the design.", + plurality(loop_count), + loop_count, + pluralSuffix(loop_count))); for (GraphLoop *loop : loops) { if (loop->isCombinational()) { @@ -232,7 +243,7 @@ CheckTiming::checkUnconstrainedEndpoints() PinSet unconstrained_ends(network_); checkUnconstrainedOutputs(unconstrained_ends); checkUnconstrainedSetups(unconstrained_ends); - pushPinErrors("Warning: There %is %d unconstrained endpoint%s.", + pushPinErrors("Warning: There {} {} unconstrained endpoint{}.", unconstrained_ends); } @@ -338,27 +349,21 @@ CheckTiming::checkGeneratedClocks() gen_clk_errors.insert(clk); } } - pushClkErrors("Warning: There %is %d generated clock%s that %is not connected to a clock source.", + pushClkErrors("Warning: There {} {} generated clock{} not connected to a clock source.", gen_clk_errors); } // Report the "msg" error for each pin in "pins". -// -// Substitutions in msg are done as follows if the pin count is one -// or greater than one. -// %is - is/are -// %d - pin count -// %s - s/"" -// %a - a/"" void -CheckTiming::pushPinErrors(const char *msg, +CheckTiming::pushPinErrors(std::string_view msg, PinSet &pins) { if (!pins.empty()) { CheckError *error = new CheckError; - std::string error_msg; - errorMsgSubst(msg, pins.size(), error_msg); - error->push_back(error_msg); + error->push_back(sta::formatRuntime(msg, + plurality(pins.size()), + pins.size(), + pluralSuffix(pins.size()))); // Sort the error pins so the output is independent of the order // the the errors are discovered. PinSeq pins1 = sortByPathName(&pins, network_); @@ -375,9 +380,10 @@ CheckTiming::pushClkErrors(const char *msg, { if (!clks.empty()) { CheckError *error = new CheckError; - std::string error_msg; - errorMsgSubst(msg, clks.size(), error_msg); - error->push_back(error_msg); + error->push_back(sta::formatRuntime(msg, + plurality(clks.size()), + clks.size(), + pluralSuffix(clks.size()))); // Sort the error clks so the output is independent of the order // the the errors are discovered. ClockSeq clks1 = sortByName(&clks); @@ -388,47 +394,4 @@ CheckTiming::pushClkErrors(const char *msg, } } -// Copy msg making substitutions for singular/plurals. -void -CheckTiming::errorMsgSubst(const char *msg, - int obj_count, - std::string &error_msg) -{ - for (const char *s = msg; *s; s++) { - char ch = *s; - if (ch == '%') { - char flag = s[1]; - if (flag == 'i') { - if (obj_count > 1) - error_msg += "are"; - else - error_msg += "is"; - s += 2; - } - else if (flag == 'a') { - if (obj_count == 1) { - error_msg += 'a'; - s++; - } - else - // Skip space after %a. - s += 2; - } - else if (flag == 's') { - if (obj_count > 1) - error_msg += 's'; - s++; - } - else if (flag == 'd') { - error_msg += std::to_string(obj_count); - s++; - } - else - criticalError(245, "unknown print flag"); - } - else - error_msg += ch; - } -} - } // namespace diff --git a/search/CheckTiming.hh b/search/CheckTiming.hh index 9cdd4227..94f845b5 100644 --- a/search/CheckTiming.hh +++ b/search/CheckTiming.hh @@ -70,13 +70,10 @@ protected: bool hasClkedCheck(Vertex *vertex); bool hasMaxDelay(Pin *pin); void checkGeneratedClocks(); - void pushPinErrors(const char *msg, + void pushPinErrors(std::string_view msg, PinSet &pins); void pushClkErrors(const char *msg, ClockSet &clks); - void errorMsgSubst(const char *msg, - int count, - std::string &error_msg); CheckErrorSeq errors_; const Mode *mode_; diff --git a/search/ClkDelays.hh b/search/ClkDelays.hh index 2b9d6a36..e8a15749 100644 --- a/search/ClkDelays.hh +++ b/search/ClkDelays.hh @@ -61,9 +61,9 @@ public: StaState *sta); private: - static float insertionDelay(Path *clk_path, + static Delay insertionDelay(Path *clk_path, StaState *sta); - static float delay(Path *clk_path, + static Delay delay(Path *clk_path, StaState *sta); static float clkTreeDelay(Path *clk_path, StaState *sta); diff --git a/search/ClkInfo.cc b/search/ClkInfo.cc index 767a44a1..e3e3a05a 100644 --- a/search/ClkInfo.cc +++ b/search/ClkInfo.cc @@ -102,7 +102,7 @@ ClkInfo::findHash(const StaState *sta) hashIncr(hash_, hash_float(uncertainty)); } hashIncr(hash_, hash_float(latency_)); - hashIncr(hash_, hash_float(delayAsFloat(insertion_))); + hashIncr(hash_, hash_float(insertion_.mean())); hashIncr(hash_, is_propagated_); hashIncr(hash_, is_gen_clk_src_path_); hashIncr(hash_, is_pulse_clk_); @@ -152,9 +152,10 @@ ClkInfo::to_string(const StaState *sta) const Network *network = sta->network(); std::string result; + const MinMax *min_max = minMax(); result += scene_->name(); result += "/"; - result += minMax()->to_string(); + result += min_max->to_string(); result += " "; if (clk_edge_) @@ -186,7 +187,7 @@ ClkInfo::to_string(const StaState *sta) const if (delayGreater(insertion_, 0.0, sta)) { result += " insert"; - result += delayAsString(insertion_, sta); + result += delayAsString(insertion_, min_max, sta); } if (uncertainties_) { diff --git a/search/ClkLatency.cc b/search/ClkLatency.cc index 0c186704..887c009e 100644 --- a/search/ClkLatency.cc +++ b/search/ClkLatency.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "ClkLatency.hh" @@ -55,8 +55,7 @@ ClkLatency::findClkDelays(const Clock *clk, clks.push_back(clk); SceneSet scenes; scenes.insert(scene); - ClkDelayMap clk_delay_map = findClkDelays(clks, scenes, - include_internal_latency); + ClkDelayMap clk_delay_map = findClkDelays(clks, scenes, include_internal_latency); return clk_delay_map[clk]; } @@ -88,7 +87,7 @@ ClkLatency::reportClkLatency(const Clock *clk, int digits) { Unit *time_unit = units_->timeUnit(); - report_->reportLine("Clock %s", clk->name()); + report_->report("Clock {}", clk->name()); for (const RiseFall *src_rf : RiseFall::range()) { for (const RiseFall *end_rf : RiseFall::range()) { Path path_min; @@ -97,47 +96,41 @@ ClkLatency::reportClkLatency(const Clock *clk, float internal_latency_min; Delay latency_min; bool exists_min; - clk_delays.delay(src_rf, end_rf, MinMax::min(), insertion_min, - delay_min, internal_latency_min, latency_min, - path_min, exists_min); + clk_delays.delay(src_rf, end_rf, MinMax::min(), insertion_min, delay_min, + internal_latency_min, latency_min, path_min, exists_min); Path path_max; Delay insertion_max; Delay delay_max; float internal_latency_max; Delay latency_max; bool exists_max; - clk_delays.delay(src_rf, end_rf, MinMax::max(), insertion_max, - delay_max, internal_latency_max, latency_max, - path_max, exists_max); + clk_delays.delay(src_rf, end_rf, MinMax::max(), insertion_max, delay_max, + internal_latency_max, latency_max, path_max, exists_max); if (exists_min & exists_max) { - report_->reportLine("%s -> %s", - src_rf->name(), - end_rf->name()); - report_->reportLine(" min max"); - - report_->reportLine("%7s %7s source latency", - delayAsString(insertion_min, this, digits), - delayAsString(insertion_max, this, digits)); - report_->reportLine("%7s %7s network latency %s", - delayAsString(delay_min, this, digits), - "", - sdc_network_->pathName(path_min.pin(this))); - report_->reportLine("%7s %7s network latency %s", - "", - delayAsString(delay_max, this, digits), - sdc_network_->pathName(path_max.pin(this))); - if (internal_latency_min != 0.0 - || internal_latency_max != 0.0) - report_->reportLine("%7s %7s internal clock latency", - time_unit->asString(internal_latency_min, digits), - time_unit->asString(internal_latency_max, digits)); - report_->reportLine("---------------"); - report_->reportLine("%7s %7s latency", - delayAsString(latency_min, this, digits), - delayAsString(latency_max, this, digits)); - Delay skew = latency_max - latency_min; - report_->reportLine(" %7s skew", - delayAsString(skew, this, digits)); + report_->report("{} -> {}", src_rf->name(), end_rf->name()); + report_->report(" min max"); + report_->report("{:>7} {:>7} source latency", + delayAsString(insertion_min, MinMax::min(), digits, this), + delayAsString(insertion_max, MinMax::max(), digits, this)); + report_->report("{:>7} {:>7} network latency {}", + delayAsString(delay_min, MinMax::min(), digits, this), + "", + sdc_network_->pathName(path_min.pin(this))); + report_->report("{:>7} {:>7} network latency {}", + "", + delayAsString(delay_max, MinMax::max(), digits, this), + sdc_network_->pathName(path_max.pin(this))); + if (internal_latency_min != 0.0 || internal_latency_max != 0.0) + report_->report("{:>7} {:>7} internal clock latency", + time_unit->asString(internal_latency_min, digits), + time_unit->asString(internal_latency_max, digits)); + report_->report("---------------"); + report_->report("{:>7} {:>7} latency", + delayAsString(latency_min, MinMax::min(), digits, this), + delayAsString(latency_max, MinMax::max(), digits, this)); + Delay skew = delayDiff(latency_max, latency_min, this); + report_->report(" {:>7} skew", + delayAsString(skew, MinMax::max(), digits, this)); report_->reportBlankLine(); } } @@ -164,9 +157,7 @@ ClkLatency::findClkDelays(ConstClockSeq &clks, Path *path = path_iter.next(); const Scene *path_scene = path->scene(this); const Clock *path_clk = path->clock(this); - if (path_clk - && scenes.contains(path_scene) - && clk_set.contains(path_clk)) { + if (path_clk && scenes.contains(path_scene) && clk_set.contains(path_clk)) { auto delays_itr = clk_delay_map.find(path_clk); if (delays_itr != clk_delay_map.end()) { const ClockEdge *path_clk_edge = path->clkEdge(this); @@ -255,10 +246,10 @@ ClkDelays::setLatency(const RiseFall *src_rf, int end_rf_index = end_rf->index(); int mm_index = min_max->index(); - float insertion = insertionDelay(path, sta); + Delay insertion = insertionDelay(path, sta); insertion_[src_rf_index][end_rf_index][mm_index] = insertion; - float delay1 = delay(path, sta); + Delay delay1 = delay(path, sta); delay_[src_rf_index][end_rf_index][mm_index] = delay1; float internal_latency = 0.0; @@ -267,7 +258,7 @@ ClkDelays::setLatency(const RiseFall *src_rf, internal_latency_[src_rf_index][end_rf_index][mm_index] = internal_latency; } - float latency = insertion + delay1 + internal_latency; + Delay latency = delaySum(delay1, delaySum(insertion, internal_latency, sta), sta); latency_[src_rf_index][end_rf_index][mm_index] = latency; path_[src_rf_index][end_rf_index][mm_index] = *path; @@ -278,23 +269,22 @@ Delay ClkDelays::latency(Path *clk_path, StaState *sta) { - - float insertion = insertionDelay(clk_path, sta); - float delay1 = delay(clk_path, sta); + Delay insertion = insertionDelay(clk_path, sta); + Delay delay1 = delay(clk_path, sta); float lib_clk_delay = clkTreeDelay(clk_path, sta); - return insertion + delay1 + lib_clk_delay; + return delaySum(delay1, delaySum(insertion, lib_clk_delay, sta), sta); } -float +Delay ClkDelays::delay(Path *clk_path, StaState *sta) { Arrival arrival = clk_path->arrival(); const ClockEdge *path_clk_edge = clk_path->clkEdge(sta); - return delayAsFloat(arrival) - path_clk_edge->time(); + return delayDiff(arrival, path_clk_edge->time(), sta); } -float +Delay ClkDelays::insertionDelay(Path *clk_path, StaState *sta) { @@ -305,8 +295,7 @@ ClkDelays::insertionDelay(Path *clk_path, const Pin *src_pin = clk_info->clkSrc(); const MinMax *min_max = clk_path->minMax(sta); const Mode *mode = clk_path->mode(sta); - return delayAsFloat(sta->search()->clockInsertion(clk, src_pin, clk_rf, min_max, - min_max, mode)); + return sta->search()->clockInsertion(clk, src_pin, clk_rf, min_max, min_max, mode); } float @@ -318,8 +307,8 @@ ClkDelays::clkTreeDelay(Path *clk_path, const LibertyPort *port = sta->network()->libertyPort(pin); const MinMax *min_max = clk_path->minMax(sta); const RiseFall *rf = clk_path->transition(sta); - float slew = delayAsFloat(clk_path->slew(sta)); + float slew = delayAsFloat(clk_path->slew(sta), min_max, sta); return port->clkTreeDelay(slew, rf, min_max); } -} // namespace +} // namespace sta diff --git a/search/ClkSkew.cc b/search/ClkSkew.cc index ddbeb397..8167d486 100644 --- a/search/ClkSkew.cc +++ b/search/ClkSkew.cc @@ -1,30 +1,30 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "ClkSkew.hh" -#include // abs +#include // abs #include #include #include @@ -78,12 +78,12 @@ ClkSkews::reportClkSkew(ConstClockSeq &clks, sort(sorted_clks, ClkNameLess()); for (const Clock *clk : sorted_clks) { - report_->reportLine("Clock %s", clk->name()); + report_->report("Clock {}", clk->name()); auto skew_itr = skews_.find(clk); if (skew_itr != skews_.end()) reportClkSkew(skew_itr->second[setup_hold->index()], digits); else - report_->reportLine("No launch/capture paths found."); + report_->report("No launch/capture paths found."); report_->reportBlankLine(); } } @@ -95,44 +95,62 @@ ClkSkews::reportClkSkew(ClkSkew &clk_skew, Unit *time_unit = units_->timeUnit(); Path *src_path = clk_skew.srcPath(); Path *tgt_path = clk_skew.tgtPath(); - float src_latency = clk_skew.srcLatency(this); + const MinMax *src_min_max = src_path->minMax(this); + Arrival src_latency = clk_skew.srcLatency(this); float tgt_latency = clk_skew.tgtLatency(this); float src_internal_clk_latency = clk_skew.srcInternalClkLatency(this); float tgt_internal_clk_latency = clk_skew.tgtInternalClkLatency(this); float uncertainty = clk_skew.uncertainty(this); if (src_internal_clk_latency != 0.0) - src_latency -= src_internal_clk_latency; - report_->reportLine("%7s source latency %s %s", - time_unit->asString(src_latency, digits), - sdc_network_->pathName(src_path->pin(this)), - src_path->transition(this)->shortName()); + delayDecr(src_latency, src_internal_clk_latency, this); + report_->report("{:>7} source latency {} {}", + delayAsString(src_latency, src_min_max, digits, this), + sdc_network_->pathName(src_path->pin(this)), + src_path->transition(this)->shortName()); if (src_internal_clk_latency != 0.0) - report_->reportLine("%7s source internal clock delay", - time_unit->asString(src_internal_clk_latency, digits)); + report_->report("{:>7} source internal clock delay", + time_unit->asString(src_internal_clk_latency, digits)); if (tgt_internal_clk_latency != 0.0) tgt_latency -= tgt_internal_clk_latency; - report_->reportLine("%7s target latency %s %s", - time_unit->asString(-tgt_latency, digits), - sdc_network_->pathName(tgt_path->pin(this)), - tgt_path->transition(this)->shortName()); + report_->report("{:>7} target latency {} {}", + time_unit->asString(-tgt_latency, digits), + sdc_network_->pathName(tgt_path->pin(this)), + tgt_path->transition(this)->shortName()); if (tgt_internal_clk_latency != 0.0) - report_->reportLine("%7s target internal clock delay", - time_unit->asString(-tgt_internal_clk_latency, digits)); + report_->report("{:>7} target internal clock delay", + time_unit->asString(-tgt_internal_clk_latency, digits)); if (uncertainty != 0.0) - report_->reportLine("%7s clock uncertainty", - time_unit->asString(uncertainty, digits)); - report_->reportLine("%7s CRPR", - time_unit->asString(delayAsFloat(-clk_skew.crpr(this)), - digits)); - report_->reportLine("--------------"); - report_->reportLine("%7s %s skew", - time_unit->asString(clk_skew.skew(), digits), - src_path->minMax(this) == MinMax::max() ? "setup" : "hold"); + report_->report("{:>7} clock uncertainty", + time_unit->asString(uncertainty, digits)); + report_->report("{:>7} CRPR", + delayAsString(delayDiff(0.0, clk_skew.crpr(this), this), + MinMax::max(), digits, this)); + report_->report("--------------"); + report_->report("{:>7} {} skew", + delayAsString(clk_skew.skew(), MinMax::max(), digits, this), + src_path->minMax(this) == MinMax::max() ? "setup" : "hold"); } -float +static float +delayAbsMax(const Delay &delay, + const StaState *sta) +{ + float min = delayAsFloat(delay, MinMax::min(), sta); + float max = delayAsFloat(delay, MinMax::max(), sta); + return std::max(std::abs(min), std::abs(max)); +} + +static bool +delayAbsGreater(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return delayAbsMax(delay1, sta) > delayAbsMax(delay2, sta); +} + +Delay ClkSkews::findWorstClkSkew(const SceneSeq &scenes, const SetupHold *setup_hold, bool include_internal_latency) @@ -143,10 +161,10 @@ ClkSkews::findWorstClkSkew(const SceneSeq &scenes, clks.push_back(clk); } findClkSkew(clks, scenes, include_internal_latency); - float worst_skew = 0.0; + Delay worst_skew = 0.0; for (const auto& [clk, clk_skews] : skews_) { - float skew = clk_skews[setup_hold->index()].skew(); - if (std::abs(skew) > std::abs(worst_skew)) + Delay skew = clk_skews[setup_hold->index()].skew(); + if (delayAbsGreater(skew, worst_skew, this)) worst_skew = skew; } return worst_skew; @@ -156,11 +174,9 @@ void ClkSkews::findClkSkew(ConstClockSeq &clks, const SceneSeq &scenes, bool include_internal_latency) -{ - if (scenes == scenes_ - && include_internal_latency == include_internal_latency_ - && clks == clks_ - && !skews_.empty()) +{ + if (scenes == scenes_ && include_internal_latency == include_internal_latency_ + && clks == clks_ && !skews_.empty()) return; skews_.clear(); @@ -188,14 +204,14 @@ ClkSkews::findClkSkew(ConstClockSeq &clks, // Reduce skews from each register source. for (size_t i = 0; i < partial_skews.size(); i++) { - for (auto& [clk, partial_skew] : partial_skews[i]) { + for (auto &[clk, partial_skew] : partial_skews[i]) { auto itr = skews_.find(clk); if (itr == skews_.end()) { // Insert new entry using emplace with piecewise_construct // This will default-construct the array, then we copy the elements - auto result = skews_.emplace(std::piecewise_construct, - std::forward_as_tuple(clk), - std::make_tuple()); + auto result = + skews_.emplace(std::piecewise_construct, std::forward_as_tuple(clk), + std::make_tuple()); itr = result.first; // Copy array elements for (int setup_hold_idx : SetupHold::rangeIndex()) @@ -206,12 +222,15 @@ ClkSkews::findClkSkew(ConstClockSeq &clks, for (int setup_hold_idx : SetupHold::rangeIndex()) { ClkSkew &final_skew = itr->second[setup_hold_idx]; ClkSkew &partial_skew_val = partial_skew[setup_hold_idx]; - float partial_skew1 = partial_skew_val.skew(); - float final_skew1 = final_skew.skew(); - if (std::abs(partial_skew1) > std::abs(final_skew1) - || (fuzzyEqual(std::abs(partial_skew1), std::abs(final_skew1)) + Delay partial_skew1 = partial_skew_val.skew(); + Delay final_skew1 = final_skew.skew(); + float partial_skew_max = delayAbsMax(partial_skew1, this); + float final_skew_max = delayAbsMax(final_skew1, this); + if (partial_skew_max > final_skew_max + || (fuzzyEqual(partial_skew_max, final_skew_max) // Break ties based on source/target path names. - && ClkSkew::srcTgtPathNameLess(partial_skew_val, final_skew, this))) + && ClkSkew::srcTgtPathNameLess(partial_skew_val, final_skew, + this))) final_skew = partial_skew_val; } } @@ -249,9 +268,8 @@ ClkSkews::findClkSkewFrom(Vertex *src_vertex, if (edge->role()->genericRole() == TimingRole::regClkToQ()) { Vertex *q_vertex = edge->to(graph_); const RiseFall *rf = edge->timingArcSet()->isRisingFallingEdge(); - const RiseFallBoth *src_rf = rf - ? rf->asRiseFallBoth() - : RiseFallBoth::riseFall(); + const RiseFallBoth *src_rf = + rf ? rf->asRiseFallBoth() : RiseFallBoth::riseFall(); findClkSkewFrom(src_vertex, q_vertex, src_rf, skews); } } @@ -271,12 +289,11 @@ ClkSkews::findClkSkewFrom(Vertex *src_vertex, const TimingRole *role = edge->role(); if (role->genericRole() == TimingRole::setup() || role->genericRole() == TimingRole::hold()) { - Vertex *tgt_vertex = edge->from(graph_); - const RiseFall *tgt_rf1 = edge->timingArcSet()->isRisingFallingEdge(); - const RiseFallBoth *tgt_rf = tgt_rf1 - ? tgt_rf1->asRiseFallBoth() - : RiseFallBoth::riseFall(); - findClkSkew(src_vertex, src_rf, tgt_vertex, tgt_rf, skews); + Vertex *tgt_vertex = edge->from(graph_); + const RiseFall *tgt_rf1 = edge->timingArcSet()->isRisingFallingEdge(); + const RiseFallBoth *tgt_rf = + tgt_rf1 ? tgt_rf1->asRiseFallBoth() : RiseFallBoth::riseFall(); + findClkSkew(src_vertex, src_rf, tgt_vertex, tgt_rf, skews); } } } @@ -299,13 +316,13 @@ ClkSkews::findClkSkew(Vertex *src_vertex, && src_rf->matches(src_path->transition(this)) && clk_set_.contains(src_clk) && scenes_set_.contains(src_scene)) { - const MinMax *tgt_min_max = src_path->minMax(this)->opposite(); + const MinMax *src_min_max = src_path->minMax(this); + const MinMax *tgt_min_max = src_min_max->opposite(); VertexPathIterator tgt_iter(tgt_vertex, this); while (tgt_iter.hasNext()) { Path *tgt_path = tgt_iter.next(); const Clock *tgt_clk = tgt_path->clock(this); - if (tgt_clk == src_clk - && tgt_path->isClock(this) + if (tgt_clk == src_clk && tgt_path->isClock(this) && tgt_rf->matches(tgt_path->transition(this)) && tgt_path->minMax(this) == tgt_min_max && tgt_path->scene(this) == src_scene) { @@ -313,17 +330,17 @@ ClkSkews::findClkSkew(Vertex *src_vertex, const SetupHold *setup_hold = src_path->minMax(this); ClkSkew &clk_skew = skews[src_clk][setup_hold->index()]; debugPrint(debug_, "clk_skew", 2, - "%s %s %s -> %s %s %s crpr = %s skew = %s", + "{} {} {} -> {} {} {} crpr = {} skew = {}", network_->pathName(src_path->pin(this)), src_path->transition(this)->shortName(), - time_unit->asString(probe.srcLatency(this)), + delayAsString(probe.srcLatency(this), src_min_max, this), network_->pathName(tgt_path->pin(this)), tgt_path->transition(this)->shortName(), time_unit->asString(probe.tgtLatency(this)), delayAsString(probe.crpr(this), this), - time_unit->asString(probe.skew())); + delayAsString(probe.skew(), MinMax::max(), this)); if (clk_skew.srcPath() == nullptr - || std::abs(probe.skew()) > std::abs(clk_skew.skew())) + || delayAbsGreater(probe.skew(), clk_skew.skew(), this)) clk_skew = probe; } } @@ -335,14 +352,14 @@ VertexSet ClkSkews::findFanout(Vertex *from) { VertexSet endpoints = makeVertexSet(this); - std::unordered_set visited; + std::unordered_set visited; findFanout1(from, visited, endpoints); return endpoints; } void ClkSkews::findFanout1(Vertex *from, - std::unordered_set &visited, + std::unordered_set &visited, VertexSet &endpoints) { visited.insert(from); @@ -380,10 +397,8 @@ ClkSkew::ClkSkew(Path *src_path, tgt_path_(tgt_path), include_internal_latency_(include_internal_latency) { - skew_ = srcLatency(sta) - - tgtLatency(sta) - - delayAsFloat(crpr(sta)) - + uncertainty(sta); + skew_ = delayDiff(delaySum(srcLatency(sta), uncertainty(sta), sta), + delaySum(tgtLatency(sta), crpr(sta), sta), sta); } ClkSkew::ClkSkew(const ClkSkew &clk_skew) @@ -403,12 +418,11 @@ ClkSkew::operator=(const ClkSkew &clk_skew) skew_ = clk_skew.skew_; } -float +Arrival ClkSkew::srcLatency(const StaState *sta) { - Arrival src_arrival = src_path_->arrival(); - return delayAsFloat(src_arrival) - src_path_->clkEdge(sta)->time() - + clkTreeDelay(src_path_, sta); + return delayDiff(delaySum(src_path_->arrival(), clkTreeDelay(src_path_, sta), sta), + src_path_->clkEdge(sta)->time(), sta); } float @@ -421,8 +435,9 @@ float ClkSkew::tgtLatency(const StaState *sta) { Arrival tgt_arrival = tgt_path_->arrival(); - return delayAsFloat(tgt_arrival) - tgt_path_->clkEdge(sta)->time() - + clkTreeDelay(tgt_path_, sta); + return delayAsFloat(delaySum(delayDiff(tgt_arrival, + tgt_path_->clkEdge(sta)->time(),sta), + clkTreeDelay(tgt_path_, sta), sta)); } float @@ -441,7 +456,7 @@ ClkSkew::clkTreeDelay(Path *clk_path, const LibertyPort *port = sta->network()->libertyPort(pin); const MinMax *min_max = clk_path->minMax(sta); const RiseFall *rf = clk_path->transition(sta); - float slew = delayAsFloat(clk_path->slew(sta)); + float slew = delayAsFloat(clk_path->slew(sta), min_max, sta); return port->clkTreeDelay(slew, rf, min_max); } else @@ -459,8 +474,8 @@ float ClkSkew::uncertainty(const StaState *sta) { const TimingRole *check_role = (src_path_->minMax(sta) == SetupHold::max()) - ? TimingRole::setup() - : TimingRole::hold(); + ? TimingRole::setup() + : TimingRole::hold(); // Uncertainty decreases slack, but increases skew. return -PathEnd::checkTgtClkUncertainty(tgt_path_, tgt_path_->clkEdge(sta), check_role, sta); @@ -477,8 +492,7 @@ ClkSkew::srcTgtPathNameLess(ClkSkew &clk_skew1, const char *tgt_path1 = network->pathName(clk_skew1.tgtPath()->pin(sta)); const char *tgt_path2 = network->pathName(clk_skew2.tgtPath()->pin(sta)); return stringLess(src_path1, src_path2) - || (stringEqual(src_path1, src_path2) - && stringEqual(tgt_path1, tgt_path2)); + || (stringEqual(src_path1, src_path2) && stringEqual(tgt_path1, tgt_path2)); } //////////////////////////////////////////////////////////////// @@ -494,10 +508,9 @@ FanOutSrchPred::searchThru(Edge *edge, { const TimingRole *role = edge->role(); return SearchPred1::searchThru(edge, mode) - && (role == TimingRole::wire() - || role == TimingRole::combinational() - || role == TimingRole::tristateEnable() - || role == TimingRole::tristateDisable()); + && (role == TimingRole::wire() || role == TimingRole::combinational() + || role == TimingRole::tristateEnable() + || role == TimingRole::tristateDisable()); } -} // namespace +} // namespace sta diff --git a/search/ClkSkew.hh b/search/ClkSkew.hh index 349589e3..1ce1cf43 100644 --- a/search/ClkSkew.hh +++ b/search/ClkSkew.hh @@ -52,13 +52,13 @@ public: void operator=(const ClkSkew &clk_skew); Path *srcPath() { return src_path_; } Path *tgtPath() { return tgt_path_; } - float srcLatency(const StaState *sta); + Arrival srcLatency(const StaState *sta); float tgtLatency(const StaState *sta); float srcInternalClkLatency(const StaState *sta); float tgtInternalClkLatency(const StaState *sta); Crpr crpr(const StaState *sta); float uncertainty(const StaState *sta); - float skew() const { return skew_; } + Delay skew() const { return skew_; } static bool srcTgtPathNameLess(ClkSkew &clk_skew1, ClkSkew &clk_skew2, const StaState *sta); @@ -70,7 +70,7 @@ private: Path *src_path_; Path *tgt_path_; bool include_internal_latency_; - float skew_; + Delay skew_; }; using ClkSkewMap = std::map; @@ -97,7 +97,7 @@ public: bool include_internal_latency, int digits); // Find worst clock skew between src/target registers. - float findWorstClkSkew(const SceneSeq &scenes, + Delay findWorstClkSkew(const SceneSeq &scenes, const SetupHold *setup_hold, bool include_internal_latency); diff --git a/search/Crpr.cc b/search/Crpr.cc index 4d1bc3a0..3d1295bb 100644 --- a/search/Crpr.cc +++ b/search/Crpr.cc @@ -236,7 +236,7 @@ CheckCrpr::findCrpr(const Path *src_clk_path, && tgt_clk_path2 && !tgt_clk_path2->isNull() && (src_clk_path2->transition(this) == tgt_clk_path2->transition(this) || same_pin)) { - debugPrint(debug_, "crpr", 2, "crpr pin %s", + debugPrint(debug_, "crpr", 2, "crpr pin {}", network_->pathName(src_clk_path2->pin(this))); crpr = findCrpr1(src_clk_path2, tgt_clk_path2); crpr_pin = src_clk_path2->pin(this); @@ -273,31 +273,28 @@ CheckCrpr::findCrpr1(const Path *src_clk_path, if (variables_->pocvEnabled()) { // Remove variation on the common path. // Note that the crpr sigma is negative to offset the - // sigma of the common clock path. - const EarlyLate *src_el = src_clk_path->minMax(this); - const EarlyLate *tgt_el = tgt_clk_path->minMax(this); - Arrival src_arrival = src_clk_path->arrival(); - Arrival tgt_arrival = tgt_clk_path->arrival(); + // std_dev of the common clock path. + const Arrival &src_arrival = src_clk_path->arrival(); + const Arrival &tgt_arrival = tgt_clk_path->arrival(); float src_clk_time = src_clk_path->clkEdge(this)->time(); float tgt_clk_time = tgt_clk_path->clkEdge(this)->time(); - float crpr_mean = std::abs(delayAsFloat(src_arrival) - src_clk_time - - (delayAsFloat(tgt_arrival) - tgt_clk_time)); + float crpr_mean = std::abs(src_arrival.mean() - src_clk_time + - (tgt_arrival.mean() - tgt_clk_time)); // Remove the sigma from both source and target path arrivals. - float crpr_sigma2 = delaySigma2(src_arrival, src_el) - + delaySigma2(tgt_arrival, tgt_el); - return makeDelay2(crpr_mean, -crpr_sigma2, -crpr_sigma2); + float crpr_sigma2 = src_arrival.stdDev2() + tgt_arrival.stdDev2(); + return makeDelay2(crpr_mean, -crpr_sigma2); } else { // The source and target edges are different so the crpr // is the min of the source and target max-min delay. float src_delta = crprArrivalDiff(src_clk_path); float tgt_delta = crprArrivalDiff(tgt_clk_path); - debugPrint(debug_, "crpr", 2, " src delta %s", + debugPrint(debug_, "crpr", 2, " src delta {}", delayAsString(src_delta, this)); - debugPrint(debug_, "crpr", 2, " tgt delta %s", + debugPrint(debug_, "crpr", 2, " tgt delta {}", delayAsString(tgt_delta, this)); float common_delay = std::min(src_delta, tgt_delta); - debugPrint(debug_, "crpr", 2, " %s delta %s", + debugPrint(debug_, "crpr", 2, " {} delta {}", network_->pathName(src_clk_path->pin(this)), delayAsString(common_delay, this)); return common_delay; @@ -308,8 +305,9 @@ float CheckCrpr::crprArrivalDiff(const Path *path) { Arrival other_arrival = otherMinMaxArrival(path); - float crpr_diff = std::abs(delayAsFloat(path->arrival()) - - delayAsFloat(other_arrival)); + const MinMax *min_max = path->minMax(this); + float crpr_diff = std::abs(delayAsFloat(path->arrival(), min_max, this) + - delayAsFloat(other_arrival, min_max->opposite(), this)); return crpr_diff; } diff --git a/search/Genclks.cc b/search/Genclks.cc index ca81bb0a..3dee07b9 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "Genclks.hh" @@ -85,10 +85,7 @@ GenclkInfo::GenclkInfo(Clock *gclk, { } -GenclkInfo::~GenclkInfo() -{ - delete src_filter_; -} +GenclkInfo::~GenclkInfo() { delete src_filter_; } void GenclkInfo::setFoundLatchFdbkEdges(bool found) @@ -202,7 +199,7 @@ Genclks::ensureInsertionDelays() // Generated clocks derived from a generated clock inherit its // insertion delay, so sort the clocks by source pin level. - sort(gclks , ClockPinMaxLevelLess(this)); + sort(gclks, ClockPinMaxLevelLess(this)); for (Clock *gclk : gclks) { if (gclk->masterClk()) { @@ -232,8 +229,7 @@ GenClkMasterSearchPred::GenClkMasterSearchPred(const StaState *sta) : bool GenClkMasterSearchPred::searchThruAllow(const TimingRole *role) const { - return (role->isWire() - || role == TimingRole::combinational() + return (role->isWire() || role == TimingRole::combinational() || role->regClkToQ()); } @@ -245,7 +241,7 @@ Genclks::checkMaster(Clock *gclk, { ensureMaster(gclk, sdc); if (gclk->masterClk() == nullptr) - report_->warn(1060, "no master clock found for generated clock %s.", + report_->warn(1060, "no master clock found for generated clock {}.", gclk->name()); } @@ -266,8 +262,7 @@ Genclks::ensureMaster(Clock *gclk, // Master source pin can actually be a clock source pin. if (master_clk != gclk) { gclk->setInferedMasterClk(master_clk); - debugPrint(debug_, "genclk", 2, " %s master clk %s", - gclk->name(), + debugPrint(debug_, "genclk", 2, " {} master clk {}", gclk->name(), master_clk->name()); found_master = true; master_clk_count++; @@ -291,8 +286,7 @@ Genclks::ensureMaster(Clock *gclk, // Master source pin can actually be a clock source pin. if (master_clk != gclk) { gclk->setInferedMasterClk(master_clk); - debugPrint(debug_, "genclk", 2, " %s master clk %s", - gclk->name(), + debugPrint(debug_, "genclk", 2, " {} master clk {}", gclk->name(), master_clk->name()); master_clk_count++; break; @@ -305,9 +299,8 @@ Genclks::ensureMaster(Clock *gclk, } if (master_clk_count > 1) report_->warn(1061, - "generated clock %s pin %s is in the fanout of multiple clocks.", - gclk->name(), - network_->pathName(src_pin)); + "generated clock {} pin {} is in the fanout of multiple clocks.", + gclk->name(), network_->pathName(src_pin)); } } @@ -346,8 +339,7 @@ GenClkFaninSrchPred::GenClkFaninSrchPred(Clock *gclk, bool GenClkFaninSrchPred::searchThruAllow(const TimingRole *role) const { - return (role == TimingRole::combinational() - || role == TimingRole::wire() + return (role == TimingRole::combinational() || role == TimingRole::wire() || !combinational_); } @@ -363,8 +355,8 @@ Genclks::findFanin(Clock *gclk, Vertex *vertex = iter.next(); if (!fanins.contains(vertex)) { fanins.insert(vertex); - debugPrint(debug_, "genclk", 2, "gen clk %s fanin %s", - gclk->name(), vertex->to_string(this).c_str()); + debugPrint(debug_, "genclk", 2, "gen clk {} fanin {}", gclk->name(), + vertex->to_string(this)); iter.enqueueAdjacentVertices(vertex, mode_); } } @@ -398,7 +390,7 @@ public: bool searchThru(Edge *edge, const Mode *mode) const override; bool searchTo(const Vertex *to_vertex, - const Mode *mode) const override; + const Mode *mode) const override; private: bool isNonGeneratedClkPin(const Pin *pin, @@ -423,12 +415,11 @@ GenClkInsertionSearchPred::searchThru(Edge *edge, { const TimingRole *role = edge->role(); EdgeSet &fdbk_edges = genclk_info_->fdbkEdges(); - return SearchPred0::searchThru(edge, mode) - && !role->isTimingCheck() - && (sta_->variables()->clkThruTristateEnabled() - || !(role == TimingRole::tristateEnable() - || role == TimingRole::tristateDisable())) - && !fdbk_edges.contains(edge); + return SearchPred0::searchThru(edge, mode) && !role->isTimingCheck() + && (sta_->variables()->clkThruTristateEnabled() + || !(role == TimingRole::tristateEnable() + || role == TimingRole::tristateDisable())) + && !fdbk_edges.contains(edge); } bool @@ -437,11 +428,11 @@ GenClkInsertionSearchPred::searchTo(const Vertex *to_vertex, { Pin *to_pin = to_vertex->pin(); return SearchPred0::searchTo(to_vertex, mode) - // Propagate through other generated clock roots but not regular - // clock roots. - && !(!gclk_->leafPins().contains(to_pin) - && isNonGeneratedClkPin(to_pin, mode->sdc())) - && genclk_info_->fanins().contains(const_cast(to_vertex)); + // Propagate through other generated clock roots but not regular + // clock roots. + && !(!gclk_->leafPins().contains(to_pin) + && isNonGeneratedClkPin(to_pin, mode->sdc())) + && genclk_info_->fanins().contains(const_cast(to_vertex)); } bool @@ -463,8 +454,7 @@ GenClkInsertionSearchPred::isNonGeneratedClkPin(const Pin *pin, void Genclks::findInsertionDelays(Clock *gclk) { - debugPrint(debug_, "genclk", 2, "find gen clk %s insertion", - gclk->name()); + debugPrint(debug_, "genclk", 2, "find gen clk {} insertion", gclk->name()); GenclkInfo *genclk_info = makeGenclkInfo(gclk); FilterPath *src_filter = genclk_info->srcFilter(); GenClkInsertionSearchPred srch_pred(gclk, genclk_info, this); @@ -492,7 +482,7 @@ Genclks::makeGenclkInfo(Clock *gclk) GenclkInfo * Genclks::genclkInfo(const Clock *gclk) const { - return findKey(genclk_info_map_, const_cast(gclk)); + return findKey(genclk_info_map_, const_cast(gclk)); } FilterPath * @@ -516,8 +506,7 @@ void Genclks::findLatchFdbkEdges(const Clock *clk) { GenclkInfo *genclk_info = genclkInfo(clk); - if (genclk_info - && !genclk_info->foundLatchFdbkEdges()) + if (genclk_info && !genclk_info->foundLatchFdbkEdges()) findLatchFdbkEdges(clk, genclk_info); } @@ -563,15 +552,15 @@ Genclks::findLatchFdbkEdges(Vertex *from_vertex, Edge *edge = edge_iter.next(); Vertex *to_vertex = edge->to(graph_); if (path_vertices.contains(to_vertex)) { - debugPrint(debug_, "genclk", 2, " found feedback edge %s", - edge->to_string(this).c_str()); + debugPrint(debug_, "genclk", 2, " found feedback edge {}", + edge->to_string(this)); fdbk_edges.insert(edge); } else if (srch_pred.searchThru(edge, mode_) && srch_pred.searchTo(to_vertex, mode_) && to_vertex->level() <= gclk_level) - findLatchFdbkEdges(to_vertex, gclk_level, srch_pred, - path_vertices, visited_vertices, fdbk_edges); + findLatchFdbkEdges(to_vertex, gclk_level, srch_pred, path_vertices, + visited_vertices, fdbk_edges); } path_vertices.erase(from_vertex); } @@ -584,11 +573,11 @@ Genclks::makeSrcFilter(Clock *gclk, ClockSet *from_clks = new ClockSet; from_clks->insert(gclk->masterClk()); const RiseFallBoth *rf = RiseFallBoth::riseFall(); - ExceptionFrom *from = sdc->makeExceptionFrom(nullptr,from_clks,nullptr,rf); + ExceptionFrom *from = sdc->makeExceptionFrom(nullptr, from_clks, nullptr, rf); PinSet *thru_pins = new PinSet(network_); thru_pins->insert(gclk->srcPin()); - ExceptionThru *thru = sdc->makeExceptionThru(thru_pins,nullptr,nullptr,rf); + ExceptionThru *thru = sdc->makeExceptionThru(thru_pins, nullptr, nullptr, rf); ExceptionThruSeq *thrus = new ExceptionThruSeq; thrus->push_back(thru); @@ -608,7 +597,7 @@ Genclks::seedSrcPins(Clock *gclk, for (const Pin *master_pin : master_clk->leafPins()) { Vertex *vertex = graph_->pinDrvrVertex(master_pin); if (vertex) { - debugPrint(debug_, "genclk", 2, " seed src pin %s", + debugPrint(debug_, "genclk", 2, " seed src pin {}", network_->pathName(master_pin)); TagGroupBldr tag_bldr(true, this); tag_bldr.init(vertex); @@ -619,8 +608,8 @@ Genclks::seedSrcPins(Clock *gclk, for (const RiseFall *rf : RiseFall::range()) { Arrival insert = search_->clockInsertion(master_clk, master_pin, rf, min_max, early_late, mode_); - Tag *tag = makeTag(gclk, master_clk, master_pin, rf, - src_filter, insert, scene, min_max); + Tag *tag = makeTag(gclk, master_clk, master_pin, rf, src_filter, insert, + scene, min_max); tag_bldr.setArrival(tag, insert); } } @@ -648,13 +637,11 @@ Genclks::makeTag(const Clock *gclk, state = state->nextState(); ExceptionStateSet *states = new ExceptionStateSet(); states->insert(state); - const ClkInfo *clk_info = search_->findClkInfo(scene, - master_clk->edge(master_rf), - master_pin, true, nullptr, true, - nullptr, insert, 0.0, nullptr, - min_max, nullptr); - return search_->findTag(scene, master_rf, min_max, clk_info, - false, nullptr, false, states, true, nullptr); + const ClkInfo *clk_info = search_->findClkInfo( + scene, master_clk->edge(master_rf), master_pin, true, nullptr, true, nullptr, + insert, 0.0, nullptr, min_max, nullptr); + return search_->findTag(scene, master_rf, min_max, clk_info, false, nullptr, false, + states, true, nullptr); } class GenClkArrivalSearchPred : public EvalPred @@ -684,12 +671,10 @@ GenClkArrivalSearchPred::searchThru(Edge *edge, { const TimingRole *role = edge->role(); return EvalPred::searchThru(edge, mode) - && (role == TimingRole::combinational() - || role->isWire() - || !combinational_) - && (sta_->variables()->clkThruTristateEnabled() - || !(role == TimingRole::tristateEnable() - || role == TimingRole::tristateDisable())); + && (role == TimingRole::combinational() || role->isWire() || !combinational_) + && (sta_->variables()->clkThruTristateEnabled() + || !(role == TimingRole::tristateEnable() + || role == TimingRole::tristateDisable())); } // Override EvalPred::searchTo to search to generated clock pin. @@ -730,12 +715,14 @@ protected: GenclkSrcArrivalVisitor::GenclkSrcArrivalVisitor(Clock *gclk, BfsFwdIterator *insert_iter, GenclkInfo *genclk_info, - const Mode *mode): + const Mode *mode) : ArrivalVisitor(mode), gclk_(gclk), insert_iter_(insert_iter), genclk_info_(genclk_info), - srch_pred_(gclk_, genclk_info, mode), + srch_pred_(gclk_, + genclk_info, + mode), mode_(mode), sdc_(mode->sdc()), genclks_(mode->genclks()) @@ -749,11 +736,15 @@ GenclkSrcArrivalVisitor::GenclkSrcArrivalVisitor(Clock *gclk, bool always_to_endpoints, SearchPred *pred, const Mode *mode) : - ArrivalVisitor(always_to_endpoints, pred, mode), + ArrivalVisitor(always_to_endpoints, + pred, + mode), gclk_(gclk), insert_iter_(insert_iter), genclk_info_(genclk_info), - srch_pred_(gclk, genclk_info, mode), + srch_pred_(gclk, + genclk_info, + mode), mode_(mode), sdc_(mode->sdc()), genclks_(mode->genclks()) @@ -770,8 +761,8 @@ GenclkSrcArrivalVisitor::copy() const void GenclkSrcArrivalVisitor::visit(Vertex *vertex) { - debugPrint(debug_, "genclk", 2, "find gen clk insert arrival %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "genclk", 2, "find gen clk insert arrival {}", + vertex->to_string(this)); tag_bldr_->init(vertex); has_fanin_one_ = graph_->hasFaninOne(vertex); genclks_->copyGenClkSrcPaths(vertex, tag_bldr_); @@ -787,8 +778,7 @@ Genclks::findSrcArrivals(Clock *gclk, GenclkInfo *genclk_info) { GenClkArrivalSearchPred eval_pred(gclk, this); - GenclkSrcArrivalVisitor arrival_visitor(gclk, &insert_iter, - genclk_info, mode_); + GenclkSrcArrivalVisitor arrival_visitor(gclk, &insert_iter, genclk_info, mode_); arrival_visitor.init(true, false, &eval_pred); // This cannot restrict the search level because loops in the clock tree // can circle back to the generated clock src pin. @@ -803,7 +793,7 @@ Genclks::copyGenClkSrcPaths(Vertex *vertex, { auto itr = vertex_src_paths_map_.find(vertex); if (itr != vertex_src_paths_map_.end()) { - const std::vector &src_paths = itr->second; + const std::vector &src_paths = itr->second; for (const Path *path : src_paths) { Path src_path = *path; Path *prev_path = src_path.prevPath(); @@ -811,11 +801,11 @@ Genclks::copyGenClkSrcPaths(Vertex *vertex, Path *prev_vpath = Path::vertexPath(prev_path, this); src_path.setPrevPath(prev_vpath); } - debugPrint(debug_, "genclk", 3, "vertex %s insert genclk %s src path %s %ss", - src_path.vertex(this)->to_string(this).c_str(), + debugPrint(debug_, "genclk", 3, "vertex {} insert genclk {} src path {} {}s", + src_path.vertex(this)->to_string(this), src_path.tag(this)->genClkSrcPathClk()->name(), - src_path.tag(this)->minMax()->to_string().c_str(), - src_path.tag(this)->to_string(true, false, this).c_str()); + src_path.tag(this)->minMax()->to_string(), + src_path.tag(this)->to_string(true, false, this)); tag_bldr->insertPath(src_path); } } @@ -858,28 +848,21 @@ Genclks::recordSrcPaths(Clock *gclk) while (path_iter.hasNext()) { Path *path = path_iter.next(); const ClockEdge *src_clk_edge = path->clkEdge(this); - if (src_clk_edge - && matchesSrcFilter(path, gclk)) { + if (src_clk_edge && matchesSrcFilter(path, gclk)) { const EarlyLate *early_late = path->minMax(this); const RiseFall *src_clk_rf = src_clk_edge->transition(); const RiseFall *rf = path->transition(this); bool inverting_path = (rf != src_clk_rf); size_t path_index = srcPathIndex(rf, path->minMax(this)); Path &src_path = src_paths[path_index]; - if ((!divide_by_1 - || (inverting_path == invert)) - && (!has_edges - || src_clk_rf == gclk->masterClkEdgeTr(rf)) + if ((!divide_by_1 || (inverting_path == invert)) + && (!has_edges || src_clk_rf == gclk->masterClkEdgeTr(rf)) && (src_path.isNull() - || delayGreater(path->arrival(), - src_path.arrival(), - early_late, + || delayGreater(path->arrival(), src_path.arrival(), early_late, this))) { - debugPrint(debug_, "genclk", 2, " %s insertion %s %s %s", - network_->pathName(gclk_pin), - early_late->to_string().c_str(), - rf->shortName(), - delayAsString(path->arrival(), this)); + debugPrint(debug_, "genclk", 2, " {} insertion {} {} {}", + network_->pathName(gclk_pin), early_late->to_string(), + rf->shortName(), delayAsString(path->arrival(), this)); src_path = *path; } } @@ -905,19 +888,17 @@ Genclks::recordSrcPaths(Clock *gclk) } } // Don't warn if the master clock is ideal. - if (!found_src_paths - && gclk->masterClk() - && gclk->masterClk()->isPropagated()) - report_->warn(1062, "generated clock %s source pin %s missing paths from master clock %s.", - gclk->name(), - network_->pathName(gclk_pin), - gclk->masterClk()->name()); + if (!found_src_paths && gclk->masterClk() && gclk->masterClk()->isPropagated()) + report_->warn( + 1062, + "generated clock {} source pin {} missing paths from master clock {}.", + gclk->name(), network_->pathName(gclk_pin), gclk->masterClk()->name()); } deleteGenclkSrcPaths(gclk); } void -Genclks:: deleteGenclkSrcPaths(Clock *gclk) +Genclks::deleteGenclkSrcPaths(Clock *gclk) { GenclkInfo *genclk_info = genclkInfo(gclk); GenClkInsertionSearchPred srch_pred(gclk, genclk_info, mode_); @@ -938,13 +919,10 @@ Genclks::matchesSrcFilter(Path *path, { Tag *tag = path->tag(this); const ExceptionStateSet *states = tag->states(); - if (tag->isGenClkSrcPath() - && states) { + if (tag->isGenClkSrcPath() && states) { for (ExceptionState *state : *states) { ExceptionPath *except = state->exception(); - if (except->isFilter() - && state->nextThru() == nullptr - && except->to() + if (except->isFilter() && state->nextThru() == nullptr && except->to() && except->to()->matches(gclk)) return true; } @@ -958,8 +936,7 @@ Genclks::srcPath(const Path *clk_path) const const Pin *src_pin = clk_path->pin(this); const ClockEdge *clk_edge = clk_path->clkEdge(this); const EarlyLate *early_late = clk_path->minMax(this); - return srcPath(clk_edge->clock(), src_pin, - clk_edge->transition(), early_late); + return srcPath(clk_edge->clock(), src_pin, clk_edge->transition(), early_late); } const Path * @@ -967,8 +944,7 @@ Genclks::srcPath(const ClockEdge *clk_edge, const Pin *src_pin, const MinMax *min_max) const { - return srcPath(clk_edge->clock(), src_pin, - clk_edge->transition(), min_max); + return srcPath(clk_edge->clock(), src_pin, clk_edge->transition(), min_max); } const Path * @@ -1016,9 +992,7 @@ ClockPinPairLess::operator()(const ClockPinPair &pair1, int clk_index2 = clk2->index(); const Pin *pin1 = pair1.second; const Pin *pin2 = pair2.second; - return (clk_index1 < clk_index2 - || (clk_index1 == clk_index2 - && pin1 < pin2)); + return (clk_index1 < clk_index2 || (clk_index1 == clk_index2 && pin1 < pin2)); } class ClockPinPairHash @@ -1054,8 +1028,7 @@ ClockPinPairEqual::operator()(const ClockPinPair &pair1, const ClockPinPair &pair2) const { - return pair1.first == pair2.first - && pair1.second == pair2.second; + return pair1.first == pair2.first && pair1.second == pair2.second; } -} // namespace +} // namespace sta diff --git a/search/Latches.cc b/search/Latches.cc index 8389c9c1..c701e7fd 100644 --- a/search/Latches.cc +++ b/search/Latches.cc @@ -70,13 +70,13 @@ Latches::latchRequired(const Path *data_path, ignore_clk_latency = path_delay->ignoreClkLatency(); } if (ignore_clk_latency) { - required = max_delay + src_clk_latency; + required = delaySum(src_clk_latency, max_delay, this); borrow = 0.0; adjusted_data_arrival = data_arrival; time_given_to_startpoint = 0.0; } else if (enable_path && disable_path) { - debugPrint(debug_, "latch", 1, "latch %s", + debugPrint(debug_, "latch", 1, "latch {}", sdc_network_->pathName(data_path->pin(this))); Delay open_latency, latency_diff, max_borrow; float nom_pulse_width, open_uncertainty; @@ -98,14 +98,16 @@ Latches::latchRequired(const Path *data_path, // checkTgtClkTime float tgt_clk_time = path_delay ? 0.0 : acct->requiredTime(check_role); // checkTgtClkArrival broken down into components. - Arrival enable_arrival = max_delay - + tgt_clk_time - + open_latency - + open_uncertainty - + PathEnd::checkSetupMcpAdjustment(data_clk_edge, enable_clk_edge, mcp, - 1, sdc) - + open_crpr; - debugPrint(debug_, "latch", 1, "data %s enable %s", + Arrival enable_arrival = delaySum(max_delay + + tgt_clk_time + + open_uncertainty + + PathEnd::checkSetupMcpAdjustment(data_clk_edge, + enable_clk_edge, + mcp, 1, sdc), + open_latency, + this); + enable_arrival = delaySum(enable_arrival, open_crpr, this); + debugPrint(debug_, "latch", 1, "data {} enable {}", delayAsString(data_arrival, this), delayAsString(enable_arrival, this)); if (delayLessEqual(data_arrival, enable_arrival, this)) { @@ -117,25 +119,31 @@ Latches::latchRequired(const Path *data_path, } else { // Data arrives while latch is transparent. - borrow = data_arrival - enable_arrival; + borrow = delayDiff(data_arrival, enable_arrival, this); if (delayLessEqual(borrow, max_borrow, this)) required = data_arrival; else { borrow = max_borrow; - required = enable_arrival + max_borrow; + required = delaySum(enable_arrival, max_borrow, this); } - time_given_to_startpoint = borrow + open_uncertainty + open_crpr; + time_given_to_startpoint = delaySum(delaySum(borrow, + open_uncertainty, + this), + open_crpr, this); // Cycle accounting for required time is with respect to the // data clock zeroth cycle. The data departs the latch // with respect to the enable clock zeroth cycle. float data_shift_to_enable_clk = acct->sourceTimeOffset(check_role) - acct->targetTimeOffset(check_role); - adjusted_data_arrival = required + data_shift_to_enable_clk; + adjusted_data_arrival = delaySum(required, data_shift_to_enable_clk, this); } } else if (disable_path) { - required = max_delay + search_->clkPathArrival(disable_path) - margin; + required = delayDiff(delaySum(max_delay, + search_->clkPathArrival(disable_path), + this), + margin, this); // Borrow cannot be determined without enable path. borrow = 0.0; adjusted_data_arrival = data_arrival; @@ -147,7 +155,7 @@ Latches::latchRequired(const Path *data_path, adjusted_data_arrival = data_arrival; time_given_to_startpoint = 0.0; } - debugPrint(debug_, "latch", 2, "req %s borrow %s time_given %s adj_arrival %s", + debugPrint(debug_, "latch", 2, "req {} borrow {} time_given {} adj_arrival {}", delayAsString(required, this), delayAsString(borrow, this), delayAsString(time_given_to_startpoint, this), @@ -176,7 +184,7 @@ Latches::latchBorrowInfo(const Path *data_path, const ClockEdge *enable_clk_edge = enable_path->clkEdge(this); const ClockEdge *disable_clk_edge = disable_path->clkEdge(this); bool is_pulse_clk = enable_path->clkInfo(this)->isPulseClk(); - nom_pulse_width = is_pulse_clk ? 0.0F : enable_clk_edge->pulseWidth(); + nom_pulse_width = is_pulse_clk ? 0.0 : enable_clk_edge->pulseWidth(); open_uncertainty = PathEnd::checkClkUncertainty(data_clk_edge, enable_clk_edge, enable_path, TimingRole::latchSetup(), sdc); @@ -190,14 +198,14 @@ Latches::latchBorrowInfo(const Path *data_path, CheckCrpr *check_crpr = search_->checkCrpr(); open_crpr = check_crpr->checkCrpr(data_path, enable_path); Crpr close_crpr = check_crpr->checkCrpr(data_path, disable_path); - crpr_diff = open_crpr - close_crpr; + crpr_diff = delayDiff(open_crpr, close_crpr, this); open_latency = PathEnd::checkTgtClkDelay(enable_path, enable_clk_edge, TimingRole::setup(), this); Arrival close_latency = PathEnd::checkTgtClkDelay(disable_path, disable_clk_edge, TimingRole::latchSetup(), this); - latency_diff = open_latency - close_latency; + latency_diff = delayDiff(open_latency, close_latency, this); } float borrow_limit; sdc->latchBorrowLimit(data_path->pin(this), disable_path->pin(this), @@ -206,8 +214,9 @@ Latches::latchBorrowInfo(const Path *data_path, if (borrow_limit_exists) max_borrow = borrow_limit; else - max_borrow = nom_pulse_width - delayAsFloat(latency_diff) - - delayAsFloat(crpr_diff) - delayAsFloat(margin); + max_borrow = delayDiff(nom_pulse_width, + delaySum(delaySum(latency_diff, crpr_diff, this), + margin, this), this); } else { nom_pulse_width = 0.0; @@ -217,12 +226,12 @@ Latches::latchBorrowInfo(const Path *data_path, open_crpr = 0.0; crpr_diff = 0.0; } - debugPrint(debug_, "latch", 2, "nom_width %s open_lat %s lat_diff %s open_uncert %s", + debugPrint(debug_, "latch", 2, "nom_width {} open_lat {} lat_diff {} open_uncert {}", delayAsString(nom_pulse_width, this), delayAsString(open_latency, this), delayAsString(latency_diff, this), delayAsString(open_uncertainty, this)); - debugPrint(debug_, "latch", 2, "open_crpr %s crpr_diff %s open_uncert %s max_borrow %s", + debugPrint(debug_, "latch", 2, "open_crpr {} crpr_diff {} open_uncert {} max_borrow {}", delayAsString(open_crpr, this), delayAsString(crpr_diff, this), delayAsString(open_uncertainty, this), @@ -349,7 +358,7 @@ Latches::latchOutArrival(const Path *data_path, if (!(excpt && excpt->isFalse())) { arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge, false, min_max, dcalc_ap, sdc); - q_arrival = data_path->arrival() + arc_delay; + q_arrival = delaySum(data_path->arrival(), arc_delay, this); // Copy the data tag but remove the drprClkPath. // Levelization does not traverse latch D->Q edges, so in some cases // level(Q) < level(D) @@ -405,7 +414,7 @@ Latches::latchOutArrival(const Path *data_path, // Latch is transparent when data arrives. arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge, false, min_max, dcalc_ap, sdc); - q_arrival = adjusted_data_arrival + arc_delay; + q_arrival = delaySum(adjusted_data_arrival, arc_delay, this); // Tag switcheroo - data passing thru gets latch enable tag. // States and path ap come from Q, everything else from enable. Path *crpr_clk_path = crprActive(mode) ? enable_path : nullptr; diff --git a/search/Levelize.cc b/search/Levelize.cc index ce5db3ab..7d588d5f 100644 --- a/search/Levelize.cc +++ b/search/Levelize.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "Levelize.hh" @@ -163,8 +163,7 @@ Levelize::findRoots() while (vertex_iter.hasNext()) { Vertex *vertex = vertex_iter.next(); if (isRoot(vertex)) { - debugPrint(debug_, "levelize", 2, "root %s%s", - vertex->to_string(this).c_str(), + debugPrint(debug_, "levelize", 2, "root {}{}", vertex->to_string(this), hasFanout(vertex) ? " fanout" : ""); roots_.insert(vertex); } @@ -175,9 +174,8 @@ Levelize::findRoots() if (hasFanout(root)) fanout_roots++; } - debugPrint(debug_, "levelize", 1, "Found %zu roots %zu with fanout", - roots_.size(), - fanout_roots); + debugPrint(debug_, "levelize", 1, "Found {} roots {} with fanout", + roots_.size(), fanout_roots); } } @@ -201,14 +199,11 @@ bool Levelize::searchThru(Edge *edge) { const TimingRole *role = edge->role(); - return !role->isTimingCheck() - && role != TimingRole::latchDtoQ() - && !edge->isDisabledLoop() - // Register/latch preset/clr edges are disabled by default. - && !(role == TimingRole::regSetClr() - && !variables_->presetClrArcsEnabled()) - && !(edge->isBidirectInstPath() - && !variables_->bidirectInstPathsEnabled()); + return !role->isTimingCheck() && role != TimingRole::latchDtoQ() + && !edge->isDisabledLoop() + // Register/latch preset/clr edges are disabled by default. + && !(role == TimingRole::regSetClr() && !variables_->presetClrArcsEnabled()) + && !(edge->isBidirectInstPath() && !variables_->bidirectInstPathsEnabled()); } bool @@ -272,7 +267,7 @@ Levelize::findBackEdges(EdgeSeq &path, EdgeSet back_edges; while (!stack.empty()) { VertexEdgeIterPair vertex_iter = stack.top(); - const auto& [vertex, edge_iter] = vertex_iter; + const auto &[vertex, edge_iter] = vertex_iter; if (edge_iter->hasNext()) { Edge *edge = edge_iter->next(); if (searchThru(edge)) { @@ -283,7 +278,7 @@ Levelize::findBackEdges(EdgeSeq &path, path.push_back(edge); stack.emplace(to_vertex, new VertexOutEdgeIterator(to_vertex, graph_)); } - else if (to_vertex->visited2()) { // on path + else if (to_vertex->visited2()) { // on path // Found a back edge (loop). recordLoop(edge, path); back_edges.insert(edge); @@ -328,7 +323,7 @@ Levelize::findCycleBackEdges() back_edge_count += back_edges.size(); } } - debugPrint(debug_, "levelize", 1, "Found %zu cycle back edges", back_edge_count); + debugPrint(debug_, "levelize", 1, "Found {} cycle back edges", back_edge_count); } // Find vertices in cycles that are were not accessible from roots. @@ -351,7 +346,7 @@ VertexSeq Levelize::findTopologicalOrder() { Stats stats(debug_, report_); - std::map in_degree; + std::map in_degree; VertexIterator vertex_iter(graph_); while (vertex_iter.hasNext()) { @@ -369,12 +364,13 @@ Levelize::findTopologicalOrder() const Pin *pin = vertex->pin(); if (graph_delay_calc_->bidirectDrvrSlewFromLoad(pin) && !vertex->isBidirectDriver()) { - Vertex *to_vertex = graph_->pinDrvrVertex(pin);; + Vertex *to_vertex = graph_->pinDrvrVertex(pin); + ; in_degree[to_vertex] += 1; } } - std::deque queue; + std::deque queue; for (Vertex *root : roots_) queue.push_back(root); @@ -413,14 +409,14 @@ Levelize::findTopologicalOrder() while (vertex_iter.hasNext()) { Vertex *vertex = vertex_iter.next(); if (in_degree[vertex] != 0) - debugPrint(debug_, "levelize", 2, "topological sort missing %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "levelize", 2, "topological sort missing {}", + vertex->to_string(this)); } } if (debug_->check("levelize", 3)) { - report_->reportLine("Topological sort"); + report_->report("Topological sort"); for (Vertex *vertex : topo_order) - report_->reportLine("%s", vertex->to_string(this).c_str()); + report_->report("{}", vertex->to_string(this)); } stats.report("Levelize topological sort"); return topo_order; @@ -430,9 +426,8 @@ void Levelize::recordLoop(Edge *edge, EdgeSeq &path) { - debugPrint(debug_, "levelize", 2, "Loop edge %s (%s)", - edge->to_string(this).c_str(), - edge->role()->to_string().c_str()); + debugPrint(debug_, "levelize", 2, "Loop edge {} ({})", + edge->to_string(this), edge->role()->to_string()); EdgeSeq *loop_edges = loopEdges(path, edge); GraphLoop *loop = new GraphLoop(loop_edges); loops_.push_back(loop); @@ -461,14 +456,12 @@ Levelize::loopEdges(EdgeSeq &path, if (from_pin == loop_pin) copy = true; if (copy) { - debugPrint(debug_, "loop", 2, " %s", - edge->to_string(this).c_str()); + debugPrint(debug_, "loop", 2, " {}", edge->to_string(this)); loop_edges->push_back(edge); loop_edges_.insert(edge); } } - debugPrint(debug_, "loop", 2, " %s", - closing_edge->to_string(this).c_str()); + debugPrint(debug_, "loop", 2, " {}", closing_edge->to_string(this)); loop_edges->push_back(closing_edge); loop_edges_.insert(closing_edge); return loop_edges; @@ -480,8 +473,8 @@ Levelize::reportPath(EdgeSeq &path) const bool first_edge = true; for (Edge *edge : path) { if (first_edge) - report_->reportLine(" %s", edge->from(graph_)->to_string(this).c_str()); - report_->reportLine(" %s", edge->to(graph_)->to_string(this).c_str()); + report_->report(" {}", edge->from(graph_)->to_string(this)); + report_->report(" {}", edge->to(graph_)->to_string(this)); first_edge = false; } } @@ -500,16 +493,16 @@ Levelize::assignLevels(VertexSeq &topo_sorted) Edge *edge = edge_iter.next(); Vertex *to_vertex = edge->to(graph_); if (searchThru(edge)) - setLevel(to_vertex, std::max(to_vertex->level(), - vertex->level() + level_space_)); + setLevel(to_vertex, + std::max(to_vertex->level(), vertex->level() + level_space_)); } // Levelize bidirect driver as if it was a fanout of the bidirect load. const Pin *pin = vertex->pin(); if (graph_delay_calc_->bidirectDrvrSlewFromLoad(pin) && !vertex->isBidirectDriver()) { Vertex *to_vertex = graph_->pinDrvrVertex(pin); - setLevel(to_vertex, std::max(to_vertex->level(), - vertex->level() + level_space_)); + setLevel(to_vertex, + std::max(to_vertex->level(), vertex->level() + level_space_)); } } } @@ -529,12 +522,9 @@ Levelize::ensureLatchLevels() Vertex *to = edge->to(graph_); if (from->level() == to->level()) { Level adjusted_level = from->level() + level_space_; - debugPrint(debug_, "levelize", 2, "latch %s %d (adjusted %d) -> %s %d", - from->to_string(this).c_str(), - from->level(), - adjusted_level, - to->to_string(this).c_str(), - to->level()); + debugPrint(debug_, "levelize", 2, "latch {} {} (adjusted {}) -> {} {}", + from->to_string(this), from->level(), adjusted_level, + to->to_string(this), to->level()); setLevel(from, adjusted_level); } } @@ -542,12 +532,11 @@ Levelize::ensureLatchLevels() } void -Levelize::setLevel(Vertex *vertex, +Levelize::setLevel(Vertex *vertex, Level level) { - debugPrint(debug_, "levelize", 3, "set level %s %d", - vertex->to_string(this).c_str(), - level); + debugPrint(debug_, "levelize", 3, "set level {} {}", + vertex->to_string(this), level); vertex->setLevel(level); max_level_ = std::max(level, max_level_); if (level >= Graph::vertex_level_max) @@ -577,8 +566,8 @@ void Levelize::relevelizeFrom(Vertex *vertex) { if (levelized_) { - debugPrint(debug_, "levelize", 1, "level invalid from %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "levelize", 1, "level invalid from {}", + vertex->to_string(this)); relevelize_from_.insert(vertex); levels_valid_ = false; } @@ -587,10 +576,9 @@ Levelize::relevelizeFrom(Vertex *vertex) void Levelize::deleteEdgeBefore(Edge *edge) { - if (levelized_ - && loop_edges_.contains(edge)) { - debugPrint(debug_, "levelize", 2, "delete loop edge %s", - edge->to_string(this).c_str()); + if (levelized_ && loop_edges_.contains(edge)) { + debugPrint(debug_, "levelize", 2, "delete loop edge {}", + edge->to_string(this)); disabled_loop_edges_.erase(edge); // Relevelize if a loop edge is removed. Incremental levelization // fails because the DFS path will be missing. @@ -611,9 +599,9 @@ void Levelize::relevelize() { for (Vertex *vertex : relevelize_from_) { - debugPrint(debug_, "levelize", 2, "relevelize from %s", - vertex->to_string(this).c_str()); - if (isRoot(vertex)) + debugPrint(debug_, "levelize", 2, "relevelize from {}", + vertex->to_string(this)); + if (isRoot(vertex)) roots_.insert(vertex); VertexSet path_vertices = makeVertexSet(this); EdgeSeq path; @@ -647,8 +635,8 @@ Levelize::visit(Vertex *vertex, // Back edges form feedback loops. recordLoop(edge, path); else if (to_vertex->level() <= level) - visit(to_vertex, edge, level+level_space, level_space, - path_vertices, path); + visit(to_vertex, edge, level + level_space, level_space, path_vertices, + path); } const TimingRole *role = edge->role(); @@ -669,8 +657,8 @@ Levelize::visit(Vertex *vertex, && !vertex->isBidirectDriver()) { Vertex *to_vertex = graph_->pinDrvrVertex(from_pin); if (to_vertex->level() <= level) - visit(to_vertex, nullptr, level+level_space, level_space, - path_vertices, path); + visit(to_vertex, nullptr, level + level_space, level_space, path_vertices, + path); } path_vertices.erase(vertex); if (from) @@ -684,12 +672,11 @@ Levelize::isDisabledLoop(Edge *edge) const } void -Levelize::setLevelIncr(Vertex *vertex, +Levelize::setLevelIncr(Vertex *vertex, Level level) { - debugPrint(debug_, "levelize", 2, "set level %s %d", - vertex->to_string(this).c_str(), - level); + debugPrint(debug_, "levelize", 2, "set level {} {}", + vertex->to_string(this), level); if (vertex->level() != level) { if (observer_) observer_->levelChangedBefore(vertex); @@ -716,11 +703,9 @@ Levelize::checkLevels() && from_level >= level // Loops with no entry edges are all level zero. && !(from_level == 0 && level == 0)) - report_->warn(617, "level check failed %s %d -> %s %d", - from_vertex->name(network_), - from_vertex->level(), - vertex->name(network_), - level); + report_->warn(617, "level check failed {} {} -> {} {}", + from_vertex->name(network_), from_vertex->level(), + vertex->name(network_), level); } } } @@ -732,18 +717,14 @@ GraphLoop::GraphLoop(EdgeSeq *edges) : { } -GraphLoop::~GraphLoop() -{ - delete edges_; -} +GraphLoop::~GraphLoop() { delete edges_; } bool GraphLoop::isCombinational() const { for (Edge *edge : *edges_) { const TimingRole *role = edge->role(); - if (!(role == TimingRole::wire() - || role == TimingRole::combinational() + if (!(role == TimingRole::wire() || role == TimingRole::combinational() || role == TimingRole::tristateEnable() || role == TimingRole::tristateDisable())) return false; @@ -759,10 +740,10 @@ GraphLoop::report(const StaState *sta) const bool first_edge = true; for (Edge *edge : *edges_) { if (first_edge) - report->reportLine(" %s", edge->from(graph)->to_string(sta).c_str()); - report->reportLine(" %s", edge->to(graph)->to_string(graph).c_str()); + report->report(" {}", edge->from(graph)->to_string(sta)); + report->report(" {}", edge->to(graph)->to_string(sta)); first_edge = false; } } -} // namespace +} // namespace sta diff --git a/search/MakeTimingModel.cc b/search/MakeTimingModel.cc index e1f9cba7..20ec6110 100644 --- a/search/MakeTimingModel.cc +++ b/search/MakeTimingModel.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "MakeTimingModel.hh" @@ -75,7 +75,8 @@ MakeTimingModel::MakeTimingModel(const char *lib_name, scene_(scene), cell_(nullptr), min_max_(MinMax::max()), - lib_builder_(new LibertyBuilder(debug_, report_)), + lib_builder_(new LibertyBuilder(debug_, + report_)), tbl_template_index_(1), sdc_(scene->sdc()), sdc_backup_(nullptr), @@ -84,10 +85,7 @@ MakeTimingModel::MakeTimingModel(const char *lib_name, scenes_.insert(scene_); } -MakeTimingModel::~MakeTimingModel() -{ - delete lib_builder_; -} +MakeTimingModel::~MakeTimingModel() { delete lib_builder_; } LibertyLibrary * MakeTimingModel::makeTimingModel() @@ -107,7 +105,7 @@ MakeTimingModel::makeTimingModel() cell_->finish(false, report_, debug_); restoreSdc(); - + return library_; } @@ -193,9 +191,8 @@ MakeTimingModel::makePorts() int from_index = network_->fromIndex(port); int to_index = network_->toIndex(port); BusDcl *bus_dcl = library_->makeBusDcl(port_name, from_index, to_index); - LibertyPort *lib_port = lib_builder_->makeBusPort(cell_, port_name, - from_index, to_index, - bus_dcl); + LibertyPort *lib_port = + lib_builder_->makeBusPort(cell_, port_name, from_index, to_index, bus_dcl); lib_port->setDirection(network_->direction(port)); PortMemberIterator *member_iter = network_->memberIterator(port); while (member_iter->hasNext()) { @@ -223,8 +220,7 @@ MakeTimingModel::checkClock(Clock *clk) { for (const Pin *pin : clk->leafPins()) { if (!network_->isTopLevelPort(pin)) - report_->warn(1355, "clock %s pin %s is inside model block.", - clk->name(), + report_->warn(1355, "clock {} pin {} is inside model block.", clk->name(), network_->pathName(pin)); } } @@ -235,7 +231,7 @@ class MakeEndTimingArcs : public PathEndVisitor { public: MakeEndTimingArcs(Sta *sta); - MakeEndTimingArcs(const MakeEndTimingArcs&) = default; + MakeEndTimingArcs(const MakeEndTimingArcs &) = default; ~MakeEndTimingArcs() override {} PathEndVisitor *copy() const override; void visit(PathEnd *path_end) override; @@ -273,25 +269,21 @@ MakeEndTimingArcs::visit(PathEnd *path_end) const Sdc *sdc = src_path->sdc(sta_); const Clock *src_clk = src_path->clock(sta_); const ClockEdge *tgt_clk_edge = path_end->targetClkEdge(sta_); - if (src_clk == sdc->defaultArrivalClock() - && tgt_clk_edge) { + if (src_clk == sdc->defaultArrivalClock() && tgt_clk_edge) { Network *network = sta_->network(); Debug *debug = sta_->debug(); const MinMax *min_max = path_end->minMax(sta_); Arrival data_delay = src_path->arrival(); Delay clk_latency = path_end->targetClkDelay(sta_); ArcDelay check_margin = path_end->margin(sta_); - Delay margin = min_max == MinMax::max() - ? data_delay - clk_latency + check_margin - : clk_latency - data_delay + check_margin; + Delay margin = (min_max == MinMax::max()) + ? delaySum(delayDiff(data_delay, clk_latency, sta_), check_margin, sta_) + : delaySum(delayDiff(clk_latency, data_delay, sta_), check_margin, sta_); float delay1 = delayAsFloat(margin, MinMax::max(), sta_); - debugPrint(debug, "make_timing_model", 2, "%s -> %s clock %s %s %s %s", - input_rf_->shortName(), - network->pathName(src_path->pin(sta_)), - tgt_clk_edge->name(), - path_end->typeName(), - min_max->to_string().c_str(), - delayAsString(margin, sta_)); + debugPrint(debug, "make_timing_model", 2, "{} -> {} clock {} {} {} {}", + input_rf_->shortName(), network->pathName(src_path->pin(sta_)), + tgt_clk_edge->name(), path_end->typeName(), + min_max->to_string(), delayAsString(margin, sta_)); if (debug->check("make_timing_model", 3)) sta_->reportPathEnd(path_end); @@ -335,15 +327,14 @@ MakeTimingModel::findTimingFromInput(Port *input_port) OutputPinDelays output_delays; for (const RiseFall *input_rf : RiseFall::range()) { const RiseFallBoth *input_rf1 = input_rf->asRiseFallBoth(); - sta_->setInputDelay(input_pin, input_rf1, - sdc_->defaultArrivalClock(), - sdc_->defaultArrivalClockEdge()->transition(), - nullptr, false, false, MinMaxAll::all(), true, 0.0, sdc_); + sta_->setInputDelay(input_pin, input_rf1, sdc_->defaultArrivalClock(), + sdc_->defaultArrivalClockEdge()->transition(), nullptr, + false, false, MinMaxAll::all(), true, 0.0, sdc_); PinSet *from_pins = new PinSet(network_); from_pins->insert(input_pin); - ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr, - input_rf1, sdc_); + ExceptionFrom *from = + sta_->makeExceptionFrom(from_pins, nullptr, nullptr, input_rf1, sdc_); search_->findFilteredArrivals(from, nullptr, nullptr, false, false); end_visitor.setInputRf(input_rf); @@ -354,8 +345,7 @@ MakeTimingModel::findTimingFromInput(Port *input_port) findOutputDelays(input_rf, output_delays); search_->deleteFilteredArrivals(); - sta_->removeInputDelay(input_pin, input_rf1, - sdc_->defaultArrivalClock(), + sta_->removeInputDelay(input_pin, input_rf1, sdc_->defaultArrivalClock(), sdc_->defaultArrivalClockEdge()->transition(), MinMaxAll::all(), sdc_); } @@ -395,7 +385,7 @@ void MakeTimingModel::makeSetupHoldTimingArcs(const Pin *input_pin, const ClockEdgeDelays &clk_margins) { - for (const auto& [clk_edge, margins] : clk_margins) { + for (const auto &[clk_edge, margins] : clk_margins) { for (const MinMax *min_max : MinMax::range()) { bool setup = (min_max == MinMax::max()); TimingArcAttrsPtr attrs = nullptr; @@ -404,16 +394,14 @@ MakeTimingModel::makeSetupHoldTimingArcs(const Pin *input_pin, bool exists; margins.value(input_rf, min_max, margin, exists); if (exists) { - debugPrint(debug_, "make_timing_model", 2, "%s %s %s -> clock %s %s", - sta_->network()->pathName(input_pin), - input_rf->shortName(), - min_max == MinMax::max() ? "setup" : "hold", - clk_edge->name(), + debugPrint(debug_, "make_timing_model", 2, "{} {} {} -> clock {} {}", + sta_->network()->pathName(input_pin), input_rf->shortName(), + min_max == MinMax::max() ? "setup" : "hold", clk_edge->name(), delayAsString(margin, sta_)); - ScaleFactorType scale_type = setup - ? ScaleFactorType::setup - : ScaleFactorType::hold; - TimingModel *check_model = makeScalarCheckModel(margin, scale_type, input_rf); + ScaleFactorType scale_type = + setup ? ScaleFactorType::setup : ScaleFactorType::hold; + TimingModel *check_model = + makeScalarCheckModel(margin, scale_type, input_rf); if (attrs == nullptr) attrs = std::make_shared(); attrs->setModel(input_rf, check_model); @@ -425,12 +413,10 @@ MakeTimingModel::makeSetupHoldTimingArcs(const Pin *input_pin, LibertyPort *clk_port = modelPort(clk_pin); if (clk_port) { const RiseFall *clk_rf = clk_edge->transition(); - const TimingRole *role = setup - ? TimingRole::setup() - : TimingRole::hold(); - lib_builder_->makeFromTransitionArcs(cell_, clk_port, - input_port, nullptr, - clk_rf, role, attrs); + const TimingRole *role = + setup ? TimingRole::setup() : TimingRole::hold(); + lib_builder_->makeFromTransitionArcs(cell_, clk_port, input_port, + nullptr, clk_rf, role, attrs); } } } @@ -442,7 +428,7 @@ void MakeTimingModel::makeInputOutputTimingArcs(const Pin *input_pin, OutputPinDelays &output_pin_delays) { - for (const auto& [output_pin, output_delays] : output_pin_delays) { + for (const auto &[output_pin, output_delays] : output_pin_delays) { TimingArcAttrsPtr attrs = nullptr; for (const RiseFall *output_rf : RiseFall::range()) { const MinMax *min_max = MinMax::max(); @@ -450,11 +436,9 @@ MakeTimingModel::makeInputOutputTimingArcs(const Pin *input_pin, bool exists; output_delays.delays.value(output_rf, min_max, delay, exists); if (exists) { - debugPrint(debug_, "make_timing_model", 2, "%s -> %s %s delay %s", - network_->pathName(input_pin), - network_->pathName(output_pin), - output_rf->shortName(), - delayAsString(delay, sta_)); + debugPrint(debug_, "make_timing_model", 2, "{} -> {} {} delay {}", + network_->pathName(input_pin), network_->pathName(output_pin), + output_rf->shortName(), delayAsString(delay, sta_)); TimingModel *gate_model = makeGateModelTable(output_pin, delay, output_rf); if (attrs == nullptr) attrs = std::make_shared(); @@ -465,8 +449,8 @@ MakeTimingModel::makeInputOutputTimingArcs(const Pin *input_pin, LibertyPort *output_port = modelPort(output_pin); LibertyPort *input_port = modelPort(input_pin); attrs->setTimingSense(output_delays.timingSense()); - lib_builder_->makeCombinationalArcs(cell_, input_port, output_port, - true, true, attrs); + lib_builder_->makeCombinationalArcs(cell_, input_port, output_port, true, true, + attrs); } } } @@ -479,7 +463,7 @@ MakeTimingModel::findClkedOutputPaths() { InstancePinIterator *output_iter = network_->pinIterator(network_->topInstance()); while (output_iter->hasNext()) { - Pin *output_pin = output_iter->next(); + Pin *output_pin = output_iter->next(); if (network_->direction(output_pin)->isOutput()) { ClockEdgeDelays clk_delays; LibertyPort *output_port = modelPort(output_pin); @@ -493,11 +477,10 @@ MakeTimingModel::findClkedOutputPaths() const MinMax *min_max = path->minMax(sta_); Arrival delay = path->arrival(); RiseFallMinMax &delays = clk_delays[clk_edge]; - delays.mergeValue(output_rf, min_max, - delayAsFloat(delay, min_max, sta_)); + delays.mergeValue(output_rf, min_max, delayAsFloat(delay, min_max, sta_)); } } - for (const auto& [clk_edge, delays] : clk_delays) { + for (const auto &[clk_edge, delays] : clk_delays) { for (const Pin *clk_pin : clk_edge->clock()->pins()) { LibertyPort *clk_port = modelPort(clk_pin); if (clk_port) { @@ -505,16 +488,16 @@ MakeTimingModel::findClkedOutputPaths() TimingArcAttrsPtr attrs = nullptr; for (const RiseFall *output_rf : RiseFall::range()) { float delay = delays.value(output_rf, min_max_) - clk_edge->time(); - TimingModel *gate_model = makeGateModelTable(output_pin, delay, output_rf); + TimingModel *gate_model = + makeGateModelTable(output_pin, delay, output_rf); if (attrs == nullptr) attrs = std::make_shared(); attrs->setModel(output_rf, gate_model); } if (attrs) { - lib_builder_->makeFromTransitionArcs(cell_, clk_port, - output_port, nullptr, - clk_rf, TimingRole::regClkToQ(), - attrs); + lib_builder_->makeFromTransitionArcs(cell_, clk_port, output_port, + nullptr, clk_rf, + TimingRole::regClkToQ(), attrs); } } } @@ -545,8 +528,10 @@ MakeTimingModel::findClkTreeDelays() for (const Clock *clk : *clks) { ClkDelays delays = sta_->findClkDelays(clk, scene_, true); for (const MinMax *min_max : MinMax::range()) { - makeClkTreePaths(lib_port, min_max, TimingSense::positive_unate, delays); - makeClkTreePaths(lib_port, min_max, TimingSense::negative_unate, delays); + makeClkTreePaths(lib_port, min_max, TimingSense::positive_unate, + delays); + makeClkTreePaths(lib_port, min_max, TimingSense::negative_unate, + delays); } } } @@ -564,15 +549,14 @@ MakeTimingModel::makeClkTreePaths(LibertyPort *lib_port, { TimingArcAttrsPtr attrs = nullptr; for (const RiseFall *clk_rf : RiseFall::range()) { - const RiseFall *end_rf = (sense == TimingSense::positive_unate) - ? clk_rf - : clk_rf->opposite(); + const RiseFall *end_rf = + (sense == TimingSense::positive_unate) ? clk_rf : clk_rf->opposite(); Path clk_path; Delay insertion, delay, latency; float lib_clk_delay; bool exists; - delays.delay(clk_rf, end_rf, min_max, insertion, delay, - lib_clk_delay, latency, clk_path, exists); + delays.delay(clk_rf, end_rf, min_max, insertion, delay, lib_clk_delay, latency, + clk_path, exists); if (exists) { TimingModel *model = makeGateModelScalar(delay, end_rf); if (attrs == nullptr) @@ -583,8 +567,8 @@ MakeTimingModel::makeClkTreePaths(LibertyPort *lib_port, if (attrs) { attrs->setTimingSense(sense); const TimingRole *role = (min_max == MinMax::min()) - ? TimingRole::clockTreePathMin() - : TimingRole::clockTreePathMax(); + ? TimingRole::clockTreePathMin() + : TimingRole::clockTreePathMax(); lib_builder_->makeClockTreePathArcs(cell_, lib_port, role, attrs); } } @@ -605,10 +589,10 @@ MakeTimingModel::makeScalarCheckModel(float value, TablePtr table = std::make_shared(value); TableTemplate *tbl_template = library_->findTableTemplate("scalar", TableTemplateType::delay); - TableModel *table_model = new TableModel(table, tbl_template, - scale_factor_type, rf); - CheckTableModel *check_model = new CheckTableModel(cell_, table_model); - return check_model; + TableModel *check_table = new TableModel(table, tbl_template, scale_factor_type, rf); + TableModels *check_tables = new TableModels(check_table); + CheckTableModel *check = new CheckTableModel(cell_, check_tables); + return check; } TimingModel * @@ -622,9 +606,12 @@ MakeTimingModel::makeGateModelScalar(Delay delay, library_->findTableTemplate("scalar", TableTemplateType::delay); TableModel *delay_model = new TableModel(delay_table, tbl_template, ScaleFactorType::cell, rf); + TableModels *delay_models = new TableModels(delay_model); TableModel *slew_model = new TableModel(slew_table, tbl_template, ScaleFactorType::cell, rf); - GateTableModel *gate_model = new GateTableModel(cell_, delay_model, slew_model); + TableModels *slew_models = new TableModels(slew_model); + GateTableModel *gate_model = new GateTableModel(cell_, delay_models, slew_models, + nullptr, nullptr); return gate_model; } @@ -637,7 +624,9 @@ MakeTimingModel::makeGateModelScalar(Delay delay, library_->findTableTemplate("scalar", TableTemplateType::delay); TableModel *delay_model = new TableModel(delay_table, tbl_template, ScaleFactorType::cell, rf); - GateTableModel *gate_model = new GateTableModel(cell_, delay_model, nullptr); + TableModels *models = new TableModels(delay_model); + GateTableModel *gate_model = new GateTableModel(cell_, models, nullptr, + nullptr, nullptr); return gate_model; } @@ -664,22 +653,20 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin, const Pin *gate_in_pin = network_->findPin(drvr_inst, gate_in_port); if (gate_in_pin) { Vertex *gate_in_vertex = graph_->pinLoadVertex(gate_in_pin); - Slew in_slew = graph_->slew(gate_in_vertex, - drvr_arc->fromEdge()->asRiseFall(), - ap_index); + Slew in_slew = graph_->slew( + gate_in_vertex, drvr_arc->fromEdge()->asRiseFall(), ap_index); float in_slew1 = delayAsFloat(in_slew); - GateTableModel *drvr_gate_model = drvr_arc->gateTableModel(scene_, - min_max_); + GateTableModel *drvr_gate_model = + drvr_arc->gateTableModel(scene_, min_max_); if (drvr_gate_model) { float output_load_cap = graph_delay_calc_->loadCap(output_pin, scene_, min_max_); - ArcDelay drvr_self_delay; - Slew drvr_self_slew; - drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap, false, + float drvr_self_delay, drvr_self_slew; + drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap, drvr_self_delay, drvr_self_slew); - const TableModel *drvr_table = drvr_gate_model->delayModel(); + const TableModel *drvr_table = drvr_gate_model->delayModels()->model(); const TableTemplate *drvr_template = drvr_table->tblTemplate(); const TableAxis *drvr_load_axis = loadCapacitanceAxis(drvr_table); if (drvr_load_axis) { @@ -689,32 +676,38 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin, for (size_t i = 0; i < drvr_axis_values.size(); i++) { float load_cap = drvr_axis_values[i]; // get slew from driver input pin - ArcDelay gate_delay; - Slew gate_slew; - drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, false, + float gate_delay, gate_slew; + drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, gate_delay, gate_slew); // Remove the self delay driving the output pin net load cap. - load_values->push_back(delayAsFloat(delay + gate_delay - - drvr_self_delay)); + load_values->push_back(delayAsFloat(delay) + + gate_delay + - drvr_self_delay); slew_values->push_back(delayAsFloat(gate_slew)); } FloatSeq axis_values = drvr_axis_values; - TableAxisPtr load_axis = - std::make_shared(TableAxisVariable::total_output_net_capacitance, - std::move(axis_values)); + TableAxisPtr load_axis = std::make_shared( + TableAxisVariable::total_output_net_capacitance, + std::move(axis_values)); - TablePtr delay_table = std::make_shared
(load_values, load_axis); - TablePtr slew_table = std::make_shared
(slew_values, load_axis); + TablePtr delay_table = + std::make_shared
(load_values, load_axis); + TablePtr slew_table = + std::make_shared
(slew_values, load_axis); - TableTemplate *model_template = ensureTableTemplate(drvr_template, - load_axis); + TableTemplate *model_template = + ensureTableTemplate(drvr_template, load_axis); TableModel *delay_model = new TableModel(delay_table, model_template, ScaleFactorType::cell, rf); + TableModels *delay_models = new TableModels(delay_model); TableModel *slew_model = new TableModel(slew_table, model_template, ScaleFactorType::cell, rf); - GateTableModel *gate_model = new GateTableModel(cell_, delay_model, - slew_model); + TableModels *slew_models = new TableModels(slew_model); + GateTableModel *gate_model = new GateTableModel(cell_, + delay_models, + slew_models, + nullptr, nullptr); return gate_model; } } @@ -737,8 +730,8 @@ MakeTimingModel::ensureTableTemplate(const TableTemplate *drvr_template, std::string template_name = "template_"; template_name += std::to_string(tbl_template_index_++); - model_template = library_->makeTableTemplate(template_name, - TableTemplateType::delay); + model_template = + library_->makeTableTemplate(template_name, TableTemplateType::delay); model_template->setAxis1(load_axis); template_map_[drvr_template] = model_template; } @@ -749,13 +742,16 @@ const TableAxis * MakeTimingModel::loadCapacitanceAxis(const TableModel *table) { if (table->axis1() - && table->axis1()->variable() == TableAxisVariable::total_output_net_capacitance) + && table->axis1()->variable() + == TableAxisVariable::total_output_net_capacitance) return table->axis1(); else if (table->axis2() - && table->axis2()->variable() == TableAxisVariable::total_output_net_capacitance) + && table->axis2()->variable() + == TableAxisVariable::total_output_net_capacitance) return table->axis2(); else if (table->axis3() - && table->axis3()->variable() == TableAxisVariable::total_output_net_capacitance) + && table->axis3()->variable() + == TableAxisVariable::total_output_net_capacitance) return table->axis3(); else return nullptr; @@ -773,9 +769,9 @@ TimingSense OutputDelays::timingSense() const { if (rf_path_exists[RiseFall::riseIndex()][RiseFall::riseIndex()] - && rf_path_exists[RiseFall::fallIndex()][RiseFall::fallIndex()] - && !rf_path_exists[RiseFall::riseIndex()][RiseFall::fallIndex()] - && !rf_path_exists[RiseFall::fallIndex()][RiseFall::riseIndex()]) + && rf_path_exists[RiseFall::fallIndex()][RiseFall::fallIndex()] + && !rf_path_exists[RiseFall::riseIndex()][RiseFall::fallIndex()] + && !rf_path_exists[RiseFall::fallIndex()][RiseFall::riseIndex()]) return TimingSense::positive_unate; else if (rf_path_exists[RiseFall::riseIndex()][RiseFall::fallIndex()] && rf_path_exists[RiseFall::fallIndex()][RiseFall::riseIndex()] @@ -791,4 +787,4 @@ OutputDelays::timingSense() const return TimingSense::none; } -} // namespace +} // namespace sta diff --git a/search/Path.cc b/search/Path.cc index 8ec27d20..e7f78bde 100644 --- a/search/Path.cc +++ b/search/Path.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "Path.hh" @@ -50,8 +50,8 @@ Path::Path() : Path::Path(const Path *path) : prev_path_(path ? path->prev_path_ : nullptr), - arrival_(path ? path->arrival_ : 0.0), - required_(path ? path->required_ : 0.0), + arrival_(path ? path->arrival_ : delay_zero), + required_(path ? path->required_ : delay_zero), vertex_id_(path ? path->vertex_id_ : vertex_id_null), tag_index_(path ? path->tag_index_ : tag_index_null), is_enum_(path ? path->is_enum_ : false), @@ -75,7 +75,7 @@ Path::Path(Vertex *vertex, Path::Path(Vertex *vertex, Tag *tag, - Arrival arrival, + const Arrival &arrival, Path *prev_path, Edge *prev_edge, TimingArc *prev_arc, @@ -99,7 +99,7 @@ Path::Path(Vertex *vertex, Path::Path(Vertex *vertex, Tag *tag, - Arrival arrival, + const Arrival &arrival, Path *prev_path, Edge *prev_edge, TimingArc *prev_arc, @@ -124,13 +124,12 @@ Path::Path(Vertex *vertex, void Path::init(Vertex *vertex, - Arrival arrival, + const Arrival &arrival, const StaState *sta) { const Graph *graph = sta->graph(); vertex_id_ = graph->id(vertex); - tag_index_ = tag_index_null, - prev_path_ = nullptr; + tag_index_ = tag_index_null, prev_path_ = nullptr; prev_arc_idx_ = 0; arrival_ = arrival; required_ = 0.0; @@ -144,8 +143,7 @@ Path::init(Vertex *vertex, { const Graph *graph = sta->graph(); vertex_id_ = graph->id(vertex); - tag_index_ = tag->index(), - prev_path_ = nullptr; + tag_index_ = tag->index(), prev_path_ = nullptr; prev_arc_idx_ = 0; arrival_ = 0.0; required_ = 0.0; @@ -155,13 +153,12 @@ Path::init(Vertex *vertex, void Path::init(Vertex *vertex, Tag *tag, - Arrival arrival, + const Arrival &arrival, const StaState *sta) { const Graph *graph = sta->graph(); vertex_id_ = graph->id(vertex); - tag_index_ = tag->index(), - prev_path_ = nullptr; + tag_index_ = tag->index(), prev_path_ = nullptr; prev_arc_idx_ = 0; arrival_ = arrival; required_ = 0.0; @@ -171,15 +168,14 @@ Path::init(Vertex *vertex, void Path::init(Vertex *vertex, Tag *tag, - Arrival arrival, + const Arrival &arrival, Path *prev_path, Edge *prev_edge, TimingArc *prev_arc, const StaState *sta) { const Graph *graph = sta->graph(); - tag_index_ = tag->index(), - prev_path_ = prev_path; + tag_index_ = tag->index(), prev_path_ = prev_path; if (prev_path) { prev_edge_id_ = graph->id(prev_edge); prev_arc_idx_ = prev_arc->index(); @@ -199,12 +195,12 @@ Path::to_string(const StaState *sta) const if (isNull()) return "null path"; else - return stringPrintTmp("%s %s %s/%s %d", - vertex(sta)->to_string(sta).c_str(), - transition(sta)->shortName(), - scene(sta)->name().c_str(), - minMax(sta)->to_string().c_str(), - tagIndex(sta)); + return sta::format("{} {} {}/{} {}", + vertex(sta)->to_string(sta), + transition(sta)->shortName(), + scene(sta)->name(), + minMax(sta)->to_string(), + tagIndex(sta)); } bool @@ -221,7 +217,7 @@ Path::vertex(const StaState *sta) const const Edge *edge = graph->edge(prev_edge_id_); return edge->to(graph); } - else + else return graph->vertex(vertex_id_); } @@ -330,7 +326,7 @@ Path::pathAnalysisPtIndex(const StaState *sta) const return scene(sta)->pathIndex(minMax(sta)); } -Slew +const Slew Path::slew(const StaState *sta) const { DcalcAPIndex slew_index = scene(sta)->dcalcAnalysisPtIndex(minMax(sta)); @@ -365,9 +361,9 @@ Slack Path::slack(const StaState *sta) const { if (minMax(sta) == MinMax::max()) - return required_ - arrival_; + return delayDiff(required_, arrival_, sta); else - return arrival_ - required_; + return delayDiff(arrival_, required_, sta); } Path * @@ -404,7 +400,7 @@ Path::prevArc(const StaState *sta) const TimingArcSet *arc_set = edge->timingArcSet(); return arc_set->findTimingArc(prev_arc_idx_); } - else + else return nullptr; } @@ -415,7 +411,7 @@ Path::prevEdge(const StaState *sta) const const Graph *graph = sta->graph(); return graph->edge(prev_edge_id_); } - else + else return nullptr; } @@ -448,8 +444,7 @@ void Path::checkPrevPath(const StaState *sta) const { if (prev_path_ && prev_path_->isNull()) - sta->report()->reportLine("path %s prev path is null.", - to_string(sta).c_str()); + sta->report()->report("path {} prev path is null.", to_string(sta)); if (prev_path_ && !prev_path_->isNull()) { Graph *graph = sta->graph(); Edge *edge = prevEdge(sta); @@ -457,10 +452,9 @@ Path::checkPrevPath(const StaState *sta) const Vertex *prev_edge_vertex = edge->from(graph); if (prev_vertex != prev_edge_vertex) { Network *network = sta->network(); - sta->report()->reportLine("path %s prev path corrupted %s vs %s.", - to_string(sta).c_str(), - prev_vertex->name(network), - prev_edge_vertex->name(network)); + sta->report()->report("path {} prev path corrupted {} vs {}.", to_string(sta), + prev_vertex->name(network), + prev_edge_vertex->name(network)); } } } @@ -478,14 +472,14 @@ Path::tgtClkMinMax(const StaState *sta) const { const MinMax *min_max = minMax(sta); switch (mode(sta)->sdc()->analysisType()) { - case AnalysisType::single: - case AnalysisType::bc_wc: - return min_max; - case AnalysisType::ocv: - return min_max->opposite(); - default: - // suppress gcc warning - return min_max; + case AnalysisType::single: + case AnalysisType::bc_wc: + return min_max; + case AnalysisType::ocv: + return min_max->opposite(); + default: + // suppress gcc warning + return min_max; } } //////////////////////////////////////////////////////////////// @@ -579,8 +573,7 @@ Path::cmpClk(const Path *path1, else return 1; } - else if (clk_edge1 == nullptr - && clk_edge2 == nullptr) + else if (clk_edge1 == nullptr && clk_edge2 == nullptr) return 0; else if (clk_edge2) return -1; @@ -594,11 +587,10 @@ Path::equal(const Path *path1, const StaState *sta) { return (path1 == nullptr && path2 == nullptr) - || (path1 - && path2 - && path1->vertexId(sta) == path2->vertexId(sta) - // Tag equal implies transition and path ap equal. - && path1->tagIndex(sta) == path2->tagIndex(sta)); + || (path1 && path2 + && path1->vertexId(sta) == path2->vertexId(sta) + // Tag equal implies transition and path ap equal. + && path1->tagIndex(sta) == path2->tagIndex(sta)); } //////////////////////////////////////////////////////////////// @@ -779,12 +771,9 @@ VertexPathIterator::findNext() Path *path = &paths_[path_index_++]; if (filtered_) { const Tag *tag = path->tag(search_); - if ((scene_ == nullptr - || path->scene(search_) == scene_) - && (rf_ == nullptr - || tag->rfIndex() == rf_->index()) - && (min_max_ == nullptr - || path->minMax(search_) == min_max_)) { + if ((scene_ == nullptr || path->scene(search_) == scene_) + && (rf_ == nullptr || tag->rfIndex() == rf_->index()) + && (min_max_ == nullptr || path->minMax(search_) == min_max_)) { next_ = path; return; } @@ -797,9 +786,7 @@ VertexPathIterator::findNext() next_ = nullptr; } -VertexPathIterator::~VertexPathIterator() -{ -} +VertexPathIterator::~VertexPathIterator() {} bool VertexPathIterator::hasNext() @@ -815,4 +802,4 @@ VertexPathIterator::next() return path; } -} // namespace +} // namespace sta diff --git a/search/PathEnd.cc b/search/PathEnd.cc index 6c644592..da7d0d77 100644 --- a/search/PathEnd.cc +++ b/search/PathEnd.cc @@ -102,7 +102,7 @@ PathEnd::sourceClkEdge(const StaState *sta) const return path_->clkEdge(sta); } -Arrival +const Arrival & PathEnd::dataArrivalTime(const StaState *) const { return path_->arrival(); @@ -111,13 +111,17 @@ PathEnd::dataArrivalTime(const StaState *) const Arrival PathEnd::dataArrivalTimeOffset(const StaState *sta) const { - return dataArrivalTime(sta) + sourceClkOffset(sta); + return delaySum(dataArrivalTime(sta), + sourceClkOffset(sta), + sta); } Required PathEnd::requiredTimeOffset(const StaState *sta) const { - return requiredTime(sta) + sourceClkOffset(sta); + return delaySum(requiredTime(sta), + sourceClkOffset(sta), + sta); } const RiseFall * @@ -259,9 +263,9 @@ Crpr PathEnd::checkCrpr(const StaState *sta) const { if (checkRole(sta)->genericRole() == TimingRole::hold()) - return -crpr(sta); + return delayDiff(delay_zero, crpr(sta), sta); else - return crpr(sta);; + return crpr(sta); } Crpr @@ -301,7 +305,7 @@ PathEnd::checkTgtClkDelay(const Path *tgt_clk_path, Delay insertion, latency; checkTgtClkDelay(tgt_clk_path, tgt_clk_edge, check_role, sta, insertion, latency); - return Delay(insertion + latency); + return delaySum(insertion, latency, sta); } void @@ -334,7 +338,8 @@ PathEnd::checkTgtClkDelay(const Path *tgt_clk_path, Delay path_insertion = search->clockInsertion(tgt_clk, tgt_src_pin, tgt_clk_rf, min_max, min_max, mode); - latency = delayRemove(clk_arrival - tgt_clk_edge->time(), path_insertion); + latency = delayRemove(delayDiff(clk_arrival, tgt_clk_edge->time(), sta), + path_insertion); } else // Ideal clock. @@ -444,7 +449,7 @@ PathEndUnconstrained::PathEndUnconstrained(Path *path) : PathEnd * PathEndUnconstrained::copy() const { - return new PathEndUnconstrained(path_); + return new PathEndUnconstrained(*this); } bool @@ -507,17 +512,6 @@ PathEndClkConstrained::PathEndClkConstrained(Path *path, { } -PathEndClkConstrained::PathEndClkConstrained(Path *path, - Path *clk_path, - Crpr crpr, - bool crpr_valid) : - PathEnd(path), - clk_path_(clk_path), - crpr_(crpr), - crpr_valid_(crpr_valid) -{ -} - void PathEndClkConstrained::setPath(Path *path) { @@ -615,21 +609,25 @@ PathEndClkConstrained::targetClkTime(const StaState *sta) const Arrival PathEndClkConstrained::targetClkArrival(const StaState *sta) const { - return targetClkArrivalNoCrpr(sta) - + checkCrpr(sta); + return delaySum(targetClkArrivalNoCrpr(sta), + checkCrpr(sta), + sta); } Arrival PathEndClkConstrained::targetClkArrivalNoCrpr(const StaState *sta) const { Sdc *sdc = path_->sdc(sta); - return targetClkTime(sta) - + targetClkDelay(sta) - + checkClkUncertainty(sourceClkEdge(sta), - targetClkEdge(sta), - targetClkPath(), - checkRole(sta), sdc) - + targetClkMcpAdjustment(sta); + Arrival clk_arrival = delaySum(targetClkDelay(sta), + targetClkTime(sta), + sta); + float uncertainty = checkClkUncertainty(sourceClkEdge(sta), + targetClkEdge(sta), + targetClkPath(), + checkRole(sta), + sdc); + return delaySum(delaySum(clk_arrival, uncertainty, sta), + targetClkMcpAdjustment(sta), sta); } Delay @@ -704,8 +702,9 @@ PathEndClkConstrained::crpr(const StaState *sta) const Required PathEndClkConstrained::requiredTime(const StaState *sta) const { - return requiredTimeNoCrpr(sta) - + checkCrpr(sta); + return delaySum(requiredTimeNoCrpr(sta), + checkCrpr(sta), + sta); } Required @@ -714,9 +713,9 @@ PathEndClkConstrained::requiredTimeNoCrpr(const StaState *sta) const Arrival tgt_clk_arrival = targetClkArrivalNoCrpr(sta); ArcDelay check_margin = margin(sta); if (checkGenericRole(sta) == TimingRole::setup()) - return tgt_clk_arrival - check_margin; + return delayDiff(tgt_clk_arrival, check_margin, sta); else - return tgt_clk_arrival + check_margin; + return delaySum(tgt_clk_arrival, check_margin, sta); } Slack @@ -725,9 +724,9 @@ PathEndClkConstrained::slack(const StaState *sta) const Arrival arrival = dataArrivalTime(sta); Required required = requiredTime(sta); if (checkGenericRole(sta) == TimingRole::setup()) - return required - arrival; + return delayDiff(required, arrival, sta); else - return arrival - required; + return delayDiff(arrival, required, sta); } int @@ -755,16 +754,6 @@ PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path, { } -PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path, - Path *clk_path, - MultiCyclePath *mcp, - Crpr crpr, - bool crpr_valid) : - PathEndClkConstrained(path, clk_path, crpr, crpr_valid), - mcp_(mcp) -{ -} - float PathEndClkConstrainedMcp::targetClkMcpAdjustment(const StaState *sta) const { @@ -862,9 +851,9 @@ PathEndClkConstrained::slackNoCrpr(const StaState *sta) const Arrival arrival = dataArrivalTime(sta); Required required = requiredTimeNoCrpr(sta); if (checkGenericRole(sta) == TimingRole::setup()) - return required - arrival; + return delayDiff(required, arrival, sta); else - return arrival - required; + return delayDiff(arrival, required, sta); } void @@ -935,24 +924,10 @@ PathEndCheck::PathEndCheck(Path *path, { } -PathEndCheck::PathEndCheck(Path *path, - TimingArc *check_arc, - Edge *check_edge, - Path *clk_path, - MultiCyclePath *mcp, - Crpr crpr, - bool crpr_valid) : - PathEndClkConstrainedMcp(path, clk_path, mcp, crpr, crpr_valid), - check_arc_(check_arc), - check_edge_(check_edge) -{ -} - PathEnd * PathEndCheck::copy() const { - return new PathEndCheck(path_, check_arc_, check_edge_, - clk_path_, mcp_, crpr_, crpr_valid_); + return new PathEndCheck(*this); } PathEnd::Type @@ -1017,10 +992,18 @@ PathEndCheck::exceptPathCmp(const PathEnd *path_end, Delay PathEndCheck::clkSkew(const StaState *sta) { - return sourceClkDelay(sta) - targetClkDelay(sta) - crpr(sta) - // Uncertainty decreases slack, but increases skew. - - checkTgtClkUncertainty(clk_path_, clk_path_->clkEdge(sta), - checkRole(sta), sta); + Delay skew = delayDiff(sourceClkDelay(sta), + targetClkDelay(sta), + sta); + skew = delayDiff(skew, crpr(sta), sta); + // Uncertainty decreases slack, but increases skew. + skew = delayDiff(skew, + checkTgtClkUncertainty(clk_path_, + clk_path_->clkEdge(sta), + checkRole(sta), + sta), + sta); + return skew; } Delay @@ -1035,7 +1018,8 @@ PathEndCheck::sourceClkDelay(const StaState *sta) const Arrival clk_arrival = src_clk_path->arrival(); const ClockEdge *src_clk_edge = src_clk_info->clkEdge(); Delay insertion = sourceClkInsertionDelay(sta); - return delayRemove(clk_arrival - src_clk_edge->time(), insertion); + return delayRemove(delayDiff(clk_arrival, src_clk_edge->time(), sta), + insertion); } else // Ideal clock. @@ -1052,9 +1036,17 @@ PathEndCheck::requiredTimeNoCrpr(const StaState *sta) const ArcDelay check_margin = margin(sta); float macro_clk_tree_delay = macroClkTreeDelay(sta); if (checkGenericRole(sta) == TimingRole::setup()) - return tgt_clk_arrival - (check_margin + macro_clk_tree_delay); + return delayDiff(tgt_clk_arrival, + delaySum(check_margin, + macro_clk_tree_delay, + sta), + sta); else - return tgt_clk_arrival + (check_margin - macro_clk_tree_delay); + return delaySum(tgt_clk_arrival, + delayDiff(check_margin, + macro_clk_tree_delay, + sta), + sta); } float @@ -1072,7 +1064,7 @@ PathEndCheck::macroClkTreeDelay(const StaState *sta) const if (clk_port) { const MinMax *min_max = clk_path_->minMax(sta); const RiseFall *rf = clk_path_->transition(sta); - float slew = delayAsFloat(clk_path_->slew(sta)); + float slew = delayAsFloat(clk_path_->slew(sta), min_max, sta); return clk_port->clkTreeDelay(slew, rf, min_max); } } @@ -1102,29 +1094,10 @@ PathEndLatchCheck::PathEndLatchCheck(Path *path, src_clk_arrival_ = search->pathClkPathArrival(path_); } -PathEndLatchCheck::PathEndLatchCheck(Path *path, - TimingArc *check_arc, - Edge *check_edge, - Path *clk_path, - Path *disable_path, - MultiCyclePath *mcp, - PathDelay *path_delay, - Delay src_clk_arrival, - Crpr crpr, - bool crpr_valid) : - PathEndCheck(path, check_arc, check_edge, clk_path, mcp, crpr, crpr_valid), - disable_path_(disable_path), - path_delay_(path_delay), - src_clk_arrival_(src_clk_arrival) -{ -} - PathEnd * PathEndLatchCheck::copy() const { - return new PathEndLatchCheck(path_, check_arc_, check_edge_, - clk_path_, disable_path_, mcp_, path_delay_, - src_clk_arrival_, crpr_, crpr_valid_); + return new PathEndLatchCheck(*this); } PathEnd::Type @@ -1276,14 +1249,16 @@ PathEndLatchCheck::targetClkWidth(const StaState *sta) const Arrival enable_arrival = search->clkPathArrival(clk_path_); const ClkInfo *enable_clk_info = clk_path_->clkInfo(sta); if (enable_clk_info->isPulseClk()) - return disable_arrival - enable_arrival; + return delayDiff(disable_arrival, enable_arrival, sta); else { if (delayGreater(enable_arrival, disable_arrival, sta)) { const Clock *disable_clk = enable_clk_info->clock(); if (disable_clk) - disable_arrival += disable_clk->period(); + disable_arrival = delaySum(disable_arrival, + disable_clk->period(), + sta); } - return disable_arrival - enable_arrival; + return delayDiff(disable_arrival, enable_arrival, sta); } } @@ -1328,22 +1303,10 @@ PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay, { } -PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay, - Path *path, - Path *clk_path, - MultiCyclePath *mcp, - Crpr crpr, - bool crpr_valid) : - PathEndClkConstrainedMcp(path, clk_path, mcp, crpr, crpr_valid), - output_delay_(output_delay) -{ -} - PathEnd * PathEndOutputDelay::copy() const { - return new PathEndOutputDelay(output_delay_, path_, clk_path_, - mcp_, crpr_, crpr_valid_); + return new PathEndOutputDelay(*this); } PathEnd::Type @@ -1416,10 +1379,14 @@ PathEndOutputDelay::targetClkArrivalNoCrpr(const StaState *sta) const else { const ClockEdge *tgt_clk_edge = targetClkEdge(sta); const TimingRole *check_role = checkRole(sta); - return targetClkTime(sta) - + tgtClkDelay(tgt_clk_edge, check_role, sta) - + targetClkUncertainty(sta) - + checkMcpAdjustment(path_, tgt_clk_edge, sta); + Arrival base = delaySum(targetClkTime(sta), + tgtClkDelay(tgt_clk_edge, check_role, sta), + sta); + return delaySum(delaySum(base, + targetClkUncertainty(sta), + sta), + checkMcpAdjustment(path_, tgt_clk_edge, sta), + sta); } } @@ -1451,7 +1418,7 @@ PathEndOutputDelay::tgtClkDelay(const ClockEdge *tgt_clk_edge, Arrival insertion, latency; tgtClkDelay(tgt_clk_edge, check_role, sta, insertion, latency); - return insertion + latency; + return delaySum(insertion, latency, sta); } void @@ -1531,24 +1498,10 @@ PathEndGatedClock::PathEndGatedClock(Path *gating_ref, { } -PathEndGatedClock::PathEndGatedClock(Path *gating_ref, - Path *clk_path, - const TimingRole *check_role, - MultiCyclePath *mcp, - ArcDelay margin, - Crpr crpr, - bool crpr_valid) : - PathEndClkConstrainedMcp(gating_ref, clk_path, mcp, crpr, crpr_valid), - check_role_(check_role), - margin_(margin) -{ -} - PathEnd * PathEndGatedClock::copy() const { - return new PathEndGatedClock(path_, clk_path_, check_role_, - mcp_, margin_, crpr_, crpr_valid_); + return new PathEndGatedClock(*this); } PathEnd::Type @@ -1647,24 +1600,10 @@ PathEndDataCheck::clkPath(Path *path, return nullptr; } -PathEndDataCheck::PathEndDataCheck(DataCheck *check, - Path *data_path, - Path *data_clk_path, - Path *clk_path, - MultiCyclePath *mcp, - Crpr crpr, - bool crpr_valid) : - PathEndClkConstrainedMcp(data_path, clk_path, mcp, crpr, crpr_valid), - data_clk_path_(data_clk_path), - check_(check) -{ -} - PathEnd * PathEndDataCheck::copy() const { - return new PathEndDataCheck(check_, path_, data_clk_path_, - clk_path_, mcp_, crpr_, crpr_valid_); + return new PathEndDataCheck(*this); } PathEnd::Type @@ -1691,17 +1630,23 @@ PathEndDataCheck::requiredTimeNoCrpr(const StaState *sta) const { Arrival data_clk_arrival = data_clk_path_->arrival(); float data_clk_time = data_clk_path_->clkEdge(sta)->time(); - Arrival data_clk_delay = data_clk_arrival - data_clk_time; - Arrival tgt_clk_arrival = targetClkTime(sta) - + data_clk_delay - + targetClkUncertainty(sta) - + targetClkMcpAdjustment(sta); + Arrival data_clk_delay = delayDiff(data_clk_arrival, + data_clk_time, + sta); + Arrival tgt_clk_arrival = + delaySum(delaySum(targetClkTime(sta), + data_clk_delay, + sta), + delaySum(targetClkUncertainty(sta), + targetClkMcpAdjustment(sta), + sta), + sta); ArcDelay check_margin = margin(sta); if (checkGenericRole(sta) == TimingRole::setup()) - return tgt_clk_arrival - check_margin; + return delayDiff(tgt_clk_arrival, check_margin, sta); else - return tgt_clk_arrival + check_margin; + return delaySum(tgt_clk_arrival, check_margin, sta); } ArcDelay @@ -1799,30 +1744,10 @@ PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay, findSrcClkArrival(sta); } -PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay, - Path *path, - Path *clk_path, - TimingArc *check_arc, - Edge *check_edge, - OutputDelay *output_delay, - Arrival src_clk_arrival, - Crpr crpr, - bool crpr_valid) : - PathEndClkConstrained(path, clk_path, crpr, crpr_valid), - path_delay_(path_delay), - check_arc_(check_arc), - check_edge_(check_edge), - output_delay_(output_delay), - src_clk_arrival_(src_clk_arrival) -{ -} - PathEnd * PathEndPathDelay::copy() const { - return new PathEndPathDelay(path_delay_, path_, clk_path_, - check_arc_, check_edge_, output_delay_, - src_clk_arrival_, crpr_, crpr_valid_); + return new PathEndPathDelay(*this); } PathEnd::Type @@ -1917,7 +1842,7 @@ PathEnd::pathDelaySrcClkOffset(const Path *path, const ClockEdge *clk_edge = path->clkEdge(sta); if (clk_edge) { if (ignoreClkLatency(path, path_delay, sta)) - offset = -delayAsFloat(src_clk_arrival); + offset = -delayAsFloat(src_clk_arrival, path->minMax(sta), sta); else // Arrival includes src clock edge time that is not counted in the // path delay. @@ -1960,8 +1885,9 @@ PathEndPathDelay::targetClkArrivalNoCrpr(const StaState *sta) const { const ClockEdge *tgt_clk_edge = targetClkEdge(sta); if (tgt_clk_edge) - return targetClkDelay(sta) - + targetClkUncertainty(sta); + return delaySum(targetClkDelay(sta), + targetClkUncertainty(sta), + sta); else if (clk_path_) return clk_path_->arrival(); else @@ -1979,19 +1905,29 @@ PathEndPathDelay::requiredTime(const StaState *sta) const { float delay = path_delay_->delay(); if (path_delay_->ignoreClkLatency()) { - Required src_offset = path_->isClock(sta) - ? path_->clkEdge(sta)->time() - : src_clk_arrival_; - return src_offset + delay - + ((minMax(sta) == MinMax::max()) ? -margin(sta) : margin(sta)); + Delay with_delay = path_->isClock(sta) + ? Delay(path_->clkEdge(sta)->time() + delay) + : delaySum(src_clk_arrival_, delay, sta); + ArcDelay m = margin(sta); + return (minMax(sta) == MinMax::max()) + ? delayDiff(with_delay, m, sta) + : delaySum(with_delay, m, sta); } else { Arrival tgt_clk_arrival = targetClkArrival(sta); float src_clk_offset = sourceClkOffset(sta); // Path delay includes target clk latency and timing check setup/hold // margin or external departure at target. - return delay - src_clk_offset + tgt_clk_arrival - + ((minMax(sta) == MinMax::max()) ? -margin(sta) : margin(sta)); + Delay base = delaySum(tgt_clk_arrival, + delay, + sta); + Delay with_src = delayDiff(base, + src_clk_offset, + sta); + ArcDelay m = margin(sta); + return (minMax(sta) == MinMax::max()) + ? delayDiff(with_src, m, sta) + : delaySum(with_src, m, sta); } } @@ -2073,22 +2009,22 @@ PathEnd::cmpSlack(const PathEnd *path_end1, { Slack slack1 = path_end1->slack(sta); Slack slack2 = path_end2->slack(sta); - if (delayZero(slack1) - && delayZero(slack2) + if (delayZero(slack1, sta) + && delayZero(slack2, sta) && path_end1->isLatchCheck() && path_end2->isLatchCheck()) { Arrival borrow1 = path_end1->borrow(sta); Arrival borrow2 = path_end2->borrow(sta); // Latch slack is zero if there is borrowing so break ties // based on borrow time. - if (delayEqual(borrow1, borrow2)) + if (delayEqual(borrow1, borrow2, sta)) return 0; else if (delayGreater(borrow1, borrow2, sta)) return -1; else return 1; } - else if (delayEqual(slack1, slack2)) + else if (delayEqual(slack1, slack2, sta)) return 0; else if (delayLess(slack1, slack2, sta)) return -1; @@ -2104,7 +2040,7 @@ PathEnd::cmpArrival(const PathEnd *path_end1, Arrival arrival1 = path_end1->dataArrivalTime(sta); Arrival arrival2 = path_end2->dataArrivalTime(sta); const MinMax *min_max = path_end1->minMax(sta); - if (delayEqual(arrival1, arrival2)) + if (delayEqual(arrival1, arrival2, sta)) return 0; else if (delayLess(arrival1, arrival2, min_max, sta)) return -1; diff --git a/search/PathEnum.cc b/search/PathEnum.cc index ed57ed28..437966a8 100644 --- a/search/PathEnum.cc +++ b/search/PathEnum.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "PathEnum.hh" @@ -41,11 +41,11 @@ namespace sta { -// A diversion is an alternate path formed by changing the previous +// A diversion is an alternate path formed by changing the previous // path/arc of before_div to after_div/div_arc in path. // // div_arc -// after_div<--------+ +// after_div<--------+ // | // <--...--before_div<--...--path<---path_end // @@ -128,13 +128,14 @@ PathEnum::PathEnum(size_t group_path_count, void PathEnum::insert(PathEnd *path_end) { - debugPrint(debug_, "path_enum", 1, "insert %s", - path_end->path()->to_string(this).c_str()); - debugPrint(debug_, "path_enum", 2, "diversion %s %s %s", - path_end->path()->to_string(this).c_str(), + debugPrint(debug_, "path_enum", 1, "insert {}", + path_end->path()->to_string(this)); + debugPrint(debug_, "path_enum", 2, "diversion {} {} {}", + path_end->path()->to_string(this), cmp_slack_ ? "slack" : "delay", - delayAsString(cmp_slack_ ? path_end->slack(this) : - path_end->dataArrivalTime(this), this)); + delayAsString(cmp_slack_ ? path_end->slack(this) + : path_end->dataArrivalTime(this), + this)); Diversion *div = new Diversion(path_end, path_end->path()); div_queue_.push(div); div_count_++; @@ -154,13 +155,11 @@ PathEnum::~PathEnum() bool PathEnum::hasNext() { - if (unique_pins_ - && !inserts_pruned_) { + if (unique_pins_ && !inserts_pruned_) { pruneDiversionQueue(); inserts_pruned_ = true; } - if (next_ == nullptr - && !div_queue_.empty()) + if (next_ == nullptr && !div_queue_.empty()) findNext(); return next_ != nullptr; } @@ -186,11 +185,10 @@ PathEnum::findNext() Vertex *vertex = path_end->vertex(this); path_counts_[vertex]++; if (debug_->check("path_enum", 2)) { - report_->reportLine("path_enum: next path %zu %s delay %s slack %s", - path_counts_[vertex], - path->to_string(this).c_str(), - delayAsString(path_end->dataArrivalTime(this), this), - delayAsString(path_end->slack(this), this)); + report_->report("path_enum: next path {} {} delay {} slack {}", + path_counts_[vertex], path->to_string(this), + delayAsString(path_end->dataArrivalTime(this), this), + delayAsString(path_end->slack(this), this)); reportDiversionPath(div); } @@ -206,9 +204,8 @@ PathEnum::findNext() else { // We have endpoint_path_count paths for this endpoint, // so we are done with it. - debugPrint(debug_, "path_enum", 1, - "endpoint_path_count reached for %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "path_enum", 1, "endpoint_path_count reached for {}", + vertex->to_string(this)); deleteDiversionPathEnd(div); } } @@ -222,12 +219,10 @@ PathEnum::reportDiversionPath(Diversion *div) Path *p = path_end->path(); Path *after_div = div->divPath(); while (p) { - report_->reportLine("path_enum: %s %s%s", - p->to_string(this).c_str(), - delayAsString(p->arrival(), this), - Path::equal(p, after_div, this) ? " <-after diversion" : ""); - if (p != path - && network_->isLatchData(p->pin(this))) + report_->report("path_enum: {} {}{}", p->to_string(this), + delayAsString(p->arrival(), this), + Path::equal(p, after_div, this) ? " <-after diversion" : ""); + if (p != path && network_->isLatchData(p->pin(this))) break; p = p->prevPath(); } @@ -235,8 +230,8 @@ PathEnum::reportDiversionPath(Diversion *div) //////////////////////////////////////////////////////////////// -using VisitedFanins = std::set>; -using VertexEdge = std::pair; +using VisitedFanins = std::set>; +using VertexEdge = std::pair; class PathEnumFaninVisitor : public PathVisitor { @@ -251,19 +246,19 @@ public: Vertex *prev_vertex, TimingArc *prev_arc); bool visitFromToPath(const Pin *from_pin, - Vertex *from_vertex, - const RiseFall *from_rf, - Tag *from_tag, - Path *from_path, - const Arrival &from_arrival, - Edge *edge, - TimingArc *arc, - ArcDelay arc_delay, - Vertex *to_vertex, - const RiseFall *to_rf, - Tag *to_tag, - Arrival &to_arrival, - const MinMax *min_max) override; + Vertex *from_vertex, + const RiseFall *from_rf, + Tag *from_tag, + Path *from_path, + const Arrival &from_arrival, + Edge *edge, + TimingArc *arc, + ArcDelay arc_delay, + Vertex *to_vertex, + const RiseFall *to_rf, + Tag *to_tag, + Arrival &to_arrival, + const MinMax *min_max) override; private: void makeDivertedPathEnd(Path *after_div, @@ -299,7 +294,7 @@ private: Vertex *prev_vertex_; bool crpr_active_; VisitedFanins visited_fanins_; - std::map unique_edge_divs_; + std::map unique_edge_divs_; }; PathEnumFaninVisitor::PathEnumFaninVisitor(PathEnd *path_end, @@ -372,8 +367,7 @@ PathEnumFaninVisitor::visitEdge(const Pin *from_pin, Path *from_path = from_iter.next(); const Mode *mode = from_path->mode(this); const Sdc *sdc = mode->sdc(); - if (pred_->searchFrom(from_vertex, mode) - && pred_->searchThru(edge, mode) + if (pred_->searchFrom(from_vertex, mode) && pred_->searchThru(edge, mode) && pred_->searchTo(to_vertex, mode) // Fanin paths are broken by path delay internal pin startpoints. && !sdc->isPathDelayInternalFromBreak(to_pin)) { @@ -382,13 +376,13 @@ PathEnumFaninVisitor::visitEdge(const Pin *from_pin, arc_set->arcsFrom(from_rf, arc1, arc2); // Filter arcs by to edge. if (arc1 && arc1->toEdge()->asRiseFall()->index() == before_div_rf_index_) { - if (!visitArc(from_pin, from_vertex, from_rf, from_path, - edge, arc1, to_pin, to_vertex, min_max_, mode)) + if (!visitArc(from_pin, from_vertex, from_rf, from_path, edge, arc1, + to_pin, to_vertex, min_max_, mode)) return false; } if (arc2 && arc2->toEdge()->asRiseFall()->index() == before_div_rf_index_) { - if (!visitArc(from_pin, from_vertex, from_rf, from_path, - edge, arc2, to_pin, to_vertex, min_max_, mode)) + if (!visitArc(from_pin, from_vertex, from_rf, from_path, edge, arc2, + to_pin, to_vertex, min_max_, mode)) return false; } } @@ -415,23 +409,20 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *, { // These paths fanin to before_div_ so we know to_vertex matches. if ((!unique_pins_ || from_vertex != prev_vertex_) - && (!unique_edges_ - || from_vertex != prev_vertex_ + && (!unique_edges_ || from_vertex != prev_vertex_ || from_rf != prev_arc_->fromEdge()->asRiseFall()) && arc != prev_arc_ && Tag::matchNoCrpr(to_tag, before_div_tag_) // Ignore paths that only differ by crpr from same vertex/edge. - && (!crpr_active_ - || !visited_fanins_.contains({from_vertex, arc}))) { - debugPrint(debug_, "path_enum", 3, "visit fanin %s -> %s %s %s", - from_path->to_string(this).c_str(), - to_vertex->to_string(this).c_str(), - to_rf->shortName(), - delayAsString(search_->deratedDelay(from_vertex, arc, edge, - false, from_path->minMax(this), - from_path->dcalcAnalysisPtIndex(this), - from_path->sdc(this)), - this)); + && (!crpr_active_ || !visited_fanins_.contains({from_vertex, arc}))) { + debugPrint(debug_, "path_enum", 3, "visit fanin {} -> {} {} {}", + from_path->to_string(this), + to_vertex->to_string(this), to_rf->shortName(), + delayAsString( + search_->deratedDelay( + from_vertex, arc, edge, false, from_path->minMax(this), + from_path->dcalcAnalysisPtIndex(this), from_path->sdc(this)), + this)); PathEnd *div_end; Path *after_div_copy; // Make the diverted path end to check slack with from_path crpr. @@ -448,21 +439,18 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *, else { if (debug_->check("path_enum", 3)) { bool unique_pins = !(!unique_pins_ || from_vertex != prev_vertex_); - bool unique_edges = !(!unique_edges_ - || from_rf != prev_arc_->fromEdge()->asRiseFall()); + bool unique_edges = + !(!unique_edges_ || from_rf != prev_arc_->fromEdge()->asRiseFall()); bool same_arc = !(arc != prev_arc_); bool tag_march = !Tag::matchNoCrpr(to_tag, before_div_tag_); - bool crpr = !(!crpr_active_ - || visited_fanins_.find({from_vertex, arc}) - == visited_fanins_.end()); - debugPrint(debug_, "path_enum", 3, " pruned %s%s%s%s%s %s %s", + bool crpr = + !(!crpr_active_ + || visited_fanins_.find({from_vertex, arc}) == visited_fanins_.end()); + debugPrint(debug_, "path_enum", 3, " pruned {}{}{}{}{} {} {}", unique_pins ? "unique_pins " : "", - unique_edges ? "unique_edges " : "", - same_arc ? "same_arc " : "", - tag_march ? "tag_march " : "", - crpr ? "crpr " : "", - edge->to_string(this).c_str(), - arc->to_string().c_str()); + unique_edges ? "unique_edges " : "", same_arc ? "same_arc " : "", + tag_march ? "tag_march " : "", crpr ? "crpr " : "", + edge->to_string(this), arc->to_string()); } } return true; @@ -495,8 +483,8 @@ PathEnumFaninVisitor::makeDivertedPathEnd(Path *after_div, Path *&after_div_copy) { Path *div_path; - path_enum_->makeDivertedPath(path_end_->path(), before_div_, after_div, - div_edge, div_arc, div_path, after_div_copy); + path_enum_->makeDivertedPath(path_end_->path(), before_div_, after_div, div_edge, + div_arc, div_path, after_div_copy); div_end = path_end_->copy(); div_end->setPath(div_path); } @@ -505,26 +493,24 @@ void PathEnumFaninVisitor::reportDiversion(const Edge *div_edge, const TimingArc *div_arc, Path *after_div) -{ +{ if (debug_->check("path_enum", 3)) { Path *path = path_end_->path(); Arrival path_delay = path_enum_->cmp_slack_ ? path_end_->slack(this) : path_end_->dataArrivalTime(this); - Arrival div_delay = path_delay - path_enum_->divSlack(before_div_, - after_div, div_edge, - div_arc); + Arrival div_delay = delayDiff(path_delay, + path_enum_->divSlack(before_div_, + after_div, div_edge, + div_arc), + this); Path *div_prev = before_div_->prevPath(); - report_->reportLine("path_enum: diversion %s %s %s -> %s", - path->to_string(this).c_str(), - path_enum_->cmp_slack_ ? "slack" : "delay", - delayAsString(path_delay, this), - delayAsString(div_delay, this)); - report_->reportLine("path_enum: from %s -> %s", - div_prev->to_string(this).c_str(), - before_div_->to_string(this).c_str()); - report_->reportLine("path_enum: to %s", - after_div->to_string(this).c_str()); + report_->report("path_enum: diversion {} {} {} -> {}", path->to_string(this), + path_enum_->cmp_slack_ ? "slack" : "delay", + delayAsString(path_delay, this), delayAsString(div_delay, this)); + report_->report("path_enum: from {} -> {}", div_prev->to_string(this), + before_div_->to_string(this)); + report_->report("path_enum: to {}", after_div->to_string(this)); } } @@ -580,7 +566,7 @@ PathEnum::divSlack(Path *before_div, Tag *q_tag; latches_->latchOutArrival(after_div, div_arc, div_edge, q_tag, div_delay, div_arrival); - return div_arrival - before_div_arrival; + return delayDiff(div_arrival, before_div_arrival, this); } else { DcalcAPIndex dcalc_ap = before_div->dcalcAnalysisPtIndex(this); @@ -589,8 +575,8 @@ PathEnum::divSlack(Path *before_div, false, before_div->minMax(this), dcalc_ap, before_div->sdc(this)); - Arrival div_arrival = search_->clkPathArrival(after_div) + div_delay; - return div_arrival - before_div_arrival; + Arrival div_arrival = delaySum(search_->clkPathArrival(after_div), div_delay, this); + return delayDiff(div_arrival, before_div_arrival, this); } } else { @@ -608,8 +594,8 @@ PathEnum::makeDiversions(PathEnd *path_end, Path *path = before; Path *prev_path = path->prevPath(); TimingArc *prev_arc = path->prevArc(this); - PathEnumFaninVisitor fanin_visitor(path_end, path, unique_pins_, - unique_edges_, this); + PathEnumFaninVisitor fanin_visitor(path_end, path, unique_pins_, unique_edges_, + this); while (prev_path) { // Fanin visitor does all the work. // While visiting the fanins the fanin_visitor finds the @@ -618,8 +604,7 @@ PathEnum::makeDiversions(PathEnd *path_end, // Do not enumerate beyond latch D to Q edges. // This breaks latch loop paths. const TimingRole *prev_role = prev_arc->role(); - if (prev_role == TimingRole::latchDtoQ() - || prev_role == TimingRole::regClkToQ()) + if (prev_role == TimingRole::latchDtoQ() || prev_role == TimingRole::regClkToQ()) break; path = prev_path; prev_path = path->prevPath(); @@ -647,14 +632,10 @@ PathEnum::makeDivertedPath(Path *path, Path *prev_copy = nullptr; while (p) { // prev_path made in next pass. - Path *copy = new Path(p->vertex(this), - p->tag(this), - p->arrival(), - // Replaced on next pass. - p->prevPath(), - p->prevEdge(this), - p->prevArc(this), - true, this); + Path *copy = + new Path(p->vertex(this), p->tag(this), p->arrival(), + // Replaced on next pass. + p->prevPath(), p->prevEdge(this), p->prevArc(this), true, this); search_->saveEnumPath(copy); if (prev_copy) prev_copy->setPrevPath(copy); @@ -664,8 +645,7 @@ PathEnum::makeDivertedPath(Path *path, after_div_copy = copy; if (first) div_path = copy; - else if (found_div - && network_->isLatchData(p->pin(this))) + else if (found_div && network_->isLatchData(p->pin(this))) break; if (p == before_div) { // Replaced on next pass. @@ -702,13 +682,11 @@ PathEnum::updatePathHeadDelays(PathSeq &paths, if (edge) { Arrival arrival; const MinMax *min_max = path->minMax(this); - if (i == path_idx_max - && edge->role()->isLatchDtoQ() + if (i == path_idx_max && edge->role()->isLatchDtoQ() && min_max == MinMax::max()) { ArcDelay arc_delay; Tag *q_tag; - latches_->latchOutArrival(after_div, arc, edge, - q_tag, arc_delay, arrival); + latches_->latchOutArrival(after_div, arc, edge, q_tag, arc_delay, arrival); path->setArrival(arrival); path->setTag(q_tag); prev_clk_info = q_tag->clkInfo(); @@ -719,7 +697,7 @@ PathEnum::updatePathHeadDelays(PathSeq &paths, path->minMax(this), path->dcalcAnalysisPtIndex(this), path->sdc(this)); - arrival = prev_arrival + arc_delay; + arrival = delaySum(prev_arrival, arc_delay, this); path->setArrival(arrival); const Tag *tag = path->tag(this); const ClkInfo *clk_info = tag->clkInfo(); @@ -729,19 +707,15 @@ PathEnum::updatePathHeadDelays(PathSeq &paths, && arc->role() != TimingRole::latchDtoQ()) { // When crpr is enabled the diverion may be from another crpr clk pin, // so update the tags to use the corresponding ClkInfo. - Tag *updated_tag = search_->findTag(path->scene(this), - path->transition(this), - path->minMax(this), - prev_clk_info, - tag->isClock(), - tag->inputDelay(), - tag->isSegmentStart(), - tag->states(), false, nullptr); + Tag *updated_tag = search_->findTag( + path->scene(this), path->transition(this), path->minMax(this), + prev_clk_info, tag->isClock(), tag->inputDelay(), + tag->isSegmentStart(), tag->states(), false, nullptr); path->setTag(updated_tag); } - debugPrint(debug_, "path_enum", 5, "update arrival %s %s %s -> %s", - path->vertex(this)->to_string(this).c_str(), - path->tag(this)->to_string(this).c_str(), + debugPrint(debug_, "path_enum", 5, "update arrival {} {} {} -> {}", + path->vertex(this)->to_string(this), + path->tag(this)->to_string(this), delayAsString(path->arrival(), this), delayAsString(arrival, this)); } @@ -750,4 +724,4 @@ PathEnum::updatePathHeadDelays(PathSeq &paths, } } -} // namespace +} // namespace sta diff --git a/search/PathGroup.cc b/search/PathGroup.cc index 47086f3b..e2ca7711 100644 --- a/search/PathGroup.cc +++ b/search/PathGroup.cc @@ -100,41 +100,42 @@ PathGroup::PathGroup(const char *name, slack_max_(slack_max), min_max_(min_max), cmp_slack_(cmp_slack), - heap_(group_path_count, PathEndLess(cmp_slack, sta)), + threshold_(min_max->initValue()), sta_(sta) { } PathGroup::~PathGroup() { - PathEndSeq path_ends = heap_.extract(); - deleteContents(path_ends); -} - -PathEndSeq -PathGroup::pathEnds() const -{ - return heap_.contents(); + deleteContents(path_ends_); } bool PathGroup::saveable(PathEnd *path_end) { + float threshold; + { + LockGuard lock(lock_); + threshold = threshold_; + } if (cmp_slack_) { // Crpr increases the slack, so check the slack // without crpr first because it is expensive to find. - Slack slack = path_end->slackNoCrpr(sta_); - if (!delayIsInitValue(slack, min_max_) - && delayLessEqual(slack, slack_max_, sta_)) { + Slack slack_no_crpr = path_end->slackNoCrpr(sta_); + if (!delayIsInitValue(slack_no_crpr, min_max_) + && delayLessEqual(slack_no_crpr, threshold, sta_) + && delayLessEqual(slack_no_crpr, slack_max_, sta_)) { // Now check with crpr. - slack = path_end->slack(sta_); - return delayLessEqual(slack, slack_max_, sta_) + Slack slack = path_end->slack(sta_); + return delayLessEqual(slack, threshold, sta_) + && delayLessEqual(slack, slack_max_, sta_) && delayGreaterEqual(slack, slack_min_, sta_); } } else { const Arrival &arrival = path_end->dataArrivalTime(sta_); - return !delayIsInitValue(arrival, min_max_); + return !delayIsInitValue(arrival, min_max_) + && delayGreaterEqual(arrival, threshold, min_max_, sta_); } return false; } @@ -176,33 +177,72 @@ void PathGroup::insert(PathEnd *path_end) { LockGuard lock(lock_); - auto [inserted, displaced] = heap_.insert(path_end); - if (inserted) - path_end->setPathGroup(this); + path_ends_.push_back(path_end); + path_end->setPathGroup(this); + if (group_path_count_ != group_path_count_max + && path_ends_.size() > static_cast(group_path_count_) * 2) + prune(); +} + +void +PathGroup::prune() +{ + sort(); + VertexPathCountMap path_counts; + size_t end_count = 0; + for (unsigned i = 0; i < path_ends_.size(); i++) { + PathEnd *path_end = path_ends_[i]; + Vertex *vertex = path_end->vertex(sta_); + // Squish up to endpoint_path_count path ends per vertex + // up to the front of path_ends_. + if (end_count < static_cast(group_path_count_) + && path_counts[vertex] < static_cast(endpoint_path_count_)) { + path_ends_[end_count++] = path_end; + path_counts[vertex]++; + } + else + delete path_end; + } + path_ends_.resize(end_count); + + // Set a threshold to the bottom of the sorted list that future + // inserts need to beat. + PathEnd *last_end = path_ends_[end_count - 1]; + if (cmp_slack_) + threshold_ = delayAsFloat(last_end->slack(sta_)); else - delete path_end; - if (displaced) - delete *displaced; + threshold_ = delayAsFloat(last_end->dataArrivalTime(sta_)); } void PathGroup::pushEnds(PathEndSeq &path_ends) { - if (!heap_.empty()) { - PathEndSeq ends = heap_.contents(); - path_ends.reserve(path_ends.size() + ends.size()); - // Append heap path ends to path_ends. - path_ends.insert(path_ends.end(), - std::make_move_iterator(ends.begin()), - std::make_move_iterator(ends.end())); - } + ensureSortedMaxPaths(); + for (PathEnd *path_end : path_ends_) + path_ends.push_back(path_end); +} + +void +PathGroup::ensureSortedMaxPaths() +{ + if (path_ends_.size() > static_cast(group_path_count_)) + prune(); + else + sort(); +} + +void +PathGroup::sort() +{ + sta::sort(path_ends_, PathEndLess(cmp_slack_, sta_)); } void PathGroup::clear() { + threshold_ = min_max_->initValue(); LockGuard lock(lock_); - heap_.clear(); + path_ends_.clear(); } //////////////////////////////////////////////////////////////// @@ -269,7 +309,7 @@ PathGroups::makeGroups(int group_path_count, const Sdc *sdc = mode_->sdc(); for (const auto& [name, group] : sdc->groupPaths()) { if (reportGroup(name, group_names)) { - PathGroup *group = PathGroup::makePathGroupSlack(name, + PathGroup *group = PathGroup::makePathGroupSlack(name.c_str(), group_path_count, endpoint_path_count, unique_pins, @@ -354,7 +394,7 @@ PathGroups::~PathGroups() } PathGroup * -PathGroups::findPathGroup(const char *name, +PathGroups::findPathGroup(const std::string &name, const MinMax *min_max) const { auto itr = named_map_[min_max->index()].find(name); @@ -376,7 +416,7 @@ PathGroups::findPathGroup(const Clock *clock, } bool -PathGroups::reportGroup(const char *group_name, +PathGroups::reportGroup(const std::string &group_name, StringSet &group_names) const { return group_names.empty() @@ -401,7 +441,7 @@ PathGroups::pathGroups(const PathEnd *path_end) const path_groups.push_back(path_delay_[mm_index]); } else { - const char *group_name = group_path->name(); + std::string group_name = group_path->name(); PathGroup *group = findPathGroup(group_name, min_max); if (group) path_groups.push_back(group); @@ -512,7 +552,7 @@ PathGroups::pushEnds(PathEndSeq &path_ends) for (const MinMax *min_max : MinMax::range()) { int mm_index = min_max->index(); for (std::string &group_name : pathGroupNames()) { - PathGroup *path_group = findPathGroup(group_name.c_str(), min_max); + PathGroup *path_group = findPathGroup(group_name, min_max); if (path_group) path_group->pushEnds(path_ends); } @@ -761,8 +801,8 @@ MakePathEndsAll::vertexEnd(Vertex *) // Only save the worst path end for each crpr tag. // PathEnum will peel the others. if (!unique_ends.contains(path_end)) { - debugPrint(debug, "path_group", 2, "insert %s %s %s %d", - path_end->vertex(sta_)->to_string(sta_).c_str(), + debugPrint(debug, "path_group", 2, "insert {} {} {} {}", + path_end->vertex(sta_)->to_string(sta_), path_end->typeName(), path_end->transition(sta_)->shortName(), path_end->path()->tag(sta_)->index()); @@ -776,8 +816,8 @@ MakePathEndsAll::vertexEnd(Vertex *) } } else - debugPrint(debug, "path_group", 3, "prune %s %s %s %d", - path_end->vertex(sta_)->to_string(sta_).c_str(), + debugPrint(debug, "path_group", 3, "prune {} {} {} {}", + path_end->vertex(sta_)->to_string(sta_), path_end->typeName(), path_end->transition(sta_)->shortName(), path_end->path()->tag(sta_)->index()); @@ -857,8 +897,11 @@ PathGroups::enumPathEnds(PathGroup *group, // enumerator. PathEnum path_enum(group_path_count, endpoint_path_count, unique_pins, unique_edges, cmp_slack, this); - for (PathEnd *end : group->pathEnds()) - path_enum.insert(end); + for (PathEnd *end : group->pathEnds()) { + if (group->saveable(end) + || group->enumMinSlackUnderMin(end)) + path_enum.insert(end); + } group->clear(); // Parallel path enumeratation to find the endpoint_path_count/max path ends. diff --git a/search/PocvMode.cc b/search/PocvMode.cc new file mode 100644 index 00000000..57186138 --- /dev/null +++ b/search/PocvMode.cc @@ -0,0 +1,48 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2025, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. +// +// Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// This notice may not be removed or altered from any source distribution. + +#include "PocvMode.hh" + +#include "EnumNameMap.hh" + +namespace sta { + +static EnumNameMap pocv_mode_map = + {{PocvMode::scalar, "scalar"}, + {PocvMode::normal, "normal"}, + {PocvMode::skew_normal, "skew_normal"}}; + +const char * +pocvModeName(PocvMode mode) +{ + return pocv_mode_map.find(mode); +} + +PocvMode +findPocvMode(const char *mode_name) +{ + return pocv_mode_map.find(mode_name, PocvMode::scalar); +} + +} // namespace diff --git a/search/Property.cc b/search/Property.cc index 3a2a973b..35e6a096 100644 --- a/search/Property.cc +++ b/search/Property.cc @@ -27,6 +27,7 @@ #include #include +#include "Format.hh" #include "StringUtil.hh" #include "MinMax.hh" #include "Transition.hh" @@ -49,39 +50,26 @@ namespace sta { class PropertyUnknown : public Exception { public: - PropertyUnknown(const char *type, - const char *property); - PropertyUnknown(const char *type, - const std::string property); + PropertyUnknown(const std::string &type, + const std::string &property); virtual ~PropertyUnknown() {} virtual const char *what() const noexcept; private: - const char *type_; - const std::string property_; + std::string msg_; }; -PropertyUnknown::PropertyUnknown(const char *type, - const char *property) : +PropertyUnknown::PropertyUnknown(const std::string &type, + const std::string &property) : Exception(), - type_(type), - property_(property) -{ -} - -PropertyUnknown::PropertyUnknown(const char *type, - const std::string property) : - Exception(), - type_(type), - property_(property) + msg_(sta::format("{} objects do not have a {} property.", type, property)) { } const char * PropertyUnknown::what() const noexcept { - return stringPrint("%s objects do not have a %s property.", - type_, property_.c_str()); + return msg_.c_str(); } //////////////////////////////////////////////////////////////// @@ -89,29 +77,27 @@ PropertyUnknown::what() const noexcept class PropertyTypeWrong : public Exception { public: - PropertyTypeWrong(const char *accessor, - const char *type); + PropertyTypeWrong(const std::string &accessor, + const std::string &type); virtual ~PropertyTypeWrong() {} virtual const char *what() const noexcept; private: - const char *accessor_; - const char *type_; + std::string msg_; }; -PropertyTypeWrong::PropertyTypeWrong(const char *accessor, - const char *type) : +PropertyTypeWrong::PropertyTypeWrong(const std::string &accessor, + const std::string &type) : Exception(), - accessor_(accessor), - type_(type) + msg_(sta::format("property accessor {} is only valid for {} properties.", + accessor, type)) { } const char * PropertyTypeWrong::what() const noexcept { - return stringPrint("property accessor %s is only valid for %s properties.", - accessor_, type_); + return msg_.c_str(); } //////////////////////////////////////////////////////////////// @@ -1133,7 +1119,7 @@ Properties::edgeDelay(Edge *edge, if (to_rf == rf) { for (const Scene *scene : sta_->scenes()) { DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); - ArcDelay arc_delay = sta_->arcDelay(edge, arc, ap_index); + const ArcDelay &arc_delay = sta_->arcDelay(edge, arc, ap_index); if (!delay_exists || delayGreater(arc_delay, delay, min_max, sta_)) { delay = arc_delay; @@ -1159,8 +1145,7 @@ Properties::getProperty(TimingArcSet *arc_set, const char *from = arc_set->from()->name(); const char *to = arc_set->to()->name(); const char *cell_name = arc_set->libertyCell()->name(); - std::string name; - stringPrint(name, "%s %s -> %s", cell_name, from, to); + std::string name = sta::format("{} {} -> {}", cell_name, from, to); return PropertyValue(name); } } diff --git a/search/ReportPath.cc b/search/ReportPath.cc index b7d3c9d2..158b7919 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -28,6 +28,7 @@ #include "ReportPath.hh" #include "ContainerHelpers.hh" +#include "Format.hh" #include "Report.hh" #include "Error.hh" #include "StringUtil.hh" @@ -134,20 +135,16 @@ ReportField::setEnabled(bool enabled) //////////////////////////////////////////////////////////////// -const float ReportPath::field_blank_ = -1.0; - ReportPath::ReportPath(StaState *sta) : StaState(sta), format_(ReportPathFormat::full), no_split_(false), - report_sigmas_(false), start_end_pt_width_(80), - plus_zero_(nullptr), - minus_zero_(nullptr) + field_width_extra_(5) { - setDigits(2); makeFields(); - setReportFields(false, false, false, false, false, false, false); + setDigits(2); + setReportFields(false, false, false, false, false, false, false, false); } ReportPath::~ReportPath() @@ -158,17 +155,16 @@ ReportPath::~ReportPath() delete field_capacitance_; delete field_slew_; delete field_fanout_; + delete field_variation_; delete field_src_attr_; delete field_edge_; delete field_case_; - - stringDelete(plus_zero_); - stringDelete(minus_zero_); } void ReportPath::makeFields() { + // The order corresponds to the default field order. field_fanout_ = makeField("fanout", "Fanout", 6, false, nullptr, true); field_capacitance_ = makeField("capacitance", "Cap", 6, false, units_->capacitanceUnit(), true); @@ -176,6 +172,8 @@ ReportPath::makeFields() true); field_incr_ = makeField("incr", "Delay", 6, false, units_->timeUnit(), true); + field_variation_ = makeField("variation", "Variation", 6, false, + units_->timeUnit(), false); field_total_ = makeField("total", "Time", 6, false, units_->timeUnit(), true); field_edge_ = makeField("edge", "", 1, false, nullptr, true); @@ -243,6 +241,7 @@ ReportPath::setReportFields(bool report_input_pin, bool report_cap, bool report_slew, bool report_fanout, + bool report_variation, bool report_src_attr) { report_input_pin_ = report_input_pin; @@ -252,6 +251,7 @@ ReportPath::setReportFields(bool report_input_pin, field_capacitance_->setEnabled(report_cap); field_slew_->setEnabled(report_slew); field_fanout_->setEnabled(report_fanout); + field_variation_->setEnabled(report_variation); field_src_attr_->setEnabled(report_src_attr); // for debug field_case_->setEnabled(false); @@ -273,17 +273,16 @@ void ReportPath::setDigits(int digits) { digits_ = digits; + minus_zero_ = sta::formatRuntime("-{:.{}f}", 0.0, digits_); + plus_zero_ = sta::formatRuntime("{:.{}f}", 0.0, digits_); - stringDelete(plus_zero_); - stringDelete(minus_zero_); - minus_zero_ = stringPrint("-%.*f", digits_, 0.0); - plus_zero_ = stringPrint("%.*f", digits_, 0.0); -} - -void -ReportPath::setReportSigmas(bool report) -{ - report_sigmas_ = report; + // Numeric field width expands with digits. + int field_width = digits + field_width_extra_; + field_capacitance_->setWidth(field_width); + field_slew_->setWidth(field_width); + field_variation_->setWidth(field_width); + field_incr_->setWidth(field_width); + field_total_->setWidth(field_width); } //////////////////////////////////////////////////////////////// @@ -342,7 +341,7 @@ ReportPath::reportPathEnds(const PathEndSeq *ends) const } else { if (format_ != ReportPathFormat::json) - report_->reportLine("No paths found."); + report_->report("No paths found."); } reportPathEndFooter(); } @@ -404,9 +403,7 @@ ReportPath::reportEndpointHeader(const PathEnd *end, const char *setup_hold = (end->minMax(this) == MinMax::min()) ? "min_delay/hold" : "max_delay/setup"; - report_->reportLine("%s group %s", - setup_hold, - group->name().c_str()); + report_->report("{} group {}", setup_hold, group->name()); reportBlankLine(); reportEndHeader(); } @@ -441,7 +438,7 @@ ReportPath::reportFull(const PathEndUnconstrained *end) const reportLine("data arrival time", end->dataArrivalTimeOffset(this), end->pathEarlyLate(this)); reportDashLine(); - report_->reportLine("(Path is unconstrained)"); + report_->report("(Path is unconstrained)"); } //////////////////////////////////////////////////////////////// @@ -476,8 +473,8 @@ ReportPath::reportFull(const PathEndCheck *end) const std::string ReportPath::checkRoleString(const PathEnd *end) const { - return stdstrPrint("library %s time", - end->checkRole(this)->to_string().c_str()); + return sta::format("library {} time", + end->checkRole(this)->to_string()); } void @@ -491,23 +488,23 @@ ReportPath::reportEndpoint(const PathEndCheck *end) const const TimingRole *check_generic_role = check_role->genericRole(); if (check_role == TimingRole::recovery() || check_role == TimingRole::removal()) { - auto reason = stdstrPrint("%s check against %s-edge clock %s", - check_role->to_string().c_str(), - rise_fall, - clk_name.c_str()); + std::string reason = sta::format("{} check against {}-edge clock {}", + check_role->to_string(), + rise_fall, + clk_name); reportEndpoint(inst_name, reason); } else if (check_generic_role == TimingRole::setup() || check_generic_role == TimingRole::hold()) { LibertyCell *cell = network_->libertyCell(inst); if (cell->isClockGate()) { - auto reason = stdstrPrint("%s clock gating-check end-point clocked by %s", - rise_fall, clk_name.c_str()); + std::string reason = sta::format("{} clock gating-check end-point clocked by {}", + rise_fall, clk_name); reportEndpoint(inst_name, reason); } else { const char *reg_desc = clkRegLatchDesc(end); - auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str()); + std::string reason = sta::format("{} clocked by {}", reg_desc, clk_name); reportEndpoint(inst_name, reason); } } @@ -556,7 +553,7 @@ ReportPath::reportFull(const PathEndLatchCheck *end) const end->latchRequired(this, req_time, borrow, adjusted_data_arrival, time_given_to_startpoint); // Adjust required to requiredTimeOffset. - req_time += end->sourceClkOffset(this); + req_time = delaySum(req_time, end->sourceClkOffset(this), this); if (path_delay) { float delay = path_delay->delay(); reportLine("max_delay", delay, delay, early_late); @@ -594,7 +591,7 @@ ReportPath::reportEndpoint(const PathEndLatchCheck *end) const const char *inst_name = cmd_network_->pathName(inst); std::string clk_name = tgtClkName(end); const char *reg_desc = latchDesc(end); - auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str()); + std::string reason = sta::format("{} clocked by {}", reg_desc, clk_name); reportEndpoint(inst_name, reason); } @@ -619,7 +616,7 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end, end->latchBorrowInfo(this, nom_pulse_width, open_latency, latency_diff, open_uncertainty, open_crpr, crpr_diff, max_borrow, borrow_limit_exists); - report_->reportLine("Time Borrowing Information"); + report_->report("Time Borrowing Information"); reportDashLineTotal(); if (borrow_limit_exists) reportLineTotal("user max time borrow", max_borrow, early_late); @@ -628,30 +625,30 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end, Arrival tgt_clk_width = end->targetClkWidth(this); const Path *tgt_clk_path = end->targetClkPath(); if (tgt_clk_path->clkInfo(search_)->isPropagated()) { - auto width_msg = stdstrPrint("%s nominal pulse width", tgt_clk_name.c_str()); + std::string width_msg = sta::format("{} nominal pulse width", tgt_clk_name); reportLineTotal(width_msg.c_str(), nom_pulse_width, early_late); - if (!delayZero(latency_diff)) + if (!delayZero(latency_diff, this)) reportLineTotalMinus("clock latency difference", latency_diff, early_late); } else { - auto width_msg = stdstrPrint("%s pulse width", tgt_clk_name.c_str()); + std::string width_msg = sta::format("{} pulse width", tgt_clk_name.c_str()); reportLineTotal(width_msg.c_str(), tgt_clk_width, early_late); } ArcDelay margin = end->margin(this); reportLineTotalMinus("library setup time", margin, early_late); reportDashLineTotal(); - if (!delayZero(crpr_diff)) + if (!delayZero(crpr_diff, this)) reportLineTotalMinus("CRPR difference", crpr_diff, early_late); reportLineTotal("max time borrow", max_borrow, early_late); } if (delayGreater(borrow, delay_zero, this) && (!fuzzyZero(open_uncertainty) - || !delayZero(open_crpr))) { + || !delayZero(open_crpr, this))) { reportDashLineTotal(); reportLineTotal("actual time borrow", borrow, early_late); if (!fuzzyZero(open_uncertainty)) reportLineTotal("open edge uncertainty", open_uncertainty, early_late); - if (!delayZero(open_crpr)) + if (!delayZero(open_crpr, this)) reportLineTotal("open edge CRPR", open_crpr, early_late); reportDashLineTotal(); reportLineTotal("time given to startpoint", time_given_to_startpoint, early_late); @@ -690,9 +687,9 @@ ReportPath::reportEndpoint(const PathEndPathDelay *end) const else { Instance *inst = network_->instance(end->vertex(this)->pin()); const char *inst_name = cmd_network_->pathName(inst); - std::string clk_name = tgtClkName(end); - const char *reg_desc = clkRegLatchDesc(end); - auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str()); + std::string reason = sta::format("{} clocked by {}", + clkRegLatchDesc(end), + tgtClkName(end)); reportEndpoint(inst_name, reason); } } @@ -720,7 +717,7 @@ ReportPath::reportFull(const PathEndPathDelay *end) const ArcDelay margin = end->margin(this); const MinMax *min_max = path_delay->minMax()->asMinMax(); if (min_max == MinMax::max()) - margin = -margin; + margin = delayDiff(delay_zero, margin, this); std::string delay_msg = min_max->to_string() + "_delay"; float delay = path_delay->delay(); @@ -734,8 +731,8 @@ ReportPath::reportFull(const PathEndPathDelay *end) const reportTgtClk(end, delay, 0.0, true); else { Arrival tgt_clk_delay = end->targetClkDelay(this); - Arrival tgt_clk_arrival = delay + tgt_clk_delay; - if (!delayZero(tgt_clk_delay)) + Arrival tgt_clk_arrival = delaySum(tgt_clk_delay, delay, this); + if (!delayZero(tgt_clk_delay, this)) reportLine(clkNetworkDelayIdealProp(isPropagated(tgt_clk_path)), tgt_clk_delay, tgt_clk_arrival, early_late); reportClkUncertainty(end, tgt_clk_arrival); @@ -820,8 +817,8 @@ ReportPath::reportEndpointOutputDelay(const PathEndClkConstrained *end) const if (network_->isTopLevelPort(pin)) { // Pin direction is "output" even for bidirects. if (tgt_clk) { - std::string clk_name = tgtClkName(end); - auto reason = stdstrPrint("output port clocked by %s", clk_name.c_str()); + std::string reason = sta::format("output port clocked by {}", + tgtClkName(end)); reportEndpoint(pin_name, reason); } else @@ -829,9 +826,8 @@ ReportPath::reportEndpointOutputDelay(const PathEndClkConstrained *end) const } else { if (tgt_clk) { - std::string clk_name = tgtClkName(end); - auto reason = stdstrPrint("internal path endpoint clocked by %s", - clk_name.c_str()); + std::string reason = sta::format("internal path endpoint clocked by {}", + tgtClkName(end)); reportEndpoint(pin_name, reason); } @@ -874,15 +870,14 @@ ReportPath::reportEndpoint(const PathEndGatedClock *end) const { Instance *inst = network_->instance(end->vertex(this)->pin()); const char *inst_name = cmd_network_->pathName(inst); - std::string clk_name = tgtClkName(end); const RiseFall *clk_end_rf = end->targetClkEndTrans(this); - const RiseFall *clk_rf = - (end->minMax(this) == MinMax::max()) ? clk_end_rf : clk_end_rf->opposite(); - const char *rise_fall = asRisingFalling(clk_rf); + const RiseFall *clk_rf = (end->minMax(this) == MinMax::max()) + ? clk_end_rf + : clk_end_rf->opposite(); // Note that target clock transition is ignored. - auto reason = stdstrPrint("%s clock gating-check end-point clocked by %s", - rise_fall, - clk_name.c_str()); + std::string reason = sta::format("{} clock gating-check end-point clocked by {}", + asRisingFalling(clk_rf), + tgtClkName(end)); reportEndpoint(inst_name, reason); } @@ -924,10 +919,11 @@ ReportPath::reportFull(const PathEndDataCheck *end) const PathExpanded clk_expanded(data_clk_path, this); float src_offset = end->sourceClkOffset(this); Delay clk_delay = end->targetClkDelay(this); + const MinMax *min_max = data_clk_path->minMax(this); Arrival clk_arrival = end->targetClkArrival(this); const ClockEdge *tgt_clk_edge = end->targetClkEdge(this); - float prev = delayAsFloat(clk_arrival) + src_offset; - float offset = prev - delayAsFloat(clk_delay) - tgt_clk_edge->time(); + float prev = delayAsFloat(clk_arrival, min_max, this) + src_offset; + float offset = prev - delayAsFloat(clk_delay, min_max, this) - tgt_clk_edge->time(); // Delay to startpoint is already included. reportPath6(data_clk_path, clk_expanded, clk_expanded.startIndex(), true, false, prev, offset); @@ -941,11 +937,9 @@ ReportPath::reportEndpoint(const PathEndDataCheck *end) const { Instance *inst = network_->instance(end->vertex(this)->pin()); const char *inst_name = cmd_network_->pathName(inst); - const char *tgt_clk_rf = asRisingFalling(end->dataClkPath()->transition(this)); - const char *tgt_clk_name = end->targetClk(this)->name(); - auto reason = stdstrPrint("%s edge-triggered data to data check clocked by %s", - tgt_clk_rf, - tgt_clk_name); + std::string reason = sta::format("{} edge-triggered data to data check clocked by {}", + asRisingFalling(end->dataClkPath()->transition(this)), + end->targetClk(this)->name()); reportEndpoint(inst_name, reason); } @@ -961,7 +955,7 @@ ReportPath::reportEndHeader() const reportField("Required", field_total_, line); line += ' '; reportField("Actual", field_total_, line); - report_->reportLineString(line); + report_->reportLine(line); // Line two. line.clear(); @@ -972,7 +966,7 @@ ReportPath::reportEndHeader() const reportField("Delay", field_total_, line); line += ' '; reportField("Slack", field_total_, line); - report_->reportLineString(line); + report_->reportLine(line); reportDashLine(field_description_->width() + field_total_->width() * 3 + 3); } @@ -987,7 +981,7 @@ ReportPath::reportEndLine(const PathEnd *end) const reportSpaceFieldDelay(end->requiredTimeOffset(this), early_late, line); reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line); reportSpaceSlack(end, line); - report_->reportLineString(line); + report_->reportLine(line); } //////////////////////////////////////////////////////////////// @@ -1001,7 +995,7 @@ ReportPath::reportSummaryHeader() const reportDescription("Endpoint", line); line += ' '; reportField("Slack", field_total_, line); - report_->reportLineString(line); + report_->reportLine(line); reportDashLine(field_description_->width() * 2 + field_total_->width() + 1); } @@ -1012,16 +1006,16 @@ ReportPath::reportSummaryLine(const PathEnd *end) const std::string line; PathExpanded expanded(end->path(), this); const EarlyLate *early_late = end->pathEarlyLate(this); - auto startpoint = pathStartpoint(end, expanded); + std::string startpoint = pathStartpoint(end, expanded); reportDescription(startpoint.c_str(), line); line += ' '; - auto endpoint = pathEndpoint(end); + std::string endpoint = pathEndpoint(end); reportDescription(endpoint.c_str(), line); if (end->isUnconstrained()) reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line); else reportSpaceFieldDelay(end->slack(this), EarlyLate::early(), line); - report_->reportLineString(line); + report_->reportLine(line); } std::string @@ -1033,12 +1027,12 @@ ReportPath::pathStartpoint(const PathEnd *end, const char *pin_name = cmd_network_->pathName(pin); if (network_->isTopLevelPort(pin)) { PortDirection *dir = network_->direction(pin); - return stdstrPrint("%s (%s)", pin_name, dir->name()); + return sta::format("{} ({})", pin_name, dir->name()); } else { Instance *inst = network_->instance(end->vertex(this)->pin()); const char *cell_name = cmd_network_->name(network_->cell(inst)); - return stdstrPrint("%s (%s)", pin_name, cell_name); + return sta::format("{} ({})", pin_name, cell_name); } } @@ -1049,12 +1043,12 @@ ReportPath::pathEndpoint(const PathEnd *end) const const char *pin_name = cmd_network_->pathName(pin); if (network_->isTopLevelPort(pin)) { PortDirection *dir = network_->direction(pin); - return stdstrPrint("%s (%s)", pin_name, dir->name()); + return sta::format("{} ({})", pin_name, dir->name()); } else { Instance *inst = network_->instance(end->vertex(this)->pin()); const char *cell_name = cmd_network_->name(network_->cell(inst)); - return stdstrPrint("%s (%s)", pin_name, cell_name); + return sta::format("{} ({})", pin_name, cell_name); } } @@ -1063,14 +1057,14 @@ ReportPath::pathEndpoint(const PathEnd *end) const void ReportPath::reportJsonHeader() const { - report_->reportLine("{\"checks\": ["); + report_->report("{{\"checks\": ["); } void ReportPath::reportJsonFooter() const { - report_->reportLine("]"); - report_->reportLine("}"); + report_->report("]"); + report_->report("}}"); } void @@ -1094,18 +1088,18 @@ ReportPath::reportJson(const PathEnd *end, PathExpanded expanded(end->path(), this); const Pin *startpoint = expanded.startPath()->vertex(this)->pin(); const Pin *endpoint = expanded.endPath()->vertex(this)->pin(); - stringAppend(result, " \"startpoint\": \"%s\",\n", + result += sta::format(" \"startpoint\": \"{}\",\n", sdc_network_->pathName(startpoint)); - stringAppend(result, " \"endpoint\": \"%s\",\n", + result += sta::format(" \"endpoint\": \"{}\",\n", sdc_network_->pathName(endpoint)); const ClockEdge *src_clk_edge = end->sourceClkEdge(this); const Path *src_clk_path = expanded.clkPath(); const Path *tgt_clk_path = end->targetClkPath(); if (src_clk_edge) { - stringAppend(result, " \"source_clock\": \"%s\",\n", + result += sta::format(" \"source_clock\": \"{}\",\n", src_clk_edge->clock()->name()); - stringAppend(result, " \"source_clock_edge\": \"%s\",\n", + result += sta::format(" \"source_clock_edge\": \"{}\",\n", src_clk_edge->transition()->name()); } if (src_clk_path) @@ -1114,41 +1108,41 @@ ReportPath::reportJson(const PathEnd *end, const ClockEdge *tgt_clk_edge = end->targetClkEdge(this); if (tgt_clk_edge) { - stringAppend(result, " \"target_clock\": \"%s\",\n", + result += sta::format(" \"target_clock\": \"{}\",\n", tgt_clk_edge->clock()->name()); - stringAppend(result, " \"target_clock_edge\": \"%s\",\n", + result += sta::format(" \"target_clock_edge\": \"{}\",\n", tgt_clk_edge->transition()->name()); } if (tgt_clk_path) reportJson(end->targetClkPath(), "target_clock_path", 2, true, result); if (end->checkRole(this)) { - stringAppend(result, " \"data_arrival_time\": %.3e,\n", + result += sta::format(" \"data_arrival_time\": {:.3e},\n", delayAsFloat(end->dataArrivalTimeOffset(this))); const MultiCyclePath *mcp = end->multiCyclePath(); if (mcp) - stringAppend(result, " \"multi_cycle_path\": %d,\n", + result += sta::format(" \"multi_cycle_path\": {},\n", mcp->pathMultiplier()); PathDelay *path_delay = end->pathDelay(); if (path_delay) - stringAppend(result, " \"path_delay\": %.3e,\n", + result += sta::format(" \"path_delay\": {:.3e},\n", path_delay->delay()); - stringAppend(result, " \"crpr\": %.3e,\n", + result += sta::format(" \"crpr\": {:.3e},\n", delayAsFloat(end->checkCrpr(this))); - stringAppend(result, " \"margin\": %.3e,\n", + result += sta::format(" \"margin\": {:.3e},\n", delayAsFloat(end->margin(this))); - stringAppend(result, " \"required_time\": %.3e,\n", + result += sta::format(" \"required_time\": {:.3e},\n", delayAsFloat(end->requiredTimeOffset(this))); - stringAppend(result, " \"slack\": %.3e\n", + result += sta::format(" \"slack\": {:.3e}\n", delayAsFloat(end->slack(this))); } result += "}"; if (!last) result += ","; - report_->reportLineString(result); + report_->reportLine(result); } void @@ -1158,7 +1152,7 @@ ReportPath::reportJson(const Path *path) const result += "{\n"; reportJson(path, "path", 0, false, result); result += "}\n"; - report_->reportLineString(result); + report_->reportLine(result); } void @@ -1179,7 +1173,7 @@ ReportPath::reportJson(const PathExpanded &expanded, bool trailing_comma, std::string &result) const { - stringAppend(result, "%*s\"%s\": [\n", indent, "", path_name); + result += sta::format("{:>{}}\"{}\": [\n", "", indent, path_name); for (size_t i = expanded.startIndex(); i < expanded.size(); i++) { const Path *path = expanded.path(i); const Pin *pin = path->vertex(this)->pin(); @@ -1190,69 +1184,69 @@ ReportPath::reportJson(const PathExpanded &expanded, const MinMax *min_max = path->minMax(this); bool is_driver = network_->isDriver(pin); - stringAppend(result, "%*s {\n", indent, ""); + result += sta::format("{:>{}} {{\n", "", indent); if (inst) { - stringAppend(result, "%*s \"instance\": \"%s\",\n", - indent, "", + result += sta::format("{:>{}} \"instance\": \"{}\",\n", + "", indent, sdc_network_->pathName(inst)); Cell *cell = network_->cell(inst); if (cell) - stringAppend(result, "%*s \"cell\": \"%s\",\n", - indent, "", + result += sta::format("{:>{}} \"cell\": \"{}\",\n", + "", indent, sdc_network_->name(cell)); - stringAppend(result, "%*s \"verilog_src\": \"%s\",\n", - indent, "", + result += sta::format("{:>{}} \"verilog_src\": \"{}\",\n", + "", indent, sdc_network_->getAttribute(inst, "src").c_str()); } - stringAppend(result, "%*s \"pin\": \"%s\",\n", - indent, "", + result += sta::format("{:>{}} \"pin\": \"{}\",\n", + "", indent, sdc_network_->pathName(pin)); if (net) { - stringAppend(result, "%*s \"net\": \"%s\",\n", - indent, "", + result += sta::format("{:>{}} \"net\": \"{}\",\n", + "", indent, sdc_network_->pathName(net)); } PinSeq pins_above; hierPinsAbove(pin, network_, pins_above); if (!pins_above.empty()) { - stringAppend(result, "%*s \"hier_pins\": [\n", indent, ""); + result += sta::format("{:>{}} \"hier_pins\": [\n", "", indent); for (const Pin *hpin : pins_above) { - stringAppend(result, "%*s \"%s\"%s\n", - indent, "", + result += sta::format("{:>{}} \"{}\"{}\n", + "", indent, sdc_network_->pathName(hpin), (hpin != pins_above.back()) ? "," : ""); } - stringAppend(result, "%*s ],\n", indent, ""); + result += sta::format("{:>{}} ],\n", "", indent); } double x, y; bool exists; network_->location(pin, x, y, exists); if (exists) { - stringAppend(result, "%*s \"x\": %.9f,\n", indent, "", x); - stringAppend(result, "%*s \"y\": %.9f,\n", indent, "", y); + result += sta::format("{:>{}} \"x\": {:.9f},\n", "", indent, x); + result += sta::format("{:>{}} \"y\": {:.9f},\n", "", indent, y); } - stringAppend(result, "%*s \"arrival\": %.3e,\n", - indent, "", + result += sta::format("{:>{}} \"arrival\": {:.3e},\n", + "", indent, delayAsFloat(path->arrival())); if (is_driver) - stringAppend(result, "%*s \"capacitance\": %.3e,\n", - indent, "", + result += sta::format("{:>{}} \"capacitance\": {:.3e},\n", + "", indent, graph_delay_calc_->loadCap(pin, rf, scene, min_max)); - stringAppend(result, "%*s \"slew\": %.3e\n", - indent, "", + result += sta::format("{:>{}} \"slew\": {:.3e}\n", + "", indent, delayAsFloat(path->slew(this))); - stringAppend(result, "%*s }%s\n", - indent, "", + result += sta::format("{:>{}} }}{}\n", + "", indent, (i < expanded.size() - 1) ? "," : ""); } - stringAppend(result, "%*s]%s\n", - indent, "", + result += sta::format("{:>{}}]{}\n", + "", indent, trailing_comma ? "," : ""); } @@ -1265,7 +1259,7 @@ ReportPath::reportSlackOnlyHeader() const reportDescription("Group", line); line += ' '; reportField("Slack", field_total_, line); - report_->reportLineString(line); + report_->reportLine(line); reportDashLine(field_description_->width() + field_total_->width() + 1); } @@ -1280,7 +1274,7 @@ ReportPath::reportSlackOnly(const PathEnd *end) const reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line); else reportSpaceFieldDelay(end->slack(this), early_late, line); - report_->reportLineString(line); + report_->reportLine(line); } //////////////////////////////////////////////////////////////// @@ -1329,7 +1323,7 @@ ReportPath::reportMpwHeaderShort() const reportField("Required", field_total_, line); line += ' '; reportField("Actual", field_total_, line); - report_->reportLineString(line); + report_->reportLine(line); line.clear(); reportDescription("Pin", line); @@ -1339,7 +1333,7 @@ ReportPath::reportMpwHeaderShort() const reportField("Width", field_total_, line); line += ' '; reportField("Slack", field_total_, line); - report_->reportLineString(line); + report_->reportLine(line); reportDashLine(field_description_->width() + field_total_->width() * 3 + 3); } @@ -1348,14 +1342,14 @@ void ReportPath::reportShort(const MinPulseWidthCheck &check) const { std::string line; - const char *pin_name = cmd_network_->pathName(check.pin(this)); - const char *hi_low = mpwCheckHiLow(check); - auto what = stdstrPrint("%s (%s)", pin_name, hi_low); + std::string what = sta::format("{} ({})", + cmd_network_->pathName(check.pin(this)), + mpwCheckHiLow(check)); reportDescription(what.c_str(), line); reportSpaceFieldTime(check.minWidth(this), line); reportSpaceFieldDelay(check.width(this), EarlyLate::late(), line); reportSpaceSlack(check.slack(this), line); - report_->reportLineString(line); + report_->reportLine(line); } void @@ -1365,19 +1359,19 @@ ReportPath::reportVerbose(const MinPulseWidthCheck &check) const const char *pin_name = cmd_network_->pathName(check.pin(this)); line += "Pin: "; line += pin_name; - report_->reportLineString(line); + report_->reportLine(line); - report_->reportLine("Check: sequential_clock_pulse_width"); + report_->report("Check: sequential_clock_pulse_width"); reportBlankLine(); reportPathHeader(); const EarlyLate *open_el = EarlyLate::late(); const ClockEdge *open_clk_edge = check.openClkEdge(this); const Clock *open_clk = open_clk_edge->clock(); - const char *open_clk_name = open_clk->name(); - const char *open_rise_fall = asRiseFall(open_clk_edge->transition()); float open_clk_time = open_clk_edge->time(); - auto open_clk_msg = stdstrPrint("clock %s (%s edge)", open_clk_name, open_rise_fall); + std::string open_clk_msg = sta::format("clock {} ({} edge)", + open_clk->name(), + asRiseFall(open_clk_edge->transition())); reportLine(open_clk_msg.c_str(), open_clk_time, open_clk_time, open_el); Arrival open_arrival = check.openArrival(this); @@ -1391,27 +1385,29 @@ ReportPath::reportVerbose(const MinPulseWidthCheck &check) const const EarlyLate *close_el = EarlyLate::late(); const ClockEdge *close_clk_edge = check.closeClkEdge(this); const Clock *close_clk = close_clk_edge->clock(); - const char *close_clk_name = close_clk->name(); - const char *close_rise_fall = asRiseFall(close_clk_edge->transition()); float close_offset = check.closeOffset(this); float close_clk_time = close_clk_edge->time() + close_offset; - auto close_clk_msg = stdstrPrint("clock %s (%s edge)", close_clk_name, close_rise_fall); + std::string close_clk_msg = sta::format("clock {} ({} edge)", + close_clk->name(), + asRiseFall(close_clk_edge->transition())); reportLine(close_clk_msg.c_str(), close_clk_time, close_clk_time, close_el); - Arrival close_arrival = check.closeArrival(this) + close_offset; + + Arrival close_arrival = delaySum(check.closeArrival(this), close_offset, this); reportLine(clk_ideal_prop, check.closeDelay(this), close_arrival, close_el); + reportLine(pin_name, delay_zero, close_arrival, close_el); if (variables_->crprEnabled()) { Crpr pessimism = check.checkCrpr(this); - close_arrival += pessimism; + close_arrival = delaySum(close_arrival, pessimism, this); reportLine("clock reconvergence pessimism", pessimism, close_arrival, close_el); } reportLine("close edge arrival time", close_arrival, close_el); reportDashLine(); float min_width = check.minWidth(this); - const char *hi_low = mpwCheckHiLow(check); - auto rpw_msg = stdstrPrint("required pulse width (%s)", hi_low); + std::string rpw_msg = sta::format("required pulse width ({})", + mpwCheckHiLow(check)); reportLine(rpw_msg.c_str(), min_width, EarlyLate::early()); reportLine("actual pulse width", check.width(this), EarlyLate::early()); reportDashLine(); @@ -1475,7 +1471,7 @@ ReportPath::reportPeriodHeaderShort() const reportField("Min", field_total_, line); line += ' '; reportField("", field_total_, line); - report_->reportLineString(line); + report_->reportLine(line); line.clear(); reportDescription("Pin", line); @@ -1485,7 +1481,7 @@ ReportPath::reportPeriodHeaderShort() const reportField("Period", field_total_, line); line += ' '; reportField("Slack", field_total_, line); - report_->reportLineString(line); + report_->reportLine(line); reportDashLine(field_description_->width() + field_total_->width() * 3 + 3); } @@ -1499,7 +1495,7 @@ ReportPath::reportShort(const MinPeriodCheck &check) const reportSpaceFieldDelay(check.period(), EarlyLate::early(), line); reportSpaceFieldDelay(check.minPeriod(this), EarlyLate::early(), line); reportSpaceSlack(check.slack(this), line); - report_->reportLineString(line); + report_->reportLine(line); } void @@ -1509,7 +1505,7 @@ ReportPath::reportVerbose(const MinPeriodCheck &check) const const char *pin_name = cmd_network_->pathName(check.pin()); line += "Pin: "; line += pin_name; - report_->reportLineString(line); + report_->reportLine(line); reportLine("period", check.period(), EarlyLate::early()); reportLine("min period", -check.minPeriod(this), EarlyLate::early()); @@ -1549,7 +1545,7 @@ ReportPath::reportMaxSkewHeaderShort() const reportField("Actual", field_total_, line); line += ' '; reportField("", field_total_, line); - report_->reportLineString(line); + report_->reportLine(line); line.clear(); reportDescription("Pin", line); @@ -1559,7 +1555,7 @@ ReportPath::reportMaxSkewHeaderShort() const reportField("Skew", field_total_, line); line += ' '; reportField("Slack", field_total_, line); - report_->reportLineString(line); + report_->reportLine(line); reportDashLine(field_description_->width() + field_total_->width() * 3 + 3); } @@ -1569,36 +1565,33 @@ ReportPath::reportShort(const MaxSkewCheck &check) const { std::string line; Pin *clk_pin = check.clkPin(this); - const char *clk_pin_name = network_->pathName(clk_pin); TimingArc *check_arc = check.checkArc(); - auto what = stdstrPrint("%s (%s->%s)", - clk_pin_name, - check_arc->fromEdge()->to_string().c_str(), - check_arc->toEdge()->to_string().c_str()); + std::string what = sta::format("{} ({}->{})", + network_->pathName(clk_pin), + check_arc->fromEdge()->to_string(), + check_arc->toEdge()->to_string()); reportDescription(what.c_str(), line); const EarlyLate *early_late = EarlyLate::early(); reportSpaceFieldDelay(check.maxSkew(this), early_late, line); - reportSpaceFieldDelay(check.skew(), early_late, line); + reportSpaceFieldDelay(check.skew(this), early_late, line); reportSpaceSlack(check.slack(this), line); - report_->reportLineString(line); + report_->reportLine(line); } void ReportPath::reportVerbose(const MaxSkewCheck &check) const { std::string line; - const char *clk_pin_name = cmd_network_->pathName(check.clkPin(this)); line += "Constrained Pin: "; - line += clk_pin_name; - report_->reportLineString(line); + line += cmd_network_->pathName(check.clkPin(this)); + report_->reportLine(line); - const char *ref_pin_name = cmd_network_->pathName(check.refPin(this)); line = "Reference Pin: "; - line += ref_pin_name; - report_->reportLineString(line); + line += cmd_network_->pathName(check.refPin(this)); + report_->reportLine(line); line = "Check: max_skew"; - report_->reportLineString(line); + report_->reportLine(line); reportBlankLine(); reportPathHeader(); @@ -1607,7 +1600,7 @@ ReportPath::reportVerbose(const MaxSkewCheck &check) const reportDashLine(); reportLine("allowable skew", check.maxSkew(this), EarlyLate::early()); - reportLine("actual skew", check.skew(), EarlyLate::late()); + reportLine("actual skew", check.skew(this), EarlyLate::late()); reportDashLine(); reportSlack(check.slack(this)); } @@ -1625,7 +1618,9 @@ ReportPath::reportSkewClkPath(const char *arrival_msg, std::string clk_name = clkName(clk, clk_end_rf != clk_rf); float clk_time = clk_edge->time(); const Arrival &clk_arrival = search_->clkPathArrival(clk_path); - Arrival clk_delay = clk_arrival - clk_time; + Arrival clk_delay = delayDiff(clk_arrival, + clk_time, + this); const MinMax *min_max = clk_path->minMax(this); Vertex *clk_vertex = clk_path->vertex(this); reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time, min_max); @@ -1669,7 +1664,7 @@ ReportPath::reportLimitShortHeader(const ReportField *field) const reportField(field->title(), field, line); line += ' '; reportField("Slack", field, line); - report_->reportLineString(line); + report_->reportLine(line); reportDashLine(field_description_->width() + field->width() * 3 + 3); } @@ -1693,7 +1688,7 @@ ReportPath::reportLimitShort(const ReportField *field, line += (slack >= 0.0) ? " (MET)" : " (VIOLATED)"; - report_->reportLineString(line); + report_->reportLine(line); } void @@ -1720,19 +1715,19 @@ ReportPath::reportLimitVerbose(const ReportField *field, line += scene->name(); line += ")"; } - report_->reportLineString(line); + report_->reportLine(line); line = min_max->to_string(); line += ' '; line += field->name(); line += ' '; reportField(limit, field, line); - report_->reportLineString(line); + report_->reportLine(line); line = field->name(); line += " "; reportField(value, field, line); - report_->reportLineString(line); + report_->reportLine(line); int name_width = strlen(field->name()) + 5; reportDashLine(name_width + field->width()); @@ -1744,7 +1739,7 @@ ReportPath::reportLimitVerbose(const ReportField *field, line += (slack >= 0.0) ? " (MET)" : " (VIOLATED)"; - report_->reportLineString(line); + report_->reportLine(line); } //////////////////////////////////////////////////////////////// @@ -1764,7 +1759,7 @@ ReportPath::reportStartpoint(const PathEnd *end, const char *pin_name = cmd_network_->pathName(pin); if (pathFromClkPin(path, pin)) { const char *clk_name = clk->name(); - auto reason = stdstrPrint("clock source '%s'", clk_name); + std::string reason = sta::format("clock source '{}'", clk_name); reportStartpoint(pin_name, reason); } else if (network_->isTopLevelPort(pin)) { @@ -1772,7 +1767,7 @@ ReportPath::reportStartpoint(const PathEnd *end, && clk != sdc->defaultArrivalClock()) { const char *clk_name = clk->name(); // Pin direction is "input" even for bidirects. - auto reason = stdstrPrint("input port clocked by %s", clk_name); + std::string reason = sta::format("input port clocked by {}", clk_name); reportStartpoint(pin_name, reason); } else @@ -1788,7 +1783,7 @@ ReportPath::reportStartpoint(const PathEnd *end, && clk_rf != clk_path->transition(this); std::string clk_name = clkName(clk, clk_inverted); const char *reg_desc = edgeRegLatchDesc(prev_edge, prev_arc); - auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str()); + std::string reason = sta::format("{} clocked by {}", reg_desc, clk_name); reportStartpoint(inst_name, reason); } else { @@ -1800,8 +1795,8 @@ ReportPath::reportStartpoint(const PathEnd *end, if (clk_edge) { Clock *clk = clk_edge->clock(); if (clk != sdc->defaultArrivalClock()) { - const char *clk_name = clk->name(); - auto reason = stdstrPrint("internal path startpoint clocked by %s", clk_name); + std::string reason = sta::format("internal path startpoint clocked by {}", + clk->name()); reportStartpoint(pin_name, reason); } else @@ -1901,7 +1896,7 @@ ReportPath::reportStartEndPoint(const char *pt, line = key; line += ": "; line += pt; - report_->reportLineString(line); + report_->reportLine(line); line.clear(); for (unsigned i = 0; i < strlen(key); i++) @@ -1910,7 +1905,7 @@ ReportPath::reportStartEndPoint(const char *pt, line += " ("; line += reason; line += ")"; - report_->reportLineString(line); + report_->reportLine(line); } else { line = key; @@ -1919,7 +1914,7 @@ ReportPath::reportStartEndPoint(const char *pt, line += " ("; line += reason; line += ")"; - report_->reportLineString(line); + report_->reportLine(line); } } @@ -1930,22 +1925,22 @@ ReportPath::reportGroup(const PathEnd *end) const line = "Path Group: "; PathGroup *group = end->pathGroup(); line += group ? group->name() : "(none)"; - report_->reportLineString(line); + report_->reportLine(line); line = "Path Type: "; line += end->minMax(this)->to_string(); - report_->reportLineString(line); + report_->reportLine(line); if (modes_.size() > 1) { line = "Mode: "; line += end->path()->mode(this)->name(); - report_->reportLineString(line); + report_->reportLine(line); } if (multiScene()) { line = "Corner: "; line += end->path()->scene(this)->name(); - report_->reportLineString(line); + report_->reportLine(line); } } @@ -1954,7 +1949,7 @@ ReportPath::reportGroup(const PathEnd *end) const std::string ReportPath::checkRoleReason(const PathEnd *end) const { - return stdstrPrint("%s time", end->checkRole(this)->to_string().c_str()); + return sta::format("{} time", end->checkRole(this)->to_string()); } std::string @@ -2066,15 +2061,19 @@ ReportPath::reportSrcClkAndPath(const Path *path, const Path *clk_path = expanded.clkPath(); const RiseFall *clk_end_rf; if (clk_path) { - clk_end_time = search_->clkPathArrival(clk_path) + time_offset; - clk_delay = clk_end_time - clk_time; + clk_end_time = delaySum(search_->clkPathArrival(clk_path), + time_offset, + this); + clk_delay = delayDiff(clk_end_time, + clk_time, + this); clk_end_rf = clk_path->transition(this); } else { // Path from input port or clk used as data. clk_end_rf = clk_rf; - clk_delay = clk_insertion + clk_latency; - clk_end_time = clk_time + clk_delay; + clk_delay = delaySum(clk_insertion, clk_latency, this); + clk_end_time = delaySum(clk_time, clk_delay, this); const Path *first_path = expanded.startPath(); const InputDelay *input_delay = pathInputDelay(first_path); @@ -2086,8 +2085,12 @@ ReportPath::reportSrcClkAndPath(const Path *path, pathInputDelayRefPath(first_path, input_delay, ref_path); if (!ref_path.isNull()) { const Arrival &ref_end_time = ref_path.arrival(); - clk_delay = ref_end_time - clk_time; - clk_end_time = ref_end_time + time_offset; + clk_delay = delayDiff(ref_end_time, + clk_time, + this); + clk_end_time = delaySum(ref_end_time, + time_offset, + this); input_has_ref_path = true; } } @@ -2127,8 +2130,10 @@ ReportPath::reportSrcClkAndPath(const Path *path, reportPath1(path, expanded, true, time_offset); else { Arrival clk_arrival = clk_end_time; - Arrival end_arrival = path->arrival() + time_offset; - Delay clk_delay = end_arrival - clk_arrival; + Arrival end_arrival = delaySum(path->arrival(), + time_offset, + this); + Delay clk_delay = delayDiff(end_arrival, clk_arrival, this); reportLine("clock network delay", clk_delay, end_arrival, early_late); Vertex *end_vertex = path->vertex(this); @@ -2187,7 +2192,7 @@ ReportPath::reportTgtClk(const PathEnd *end, bool is_prop) const { const ClockEdge *clk_edge = end->targetClkEdge(this); - Clock *clk = clk_edge->clock(); + const Clock *clk = clk_edge->clock(); const RiseFall *clk_rf = clk_edge->transition(); const RiseFall *clk_end_rf = end->targetClkEndTrans(this); std::string clk_name = clkName(clk, clk_end_rf != clk_rf); @@ -2196,7 +2201,7 @@ ReportPath::reportTgtClk(const PathEnd *end, + end->targetClkMcpAdjustment(this) + src_offset; Arrival clk_delay = end->targetClkDelay(this); - Arrival clk_arrival = clk_time + clk_delay; + Arrival clk_arrival = delaySum(clk_delay, clk_time, this); const MinMax *min_max = end->path()->tgtClkMinMax(this); const Path *clk_path = end->targetClkPath(); reportClkLine(clk, clk_name.c_str(), clk_end_rf, prev_time, clk_time, min_max); @@ -2225,7 +2230,7 @@ ReportPath::reportTgtClk(const PathEnd *end, } else { // Output departure. - Arrival clk_arrival = clk_time + clk_delay; + Arrival clk_arrival = delaySum(clk_time, clk_delay, this); reportLine(clkNetworkDelayIdealProp(clk->isPropagated()), clk_delay, clk_arrival, min_max); } @@ -2241,9 +2246,11 @@ ReportPath::reportTgtClk(const PathEnd *end, if (clk_path) { Vertex *clk_vertex = clk_path->vertex(this); reportLine(descriptionField(clk_vertex).c_str(), - prev_time - + end->targetClkArrival(this) - + end->sourceClkOffset(this), + delaySum(delaySum(prev_time, + end->targetClkArrival(this), + this), + end->sourceClkOffset(this), + this), min_max, clk_end_rf); } } @@ -2264,7 +2271,7 @@ ReportPath::tgtClkInsertionOffet(const Path *clk_path, min_max, min_max, mode); Arrival tgt_insertion = search_->clockInsertion(clk, src_pin, clk_rf, min_max, early_late, mode); - return delayAsFloat(tgt_insertion - path_insertion); + return delayAsFloat(delayDiff(tgt_insertion, path_insertion, this)); } bool @@ -2325,13 +2332,20 @@ ReportPath::reportClkLine(const Clock *clk, const MinMax *min_max) const { const char *rise_fall = asRiseFall(clk_rf); - auto clk_msg = stdstrPrint("clock %s (%s edge)", clk_name, rise_fall); + std::string clk_msg = sta::format("clock {} ({} edge)", clk_name, rise_fall); if (clk->isPropagated()) - reportLine(clk_msg.c_str(), clk_time - prev_time, clk_time, min_max); + reportLine(clk_msg.c_str(), + delayDiff(clk_time, prev_time, this), + clk_time, + min_max); else { // Report ideal clock slew. float clk_slew = clk->slew(clk_rf, min_max); - reportLine(clk_msg.c_str(), clk_slew, clk_time - prev_time, clk_time, min_max); + reportLine(clk_msg.c_str(), + clk_slew, + delayDiff(clk_time, prev_time, this), + clk_time, + min_max); } } @@ -2433,13 +2447,16 @@ ReportPath::reportClkSrcLatency(Arrival insertion, float clk_time, const EarlyLate *early_late) const { - reportLine("clock source latency", insertion, clk_time + insertion, early_late); + Arrival clk_arrival = delaySum(clk_time, + insertion, + this); + reportLine("clock source latency", insertion, clk_arrival, early_late); } void ReportPath::reportPathLine(const Path *path, - Arrival incr, - Arrival time, + const Delay &incr, + const Arrival &time, const char *line_case) const { Vertex *vertex = path->vertex(this); @@ -2461,7 +2478,7 @@ ReportPath::reportPathLine(const Path *path, if (is_driver && field_capacitance_->enabled()) cap = graph_delay_calc_->loadCap(pin, rf, scene, min_max); reportLine(what.c_str(), cap, slew, field_blank_, - incr, time, false, early_late, rf, src_attr, + incr, field_blank_, time, false, early_late, rf, src_attr, line_case); } @@ -2474,13 +2491,16 @@ ReportPath::reportRequired(const PathEnd *end, float macro_clk_tree_delay = end->macroClkTreeDelay(this); ArcDelay margin = end->margin(this); if (end->minMax(this) == MinMax::min()) { - margin = -margin; + margin = delayDiff(delay_zero, margin, this); macro_clk_tree_delay = -macro_clk_tree_delay; } if (macro_clk_tree_delay != 0.0) reportLine("macro clock tree delay", -macro_clk_tree_delay, - req_time + margin, early_late); - reportLine(margin_msg.c_str(), -margin, req_time, early_late); + delaySum(req_time, margin, this), early_late); + reportLine(margin_msg.c_str(), + delayDiff(delay_zero, margin, this), + req_time, + early_late); reportLine("data required time", req_time, early_late); reportDashLine(); } @@ -2531,7 +2551,7 @@ ReportPath::reportCommonClkPessimism(const PathEnd *end, { if (variables_->crprEnabled()) { Crpr pessimism = end->checkCrpr(this); - clk_arrival += pessimism; + clk_arrival = delaySum(clk_arrival, pessimism, this); reportLine("clock reconvergence pessimism", pessimism, clk_arrival, end->clkEarlyLate(this)); } @@ -2543,11 +2563,15 @@ ReportPath::reportClkUncertainty(const PathEnd *end, { const EarlyLate *early_late = end->clkEarlyLate(this); float uncertainty = end->targetNonInterClkUncertainty(this); - clk_arrival += uncertainty; + clk_arrival = delaySum(clk_arrival, + uncertainty, + this); if (uncertainty != 0.0) reportLine("clock uncertainty", uncertainty, clk_arrival, early_late); float inter_uncertainty = end->interClkUncertainty(this); - clk_arrival += inter_uncertainty; + clk_arrival = delaySum(clk_arrival, + inter_uncertainty, + this); if (inter_uncertainty != 0.0) reportLine("inter-clock uncertainty", inter_uncertainty, clk_arrival, early_late); @@ -2581,7 +2605,7 @@ ReportPath::reportPath(const Path *path) const case ReportPathFormat::endpoint: case ReportPathFormat::summary: case ReportPathFormat::slack_only: - report_->reportLine("Format not supported."); + report_->report("Format not supported."); break; } } @@ -2659,7 +2683,9 @@ ReportPath::reportPath4(const Path *path, reportPath5(latch_enable_path, enable_expanded, skip_first_path, propagated_clk, report_clk_path, time_offset); } - Arrival time = latch_enable_time + latch_time_given; + Arrival time = delaySum(latch_enable_time, + latch_time_given, + this); Arrival incr = latch_time_given; if (delayGreaterEqual(incr, 0.0, this)) reportLine("time given to startpoint", incr, time, early_late); @@ -2668,7 +2694,10 @@ ReportPath::reportPath4(const Path *path, // Override latch D arrival with enable + given. reportPathLine(expanded.path(0), delay_zero, time, "latch_D"); reportPath6(path, expanded, 1, propagated_clk, report_clk_path, - latch_enable_time + latch_time_given, time_offset); + delaySum(latch_enable_time, + latch_time_given, + this), + time_offset); } } else @@ -2689,7 +2718,9 @@ ReportPath::reportPath5(const Path *path, if (skip_first_path) { path_first_index = 1; const Path *start = expanded.path(0); - prev_time = start->arrival() + time_offset; + prev_time = delaySum(start->arrival(), + time_offset, + this); } reportPath6(path, expanded, path_first_index, propagated_clk, report_clk_path, prev_time, time_offset); @@ -2717,7 +2748,7 @@ ReportPath::reportPath6(const Path *path, const TimingArc *prev_arc = path1->prevArc(this); Vertex *vertex = path1->vertex(this); Pin *pin = vertex->pin(); - Arrival time = path1->arrival() + time_offset; + Arrival time = delaySum(path1->arrival(), time_offset, this); Delay incr = 0.0; const char *line_case = nullptr; bool is_clk_start = path1->vertex(this) == clk_start; @@ -2746,7 +2777,9 @@ ReportPath::reportPath6(const Path *path, // The delay calculator annotates wire delays on the edges // from the input to the loads. Report the wire delay on the // input pin instead. - Arrival next_time = next_path->arrival() + time_offset; + Arrival next_time = delaySum(next_path->arrival(), + time_offset, + this); incr = delayIncr(next_time, time, min_max); time = next_time; line_case = "input_drive"; @@ -2755,7 +2788,7 @@ ReportPath::reportPath6(const Path *path, if (!propagated_clk) // Clock latency at path endpoint in case latency was set // on a clock pin other than the clock source. - time = search_->clkPathArrival(path1) + time_offset; + time = delaySum(search_->clkPathArrival(path1), time_offset, this); incr = 0.0; line_case = "clk_first"; } @@ -2772,7 +2805,9 @@ ReportPath::reportPath6(const Path *path, if (!propagated_clk) { // Ideal clock. const ClockEdge *src_clk_edge = path->clkEdge(this); - time = search_->clkPathArrival(path1) + time_offset; + time = delaySum(search_->clkPathArrival(path1), + time_offset, + this); if (src_clk_edge) { Clock *src_clk = src_clk_edge->clock(); const RiseFall *src_clk_rf = src_clk_edge->transition(); @@ -2803,6 +2838,8 @@ ReportPath::reportPath6(const Path *path, } if (vertex->isDriver(network_)) { + // Report delay arc pocv variation between input and driver. + reportVariation(path1); float cap = field_blank_; float fanout = field_blank_; if (field_capacitance_->enabled()) @@ -2811,13 +2848,13 @@ ReportPath::reportPath6(const Path *path, fanout = drvrFanout(vertex, scene, min_max); const std::string what = descriptionField(vertex); reportLine(what.c_str(), cap, slew, fanout, - incr, time, false, min_max, rf, src_attr, + incr, field_blank_, time, false, min_max, rf, src_attr, line_case); if (report_net_) { const std::string what2 = descriptionNet(pin); reportLine(what2.c_str(), field_blank_, field_blank_, field_blank_, - field_blank_, field_blank_, false, min_max, + field_blank_, field_blank_, field_blank_, false, min_max, nullptr, src_attr, ""); } prev_time = time; @@ -2830,7 +2867,7 @@ ReportPath::reportPath6(const Path *path, || is_clk_start) { const std::string what = descriptionField(vertex); reportLine(what.c_str(), field_blank_, slew, field_blank_, - incr, time, false, min_max, rf, src_attr, + incr, field_blank_, time, false, min_max, rf, src_attr, line_case); prev_time = time; } @@ -2841,6 +2878,59 @@ ReportPath::reportPath6(const Path *path, } } +void +ReportPath::reportVariation(const Path *path) const +{ + if (field_variation_->enabled()) { + const Edge *prev_edge = path->prevEdge(this); + if (prev_edge) { + const TimingArc *prev_arc = path->prevArc(this); + const MinMax *min_max = path->minMax(this); + DcalcAPIndex slew_index = path->dcalcAnalysisPtIndex(this); + const ArcDelay &arc_delay=graph_->arcDelay(prev_edge, prev_arc,slew_index); + switch (variables_->pocvMode()) { + case PocvMode::normal: { + float std_dev = arc_delay.stdDev(); + reportLine("sigma", field_blank_, field_blank_, field_blank_, + field_blank_, std_dev, field_blank_, true, min_max, nullptr, + "", nullptr); + break; + } + case PocvMode::skew_normal: { + float mean = arc_delay.mean(); + reportLine("mean", field_blank_, field_blank_, field_blank_, + field_blank_, mean, field_blank_, true, min_max, nullptr, + "", nullptr); + float mean_shift = arc_delay.meanShift(); + reportLine("mean_shift", field_blank_, field_blank_, field_blank_, + field_blank_, mean_shift, field_blank_, true, min_max, nullptr, + "", nullptr); + float std_dev = arc_delay.stdDev(); + reportLine("std_dev", field_blank_, field_blank_, field_blank_, + field_blank_, std_dev, field_blank_, true, min_max, nullptr, + "", nullptr); + // skewness is dimensionless, so scale it to the field's time units. + float skewness = arc_delay.skewness() * units_->timeUnit()->scale(); + reportLine("skewness", field_blank_, field_blank_, field_blank_, + field_blank_, skewness, field_blank_, true, min_max, nullptr, + "", nullptr); + break; + } + default: + break; + } + } + } +} + +Delay +ReportPath::delayIncr(const Delay &time, + const Delay &prev, + const MinMax *min_max) const +{ + return delayAsFloat(time, min_max, this) - delayAsFloat(prev, min_max, this); +} + void ReportPath::reportHierPinsThru(const Path *path) const { @@ -2850,24 +2940,13 @@ ReportPath::reportHierPinsThru(const Path *path) const for (const Pin *hpin : hierPinsThruEdge(prev_edge, network_, graph_)) { const std::string what = descriptionField(hpin); reportLine(what.c_str(), field_blank_, field_blank_, field_blank_, - field_blank_, field_blank_, false, path->minMax(this), + field_blank_, field_blank_, field_blank_, false, path->minMax(this), nullptr, "", ""); } } } } -Delay -ReportPath::delayIncr(Delay time, - Delay prev, - const MinMax *min_max) const -{ - if (report_sigmas_) - return delayRemove(time, prev); - else - return delayAsFloat(time, min_max, this) - delayAsFloat(prev, min_max, this); -} - bool ReportPath::nextArcAnnotated(const Path *next_path, size_t next_index, @@ -2908,7 +2987,7 @@ ReportPath::descriptionField(const Pin *pin) const Instance *inst = network_->instance(pin); name2 = network_->cellName(inst); } - return stdstrPrint("%s (%s)", pin_name, name2); + return sta::format("{} ({})", pin_name, name2); } std::string @@ -2916,14 +2995,14 @@ ReportPath::descriptionNet(const Pin *pin) const { if (network_->isTopLevelPort(pin)) { const char *pin_name = cmd_network_->pathName(pin); - return stdstrPrint("%s (net)", pin_name); + return sta::format("{} (net)", pin_name); } else { Net *net = network_->net(pin); if (net) { Net *highest_net = network_->highestNetAbove(net); const char *net_name = cmd_network_->pathName(highest_net); - return stdstrPrint("%s (net)", net_name); + return sta::format("{} (net)", net_name); } else return "(unconnected)"; @@ -2974,7 +3053,9 @@ ReportPath::reportInputExternalDelay(const Path *first_path, const Pin *first_pin = first_path->pin(graph_); if (!pathFromClkPin(first_path, first_pin)) { const RiseFall *rf = first_path->transition(this); - Arrival time = first_path->arrival() + time_offset; + Arrival time = delaySum(first_path->arrival(), + time_offset, + this); const EarlyLate *early_late = first_path->minMax(this); InputDelay *input_delay = pathInputDelay(first_path); if (input_delay) { @@ -3044,7 +3125,7 @@ ReportPath::reportPathHeader() const } } trimRight(line); - report_->reportLineString(line); + report_->reportLine(line); reportDashLine(); } @@ -3054,7 +3135,7 @@ ReportPath::reportLine(const char *what, Delay total, const EarlyLate *early_late) const { - reportLine(what, field_blank_, field_blank_, field_blank_, + reportLine(what, field_blank_, field_blank_, field_blank_, field_blank_, field_blank_, total, false, early_late, nullptr, "", nullptr); } @@ -3066,8 +3147,8 @@ ReportPath::reportLineNegative(const char *what, const EarlyLate *early_late) const { reportLine(what, field_blank_, field_blank_, field_blank_, - field_blank_, total, true, early_late, nullptr, - "", nullptr); + field_blank_, field_blank_, total, true /* tota_with_minus */, + early_late, nullptr, "", nullptr); } // Report total, and transition suffix. @@ -3078,55 +3159,56 @@ ReportPath::reportLine(const char *what, const RiseFall *rf) const { reportLine(what, field_blank_, field_blank_, field_blank_, - field_blank_, total, false, early_late, rf, "", + field_blank_, field_blank_, total, false, early_late, rf, "", nullptr); } // Report increment, and total. void ReportPath::reportLine(const char *what, - Delay incr, - Delay total, + const Delay &incr, + const Delay &total, const EarlyLate *early_late) const { reportLine(what, field_blank_, field_blank_, field_blank_, - incr, total, false, early_late, nullptr, "", + incr, field_blank_, total, false, early_late, nullptr, "", nullptr); } // Report increment, total, and transition suffix. void ReportPath::reportLine(const char *what, - Delay incr, - Delay total, + const Delay &incr, + const Delay &total, const EarlyLate *early_late, const RiseFall *rf) const { reportLine(what, field_blank_, field_blank_, field_blank_, - incr, total, false, early_late, rf, "", + incr, field_blank_, total, false, early_late, rf, "", nullptr); } // Report slew, increment, and total. void ReportPath::reportLine(const char *what, - Slew slew, - Delay incr, - Delay total, + const Slew &slew, + const Delay &incr, + const Delay &total, const EarlyLate *early_late) const { reportLine(what, field_blank_, slew, field_blank_, - incr, total, false, early_late, nullptr, + incr, field_blank_, total, false, early_late, nullptr, "", nullptr); } void ReportPath::reportLine(const char *what, float cap, - Slew slew, + const Slew &slew, float fanout, - Delay incr, - Delay total, + const Delay &incr, + float variation, + const Delay &total, bool total_with_minus, const EarlyLate *early_late, const RiseFall *rf, @@ -3149,9 +3231,9 @@ ReportPath::reportLine(const char *what, if (fanout == field_blank_) reportFieldBlank(field, line); else - line += stdstrPrint("%*d", - field_fanout_->width(), - static_cast(fanout)); + line += sta::format("{:{}}", + static_cast(fanout), + field_fanout_->width()); } else if (field == field_capacitance_) reportField(cap, field, line); @@ -3159,6 +3241,8 @@ ReportPath::reportLine(const char *what, reportFieldDelay(slew, early_late, field, line); else if (field == field_incr_) reportFieldDelay(incr, early_late, field, line); + else if (field == field_variation_) + reportFieldDelay(variation, early_late, field, line); else if (field == field_total_) { if (total_with_minus) reportFieldDelayMinus(total, early_late, field, line); @@ -3171,6 +3255,8 @@ ReportPath::reportLine(const char *what, else reportFieldBlank(field, line); } + else if (field == field_variation_) + reportFieldBlank(field, line); else if (field == field_src_attr_) { if (src_attr != "") reportField(src_attr.c_str(), field, line); @@ -3187,7 +3273,7 @@ ReportPath::reportLine(const char *what, // Trim trailing spaces and report the line. std::string line_stdstr = line; trimRight(line_stdstr); - report_->reportLineString(line_stdstr.c_str()); + report_->reportLine(line_stdstr); } //////////////////////////////////////////////////////////////// @@ -3195,7 +3281,7 @@ ReportPath::reportLine(const char *what, // Only the total field. void ReportPath::reportLineTotal(const char *what, - Delay incr, + const Delay &incr, const EarlyLate *early_late) const { reportLineTotal1(what, incr, false, early_late); @@ -3204,7 +3290,7 @@ ReportPath::reportLineTotal(const char *what, // Only the total field and always with leading minus sign. void ReportPath::reportLineTotalMinus(const char *what, - Delay decr, + const Delay &decr, const EarlyLate *early_late) const { reportLineTotal1(what, decr, true, early_late); @@ -3212,7 +3298,7 @@ ReportPath::reportLineTotalMinus(const char *what, void ReportPath::reportLineTotal1(const char *what, - Delay incr, + const Delay &incr, bool incr_with_minus, const EarlyLate *early_late) const { @@ -3223,7 +3309,7 @@ ReportPath::reportLineTotal1(const char *what, reportFieldDelayMinus(incr, early_late, field_total_, line); else reportFieldDelay(incr, early_late, field_total_, line); - report_->reportLineString(line); + report_->reportLine(line); } void @@ -3270,11 +3356,11 @@ ReportPath::reportFieldTime(float value, if (delayAsFloat(value) == field_blank_) reportFieldBlank(field, line); else { - const char *str = units_->timeUnit()->asString(value, digits_); - if (stringEq(str, minus_zero_)) + std::string str = units_->timeUnit()->asString(value, digits_); + if (str == minus_zero_) // Filter "-0.00" fields. str = plus_zero_; - reportField(str, field, line); + reportField(str.c_str(), field, line); } } @@ -3287,7 +3373,7 @@ ReportPath::reportSpaceFieldTime(float value, } void -ReportPath::reportSpaceFieldDelay(Delay value, +ReportPath::reportSpaceFieldDelay(const Delay &value, const EarlyLate *early_late, std::string &line) const { @@ -3296,20 +3382,20 @@ ReportPath::reportSpaceFieldDelay(Delay value, } void -ReportPath::reportTotalDelay(Delay value, +ReportPath::reportTotalDelay(const Delay &value, const EarlyLate *early_late, std::string &line) const { - const char *str = delayAsString(value, early_late, this, digits_); - if (stringEq(str, minus_zero_)) + std::string str = delayAsString(value, early_late, digits_, this); + if (str == minus_zero_) // Filter "-0.00" fields. str = plus_zero_; - reportField(str, field_total_, line); + reportField(str.c_str(), field_total_, line); } // Total time always with leading minus sign. void -ReportPath::reportFieldDelayMinus(Delay value, +ReportPath::reportFieldDelayMinus(const Delay &value, const EarlyLate *early_late, const ReportField *field, std::string &line) const @@ -3317,33 +3403,30 @@ ReportPath::reportFieldDelayMinus(Delay value, if (delayAsFloat(value) == field_blank_) reportFieldBlank(field, line); else { - const char *str = report_sigmas_ - ? delayAsString(-value, this, digits_) - // Opposite min/max for negative value. - : delayAsString(-value, early_late->opposite(), this, digits_); - if (stringEq(str, plus_zero_)) + // Opposite min/max for negative value. + std::string str = delayAsString(delayDiff(delay_zero, value, this), + early_late->opposite(), digits_, this); + if (str == plus_zero_) // Force leading minus sign. str = minus_zero_; - reportField(str, field, line); + reportField(str.c_str(), field, line); } } void -ReportPath::reportFieldDelay(Delay value, +ReportPath::reportFieldDelay(const Delay &value, const EarlyLate *early_late, const ReportField *field, std::string &line) const { - if (delayAsFloat(value) == field_blank_) + if (value.mean() == field_blank_) reportFieldBlank(field, line); else { - const char *str = report_sigmas_ - ? delayAsString(value, this, digits_) - : delayAsString(value, early_late, this, digits_); - if (stringEq(str, minus_zero_)) + std::string str = delayAsString(value, early_late, digits_, this); + if (str == minus_zero_) // Filter "-0.00" fields. str = plus_zero_; - reportField(str, field, line); + reportField(str.c_str(), field, line); } } @@ -3357,13 +3440,12 @@ ReportPath::reportField(float value, else { Unit *unit = field->unit(); if (unit) { - const char *value_str = unit->asString(value, digits_); - reportField(value_str, field, line); + std::string value_str = unit->asString(value, digits_); + reportField(value_str.c_str(), field, line); } else { // fanout - std::string value_str; - stringPrint(value_str, "%.0f", value); + std::string value_str = sta::format("{:.0f}", value); reportField(value_str.c_str(), field, line); } } @@ -3400,7 +3482,7 @@ ReportPath::reportDashLine() const } } line += "------"; - report_->reportLineString(line); + report_->reportLine(line); } void @@ -3409,7 +3491,7 @@ ReportPath::reportDashLine(int line_width) const std::string line; for (int i = 0; i < line_width; i++) line += '-'; - report_->reportLineString(line); + report_->reportLine(line); } void diff --git a/search/ReportPath.hh b/search/ReportPath.hh index 642d4314..cec91ba7 100644 --- a/search/ReportPath.hh +++ b/search/ReportPath.hh @@ -56,12 +56,11 @@ public: bool report_cap, bool report_slew, bool report_fanout, + bool report_variation, bool report_src_attr); int digits() const { return digits_; } void setDigits(int digits); void setNoSplit(bool no_split); - bool reportSigmas() const { return report_sigmas_; } - void setReportSigmas(bool report); ReportField *findField(const char *name) const; // Header above reportPathEnd results. @@ -267,8 +266,8 @@ protected: float clk_time, const EarlyLate *early_late) const; void reportPathLine(const Path *path, - Delay incr, - Arrival time, + const Delay &incr, + const Arrival &time, const char *line_case) const; void reportCommonClkPessimism(const PathEnd *end, Arrival &clk_arrival) const ; @@ -331,6 +330,7 @@ protected: bool report_clk_path, Arrival prev_time, float time_offset) const; + void reportVariation(const Path *path) const; void reportHierPinsThru(const Path *path) const; void reportInputExternalDelay(const Path *path, float time_offset) const; @@ -345,38 +345,39 @@ protected: const EarlyLate *early_late, const RiseFall *rf) const; void reportLine(const char *what, - Delay incr, - Delay total, + const Delay &incr, + const Delay &total, const EarlyLate *early_late) const; void reportLine(const char *what, - Delay incr, - Delay total, + const Delay &incr, + const Delay &total, const EarlyLate *early_late, const RiseFall *rf) const; void reportLine(const char *what, - Slew slew, - Delay incr, - Delay total, + const Slew &slew, + const Delay &incr, + const Delay &total, const EarlyLate *early_late) const; void reportLine(const char *what, float cap, - Slew slew, + const Slew &slew, float fanout, - Delay incr, - Delay total, + const Delay &incr, + float variation, + const Delay &total, bool total_with_minus, const EarlyLate *early_late, const RiseFall *rf, std::string src_attr, const char *line_case) const; void reportLineTotal(const char *what, - Delay incr, + const Delay &incr, const EarlyLate *early_late) const; void reportLineTotalMinus(const char *what, - Delay decr, + const Delay &decr, const EarlyLate *early_late) const; void reportLineTotal1(const char *what, - Delay incr, + const Delay &incr, bool incr_with_minus, const EarlyLate *early_late) const; void reportDashLineTotal() const; @@ -391,17 +392,17 @@ protected: std::string &result) const; void reportSpaceFieldTime(float value, std::string &result) const; - void reportSpaceFieldDelay(Delay value, + void reportSpaceFieldDelay(const Delay &value, const EarlyLate *early_late, std::string &result) const; - void reportFieldDelayMinus(Delay value, + void reportFieldDelayMinus(const Delay &value, const EarlyLate *early_late, const ReportField *field, std::string &result) const; - void reportTotalDelay(Delay value, + void reportTotalDelay(const Delay &value, const EarlyLate *early_late, std::string &result) const; - void reportFieldDelay(Delay value, + void reportFieldDelay(const Delay &value, const EarlyLate *early_late, const ReportField *field, std::string &result) const; @@ -465,8 +466,8 @@ protected: Path &ref_path) const; const char *asRisingFalling(const RiseFall *rf) const; const char *asRiseFall(const RiseFall *rf) const; - Delay delayIncr(Delay time, - Delay prev, + Delay delayIncr(const Delay &time, + const Delay &prev, const MinMax *min_max) const; // Path options. @@ -477,7 +478,6 @@ protected: bool report_net_; bool no_split_; int digits_; - bool report_sigmas_; int start_end_pt_width_; @@ -487,14 +487,16 @@ protected: ReportField *field_capacitance_; ReportField *field_slew_; ReportField *field_fanout_; + ReportField *field_variation_; ReportField *field_src_attr_; ReportField *field_edge_; ReportField *field_case_; - const char *plus_zero_; - const char *minus_zero_; + std::string plus_zero_; + std::string minus_zero_; - static const float field_blank_; + int field_width_extra_; + static constexpr float field_blank_ = -1; static const float field_skip_; }; diff --git a/search/Search.cc b/search/Search.cc index 92fe7f7d..ae6bbfbf 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "Search.hh" @@ -28,7 +28,7 @@ #include "ContainerHelpers.hh" #include "Mutex.hh" -#include "Report.hh" +#include "Report.hh" #include "Debug.hh" #include "Stats.hh" #include "Fuzzy.hh" @@ -89,11 +89,9 @@ EvalPred::searchThru(Edge *edge, { const TimingRole *role = edge->role(); return SearchPred0::searchThru(edge, mode) - && (sta_->variables()->dynamicLoopBreaking() - || !edge->isDisabledLoop()) - && (search_thru_latches_ - || role->isLatchDtoQ() - || sta_->latches()->latchDtoQState(edge, mode) == LatchEnableState::open); + && (sta_->variables()->dynamicLoopBreaking() || !edge->isDisabledLoop()) + && (search_thru_latches_ || role->isLatchDtoQ() + || sta_->latches()->latchDtoQState(edge, mode) == LatchEnableState::open); } bool @@ -103,10 +101,9 @@ EvalPred::searchTo(const Vertex *to_vertex, const Pin *to_pin = to_vertex->pin(); const Sdc *sdc = mode->sdc(); return SearchPred0::searchTo(to_vertex, mode) - && !(sdc->isLeafPinClock(to_pin) - && !sdc->isPathDelayInternalTo(to_pin)) - // Fanin paths are broken by path delay internal pin startpoints. - && !sdc->isPathDelayInternalFromBreak(to_pin); + && !(sdc->isLeafPinClock(to_pin) && !sdc->isPathDelayInternalTo(to_pin)) + // Fanin paths are broken by path delay internal pin startpoints. + && !sdc->isPathDelayInternalFromBreak(to_pin); } //////////////////////////////////////////////////////////////// @@ -130,8 +127,7 @@ bool SearchThru::searchThru(Edge *edge, const Mode *mode) const { - return EvalPred::searchThru(edge, mode) - && !edge->role()->isLatchDtoQ(); + return EvalPred::searchThru(edge, mode) && !edge->role()->isLatchDtoQ(); } //////////////////////////////////////////////////////////////// @@ -159,7 +155,6 @@ protected: TagGroupBldr *tag_bldr_; const StaState *sta_; - }; SearchAdj::SearchAdj(TagGroupBldr *tag_bldr, @@ -184,30 +179,25 @@ SearchAdj::searchThru(Edge *edge, const TimingRole *role = edge->role(); const Variables *variables = sta_->variables(); return !role->isTimingCheck() - && !role->isLatchDtoQ() - // Register/latch preset/clr edges are disabled by default. - && !(role == TimingRole::regSetClr() - && !variables->presetClrArcsEnabled()) - && !(edge->isBidirectInstPath() - && !variables->bidirectInstPathsEnabled()) - && (!edge->isDisabledLoop() - || (variables->dynamicLoopBreaking() - && hasPendingLoopPaths(edge))); + && !role->isLatchDtoQ() + // Register/latch preset/clr edges are disabled by default. + && !(role == TimingRole::regSetClr() && !variables->presetClrArcsEnabled()) + && !(edge->isBidirectInstPath() && !variables->bidirectInstPathsEnabled()) + && (!edge->isDisabledLoop() + || (variables->dynamicLoopBreaking() && hasPendingLoopPaths(edge))); } bool SearchAdj::loopEnabled(Edge *edge) const { return !edge->isDisabledLoop() - || (sta_->variables()->dynamicLoopBreaking() - && hasPendingLoopPaths(edge)); + || (sta_->variables()->dynamicLoopBreaking() && hasPendingLoopPaths(edge)); } bool SearchAdj::hasPendingLoopPaths(Edge *edge) const { - if (tag_bldr_ - && tag_bldr_->hasLoopTag()) { + if (tag_bldr_ && tag_bldr_->hasLoopTag()) { const Graph *graph = sta_->graph(); Search *search = sta_->search(); Vertex *from_vertex = edge->from(graph); @@ -218,8 +208,7 @@ SearchAdj::hasPendingLoopPaths(Edge *edge) const // does not matter. Tag *to_tag = search->thruTag(from_tag, edge, RiseFall::rise(), nullptr); if (to_tag - && (prev_tag_group == nullptr - || !prev_tag_group->hasTag(from_tag))) + && (prev_tag_group == nullptr || !prev_tag_group->hasTag(from_tag))) return true; } } @@ -243,19 +232,24 @@ Search::Search(StaState *sta) : crpr_approx_missing_requireds_(true), search_thru_(new SearchThru(this)), - search_adj_(new SearchAdj(nullptr, this)), + search_adj_(new SearchAdj(nullptr, + this)), eval_pred_(new EvalPred(this)), - + arrivals_exist_(false), arrivals_seeded_(false), invalid_arrivals_(makeVertexSet(this)), - arrival_iter_(new BfsFwdIterator(BfsIndex::arrival, nullptr, this)), + arrival_iter_(new BfsFwdIterator(BfsIndex::arrival, + nullptr, + this)), arrival_visitor_(new ArrivalVisitor(this)), requireds_exist_(false), requireds_seeded_(false), invalid_requireds_(makeVertexSet(this)), - required_iter_(new BfsBkwdIterator(BfsIndex::required, search_adj_, this)), + required_iter_(new BfsBkwdIterator(BfsIndex::required, + search_adj_, + this)), tns_exists_(false), invalid_tns_(makeVertexSet(this)), @@ -263,12 +257,14 @@ Search::Search(StaState *sta) : clk_info_set_(new ClkInfoSet(ClkInfoLess(this))), tag_capacity_(128), - tags_(new Tag*[tag_capacity_]), - tag_set_(new TagSet(tag_capacity_, TagHash(this), TagEqual(this))), + tags_(new Tag *[tag_capacity_]), + tag_set_(new TagSet(tag_capacity_, + TagHash(this), + TagEqual(this))), tag_next_(0), tag_group_capacity_(tag_capacity_), - tag_groups_(new TagGroup*[tag_group_capacity_]), + tag_groups_(new TagGroup *[tag_group_capacity_]), tag_group_set_(new TagGroupSet(tag_group_capacity_)), tag_group_next_(0), @@ -310,8 +306,8 @@ Search::~Search() deleteTags(); delete tag_set_; delete clk_info_set_; - delete [] tags_; - delete [] tag_groups_; + delete[] tags_; + delete[] tag_groups_; delete tag_group_set_; delete search_thru_; delete search_adj_; @@ -476,8 +472,8 @@ Search::deletePathsIncr(Vertex *vertex) void Search::deletePaths(Vertex *vertex) { - debugPrint(debug_, "search", 4, "delete paths %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "search", 4, "delete paths {}", + vertex->to_string(this)); TagGroup *tag_group = tagGroup(vertex); if (tag_group) { vertex->deletePaths(); @@ -521,15 +517,10 @@ Search::findPathEnds(ExceptionFrom *from, const ModeSeq modes = Scene::modesSorted(scenes); PathEndSeq path_ends; for (Mode *mode : modes) { - PathGroups *path_groups = mode->makePathGroups(group_path_count, - endpoint_path_count, - unique_pins, unique_edges, - slack_min, slack_max, - group_names, - setup, hold, - recovery, removal, - clk_gating_setup, clk_gating_hold, - unconstrained_paths_); + PathGroups *path_groups = mode->makePathGroups( + group_path_count, endpoint_path_count, unique_pins, unique_edges, slack_min, + slack_max, group_names, setup, hold, recovery, removal, clk_gating_setup, + clk_gating_hold, unconstrained_paths_); SceneSeq mode_scenes; for (Scene *scene : scenes) { if (scene->mode() == mode) @@ -555,10 +546,7 @@ Search::findFilteredArrivals(ExceptionFrom *from, filter_from_ = from; filter_thrus_ = thrus; filter_to_ = to; - if ((from - && (from->pins() - || from->instances())) - || thrus) { + if ((from && (from->pins() || from->instances())) || thrus) { for (const Mode *mode : modes_) { Sdc *sdc = mode->sdc(); sdc->makeFilter(from ? from->clone(network_) : nullptr, @@ -583,9 +571,7 @@ Search::deleteFilteredArrivals() { if (have_filter_) { ExceptionThruSeq *thrus = filter_thrus_; - if ((filter_from_ - && (filter_from_->pins() - || filter_from_->instances())) + if ((filter_from_ && (filter_from_->pins() || filter_from_->instances())) || thrus) { for (Vertex *vertex : filtered_arrivals_) { deletePathsIncr(vertex); @@ -598,14 +584,13 @@ Search::deleteFilteredArrivals() while (vertex_iter.hasNext()) { Vertex *vertex = vertex_iter.next(); TagGroup *tag_group = tagGroup(vertex); - if (tag_group - && tag_group->hasFilterTag()) + if (tag_group && tag_group->hasFilterTag()) filtered_arrivals_.erase(vertex); } if (!filtered_arrivals_.empty()) { - report_->reportLine("Filtered verticies mismatch"); + report_->report("Filtered verticies mismatch"); for (Vertex *vertex : filtered_arrivals_) - report_->reportLine(" %s", vertex->to_string(this).c_str()); + report_->report(" {}", vertex->to_string(this)); } } filtered_arrivals_.clear(); @@ -623,8 +608,7 @@ Search::deleteFilterTagGroups() { for (TagGroupIndex i = 0; i < tag_group_next_; i++) { TagGroup *group = tag_groups_[i]; - if (group - && group->hasFilterTag()) + if (group && group->hasFilterTag()) deleteTagGroup(group); } } @@ -643,9 +627,7 @@ Search::deleteFilterTags() { for (TagIndex i = 0; i < tag_next_; i++) { Tag *tag = tags_[i]; - if (tag - && (tag->isFilter() - || tag->clkInfo()->crprPathRefsFilter())) { + if (tag && (tag->isFilter() || tag->clkInfo()->crprPathRefsFilter())) { tags_[i] = nullptr; tag_set_->erase(tag); delete tag; @@ -656,7 +638,7 @@ Search::deleteFilterTags() void Search::deleteFilterClkInfos() { - for (auto itr = clk_info_set_->cbegin(); itr != clk_info_set_->cend(); ) { + for (auto itr = clk_info_set_->cbegin(); itr != clk_info_set_->cend();) { const ClkInfo *clk_info = *itr; if (clk_info->crprPathRefsFilter()) { itr = clk_info_set_->erase(itr); @@ -680,13 +662,14 @@ Search::findFilteredArrivals(bool thru_latches) // Iterate until data arrivals at all latches stop changing. postpone_latch_outputs_ = true; enqueuePendingClkFanouts(); - for (int pass = 1; pass == 1 || (thru_latches && havePendingLatchOutputs()) ; pass++) { + for (int pass = 1; pass == 1 || (thru_latches && havePendingLatchOutputs()); + pass++) { if (thru_latches) enqueuePendingLatchOutputs(); - debugPrint(debug_, "search", 1, "find arrivals pass %d", pass); + debugPrint(debug_, "search", 1, "find arrivals pass {}", pass); int arrival_count = arrival_iter_->visitParallel(max_level, arrival_visitor_); deleteTagsPrev(); - debugPrint(debug_, "search", 1, "found %d arrivals", arrival_count); + debugPrint(debug_, "search", 1, "found {} arrivals", arrival_count); postpone_latch_outputs_ = false; } arrivals_exist_ = true; @@ -696,12 +679,12 @@ Search::findFilteredArrivals(bool thru_latches) void Search::deleteTagsPrev() { - for (Tag** tags: tags_prev_) - delete [] tags; + for (Tag **tags : tags_prev_) + delete[] tags; tags_prev_.clear(); - for (TagGroup** tag_groups: tag_groups_prev_) - delete [] tag_groups; + for (TagGroup **tag_groups : tag_groups_prev_) + delete[] tag_groups; tag_groups_prev_.clear(); } @@ -824,8 +807,7 @@ Search::deleteEdgeBefore(Edge *edge) bool Search::arrivalsValid() { - return arrivals_exist_ - && invalid_arrivals_.empty(); + return arrivals_exist_ && invalid_arrivals_.empty(); } void @@ -872,8 +854,8 @@ void Search::arrivalInvalid(Vertex *vertex) { if (arrivals_exist_) { - debugPrint(debug_, "search", 2, "arrival invalid %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "search", 2, "arrival invalid {}", + vertex->to_string(this)); if (!arrival_iter_->inQueue(vertex)) { // Lock for StaDelayCalcObserver called by delay calc threads. LockGuard lock(invalid_arrivals_lock_); @@ -951,8 +933,8 @@ void Search::requiredInvalid(Vertex *vertex) { if (requireds_exist_) { - debugPrint(debug_, "search", 2, "required invalid %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "search", 2, "required invalid {}", + vertex->to_string(this)); if (!required_iter_->inQueue(vertex)) { // Lock for StaDelayCalcObserver called by delay calc threads. LockGuard lock(invalid_arrivals_lock_); @@ -1020,9 +1002,10 @@ Search::findAllArrivals(bool thru_latches, arrival_visitor_->init(false, clks_only, eval_pred_); // Iterate until data arrivals at all latches stop changing. postpone_latch_outputs_ = true; - for (int pass = 1; pass == 1 || (thru_latches && havePendingLatchOutputs()); pass++) { + for (int pass = 1; pass == 1 || (thru_latches && havePendingLatchOutputs()); + pass++) { enqueuePendingLatchOutputs(); - debugPrint(debug_, "search", 1, "find arrivals pass %d", pass); + debugPrint(debug_, "search", 1, "find arrivals pass {}", pass); findArrivals1(levelize_->maxLevel()); if (pass > 2) postpone_latch_outputs_ = false; @@ -1045,8 +1028,8 @@ void Search::enqueuePendingLatchOutputs() { for (Vertex *latch_vertex : pending_latch_outputs_) { - debugPrint(debug_, "search", 2, "enqueue latch output %s", - latch_vertex->to_string(this).c_str()); + debugPrint(debug_, "search", 2, "enqueue latch output {}", + latch_vertex->to_string(this)); arrival_iter_->enqueue(latch_vertex); } clearPendingLatchOutputs(); @@ -1056,8 +1039,8 @@ void Search::enqueuePendingClkFanouts() { for (Vertex *vertex : pending_clk_endpoints_) { - debugPrint(debug_, "search", 2, "enqueue clk fanout %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "search", 2, "enqueue clk fanout {}", + vertex->to_string(this)); arrival_iter_->enqueueAdjacentVertices(vertex, search_adj_); } pending_clk_endpoints_.clear(); @@ -1086,7 +1069,7 @@ Search::findArrivals(Level level) void Search::findArrivals1(Level level) { - debugPrint(debug_, "search", 1, "find arrivals to level %d", level); + debugPrint(debug_, "search", 1, "find arrivals to level {}", level); findArrivalsSeed(); Stats stats(debug_, report_); int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_); @@ -1095,7 +1078,7 @@ Search::findArrivals1(Level level) deleteUnusedTagGroups(); stats.report("Find arrivals"); arrivals_exist_ = true; - debugPrint(debug_, "search", 1, "found %d arrivals", arrival_count); + debugPrint(debug_, "search", 1, "found {} arrivals", arrival_count); } void @@ -1119,7 +1102,9 @@ Search::findArrivalsSeed() //////////////////////////////////////////////////////////////// ArrivalVisitor::ArrivalVisitor(const StaState *sta) : - PathVisitor(nullptr, false, sta) + PathVisitor(nullptr, + false, + sta) { init0(); init(true, false, nullptr); @@ -1129,7 +1114,9 @@ ArrivalVisitor::ArrivalVisitor(const StaState *sta) : ArrivalVisitor::ArrivalVisitor(bool always_to_endpoints, SearchPred *pred, const StaState *sta) : - PathVisitor(pred, true, sta) + PathVisitor(pred, + true, + sta) { init0(); init(always_to_endpoints, false, pred); @@ -1154,7 +1141,6 @@ ArrivalVisitor::init(bool always_to_endpoints, crpr_active_ = variables_->crprEnabled(); } - VertexVisitor * ArrivalVisitor::copy() const { @@ -1184,21 +1170,19 @@ ArrivalVisitor::setAlwaysToEndpoints(bool to_endpoints) void ArrivalVisitor::visit(Vertex *vertex) { - debugPrint(debug_, "search", 2, "find arrivals %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "search", 2, "find arrivals {}", + vertex->to_string(this)); Pin *pin = vertex->pin(); tag_bldr_->init(vertex); has_fanin_one_ = graph_->hasFaninOne(vertex); - if (crpr_active_ - && !has_fanin_one_) + if (crpr_active_ && !has_fanin_one_) tag_bldr_no_crpr_->init(vertex); visitFaninPaths(vertex); if (crpr_active_ && search_->crprPathPruningEnabled() // No crpr for ideal clocks. - && tag_bldr_->hasPropagatedClk() - && !has_fanin_one_) + && tag_bldr_->hasPropagatedClk() && !has_fanin_one_) pruneCrprArrivals(); // Insert paths that originate here. @@ -1209,14 +1193,11 @@ ArrivalVisitor::visit(Vertex *vertex) // If vertex is a latch data input arrival that changed from the // previous eval pass enqueue the latch outputs to be re-evaled on the // next pass. - if (arrivals_changed - && network_->isLatchData(pin)) + if (arrivals_changed && network_->isLatchData(pin)) search_->enqueueLatchDataOutputs(vertex); - if ((always_to_endpoints_ - || arrivals_changed)) { - if (clks_only_ - && vertex->isRegClk()) { + if ((always_to_endpoints_ || arrivals_changed)) { + if (clks_only_ && vertex->isRegClk()) { debugPrint(debug_, "search", 3, "postponing clk fanout"); search_->postponeClkFanouts(vertex); } @@ -1244,22 +1225,18 @@ ArrivalVisitor::seedArrivals(Vertex *vertex) if (search_->isInputArrivalSrchStart(vertex)) search_->seedInputArrival(pin, vertex, mode, tag_bldr_); // Do not apply input delay to bidir load vertices. - if (!(network_->direction(pin)->isBidirect() - && !vertex->isBidirectDriver()) - && !network_->isTopLevelPort(pin) - && sdc->hasInputDelay(pin)) + if (!(network_->direction(pin)->isBidirect() && !vertex->isBidirectDriver()) + && !network_->isTopLevelPort(pin) && sdc->hasInputDelay(pin)) search_->seedInputSegmentArrival(pin, vertex, mode, tag_bldr_); - if (sdc->isPathDelayInternalFrom(pin) - && !sdc->isLeafPinClock(pin)) + if (sdc->isPathDelayInternalFrom(pin) && !sdc->isLeafPinClock(pin)) // set_min/max_delay -from internal pin. search_->makeUnclkedPaths(vertex, false, true, tag_bldr_, mode); if (search_->isSrchRoot(vertex, mode)) { bool is_reg_clk = vertex->isRegClk(); if (is_reg_clk // Internal roots isolated by disabled pins are seeded with no clock. - || (search_->unconstrainedPaths() - && !network_->isTopLevelPort(pin))) { - debugPrint(debug_, "search", 2, "arrival seed unclked root %s", + || (search_->unconstrainedPaths() && !network_->isTopLevelPort(pin))) { + debugPrint(debug_, "search", 2, "arrival seed unclked root {}", network_->pathName(pin)); search_->makeUnclkedPaths(vertex, is_reg_clk, false, tag_bldr_, mode); } @@ -1270,7 +1247,7 @@ ArrivalVisitor::seedArrivals(Vertex *vertex) // These paths are required to report path delays from unclocked registers // For example, "set_max_delay -to" from an unclocked source register. if (vertex->isRegClk() && !is_clk) { - debugPrint(debug_, "search", 2, "arrival seed unclked reg clk %s", + debugPrint(debug_, "search", 2, "arrival seed unclked reg clk {}", network_->pathName(pin)); search_->makeUnclkedPaths(vertex, true, false, tag_bldr_, mode); } @@ -1286,8 +1263,7 @@ ArrivalVisitor::constrainedRequiredsInvalid(Vertex *vertex, bool is_clk) { Pin *pin = vertex->pin(); - if (network_->isLoad(pin) - && search_->requiredsExist()) { + if (network_->isLoad(pin) && search_->requiredsExist()) { if (is_clk && network_->isCheckClk(pin)) { VertexOutEdgeIterator edge_iter(vertex, graph_); while (edge_iter.hasNext()) { @@ -1326,15 +1302,14 @@ Search::arrivalsChanged(Vertex *vertex, Path *paths1 = vertex->paths(); if (paths1) { TagGroup *tag_group = tagGroup(vertex); - if (tag_group == nullptr - || tag_group->pathCount() != tag_bldr->pathCount()) + if (tag_group == nullptr || tag_group->pathCount() != tag_bldr->pathCount()) return true; for (auto const [tag1, path_index1] : *tag_group->pathIndexMap()) { Path *path1 = &paths1[path_index1]; Path *path2 = tag_bldr->tagMatchPath(tag1); if (path2 == nullptr || path1->tag(this) != path2->tag(this) - || !delayEqual(path1->arrival(), path2->arrival()) + || !delayEqual(path1->arrival(), path2->arrival(), this) || path1->prevEdge(this) != path2->prevEdge(this) || path1->prevArc(this) != path2->prevArc(this) || path1->prevPath() != path2->prevPath()) @@ -1362,16 +1337,12 @@ ArrivalVisitor::visitFromToPath(const Pin * /* from_pin */, Arrival &to_arrival, const MinMax *min_max) { - debugPrint(debug_, "search", 3, " %s", - from_vertex->to_string(this).c_str()); - debugPrint(debug_, "search", 3, " %s -> %s %s", - from_rf->shortName(), - to_rf->shortName(), - min_max->to_string().c_str()); - debugPrint(debug_, "search", 3, " from tag: %s", - from_tag->to_string(this).c_str()); - debugPrint(debug_, "search", 3, " to tag : %s", - to_tag->to_string(this).c_str()); + debugPrint(debug_, "search", 3, " {}", from_vertex->to_string(this)); + debugPrint(debug_, "search", 3, " {} -> {} {}", from_rf->shortName(), + to_rf->shortName(), min_max->to_string()); + debugPrint(debug_, "search", 3, " from tag: {}", + from_tag->to_string(this)); + debugPrint(debug_, "search", 3, " to tag : {}", to_tag->to_string(this)); const ClkInfo *to_clk_info = to_tag->clkInfo(); bool to_is_clk = to_tag->isClock(); Path *match; @@ -1379,16 +1350,13 @@ ArrivalVisitor::visitFromToPath(const Pin * /* from_pin */, tag_bldr_->tagMatchPath(to_tag, match, path_index); if (match == nullptr || delayGreater(to_arrival, match->arrival(), min_max, this)) { - debugPrint(debug_, "search", 3, " %s + %s = %s %s %s", - delayAsString(from_arrival, this), - delayAsString(arc_delay, this), - delayAsString(to_arrival, this), - min_max == MinMax::max() ? ">" : "<", + debugPrint(debug_, "search", 3, " {} + {} = {} {} {}", + delayAsString(from_arrival, this), delayAsString(arc_delay, this), + delayAsString(to_arrival, this), min_max == MinMax::max() ? ">" : "<", match ? delayAsString(match->arrival(), this) : "MIA"); - tag_bldr_->setMatchPath(match, path_index, to_tag, to_arrival, from_path, edge, arc); - if (crpr_active_ - && !has_fanin_one_ - && to_clk_info->hasCrprClkPin() + tag_bldr_->setMatchPath(match, path_index, to_tag, to_arrival, from_path, edge, + arc); + if (crpr_active_ && !has_fanin_one_ && to_clk_info->hasCrprClkPin() && !to_is_clk) { tag_bldr_no_crpr_->tagMatchPath(to_tag, match, path_index); if (match == nullptr @@ -1406,13 +1374,12 @@ ArrivalVisitor::pruneCrprArrivals() { CheckCrpr *crpr = search_->checkCrpr(); PathIndexMap &path_index_map = tag_bldr_->pathIndexMap(); - for (auto path_itr = path_index_map.cbegin(); path_itr != path_index_map.cend(); ) { + for (auto path_itr = path_index_map.cbegin(); path_itr != path_index_map.cend();) { Tag *tag = path_itr->first; size_t path_index = path_itr->second; const ClkInfo *clk_info = tag->clkInfo(); bool deleted_tag = false; - if (!tag->isClock() - && clk_info->hasCrprClkPin()) { + if (!tag->isClock() && clk_info->hasCrprClkPin()) { const MinMax *min_max = tag->minMax(); Path *path_no_crpr = tag_bldr_no_crpr_->tagMatchPath(tag); if (path_no_crpr) { @@ -1420,9 +1387,9 @@ ArrivalVisitor::pruneCrprArrivals() const ClkInfo *clk_info_no_crpr = path_no_crpr->clkInfo(this); Arrival max_crpr = crpr->maxCrpr(clk_info_no_crpr); Arrival max_arrival_max_crpr = (min_max == MinMax::max()) - ? max_arrival - max_crpr - : max_arrival + max_crpr; - debugPrint(debug_, "search", 4, " cmp %s %s - %s = %s", + ? delayDiff(max_arrival, max_crpr, this) + : delaySum(max_arrival, max_crpr, this); + debugPrint(debug_, "search", 4, " cmp {} {} - {} = {}", tag->to_string(this).c_str(), delayAsString(max_arrival, this), delayAsString(max_crpr, this), @@ -1432,9 +1399,9 @@ ArrivalVisitor::pruneCrprArrivals() // does not match the path min/max. if (delayGreater(max_arrival_max_crpr, arrival, min_max, this) && clk_info_no_crpr->crprClkPath(this)->minMax(this) - == clk_info->crprClkPath(this)->minMax(this)) { - debugPrint(debug_, "search", 3, " pruned %s", - tag->to_string(this).c_str()); + == clk_info->crprClkPath(this)->minMax(this)) { + debugPrint(debug_, "search", 3, " pruned {}", + tag->to_string(this)); path_itr = path_index_map.erase(path_itr); deleted_tag = true; } @@ -1547,24 +1514,21 @@ Search::seedClkArrivals(const Pin *pin, ClockSet *clks = sdc->findLeafPinClocks(pin); if (clks) { for (const Clock *clk : *clks) { - debugPrint(debug_, "search", 2, "arrival seed clk %s/%s pin %s", - mode->name().c_str(), - clk->name(), - network_->pathName(pin)); + debugPrint(debug_, "search", 2, "arrival seed clk {}/{} pin {}", + mode->name(), clk->name(), network_->pathName(pin)); for (Scene *scene : mode->scenes()) { for (const MinMax *min_max : MinMax::range()) { for (const RiseFall *rf : RiseFall::range()) { const ClockEdge *clk_edge = clk->edge(rf); const EarlyLate *early_late = min_max; - if (clk->isGenerated() - && clk->masterClk() == nullptr) - seedClkDataArrival(pin, rf, clk, clk_edge, min_max, - 0.0, scene, tag_bldr); + if (clk->isGenerated() && clk->masterClk() == nullptr) + seedClkDataArrival(pin, rf, clk, clk_edge, min_max, 0.0, scene, + tag_bldr); else { - Arrival insertion = clockInsertion(clk, pin, rf, min_max, - early_late, mode); - seedClkArrival(pin, rf, clk, clk_edge, min_max, - insertion, scene, tag_bldr); + Arrival insertion = + clockInsertion(clk, pin, rf, min_max, early_late, mode); + seedClkArrival(pin, rf, clk, clk_edge, min_max, insertion, scene, + tag_bldr); } } } @@ -1588,12 +1552,10 @@ Search::seedClkArrival(const Pin *pin, float latency = 0.0; bool latency_exists; // Check for clk pin latency. - sdc->clockLatency(clk, pin, rf, min_max, - latency, latency_exists); + sdc->clockLatency(clk, pin, rf, min_max, latency, latency_exists); if (!latency_exists) { // Check for clk latency (lower priority). - sdc->clockLatency(clk, rf, min_max, - latency, latency_exists); + sdc->clockLatency(clk, rf, min_max, latency, latency_exists); if (latency_exists) { // Propagated pin overrides latency on clk. if (sdc->isPropagatedClock(pin)) { @@ -1603,8 +1565,7 @@ Search::seedClkArrival(const Pin *pin, } } else - is_propagated = sdc->isPropagatedClock(pin) - || clk->isPropagated(); + is_propagated = sdc->isPropagatedClock(pin) || clk->isPropagated(); } const ClockUncertainties *uncertainties = sdc->clockUncertainties(pin); @@ -1613,16 +1574,15 @@ Search::seedClkArrival(const Pin *pin, // Propagate liberty "pulse_clock" transition to transitive fanout. LibertyPort *port = network_->libertyPort(pin); const RiseFall *pulse_clk_sense = (port ? port->pulseClkSense() : nullptr); - const ClkInfo *clk_info = findClkInfo(scene, clk_edge, pin, is_propagated, - nullptr, false, - pulse_clk_sense, insertion, latency, + const ClkInfo *clk_info = findClkInfo(scene, clk_edge, pin, is_propagated, nullptr, + false, pulse_clk_sense, insertion, latency, uncertainties, min_max, nullptr); // Only false_paths -from apply to clock tree pins. ExceptionStateSet *states = nullptr; sdc->exceptionFromClkStates(pin,rf,clk,rf,min_max,states); Tag *tag = findTag(scene, rf, min_max, clk_info, true, nullptr, false, states, true, nullptr); - Arrival arrival(clk_edge->time() + insertion); + Arrival arrival = delaySum(insertion, clk_edge->time(), this); tag_bldr->setArrival(tag, arrival); } @@ -1635,11 +1595,11 @@ Search::seedClkDataArrival(const Pin *pin, Arrival insertion, Scene *scene, TagGroupBldr *tag_bldr) -{ +{ Tag *tag = clkDataTag(pin, clk, rf, clk_edge, insertion, min_max, scene); if (tag) { // Data arrivals include insertion delay. - Arrival arrival(clk_edge->time() + insertion); + Arrival arrival = delaySum(insertion, clk_edge->time(), this); tag_bldr->setArrival(tag, arrival); } } @@ -1656,12 +1616,11 @@ Search::clkDataTag(const Pin *pin, Sdc *sdc = scene->sdc(); ExceptionStateSet *states = nullptr; if (sdc->exceptionFromStates(pin, rf, clk, rf, min_max, states)) { - bool is_propagated = (clk->isPropagated() - || sdc->isPropagatedClock(pin)); - const ClkInfo *clk_info = findClkInfo(scene, clk_edge, pin, is_propagated, - insertion, min_max); - return findTag(scene, rf, min_max, clk_info, false, nullptr, false, - states, true, nullptr); + bool is_propagated = (clk->isPropagated() || sdc->isPropagatedClock(pin)); + const ClkInfo *clk_info = + findClkInfo(scene, clk_edge, pin, is_propagated, insertion, min_max); + return findTag(scene, rf, min_max, clk_info, false, nullptr, false, states, true, + nullptr); } else return nullptr; @@ -1748,8 +1707,7 @@ Search::isInputArrivalSrchStart(Vertex *vertex) PortDirection *dir = network_->direction(pin); bool is_top_level_port = network_->isTopLevelPort(pin); return (is_top_level_port - && (dir->isInput() - || (dir->isBidirect() && vertex->isBidirectDriver()))) ; + && (dir->isInput() || (dir->isBidirect() && vertex->isBidirectDriver()))); } void @@ -1792,10 +1750,9 @@ Search::seedInputArrival1(const Pin *pin, // Input arrival wrt a clock source pin is the clock insertion // delay (source latency), but arrivals wrt other clocks // propagate. - if (pin_clks == nullptr - || !pin_clks->contains(input_clk)) - seedInputDelayArrival(pin, vertex, input_delay, is_segment_start, - mode, tag_bldr); + if (pin_clks == nullptr || !pin_clks->contains(input_clk)) + seedInputDelayArrival(pin, vertex, input_delay, is_segment_start, mode, + tag_bldr); } } } @@ -1809,17 +1766,14 @@ Search::seedInputDelayArrival(const Pin *pin, TagGroupBldr *tag_bldr) { debugPrint(debug_, "search", 2, - input_delay - ? "arrival seed input arrival %s" - : "arrival seed input %s", + input_delay ? "arrival seed input arrival {}" : "arrival seed input {}", vertex->to_string(this).c_str()); const ClockEdge *clk_edge = nullptr; const Pin *ref_pin = nullptr; const Sdc *sdc = mode->sdc(); if (input_delay) { clk_edge = input_delay->clkEdge(); - if (clk_edge == nullptr - && variables_->useDefaultArrivalClock()) + if (clk_edge == nullptr && variables_->useDefaultArrivalClock()) clk_edge = sdc->defaultArrivalClockEdge(); ref_pin = input_delay->refPin(); } @@ -1835,12 +1789,10 @@ Search::seedInputDelayArrival(const Pin *pin, while (ref_path_iter.hasNext()) { Path *ref_path = ref_path_iter.next(); if (ref_path->isClock(this) - && (clk == nullptr - || ref_path->clock(this) == clk)) { + && (clk == nullptr || ref_path->clock(this) == clk)) { float ref_arrival, ref_insertion, ref_latency; - inputDelayRefPinArrival(ref_path, ref_path->clkEdge(this), min_max, - sdc, ref_arrival, ref_insertion, - ref_latency); + inputDelayRefPinArrival(ref_path, ref_path->clkEdge(this), min_max, sdc, + ref_arrival, ref_insertion, ref_latency); seedInputDelayArrival(pin, input_delay, ref_path->clkEdge(this), ref_arrival, ref_insertion, ref_latency, is_segment_start, min_max, scene, tag_bldr); @@ -1852,12 +1804,12 @@ Search::seedInputDelayArrival(const Pin *pin, else { for (const MinMax *min_max : MinMax::range()) { float clk_arrival, clk_insertion, clk_latency; - inputDelayClkArrival(input_delay, clk_edge, min_max, mode, - clk_arrival, clk_insertion, clk_latency); + inputDelayClkArrival(input_delay, clk_edge, min_max, mode, clk_arrival, + clk_insertion, clk_latency); for (Scene *scene : mode->scenes()) { - seedInputDelayArrival(pin, input_delay, clk_edge, - clk_arrival, clk_insertion, clk_latency, - is_segment_start, min_max, scene, tag_bldr); + seedInputDelayArrival(pin, input_delay, clk_edge, clk_arrival, clk_insertion, + clk_latency, is_segment_start, min_max, scene, + tag_bldr); } } } @@ -1878,8 +1830,8 @@ Search::inputDelayRefPinArrival(Path *ref_path, Clock *clk = clk_edge->clock(); if (clk->isPropagated()) { const ClkInfo *clk_info = ref_path->clkInfo(this); - ref_arrival = delayAsFloat(ref_path->arrival()); - ref_insertion = delayAsFloat(clk_info->insertion()); + ref_arrival = delayAsFloat(ref_path->arrival(), min_max, this); + ref_insertion = delayAsFloat(clk_info->insertion(), min_max, this); ref_latency = clk_info->latency(); } else { @@ -1911,15 +1863,13 @@ Search::seedInputDelayArrival(const Pin *pin, bool exists; input_delay->delays()->value(rf, min_max, delay, exists); if (exists) - seedInputDelayArrival(pin, rf, clk_arrival + delay, - input_delay, clk_edge, - clk_insertion, clk_latency, is_segment_start, - min_max, scene, tag_bldr); + seedInputDelayArrival(pin, rf, clk_arrival + delay, input_delay, clk_edge, + clk_insertion, clk_latency, is_segment_start, min_max, + scene, tag_bldr); } else - seedInputDelayArrival(pin, rf, 0.0, nullptr, clk_edge, - clk_insertion, clk_latency, is_segment_start, - min_max, scene, tag_bldr); + seedInputDelayArrival(pin, rf, 0.0, nullptr, clk_edge, clk_insertion, + clk_latency, is_segment_start, min_max, scene, tag_bldr); } } @@ -1961,13 +1911,11 @@ Search::inputDelayClkArrival(InputDelay *input_delay, const RiseFall *clk_rf = clk_edge->transition(); if (!input_delay->sourceLatencyIncluded()) { const EarlyLate *early_late = min_max; - clk_insertion = delayAsFloat(clockInsertion(clk, clk->defaultPin(), - clk_rf, min_max, - early_late, mode)); + clk_insertion = delayAsFloat( + clockInsertion(clk, clk->defaultPin(), clk_rf, min_max, early_late, mode)); clk_arrival += clk_insertion; } - if (!clk->isPropagated() - && !input_delay->networkLatencyIncluded()) { + if (!clk->isPropagated() && !input_delay->networkLatencyIncluded()) { clk_latency = mode->sdc()->clockLatency(clk, clk_rf, min_max); clk_arrival += clk_latency; } @@ -2001,21 +1949,19 @@ Search::inputDelayTag(const Pin *pin, Sdc *sdc = scene->sdc(); ExceptionStateSet *states = nullptr; Tag *tag = nullptr; - if (sdc->exceptionFromStates(pin,rf,clk,clk_rf,min_max,states)) { - const ClkInfo *clk_info = findClkInfo(scene, clk_edge, clk_pin, - is_propagated, nullptr, - false, nullptr, clk_insertion, clk_latency, - clk_uncertainties, min_max, nullptr); - tag = findTag(scene, rf, min_max, clk_info, false, - input_delay, is_segment_start, states, true, nullptr); + if (sdc->exceptionFromStates(pin, rf, clk, clk_rf, min_max, states)) { + const ClkInfo *clk_info = + findClkInfo(scene, clk_edge, clk_pin, is_propagated, nullptr, false, nullptr, + clk_insertion, clk_latency, clk_uncertainties, min_max, nullptr); + tag = findTag(scene, rf, min_max, clk_info, false, input_delay, is_segment_start, + states, true, nullptr); } if (tag) { const ClkInfo *clk_info = tag->clkInfo(); // Check for state changes on existing tag exceptions (pending -thru pins). - tag = mutateTag(tag, pin, rf, false, clk_info, - pin, rf, false, false, is_segment_start, clk_info, - input_delay, nullptr); + tag = mutateTag(tag, pin, rf, false, clk_info, pin, rf, false, false, + is_segment_start, clk_info, input_delay, nullptr); } return tag; } @@ -2026,7 +1972,7 @@ PathVisitor::PathVisitor(const StaState *sta) : StaState(sta), pred_(sta->search()->evalPred()), - tag_cache_( nullptr) + tag_cache_(nullptr) { } @@ -2036,16 +1982,14 @@ PathVisitor::PathVisitor(SearchPred *pred, StaState(sta), pred_(pred), - tag_cache_(make_tag_cache - ? new TagSet(128, TagSet::hasher(sta), TagSet::key_equal(sta)) - : nullptr) + tag_cache_(make_tag_cache ? new TagSet(128, + TagSet::hasher(sta), + TagSet::key_equal(sta)) + : nullptr) { } -PathVisitor::~PathVisitor() -{ - delete tag_cache_; -} +PathVisitor::~PathVisitor() { delete tag_cache_; } void PathVisitor::visitFaninPaths(Vertex *to_vertex) @@ -2070,8 +2014,7 @@ PathVisitor::visitFanoutPaths(Vertex *from_vertex) Edge *edge = edge_iter.next(); Vertex *to_vertex = edge->to(graph_); const Pin *to_pin = to_vertex->pin(); - debugPrint(debug_, "search", 3, " %s", - to_vertex->to_string(this).c_str()); + debugPrint(debug_, "search", 3, " {}", to_vertex->to_string(this)); if (!visitEdge(from_pin, from_vertex, edge, to_pin, to_vertex)) break; } @@ -2093,19 +2036,18 @@ PathVisitor::visitEdge(const Pin *from_pin, Path *from_path = from_iter.next(); const Mode *mode = from_path->mode(this); if (mode == prev_mode - || (pred_->searchFrom(from_vertex, mode) - && pred_->searchThru(edge, mode) + || (pred_->searchFrom(from_vertex, mode) && pred_->searchThru(edge, mode) && pred_->searchTo(to_vertex, mode))) { - prev_mode = mode; + prev_mode = mode; const MinMax *min_max = from_path->minMax(this); const RiseFall *from_rf = from_path->transition(this); TimingArc *arc1, *arc2; arc_set->arcsFrom(from_rf, arc1, arc2); - if (!visitArc(from_pin, from_vertex, from_rf, from_path, - edge, arc1, to_pin, to_vertex, min_max, mode)) + if (!visitArc(from_pin, from_vertex, from_rf, from_path, edge, arc1, to_pin, + to_vertex, min_max, mode)) return false; - if (!visitArc(from_pin, from_vertex, from_rf, from_path, - edge, arc2, to_pin, to_vertex, min_max, mode)) + if (!visitArc(from_pin, from_vertex, from_rf, from_path, edge, arc2, to_pin, + to_vertex, min_max, mode)) return false; } } @@ -2128,8 +2070,8 @@ PathVisitor::visitArc(const Pin *from_pin, if (arc) { const RiseFall *to_rf = arc->toEdge()->asRiseFall(); if (searchThru(from_vertex, from_rf, edge, to_vertex, to_rf, mode)) - return visitFromPath(from_pin, from_vertex, from_rf, from_path, - edge, arc, to_pin, to_vertex, to_rf, min_max); + return visitFromPath(from_pin, from_vertex, from_rf, from_path, edge, arc, + to_pin, to_vertex, to_rf, min_max); } return true; } @@ -2160,7 +2102,7 @@ PathVisitor::visitFromPath(const Pin *from_pin, DcalcAPIndex dcalc_ap = from_path->dcalcAnalysisPtIndex(this); Arrival to_arrival; if (from_clk_info->isGenClkSrcPath()) { - if (!sdc->clkStopPropagation(clk,from_pin,from_rf,to_pin,to_rf) + if (!sdc->clkStopPropagation(clk, from_pin, from_rf, to_pin, to_rf) && (variables_->clkThruTristateEnabled() || !(role == TimingRole::tristateEnable() || role == TimingRole::tristateDisable()))) { @@ -2169,39 +2111,35 @@ PathVisitor::visitFromPath(const Pin *from_pin, Genclks *genclks = mode->genclks(); VertexSet *fanins = genclks->fanins(gclk); // Note: encountering a latch d->q edge means find the - // latch feedback edges, but they are referenced for + // latch feedback edges, but they are referenced for // other edges in the gen clk fanout. if (role == TimingRole::latchDtoQ()) genclks->findLatchFdbkEdges(gclk); EdgeSet &fdbk_edges = genclks->latchFdbkEdges(gclk); - if ((role == TimingRole::combinational() - || role == TimingRole::wire() + if ((role == TimingRole::combinational() || role == TimingRole::wire() || !gclk->combinational()) - && fanins->contains(to_vertex) - && !fdbk_edges.contains(edge)) { - arc_delay = search_->deratedDelay(from_vertex, arc, edge, - true, min_max, dcalc_ap, sdc); + && fanins->contains(to_vertex) && !fdbk_edges.contains(edge)) { + arc_delay = search_->deratedDelay(from_vertex, arc, edge, true, min_max, + dcalc_ap, sdc); DcalcAPIndex dcalc_ap = scene->dcalcAnalysisPtIndex(min_max->opposite()); Delay arc_delay_opp = search_->deratedDelay(from_vertex, arc, edge, true, min_max, dcalc_ap, sdc); - bool arc_delay_min_max_eq = - fuzzyEqual(delayAsFloat(arc_delay), delayAsFloat(arc_delay_opp)); + bool arc_delay_min_max_eq = delayEqual(arc_delay, arc_delay_opp, this); to_tag = search_->thruClkTag(from_path, from_vertex, from_tag, true, edge, to_rf, arc_delay_min_max_eq, min_max, scene); - if (to_tag) - to_arrival = from_arrival + arc_delay; + if (to_tag) + to_arrival = delaySum(from_arrival, arc_delay, this); } } } } else if (role->genericRole() == TimingRole::regClkToQ()) { - if (clk == nullptr - || !sdc->clkStopPropagation(from_pin, clk)) { - arc_delay = search_->deratedDelay(from_vertex, arc, edge, false, - min_max, dcalc_ap, sdc); + if (clk == nullptr || !sdc->clkStopPropagation(from_pin, clk)) { + arc_delay = search_->deratedDelay(from_vertex, arc, edge, false, min_max, + dcalc_ap, sdc); // Remove clock network delay for macros created with propagated // clocks when used in a context with ideal clocks. @@ -2210,14 +2148,15 @@ PathVisitor::visitFromPath(const Pin *from_pin, const LibertyCell *inst_cell = clk_port->libertyCell(); if (inst_cell->isMacro()) { float slew = delayAsFloat(from_path->slew(this)); - arc_delay -= clk_port->clkTreeDelay(slew, from_rf, min_max); + arc_delay = delayDiff(arc_delay, + clk_port->clkTreeDelay(slew, from_rf, min_max), + this); } } // Propagate from unclocked reg/latch clk pins, which have no // clk but are distinguished with a segment_start flag. - if ((clk_edge == nullptr - && from_tag->isSegmentStart()) + if ((clk_edge == nullptr && from_tag->isSegmentStart()) // Do not propagate paths from input ports with default // input arrival clk thru CLK->Q edges. || (clk != sdc->defaultArrivalClock() @@ -2228,24 +2167,21 @@ PathVisitor::visitFromPath(const Pin *from_pin, const ClkInfo *to_clk_info = from_clk_info; if (from_clk_info->crprClkPath(this) == nullptr || network_->direction(to_pin)->isInternal()) - to_clk_info = search_->clkInfoWithCrprClkPath(from_clk_info, - from_path); - to_tag = search_->fromRegClkTag(from_pin, from_rf, clk, clk_rf, - to_clk_info, to_pin, to_rf, min_max, - from_tag->scene()); + to_clk_info = search_->clkInfoWithCrprClkPath(from_clk_info, from_path); + to_tag = search_->fromRegClkTag(from_pin, from_rf, clk, clk_rf, to_clk_info, + to_pin, to_rf, min_max, from_tag->scene()); if (to_tag) to_tag = search_->thruTag(to_tag, edge, to_rf, tag_cache_); from_arrival = search_->clkPathArrival(from_path, from_clk_info, clk_edge, min_max); - to_arrival = from_arrival + arc_delay; + to_arrival = delaySum(from_arrival, arc_delay, this); } else to_tag = nullptr; } } else if (edge->role() == TimingRole::latchDtoQ()) { - if (min_max == MinMax::max() - && clk) { + if (min_max == MinMax::max() && clk) { bool postponed = false; if (search_->postponeLatchOutputs()) { const Path *from_clk_path = from_clk_info->crprClkPath(this); @@ -2257,21 +2193,19 @@ PathVisitor::visitFromPath(const Pin *from_pin, // Crpr clk path on latch data input is required to find Q // arrival. If the data clk path level is >= Q level the // crpr clk path prev_path pointers are not complete. - debugPrint(debug_, "search", 3, "postponed latch eval %d %s -> %s %d", - d_clk_level, - d_clk_vertex->to_string(this).c_str(), - edge->to_string(this).c_str(), - q_level); + debugPrint(debug_, "search", 3, "postponed latch eval {} {} -> {} {}", + d_clk_level, d_clk_vertex->to_string(this), + edge->to_string(this), q_level); postponed = true; search_->enqueueLatchOutput(to_vertex); } } } if (!postponed) { - arc_delay = search_->deratedDelay(from_vertex, arc, edge, false, - min_max, dcalc_ap, sdc); - latches_->latchOutArrival(from_path, arc, edge, to_tag, - arc_delay, to_arrival); + arc_delay = search_->deratedDelay(from_vertex, arc, edge, false, min_max, + dcalc_ap, sdc); + latches_->latchOutArrival(from_path, arc, edge, to_tag, arc_delay, + to_arrival); if (to_tag) to_tag = search_->thruTag(to_tag, edge, to_rf, tag_cache_); } @@ -2287,29 +2221,25 @@ PathVisitor::visitFromPath(const Pin *from_pin, && sdc->clkDisabledByHpinThru(clk, from_pin, to_pin)) // Generated clock source pins have arrivals for the source clock. // Do not propagate them past the generated clock source pin. - && !(clks - && !clks->contains(const_cast(from_tag->clock())))) { + && !(clks && !clks->contains(const_cast(from_tag->clock())))) { // Propagate arrival as non-clock at the end of the clock tree. bool to_propagates_clk = - !sdc->clkStopPropagation(clk,from_pin,from_rf,to_pin,to_rf) - && (variables_->clkThruTristateEnabled() - || !(role == TimingRole::tristateEnable() - || role == TimingRole::tristateDisable())); - arc_delay = search_->deratedDelay(from_vertex, arc, edge, - to_propagates_clk, min_max, - dcalc_ap, sdc); - DcalcAPIndex dcalc_ap_opp = - scene->dcalcAnalysisPtIndex(min_max->opposite()); - Delay arc_delay_opp = search_->deratedDelay(from_vertex, arc, edge, - to_propagates_clk, - min_max, dcalc_ap_opp, sdc); + !sdc->clkStopPropagation(clk, from_pin, from_rf, to_pin, to_rf) + && (variables_->clkThruTristateEnabled() + || !(role == TimingRole::tristateEnable() + || role == TimingRole::tristateDisable())); + arc_delay = search_->deratedDelay(from_vertex, arc, edge, to_propagates_clk, + min_max, dcalc_ap, sdc); + DcalcAPIndex dcalc_ap_opp = scene->dcalcAnalysisPtIndex(min_max->opposite()); + Delay arc_delay_opp = search_->deratedDelay( + from_vertex, arc, edge, to_propagates_clk, min_max, dcalc_ap_opp, sdc); bool arc_delay_min_max_eq = fuzzyEqual(delayAsFloat(arc_delay), delayAsFloat(arc_delay_opp)); to_tag = search_->thruClkTag(from_path, from_vertex, from_tag, to_propagates_clk, edge, to_rf, arc_delay_min_max_eq, min_max, scene); - to_arrival = from_arrival + arc_delay; + to_arrival = delaySum(from_arrival, arc_delay, this); } } else { @@ -2317,18 +2247,16 @@ PathVisitor::visitFromPath(const Pin *from_pin, || sdc->isPathDelayInternalToBreak(from_pin))) { arc_delay = search_->deratedDelay(from_vertex, arc, edge, false, min_max, dcalc_ap, sdc); - if (!delayInf(arc_delay)) { - to_arrival = from_arrival + arc_delay; + if (!delayInf(arc_delay, this)) { + to_arrival = delaySum(from_arrival, arc_delay, this); to_tag = search_->thruTag(from_tag, edge, to_rf, tag_cache_); } } } if (to_tag) - return visitFromToPath(from_pin, from_vertex, from_rf, - from_tag, from_path, from_arrival, - edge, arc, arc_delay, - to_vertex, to_rf, to_tag, to_arrival, - min_max); + return visitFromToPath(from_pin, from_vertex, from_rf, from_tag, from_path, + from_arrival, edge, arc, arc_delay, to_vertex, to_rf, + to_tag, to_arrival, min_max); else return true; } @@ -2349,17 +2277,15 @@ Search::clkPathArrival(const Path *clk_path, const MinMax *min_max) const { const Scene *scene = clk_path->scene(this); - if (clk_path->vertex(this)->isRegClk() - && clk_path->isClock(this) - && clk_edge + if (clk_path->vertex(this)->isRegClk() && clk_path->isClock(this) && clk_edge && !clk_info->isPropagated()) { // Ideal clock, apply ideal insertion delay and latency. const EarlyLate *early_late = min_max; - return clk_edge->time() - + clockInsertion(clk_edge->clock(), clk_info->clkSrc(), - clk_edge->transition(), min_max, - early_late, scene->mode()) - + clk_info->latency(); + Arrival insertion = clockInsertion(clk_edge->clock(), clk_info->clkSrc(), + clk_edge->transition(), min_max, + early_late, scene->mode()); + return delaySum(delaySum(insertion, clk_edge->time(), this), + clk_info->latency(), this); } else return clk_path->arrival(); @@ -2424,10 +2350,10 @@ Search::fromUnclkedInputTag(const Pin *pin, ExceptionStateSet *states = nullptr; if (sdc->exceptionFromStates(pin, rf, nullptr, nullptr, min_max, states) && (!require_exception || states)) { - const ClkInfo *clk_info = findClkInfo(scene, nullptr, nullptr, false, - 0.0, min_max); - return findTag(scene, rf, min_max, clk_info, false, nullptr, - is_segment_start, states, true, nullptr); + const ClkInfo *clk_info = + findClkInfo(scene, nullptr, nullptr, false, 0.0, min_max); + return findTag(scene, rf, min_max, clk_info, false, nullptr, is_segment_start, + states, true, nullptr); } return nullptr; } @@ -2445,12 +2371,11 @@ Search::fromRegClkTag(const Pin *from_pin, { Sdc *sdc = scene->sdc(); ExceptionStateSet *states = nullptr; - if (sdc->exceptionFromStates(from_pin, from_rf, clk, clk_rf, - min_max, states)) { + if (sdc->exceptionFromStates(from_pin, from_rf, clk, clk_rf, min_max, states)) { // Hack for filter -from reg/Q. sdc->filterRegQStates(to_pin, to_rf, min_max, states); - return findTag(scene, to_rf, min_max, clk_info, false, nullptr, - false, states, true, nullptr); + return findTag(scene, to_rf, min_max, clk_info, false, nullptr, false, states, + true, nullptr); } else return nullptr; @@ -2463,18 +2388,12 @@ Search::clkInfoWithCrprClkPath(const ClkInfo *from_clk_info, { Scene *scene = from_clk_info->scene(); if (crprActive(scene->mode())) - return findClkInfo(scene, - from_clk_info->clkEdge(), - from_clk_info->clkSrc(), - from_clk_info->isPropagated(), - from_clk_info->genClkSrc(), + return findClkInfo(scene, from_clk_info->clkEdge(), from_clk_info->clkSrc(), + from_clk_info->isPropagated(), from_clk_info->genClkSrc(), from_clk_info->isGenClkSrcPath(), - from_clk_info->pulseClkSense(), - from_clk_info->insertion(), - from_clk_info->latency(), - from_clk_info->uncertainties(), - from_clk_info->minMax(), - from_path); + from_clk_info->pulseClkSense(), from_clk_info->insertion(), + from_clk_info->latency(), from_clk_info->uncertainties(), + from_clk_info->minMax(), from_path); else return from_clk_info; } @@ -2493,8 +2412,8 @@ Search::thruTag(Tag *from_tag, const RiseFall *from_rf = from_tag->transition(); const ClkInfo *from_clk_info = from_tag->clkInfo(); bool to_is_reg_clk = to_vertex->isRegClk(); - Tag *to_tag = mutateTag(from_tag, from_pin, from_rf, false, from_clk_info, - to_pin, to_rf, false, to_is_reg_clk, false, + Tag *to_tag = mutateTag(from_tag, from_pin, from_rf, false, from_clk_info, to_pin, + to_rf, false, to_is_reg_clk, false, // input delay is not propagated. from_clk_info, nullptr, tag_cache); return to_tag; @@ -2520,15 +2439,12 @@ Search::thruClkTag(Path *from_path, bool from_is_clk = from_tag->isClock(); bool to_is_reg_clk = to_vertex->isRegClk(); const TimingRole *role = edge->role(); - bool to_is_clk = (from_is_clk - && to_propagates_clk - && (role->isWire() - || role == TimingRole::combinational())); - const ClkInfo *to_clk_info = thruClkInfo(from_path, from_vertex, - from_clk_info, from_is_clk, - edge, to_vertex, to_pin, to_is_clk, - arc_delay_min_max_eq, min_max, scene); - Tag *to_tag = mutateTag(from_tag,from_pin,from_rf,from_is_clk,from_clk_info, + bool to_is_clk = (from_is_clk && to_propagates_clk + && (role->isWire() || role == TimingRole::combinational())); + const ClkInfo *to_clk_info = thruClkInfo( + from_path, from_vertex, from_clk_info, from_is_clk, edge, to_vertex, to_pin, + to_is_clk, arc_delay_min_max_eq, min_max, scene); + Tag *to_tag = mutateTag(from_tag, from_pin, from_rf, from_is_clk, from_clk_info, to_pin, to_rf, to_is_clk, to_is_reg_clk, false, to_clk_info, nullptr, nullptr); return to_tag; @@ -2556,8 +2472,7 @@ Search::thruClkInfo(Path *from_path, bool from_clk_prop = from_clk_info->isPropagated(); bool to_clk_prop = from_clk_prop; - if (!from_clk_prop - && sdc->isPropagatedClock(to_pin)) { + if (!from_clk_prop && sdc->isPropagatedClock(to_pin)) { to_clk_prop = true; changed = true; } @@ -2566,9 +2481,7 @@ Search::thruClkInfo(Path *from_path, // so that generated clock crpr info can be (later) safely set on // the clkinfo. const Pin *gen_clk_src = nullptr; - if (from_clk_info->isGenClkSrcPath() - && crprActive(mode) - && sdc->isClock(to_pin)) { + if (from_clk_info->isGenClkSrcPath() && crprActive(mode) && sdc->isClock(to_pin)) { // Don't care that it could be a regular clock root. gen_clk_src = to_pin; changed = true; @@ -2578,9 +2491,7 @@ Search::thruClkInfo(Path *from_path, if (crprActive(mode) // Update crpr clk path for combinational paths leaving the clock // network (ie, tristate en->out) and buffer driving reg clk. - && ((from_is_clk - && !to_is_clk - && !from_vertex->isRegClk()) + && ((from_is_clk && !to_is_clk && !from_vertex->isRegClk()) || (to_vertex->isRegClk() // If the wire delay to the reg clk pin is zero, // leave the crpr_clk_path null to indicate that @@ -2598,8 +2509,8 @@ Search::thruClkInfo(Path *from_path, to_pulse_sense = port->pulseClkSense(); changed = true; } - else if (from_pulse_sense && - edge->timingArcSet()->sense() == TimingSense::negative_unate) { + else if (from_pulse_sense + && edge->timingArcSet()->sense() == TimingSense::negative_unate) { to_pulse_sense = from_pulse_sense->opposite(); changed = true; } @@ -2609,8 +2520,7 @@ Search::thruClkInfo(Path *from_path, float to_latency = from_clk_info->latency(); float latency; bool exists; - sdc->clockLatency(from_clk, to_pin, clk_rf, min_max, - latency, exists); + sdc->clockLatency(from_clk, to_pin, clk_rf, min_max, latency, exists); if (exists) { // Latency on pin has precedence over fanin or hierarchical // pin latency. @@ -2620,8 +2530,7 @@ Search::thruClkInfo(Path *from_path, } else { // Check for hierarchical pin latency thru edge. - sdc->clockLatency(edge, clk_rf, min_max, - latency, exists); + sdc->clockLatency(edge, clk_rf, min_max, latency, exists); if (exists) { to_latency = latency; to_clk_prop = false; @@ -2637,11 +2546,10 @@ Search::thruClkInfo(Path *from_path, } if (changed) - to_clk_info = findClkInfo(scene, from_clk_edge, from_clk_info->clkSrc(), - to_clk_prop, gen_clk_src, - from_clk_info->isGenClkSrcPath(), - to_pulse_sense, to_insertion, to_latency, - to_uncertainties, min_max, to_crpr_clk_path); + to_clk_info = findClkInfo( + scene, from_clk_edge, from_clk_info->clkSrc(), to_clk_prop, gen_clk_src, + from_clk_info->isGenClkSrcPath(), to_pulse_sense, to_insertion, to_latency, + to_uncertainties, min_max, to_crpr_clk_path); return to_clk_info; } @@ -2679,7 +2587,7 @@ Search::mutateTag(Tag *from_tag, for (ExceptionState *state : *from_states) { ExceptionPath *exception = state->exception(); // One edge may traverse multiple hierarchical thru pins. - while (state->matchesNextThru(from_pin,to_pin,to_rf,min_max,network_)) { + while (state->matchesNextThru(from_pin, to_pin, to_rf, min_max, network_)) { // Found a -thru that we've been waiting for. state = state->nextState(); state_change = true; @@ -2691,20 +2599,16 @@ Search::mutateTag(Tag *from_tag, // Don't propagate a completed false path -thru unless it is a // clock. Clocks carry the completed false path to disable // downstream paths that use the clock as data. - if ((state->isComplete() - && exception->isFalse() - && !from_is_clk) + if ((state->isComplete() && exception->isFalse() && !from_is_clk) // to_pin/edge completes a loop path. - || (exception->isLoop() - && state->isComplete())) + || (exception->isLoop() && state->isComplete())) return nullptr; // Kill path delay tags past the -to pin. if ((exception->isPathDelay() && sdc->isCompleteTo(state, to_pin, to_rf, min_max)) // Kill loop tags at register clock pins. - || (exception->isLoop() - && to_is_reg_clk)) { + || (exception->isLoop() && to_is_reg_clk)) { state_change = true; break; } @@ -2720,19 +2624,16 @@ Search::mutateTag(Tag *from_tag, for (auto state : *from_states) { ExceptionPath *exception = state->exception(); // One edge may traverse multiple hierarchical thru pins. - while (state->matchesNextThru(from_pin,to_pin,to_rf,min_max,network_)) + while (state->matchesNextThru(from_pin, to_pin, to_rf, min_max, network_)) // Found a -thru that we've been waiting for. state = state->nextState(); // Don't propagate a completed false path -thru unless it is a // clock. Clocks carry the completed false path to disable // downstream paths that use the clock as data. - if ((state->isComplete() - && exception->isFalse() - && !from_is_clk) + if ((state->isComplete() && exception->isFalse() && !from_is_clk) // to_pin/edge completes a loop path. - || (exception->isLoop() - && state->isComplete())) { + || (exception->isLoop() && state->isComplete())) { delete new_states; return nullptr; } @@ -2741,8 +2642,7 @@ Search::mutateTag(Tag *from_tag, if (!((exception->isPathDelay() && sdc->isCompleteTo(state, from_pin, from_rf, min_max)) // Kill loop tags at register clock pins. - || (to_is_reg_clk - && exception->isLoop()))) + || (to_is_reg_clk && exception->isLoop()))) new_states->insert(state); } } @@ -2753,20 +2653,18 @@ Search::mutateTag(Tag *from_tag, if (new_states) return findTag(scene, to_rf, min_max, to_clk_info, to_is_clk, - from_tag->inputDelay(), to_is_segment_start, - new_states, true, tag_cache); + from_tag->inputDelay(), to_is_segment_start, new_states, true, + tag_cache); else { // No state change. - if (to_clk_info == from_clk_info - && to_is_clk == from_is_clk + if (to_clk_info == from_clk_info && to_is_clk == from_is_clk && from_tag->isSegmentStart() == to_is_segment_start && from_tag->inputDelay() == to_input_delay) { return tags_[tagsTableRfIndex(from_tag->index(), to_rf)]; } else - return findTag(scene, to_rf, min_max, to_clk_info, to_is_clk, - to_input_delay, to_is_segment_start, - from_states, false, tag_cache); + return findTag(scene, to_rf, min_max, to_clk_info, to_is_clk, to_input_delay, + to_is_segment_start, from_states, false, tag_cache); } } @@ -2792,9 +2690,8 @@ Search::findTagGroup(TagGroupBldr *tag_bldr) // can use Search::tagGroup(TagGroupIndex) without returning gubbish. if (tag_group_next_ == tag_group_capacity_) { TagGroupIndex tag_capacity = tag_group_capacity_ * 2; - TagGroup **tag_groups = new TagGroup*[tag_capacity]; - memcpy(tag_groups, tag_groups_, - tag_group_capacity_ * sizeof(TagGroup*)); + TagGroup **tag_groups = new TagGroup *[tag_capacity]; + memcpy(tag_groups, tag_groups_, tag_group_capacity_ * sizeof(TagGroup *)); tag_groups_prev_.push_back(tag_groups_); tag_groups_ = tag_groups; tag_group_capacity_ = tag_capacity; @@ -2864,7 +2761,6 @@ private: const StaState *sta_; }; - ReportPathLess::ReportPathLess(const StaState *sta) : sta_(sta) { @@ -2881,12 +2777,12 @@ void Search::reportArrivals(Vertex *vertex, bool report_tag_index) const { - report_->reportLine("Vertex %s", vertex->to_string(this).c_str()); + report_->report("Vertex {}", vertex->to_string(this)); TagGroup *tag_group = tagGroup(vertex); if (tag_group) { if (report_tag_index) - report_->reportLine("Group %u", tag_group->index()); - std::vector paths; + report_->report("Group {}", tag_group->index()); + std::vector paths; VertexPathIterator path_iter(vertex, this); while (path_iter.hasNext()) { const Path *path = path_iter.next(); @@ -2896,7 +2792,7 @@ Search::reportArrivals(Vertex *vertex, for (const Path *path : paths) { const Tag *tag = path->tag(this); const RiseFall *rf = tag->transition(); - const char *req = delayAsString(path->required(), this); + std::string req = delayAsString(path->required(), this); bool report_prev = false; std::string prev_str; if (report_prev) { @@ -2918,17 +2814,14 @@ Search::reportArrivals(Vertex *vertex, else prev_str += "NULL"; } - report_->reportLine(" %s %s %s / %s %s%s", - rf->shortName(), - path->minMax(this)->to_string().c_str(), - delayAsString(path->arrival(), this), - req, - tag->to_string(report_tag_index, false, this).c_str(), - prev_str.c_str()); + report_->report(" {} {} {} / {} {}{}", rf->shortName(), + path->minMax(this)->to_string(), + delayAsString(path->arrival(), this), req, + tag->to_string(report_tag_index, false, this), prev_str); } } else - report_->reportLine(" no arrivals"); + report_->report(" no arrivals"); } TagGroup * @@ -2959,10 +2852,8 @@ Search::reportTagGroups() const for (TagGroupIndex i = 0; i < tag_group_next_; i++) { TagGroup *tag_group = tag_groups_[i]; if (tag_group) { - report_->reportLine("Group %4u hash = %4lu (%4lu)", - i, - tag_group->hash(), - tag_group->hash() % tag_group_set_->bucket_count()); + report_->report("Group {:4} hash = {:4} ({:4})", i, tag_group->hash(), + tag_group->hash() % tag_group_set_->bucket_count()); tag_group->reportArrivalMap(this); } } @@ -2971,9 +2862,8 @@ Search::reportTagGroups() const if (tag_group_set_->bucket_size(i) > long_hash) long_hash = i; } - report_->reportLine("Longest hash bucket length %zu hash=%zu", - tag_group_set_->bucket_size(long_hash), - long_hash); + report_->report("Longest hash bucket length {} hash={}", + tag_group_set_->bucket_size(long_hash), long_hash); } void @@ -2995,7 +2885,7 @@ Search::reportPathCountHistogram() const for (size_t path_count = 0; path_count < vertex_counts.size(); path_count++) { int vertex_count = vertex_counts[path_count]; if (vertex_count > 0) - report_->reportLine("%6lu %6d",path_count, vertex_count); + report_->report("{:6} {:6}", path_count, vertex_count); } } @@ -3025,8 +2915,8 @@ Search::findTag(Scene *scene, bool own_states, TagSet *tag_cache) { - Tag probe(scene, 0, rf, min_max, clk_info, is_clk, - input_delay, is_segment_start, states, false); + Tag probe(scene, 0, rf, min_max, clk_info, is_clk, input_delay, is_segment_start, + states, false); if (tag_cache) { Tag *tag = findKey(tag_cache, &probe); if (tag) @@ -3039,8 +2929,8 @@ Search::findTag(Scene *scene, // Make rise/fall versions of the tag to avoid tag_set lookups when the // only change is the rise/fall edge. for (const RiseFall *rf1 : RiseFall::range()) { - ExceptionStateSet *new_states = !own_states && states - ? new ExceptionStateSet(*states) : states; + ExceptionStateSet *new_states = + !own_states && states ? new ExceptionStateSet(*states) : states; TagIndex tag_index = tag_next_++; Tag *tag1 = new Tag(scene, tag_index, rf1, min_max, clk_info, is_clk, input_delay, is_segment_start, new_states, true); @@ -3063,8 +2953,8 @@ Search::findTag(Scene *scene, // can use Search::tag(TagIndex) without returning gubbish. if (tag_next_ == tag_capacity_) { TagIndex tag_capacity = tag_capacity_ * 2; - Tag **tags = new Tag*[tag_capacity]; - memcpy(tags, tags_, tag_capacity_ * sizeof(Tag*)); + Tag **tags = new Tag *[tag_capacity]; + memcpy(tags, tags_, tag_capacity_ * sizeof(Tag *)); tags_prev_.push_back(tags_); tags_ = tags; tag_capacity_ = tag_capacity; @@ -3082,29 +2972,28 @@ Search::reportTags() const for (TagIndex i = 0; i < tag_next_; i++) { Tag *tag = tags_[i]; if (tag) - report_->reportLine("%s", tag->to_string(this).c_str()) ; + report_->report("{}", tag->to_string(this)); } size_t long_hash = 0; for (size_t i = 0; i < tag_set_->bucket_count(); i++) { if (tag_set_->bucket_size(i) > long_hash) long_hash = i; } - report_->reportLine("Longest hash bucket length %zu hash=%zu", - tag_set_->bucket_size(long_hash), - long_hash); + report_->report("Longest hash bucket length {} hash={}", + tag_set_->bucket_size(long_hash), long_hash); } void Search::reportClkInfos() const { - std::vector clk_infos; + std::vector clk_infos; // set -> vector for sorting. for (const ClkInfo *clk_info : *clk_info_set_) clk_infos.push_back(clk_info); sort(clk_infos, ClkInfoLess(this)); for (const ClkInfo *clk_info : clk_infos) - report_->reportLine("%s", clk_info->to_string(this).c_str()); - report_->reportLine("%zu clk infos", clk_info_set_->size()); + report_->report("{}", clk_info->to_string(this)); + report_->report("{} clk infos", clk_info_set_->size()); } const ClkInfo * @@ -3122,16 +3011,14 @@ Search::findClkInfo(Scene *scene, Path *crpr_clk_path) { const ClkInfo probe(scene, clk_edge, clk_src, is_propagated, gen_clk_src, - gen_clk_src_path, pulse_clk_sense, - insertion, latency, uncertainties, min_max, - crpr_clk_path, this); + gen_clk_src_path, pulse_clk_sense, insertion, latency, + uncertainties, min_max, crpr_clk_path, this); LockGuard lock(clk_info_lock_); const ClkInfo *clk_info = findKey(clk_info_set_, &probe); if (clk_info == nullptr) { - clk_info = new ClkInfo(scene, clk_edge, clk_src, - is_propagated, gen_clk_src, gen_clk_src_path, - pulse_clk_sense, insertion, latency, uncertainties, - min_max, crpr_clk_path, this); + clk_info = new ClkInfo(scene, clk_edge, clk_src, is_propagated, gen_clk_src, + gen_clk_src_path, pulse_clk_sense, insertion, latency, + uncertainties, min_max, crpr_clk_path, this); clk_info_set_->insert(clk_info); } return clk_info; @@ -3145,9 +3032,8 @@ Search::findClkInfo(Scene *scene, Arrival insertion, const MinMax *min_max) { - return findClkInfo(scene, clk_edge, clk_src, is_propagated, - nullptr, false, nullptr, - insertion, 0.0, nullptr, min_max, nullptr); + return findClkInfo(scene, clk_edge, clk_src, is_propagated, nullptr, false, + nullptr, insertion, 0.0, nullptr, min_max, nullptr); } int @@ -3166,8 +3052,8 @@ Search::deratedDelay(const Vertex *from_vertex, const Sdc *sdc) { float derate = timingDerate(from_vertex, arc, edge, is_clk, sdc, min_max); - ArcDelay delay = graph_->arcDelay(edge, arc, dcalc_ap); - return delay * derate; + const ArcDelay &delay = graph_->arcDelay(edge, arc, dcalc_ap); + return delayProduct(delay, derate, this);; } float @@ -3178,8 +3064,7 @@ Search::timingDerate(const Vertex *from_vertex, const Sdc *sdc, const MinMax *min_max) { - PathClkOrData derate_clk_data = - is_clk ? PathClkOrData::clk : PathClkOrData::data; + PathClkOrData derate_clk_data = is_clk ? PathClkOrData::clk : PathClkOrData::data; const TimingRole *role = edge->role(); const Pin *pin = from_vertex->pin(); if (role->isWire()) { @@ -3194,11 +3079,10 @@ Search::timingDerate(const Vertex *from_vertex, rf = arc->toEdge()->asRiseFall(); } else { - derate_type = TimingDerateCellType::cell_delay; - rf = arc->fromEdge()->asRiseFall(); + derate_type = TimingDerateCellType::cell_delay; + rf = arc->fromEdge()->asRiseFall(); } - return sdc->timingDerateInstance(pin, derate_type, derate_clk_data, - rf, min_max); + return sdc->timingDerateInstance(pin, derate_type, derate_clk_data, rf, min_max); } } @@ -3218,7 +3102,7 @@ Search::clockDomains(const Vertex *vertex, // Return value. ClockSet &clks) const { - VertexPathIterator path_iter(const_cast(vertex), this); + VertexPathIterator path_iter(const_cast(vertex), this); while (path_iter.hasNext()) { Path *path = path_iter.next(); const Clock *clk = path->clock(this); @@ -3272,11 +3156,10 @@ Search::clocks(const Vertex *vertex, // Return value. ClockSet &clks) const { - VertexPathIterator path_iter(const_cast(vertex), this); + VertexPathIterator path_iter(const_cast(vertex), this); while (path_iter.hasNext()) { Path *path = path_iter.next(); - if (path->isClock(this) - && path->mode(this) == mode) + if (path->isClock(this) && path->mode(this) == mode) clks.insert(const_cast(path->clock(this))); } } @@ -3293,7 +3176,7 @@ void Search::findRequireds(Level level) { Stats stats(debug_, report_); - debugPrint(debug_, "search", 1, "find requireds to level %d", level); + debugPrint(debug_, "search", 1, "find requireds to level {}", level); RequiredVisitor req_visitor(this); if (!requireds_seeded_) seedRequireds(); @@ -3301,7 +3184,7 @@ Search::findRequireds(Level level) int required_count = required_iter_->visitParallel(level, &req_visitor); deleteTagsPrev(); requireds_exist_ = true; - debugPrint(debug_, "search", 1, "found %d requireds", required_count); + debugPrint(debug_, "search", 1, "found {} requireds", required_count); stats.report("Find requireds"); } @@ -3323,8 +3206,8 @@ Search::endpoints() while (vertex_iter.hasNext()) { Vertex *vertex = vertex_iter.next(); if (isEndpoint(vertex)) { - debugPrint(debug_, "endpoint", 2, "insert %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "endpoint", 2, "insert {}", + vertex->to_string(this)); endpoints_.insert(vertex); } } @@ -3333,15 +3216,13 @@ Search::endpoints() if (!invalid_endpoints_.empty()) { for (Vertex *vertex : invalid_endpoints_) { if (isEndpoint(vertex)) { - debugPrint(debug_, "endpoint", 2, "insert %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "endpoint", 2, "insert {}", + vertex->to_string(this)); endpoints_.insert(vertex); } else { - if (debug_->check("endpoint", 2) - && endpoints_.contains(vertex)) - report_->reportLine("endpoint: remove %s", - vertex->to_string(this).c_str()); + if (debug_->check("endpoint", 2) && endpoints_.contains(vertex)) + report_->report("endpoint: remove {}", vertex->to_string(this)); endpoints_.erase(vertex); } } @@ -3353,8 +3234,7 @@ Search::endpoints() void Search::endpointInvalid(Vertex *vertex) { - debugPrint(debug_, "endpoint", 2, "invalid %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "endpoint", 2, "invalid {}", vertex->to_string(this)); invalid_endpoints_.insert(vertex); } @@ -3394,16 +3274,13 @@ Search::isEndpoint(Vertex *vertex, const Pin *pin = vertex->pin(); const Sdc *sdc = mode->sdc(); return hasFanin(vertex, pred, graph_, mode) - && ((vertex->hasChecks() - && hasEnabledChecks(vertex, mode)) - || sdc->isConstrainedEnd(pin) - || !hasFanout(vertex, pred, graph_, mode) - || sdc->isPathDelayInternalTo(pin) - // Unconstrained paths at register clk pins. - || (unconstrained_paths_ - && vertex->isRegClk()) - || (variables_->gatedClkChecksEnabled() - && gated_clk_->isGatedClkEnable(vertex, mode))); + && ((vertex->hasChecks() && hasEnabledChecks(vertex, mode)) + || sdc->isConstrainedEnd(pin) || !hasFanout(vertex, pred, graph_, mode) + || sdc->isPathDelayInternalTo(pin) + // Unconstrained paths at register clk pins. + || (unconstrained_paths_ && vertex->isRegClk()) + || (variables_->gatedClkChecksEnabled() + && gated_clk_->isGatedClkEnable(vertex, mode))); } bool @@ -3496,8 +3373,8 @@ FindEndRequiredVisitor::visit(PathEnd *path_end) void Search::seedRequired(Vertex *vertex) { - debugPrint(debug_, "search", 2, "required seed %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "search", 2, "required seed {}", + vertex->to_string(this)); RequiredCmp required_cmp; FindEndRequiredVisitor seeder(&required_cmp, this); required_cmp.requiredsInit(vertex, this); @@ -3568,10 +3445,10 @@ RequiredCmp::requiredsSave(Vertex *vertex, while (path_iter.hasNext()) { Path *path = path_iter.next(); size_t path_index = path->pathIndex(sta); - Required req = requireds_[path_index]; - Required &prev_req = path->required(); - bool changed = !delayEqual(prev_req, req); - debugPrint(debug, "search", 3, "required %s save %s -> %s%s", + const Required req = requireds_[path_index]; + const Required &prev_req = path->required(); + bool changed = !delayEqual(prev_req, req, sta); + debugPrint(debug, "search", 3, "required {} save {} -> {}{}", path->to_string(sta).c_str(), delayAsString(prev_req, sta), delayAsString(req, sta), @@ -3599,7 +3476,9 @@ RequiredVisitor::RequiredVisitor(const StaState *sta) : RequiredVisitor::RequiredVisitor(bool make_tag_cache, const StaState *sta) : - PathVisitor(sta->search()->evalPred(), make_tag_cache, sta), + PathVisitor(sta->search()->evalPred(), + make_tag_cache, + sta), required_cmp_(new RequiredCmp), visit_path_ends_(new VisitPathEnds(sta)) { @@ -3620,8 +3499,8 @@ RequiredVisitor::copy() const void RequiredVisitor::visit(Vertex *vertex) { - debugPrint(debug_, "search", 2, "find required %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "search", 2, "find required {}", + vertex->to_string(this)); required_cmp_->requiredsInit(vertex, this); // Back propagate requireds from fanout. visitFanoutPaths(vertex); @@ -3655,13 +3534,10 @@ RequiredVisitor::visitFromToPath(const Pin *, { // Don't propagate required times through latch D->Q edges. if (!edge->role()->isLatchDtoQ()) { - debugPrint(debug_, "search", 3, " %s -> %s %s", - from_rf->shortName(), - to_rf->shortName(), - min_max->to_string().c_str()); - debugPrint(debug_, "search", 3, " from tag %2u: %s", - from_tag->index(), - from_tag->to_string(this).c_str()); + debugPrint(debug_, "search", 3, " {} -> {} {}", from_rf->shortName(), + to_rf->shortName(), min_max->to_string()); + debugPrint(debug_, "search", 3, " from tag {:2}: {}", from_tag->index(), + from_tag->to_string(this)); size_t path_index = from_path->pathIndex(this); const MinMax *req_min = min_max->opposite(); TagGroup *to_tag_group = search_->tagGroup(to_vertex); @@ -3669,12 +3545,12 @@ RequiredVisitor::visitFromToPath(const Pin *, if (to_tag_group && to_tag_group->hasTag(to_tag)) { size_t to_path_index = to_tag_group->pathIndex(to_tag); Path &to_path = to_vertex->paths()[to_path_index]; - Required &to_required = to_path.required(); - Required from_required = to_required - arc_delay; - debugPrint(debug_, "search", 3, " to tag %2u: %s", + const Required &to_required = to_path.required(); + Required from_required = delayDiff(to_required, arc_delay, this); + debugPrint(debug_, "search", 3, " to tag {:2}: {}", to_tag->index(), to_tag->to_string(this).c_str()); - debugPrint(debug_, "search", 3, " %s - %s = %s %s %s", + debugPrint(debug_, "search", 3, " {} - {} = {} {} {}", delayAsString(to_required, this), delayAsString(arc_delay, this), delayAsString(from_required, this), @@ -3694,17 +3570,16 @@ RequiredVisitor::visitFromToPath(const Pin *, Tag *to_path_tag = to_path->tag(this); if (Tag::matchNoCrpr(to_path_tag, to_tag)) { Required to_required = to_path->required(); - Required from_required = to_required - arc_delay; - debugPrint(debug_, "search", 3, " to tag %2u: %s", + Required from_required = delayDiff(to_required, arc_delay, this); + debugPrint(debug_, "search", 3, " to tag {:2}: {}", to_path_tag->index(), to_path_tag->to_string(this).c_str()); - debugPrint(debug_, "search", 3, " %s - %s = %s %s %s", + debugPrint(debug_, "search", 3, " {} - {} = {} {} {}", delayAsString(to_required, this), delayAsString(arc_delay, this), delayAsString(from_required, this), min_max == MinMax::max() ? "<" : ">", - delayAsString(required_cmp_->required(path_index), - this)); + delayAsString(required_cmp_->required(path_index), this)); required_cmp_->requiredSet(path_index, from_required, req_min, this); break; } @@ -3743,9 +3618,7 @@ bool Search::matchesFilter(Path *path, const ClockEdge *to_clk_edge) { - if (!have_filter_ - && filter_from_ == nullptr - && filter_to_ == nullptr) + if (!have_filter_ && filter_from_ == nullptr && filter_to_ == nullptr) return true; else if (have_filter_) { // -from pins|inst @@ -3754,29 +3627,25 @@ Search::matchesFilter(Path *path, ExceptionStateSet *states = path->tag(this)->states(); if (states) { for (auto state : *states) { - if (state->exception()->isFilter() - && state->nextThru() == nullptr + if (state->exception()->isFilter() && state->nextThru() == nullptr && matchesFilterTo(path, to_clk_edge)) return true; } } return false; } - else if (filter_from_ - && filter_from_->pins() == nullptr - && filter_from_->instances() == nullptr - && filter_from_->clks()) { + else if (filter_from_ && filter_from_->pins() == nullptr + && filter_from_->instances() == nullptr && filter_from_->clks()) { // -from clks const ClockEdge *path_clk_edge = path->clkEdge(this); const Clock *path_clk = path_clk_edge ? path_clk_edge->clock() : nullptr; const RiseFall *path_clk_rf = - path_clk_edge ? path_clk_edge->transition() : nullptr; - return filter_from_->clks()->contains(const_cast(path_clk)) - && filter_from_->transition()->matches(path_clk_rf) - && matchesFilterTo(path, to_clk_edge); + path_clk_edge ? path_clk_edge->transition() : nullptr; + return filter_from_->clks()->contains(const_cast(path_clk)) + && filter_from_->transition()->matches(path_clk_rf) + && matchesFilterTo(path, to_clk_edge); } - else if (filter_from_ == nullptr - && filter_to_) + else if (filter_from_ == nullptr && filter_to_) // -to return matchesFilterTo(path, to_clk_edge); else { @@ -3818,12 +3687,10 @@ Search::exceptionTo(ExceptionPathType type, for (auto state : *states) { ExceptionPath *exception = state->exception(); int priority = exception->priority(min_max); - if ((type == ExceptionPathType::any - || exception->type() == type) + if ((type == ExceptionPathType::any || exception->type() == type) && sdc->isCompleteTo(state, pin, rf, clk_edge, min_max, match_min_max_exactly, require_to_pin) - && (hi_priority_exception == nullptr - || priority > hi_priority + && (hi_priority_exception == nullptr || priority > hi_priority || (priority == hi_priority && exception->tighterThan(hi_priority_exception)))) { hi_priority = priority; @@ -3832,8 +3699,7 @@ Search::exceptionTo(ExceptionPathType type, } } // Check for -to exceptions originating at the end pin or target clock. - sdc->exceptionTo(type, pin, rf, clk_edge, min_max, - match_min_max_exactly, + sdc->exceptionTo(type, pin, rf, clk_edge, min_max, match_min_max_exactly, hi_priority_exception, hi_priority); return hi_priority_exception; } @@ -3857,8 +3723,8 @@ Search::groupPathsTo(const PathEnd *path_end) const for (auto state : *states) { ExceptionPath *exception = state->exception(); if (exception->isGroupPath() - && sdc->exceptionMatchesTo(exception, pin, rf, clk_edge, min_max, - false, false)) + && sdc->exceptionMatchesTo(exception, pin, rf, clk_edge, min_max, false, + false)) group_paths.push_back(exception); } } @@ -3873,14 +3739,14 @@ Slack Search::totalNegativeSlack(const MinMax *min_max) { tnsPreamble(); - Slack tns = 0.0; + DelayDbl tns = 0.0; for (Scene *scene : scenes_) { size_t path_index = scene->pathIndex(min_max); - Slack tns1 = tns_[path_index]; + DelayDbl tns1 = tns_[path_index]; if (delayLess(tns1, tns, this)) tns = tns1; } - return tns; + return delayDblAsDelay(tns); } Slack @@ -3889,7 +3755,7 @@ Search::totalNegativeSlack(const Scene *scene, { tnsPreamble(); PathAPIndex path_ap_index = scene->pathIndex(min_max); - return tns_[path_ap_index]; + return delayDblAsDelay(tns_[path_ap_index]); } void @@ -3908,10 +3774,8 @@ Search::tnsPreamble() void Search::tnsInvalid(Vertex *vertex) { - if ((tns_exists_ || worst_slacks_) - && isEndpoint(vertex)) { - debugPrint(debug_, "tns", 2, "tns invalid %s", - vertex->to_string(this).c_str()); + if ((tns_exists_ || worst_slacks_) && isEndpoint(vertex)) { + debugPrint(debug_, "tns", 2, "tns invalid {}", vertex->to_string(this)); LockGuard lock(tns_lock_); invalid_tns_.insert(vertex); } @@ -3924,8 +3788,7 @@ Search::updateInvalidTns() for (Vertex *vertex : invalid_tns_) { // Network edits can change endpointedness since tnsInvalid was called. if (isEndpoint(vertex)) { - debugPrint(debug_, "tns", 2, "update tns %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "tns", 2, "update tns {}", vertex->to_string(this)); SlackSeq slacks(path_count); wnsSlacks(vertex, slacks); @@ -3973,10 +3836,10 @@ Search::tnsIncr(Vertex *vertex, PathAPIndex path_ap_index) { if (delayLess(slack, 0.0, this)) { - debugPrint(debug_, "tns", 3, "tns+ %s %s", + debugPrint(debug_, "tns", 3, "tns+ {} {}", delayAsString(slack, this), vertex->to_string(this).c_str()); - tns_[path_ap_index] += slack; + delayIncr(tns_[path_ap_index], slack, this); if (tns_slacks_[path_ap_index].contains(vertex)) report_->critical(1513, "tns incr existing vertex"); tns_slacks_[path_ap_index][vertex] = slack; @@ -3992,10 +3855,10 @@ Search::tnsDecr(Vertex *vertex, findKeyValue(tns_slacks_[path_ap_index], vertex, slack, found); if (found && delayLess(slack, 0.0, this)) { - debugPrint(debug_, "tns", 3, "tns- %s %s", + debugPrint(debug_, "tns", 3, "tns- {} {}", delayAsString(slack, this), vertex->to_string(this).c_str()); - tns_[path_ap_index] -= slack; + delayDecr(tns_[path_ap_index], slack, this); tns_slacks_[path_ap_index].erase(vertex); } } @@ -4004,8 +3867,7 @@ Search::tnsDecr(Vertex *vertex, void Search::tnsNotifyBefore(Vertex *vertex) { - if (tns_exists_ - && isEndpoint(vertex)) { + if (tns_exists_ && isEndpoint(vertex)) { size_t path_count = scenePathCount(); for (size_t i = 0; i < path_count; i++) { tnsDecr(vertex, i); @@ -4052,10 +3914,10 @@ Search::wnsTnsPreamble() findAllArrivals(); // Required times are only needed at endpoints. if (requireds_seeded_) { - for (auto itr = invalid_requireds_.begin(); itr != invalid_requireds_.end(); ) { + for (auto itr = invalid_requireds_.begin(); itr != invalid_requireds_.end();) { Vertex *vertex = *itr; - debugPrint(debug_, "search", 2, "tns update required %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "search", 2, "tns update required {}", + vertex->to_string(this)); if (isEndpoint(vertex)) { seedRequired(vertex); // If the endpoint has fanout it's required time @@ -4163,4 +4025,4 @@ Search::wnsSlack(Vertex *vertex, return slacks[path_ap_index]; } -} // namespace +} // namespace sta diff --git a/search/Search.i b/search/Search.i index cb8dde7e..0403b236 100644 --- a/search/Search.i +++ b/search/Search.i @@ -39,6 +39,7 @@ #include "Bfs.hh" #include "Scene.hh" #include "Sta.hh" +#include "StaConfig.hh" using namespace sta; @@ -155,26 +156,29 @@ find_requireds() Sta::sta()->findRequireds(); } -Slack +float total_negative_slack_cmd(const MinMax *min_max) { - return Sta::sta()->totalNegativeSlack(min_max); + Sta *sta = Sta::sta(); + return delayAsFloat(sta->totalNegativeSlack(min_max), min_max, sta); } -Slack +float total_negative_slack_scene_cmd(const Scene *scene, const MinMax *min_max) { - return Sta::sta()->totalNegativeSlack(scene, min_max); + Sta *sta = Sta::sta(); + return delayAsFloat(sta->totalNegativeSlack(scene, min_max), min_max, sta); } -Slack +float worst_slack_cmd(const MinMax *min_max) { + Sta *sta = Sta::sta(); Slack worst_slack; Vertex *worst_vertex; - Sta::sta()->worstSlack(min_max, worst_slack, worst_vertex); - return worst_slack; + sta->worstSlack(min_max, worst_slack, worst_vertex); + return delayAsFloat(worst_slack, min_max, sta); } Vertex * @@ -186,14 +190,15 @@ worst_slack_vertex(const MinMax *min_max) return worst_vertex;; } -Slack +float worst_slack_scene(const Scene *scene, const MinMax *min_max) { + Sta *sta = Sta::sta(); Slack worst_slack; Vertex *worst_vertex; - Sta::sta()->worstSlack(scene, min_max, worst_slack, worst_vertex); - return worst_slack; + sta->worstSlack(scene, min_max, worst_slack, worst_vertex); + return delayAsFloat(worst_slack, min_max, sta); } Path * @@ -224,7 +229,7 @@ vertex_worst_slack_path(Vertex *vertex, return sta->vertexWorstSlackPath(vertex, min_max); } -Slack +float endpoint_slack(const Pin *pin, const char *path_group_name, const MinMax *min_max) @@ -233,10 +238,10 @@ endpoint_slack(const Pin *pin, sta->ensureLibLinked(); if (sta->isPathGroupName(path_group_name, sta->cmdSdc())) { Slack slack = sta->endpointSlack(pin, std::string(path_group_name), min_max); - return sta->units()->timeUnit()->staToUser(delayAsFloat(slack)); + return sta->units()->timeUnit()->staToUser(delayAsFloat(slack, min_max, sta)); } else { - sta->report()->error(1577, "%s is not a known path group name.", + sta->report()->error(1577, "{} is not a known path group name.", path_group_name); return INF; } @@ -317,7 +322,7 @@ report_loops() Report *report = sta->report(); for (GraphLoop *loop : sta->graphLoops()) { loop->report(sta); - report->reportLineString(""); + report->reportLine(""); } } @@ -407,6 +412,7 @@ set_report_path_fields(bool report_input_pin, bool report_cap, bool report_slew, bool report_fanout, + bool report_variation, bool report_src_attr) { Sta::sta()->setReportPathFields(report_input_pin, @@ -415,6 +421,7 @@ set_report_path_fields(bool report_input_pin, report_cap, report_slew, report_fanout, + report_variation, report_src_attr); } @@ -429,19 +436,7 @@ set_report_path_field_properties(const char *field_name, if (field) field->setProperties(title, width, left_justify); else - sta->report()->warn(1575, "unknown report path field %s", field_name); -} - -void -set_report_path_field_width(const char *field_name, - int width) -{ - Sta *sta = Sta::sta(); - ReportField *field = sta->findReportPathField(field_name); - if (field) - field->setWidth(width); - else - sta->report()->warn(1576, "unknown report path field %s", field_name); + sta->report()->warn(1575, "unknown report path field {}", field_name); } void @@ -456,12 +451,6 @@ set_report_path_no_split(bool no_split) Sta::sta()->setReportPathNoSplit(no_split); } -void -set_report_path_sigmas(bool report_sigmas) -{ - Sta::sta()->setReportPathSigmas(report_sigmas); -} - void report_path_cmd(Path *path) { @@ -480,25 +469,28 @@ report_path_ends(PathEndSeq *ends) void report_arrival_wrt_clks(const Pin *pin, const Scene *scene, + bool report_variance, int digits) { - Sta::sta()->reportArrivalWrtClks(pin, scene, digits); + Sta::sta()->reportArrivalWrtClks(pin, scene, report_variance, digits); } void report_required_wrt_clks(const Pin *pin, const Scene *scene, + bool report_variance, int digits) { - Sta::sta()->reportRequiredWrtClks(pin, scene, digits); + Sta::sta()->reportRequiredWrtClks(pin, scene, report_variance, digits); } void report_slack_wrt_clks(const Pin *pin, const Scene *scene, + bool report_variance, int digits) { - Sta::sta()->reportSlackWrtClks(pin, scene, digits); + Sta::sta()->reportSlackWrtClks(pin, scene, report_variance, digits); } //////////////////////////////////////////////////////////////// @@ -518,7 +510,9 @@ float worst_clk_skew_cmd(const SetupHold *setup_hold, bool include_internal_latency) { - return Sta::sta()->findWorstClkSkew(setup_hold, include_internal_latency); + Sta *sta = Sta::sta(); + Delay skew = sta->findWorstClkSkew(setup_hold, include_internal_latency); + return delayAsFloat(skew, MinMax::max(), sta); } //////////////////////////////////////////////////////////////// @@ -571,7 +565,7 @@ report_max_skew_checks(const Net *net, //////////////////////////////////////////////////////////////// -Slack +float find_clk_min_period(const Clock *clk, bool ignore_port_paths) { @@ -963,39 +957,37 @@ set_crpr_mode(const char *mode) { Sta *sta = Sta::sta(); if (stringEq(mode, "same_pin")) - Sta::sta()->setCrprMode(CrprMode::same_pin); + sta->setCrprMode(CrprMode::same_pin); else if (stringEq(mode, "same_transition")) - Sta::sta()->setCrprMode(CrprMode::same_transition); + sta->setCrprMode(CrprMode::same_transition); else - sta->report()->critical(1573, "unknown common clk pessimism mode."); + sta->report()->error(1573, "unknown common clk pessimism mode."); } -bool -pocv_enabled() +const char * +pocv_mode() { - return Sta::sta()->pocvEnabled(); + return pocvModeName(Sta::sta()->pocvMode()); } void -set_pocv_enabled(bool enabled) +set_pocv_mode(const char *mode_name) { -#if !SSTA - if (enabled) - Sta::sta()->report()->error(1574, "POCV support requires compilation with SSTA=1."); -#endif - return Sta::sta()->setPocvEnabled(enabled); + Sta *sta = Sta::sta(); + PocvMode mode = findPocvMode(mode_name); + sta->setPocvMode(mode); } float -pocv_sigma_factor() +pocv_quantile() { - return Sta::sta()->sigmaFactor(); + return Sta::sta()->pocvQuantile(); } void -set_pocv_sigma_factor(float factor) +set_pocv_quantile(float quantile) { - Sta::sta()->setSigmaFactor(factor); + Sta::sta()->setPocvQuantile(quantile); } bool @@ -1141,58 +1133,83 @@ Vertex *vertex() { return self->vertex(Sta::sta()); } Path *path() { return self->path(); } RiseFall *end_transition() { return const_cast(self->path()->transition(Sta::sta())); } -Slack slack() { return self->slack(Sta::sta()); } -ArcDelay margin() { return self->margin(Sta::sta()); } -Required data_required_time() { return self->requiredTimeOffset(Sta::sta()); } -Arrival data_arrival_time() { return self->dataArrivalTimeOffset(Sta::sta()); } + +float +slack() +{ + Sta *sta = Sta::sta(); + return delayAsFloat(self->slack(sta), self->minMax(sta), sta); +} + +float +margin() +{ + Sta *sta = Sta::sta(); + return delayAsFloat(self->margin(sta), self->minMax(sta), sta); +} + +float +data_required_time() +{ + Sta *sta = Sta::sta(); + return delayAsFloat(self->requiredTimeOffset(sta), self->minMax(sta), sta); +} + +float +data_arrival_time() +{ + Sta *sta = Sta::sta(); + return delayAsFloat(self->dataArrivalTimeOffset(sta), self->minMax(sta), sta); +} + +float +target_clk_delay() +{ + Sta *sta = Sta::sta(); + return delayAsFloat(self->targetClkDelay(sta), self->minMax(sta), sta); +} + +float +source_clk_latency() +{ + Sta *sta = Sta::sta(); + return delayAsFloat(self->sourceClkLatency(sta), self->minMax(sta), sta); +} + +float +clk_skew() +{ + Sta *sta = Sta::sta(); + return delayAsFloat(self->clkSkew(sta), self->minMax(sta), sta); +} + const TimingRole *check_role() { return self->checkRole(Sta::sta()); } MinMax *min_max() { return const_cast(self->minMax(Sta::sta())); } -float source_clk_offset() { return self->sourceClkOffset(Sta::sta()); } -Arrival source_clk_latency() { return self->sourceClkLatency(Sta::sta()); } -Arrival source_clk_insertion_delay() -{ return self->sourceClkInsertionDelay(Sta::sta()); } const Clock *target_clk() { return self->targetClk(Sta::sta()); } const ClockEdge *target_clk_edge() { return self->targetClkEdge(Sta::sta()); } Path *target_clk_path() { return self->targetClkPath(); } -float target_clk_time() { return self->targetClkTime(Sta::sta()); } -float target_clk_offset() { return self->targetClkOffset(Sta::sta()); } -float target_clk_mcp_adjustment() -{ return self->targetClkMcpAdjustment(Sta::sta()); } -Arrival target_clk_delay() { return self->targetClkDelay(Sta::sta()); } -Arrival target_clk_insertion_delay() -{ return self->targetClkInsertionDelay(Sta::sta()); } -float target_clk_uncertainty() -{ return self->targetNonInterClkUncertainty(Sta::sta()); } -float inter_clk_uncertainty() -{ return self->interClkUncertainty(Sta::sta()); } -Arrival target_clk_arrival() { return self->targetClkArrival(Sta::sta()); } -bool path_delay_margin_is_external() -{ return self->pathDelayMarginIsExternal();} -Crpr check_crpr() { return self->checkCrpr(Sta::sta()); } -RiseFall *target_clk_end_trans() -{ return const_cast(self->targetClkEndTrans(Sta::sta())); } -Delay clk_skew() { return self->clkSkew(Sta::sta()); } - } %extend Path { float arrival() { - return delayAsFloat(self->arrival()); + Sta *sta = Sta::sta(); + return delayAsFloat(self->arrival(), self->minMax(sta), sta); } float required() { - return delayAsFloat(self->required()); + Sta *sta = Sta::sta(); + return delayAsFloat(self->required(), self->minMax(sta), sta); } float slack() { Sta *sta = Sta::sta(); - return delayAsFloat(self->slack(sta)); + return delayAsFloat(self->slack(sta), self->minMax(sta), sta); } const Pin * diff --git a/search/Search.tcl b/search/Search.tcl index f7a548c5..73ef64b3 100644 --- a/search/Search.tcl +++ b/search/Search.tcl @@ -683,7 +683,6 @@ proc_redirect report_path { proc parse_report_path_options { cmd args_var default_format unknown_key_is_error } { variable path_options - variable report_path_field_width_extra global sta_report_default_digits upvar 1 $args_var args @@ -691,7 +690,7 @@ proc parse_report_path_options { cmd args_var default_format unset path_options } parse_key_args $cmd args path_options {-format -digits -fields} \ - path_options {-no_line_splits -report_sigmas} $unknown_key_is_error + path_options {-no_line_splits} $unknown_key_is_error set format $default_format if [info exists path_options(-format)] { @@ -712,24 +711,8 @@ proc parse_report_path_options { cmd args_var default_format check_positive_integer "-digits" $digits } - set report_sigmas [info exists path_options(-report_sigmas)] - set_report_path_sigmas $report_sigmas - set path_options(num_fmt) "%.${digits}f" set_report_path_digits $digits - # Numeric field width expands with digits. - set field_width [expr $digits + $report_path_field_width_extra] - if { $report_sigmas } { - set delay_field_width [expr $field_width * 3 + $report_path_field_width_extra] - } else { - set delay_field_width $field_width - } - foreach field {total incr} { - set_report_path_field_width $field $delay_field_width - } - foreach field {capacitance slew} { - set_report_path_field_width $field $field_width - } set report_input_pin 0 set report_hier_pins 0 @@ -737,6 +720,7 @@ proc parse_report_path_options { cmd args_var default_format set report_net 0 set report_slew 0 set report_fanout 0 + set report_variation 0 set report_src_attr 0 if { [info exists path_options(-fields)] } { foreach field $path_options(-fields) { @@ -752,6 +736,8 @@ proc parse_report_path_options { cmd args_var default_format set report_slew 1 } elseif { [string match "fanout" $field] } { set report_fanout 1 + } elseif { [string match "variation" $field] } { + set report_variation 1 } elseif { [string match "src*" $field] } { set report_src_attr 1 } else { @@ -759,20 +745,21 @@ proc parse_report_path_options { cmd args_var default_format } } } + set_report_path_fields $report_input_pin $report_hier_pins $report_net \ - $report_cap $report_slew $report_fanout $report_src_attr + $report_cap $report_slew $report_fanout $report_variation $report_src_attr set_report_path_no_split [info exists path_options(-no_line_splits)] } ################################################################ -define_cmd_args "report_arrival" {[-scene scene] [-digits digits] pin} +define_cmd_args "report_arrival" {[-scene scene] [-report_variance] [-digits digits] pin} proc report_arrival { args } { global sta_report_default_digits - parse_key_args "report_arrival" args keys {-scene -digits} flags {} + parse_key_args "report_arrival" args keys {-scene -digits} flags {-report_variance} check_argc_eq1 "report_arrival" $args set pin [get_port_pin_error "pin" [lindex $args 0]] @@ -783,17 +770,18 @@ proc report_arrival { args } { } else { set digits $sta_report_default_digits } - report_arrival_wrt_clks $pin $scene $digits + set report_variance [info exists flags(-report_variance)] + report_arrival_wrt_clks $pin $scene $report_variance $digits } ################################################################ -define_cmd_args "report_required" {[-scene scene] [-digits digits] pin} +define_cmd_args "report_required" {[-scene scene] [-report_variance] [-digits digits] pin} proc report_required { args } { global sta_report_default_digits - parse_key_args "report_required" args keys {-scene -digits} flags {} + parse_key_args "report_required" args keys {-scene -digits} flags {-report_variance} check_argc_eq1 "report_required" $args set pin [get_port_pin_error "pin" [lindex $args 0]] @@ -804,17 +792,18 @@ proc report_required { args } { } else { set digits $sta_report_default_digits } - report_required_wrt_clks $pin $scene $digits + set report_variance [info exists flags(-report_variance)] + report_required_wrt_clks $pin $scene $report_variance $digits } ################################################################ -define_cmd_args "report_slack" {[-scene scene] [-digits digits] pin} +define_cmd_args "report_slack" {[-scene scene] [-report_variance] [-digits digits] pin} proc report_slack { args } { global sta_report_default_digits - parse_key_args "report_slack" args keys {-scene -digits} flags {} + parse_key_args "report_slack" args keys {-scene -digits} flags {-report_variance} check_argc_eq1 "report_slack" $args set pin [get_port_pin_error "pin" [lindex $args 0]] @@ -825,7 +814,8 @@ proc report_slack { args } { } else { set digits $sta_report_default_digits } - report_slack_wrt_clks $pin $scene $digits + set report_variance [info exists flags(-report_variance)] + report_slack_wrt_clks $pin $scene $report_variance $digits } ################################################################ diff --git a/search/Sim.cc b/search/Sim.cc index 31e7ca8e..bf459097 100644 --- a/search/Sim.cc +++ b/search/Sim.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "Sim.hh" @@ -68,10 +68,7 @@ Sim::Sim(StaState *sta) : { } -Sim::~Sim() -{ - delete observer_; -} +Sim::~Sim() { delete observer_; } void Sim::copyState(const StaState *sta) @@ -92,9 +89,8 @@ Sim::functionSense(const FuncExpr *expr, const Pin *input_pin, const Instance *inst) { - debugPrint(debug_, "sim", 4, "find sense pin %s %s", - network_->pathName(input_pin), - expr->to_string().c_str()); + debugPrint(debug_, "sim", 4, "find sense pin {} {}", network_->pathName(input_pin), + expr->to_string()); bool increasing, decreasing; { LockGuard lock(bdd_lock_); @@ -103,10 +99,10 @@ Sim::functionSense(const FuncExpr *expr, LibertyPort *input_port = network_->libertyPort(input_pin); DdNode *input_node = bdd_.ensureNode(input_port); unsigned int input_index = Cudd_NodeReadIndex(input_node); - increasing = (Cudd_Increasing(cudd_mgr, bdd, input_index) - == Cudd_ReadOne(cudd_mgr)); - decreasing = (Cudd_Decreasing(cudd_mgr, bdd, input_index) - == Cudd_ReadOne(cudd_mgr)); + increasing = + (Cudd_Increasing(cudd_mgr, bdd, input_index) == Cudd_ReadOne(cudd_mgr)); + decreasing = + (Cudd_Decreasing(cudd_mgr, bdd, input_index) == Cudd_ReadOne(cudd_mgr)); Cudd_RecursiveDeref(cudd_mgr, bdd); bdd_.clearVarMap(); } @@ -119,7 +115,7 @@ Sim::functionSense(const FuncExpr *expr, sense = TimingSense::negative_unate; else sense = TimingSense::non_unate; - debugPrint(debug_, "sim", 4, " %s", to_string(sense)); + debugPrint(debug_, "sim", 4, " {}", to_string(sense)); return sense; } @@ -159,16 +155,17 @@ Sim::funcBddSim(const FuncExpr *expr, LogicValue value = simValue(pin); int var_index = Cudd_NodeReadIndex(port_node); switch (value) { - case LogicValue::zero: - bdd = Cudd_bddCompose(cudd_mgr, bdd, Cudd_ReadLogicZero(cudd_mgr), var_index); - Cudd_Ref(bdd); - break; - case LogicValue::one: - bdd = Cudd_bddCompose(cudd_mgr, bdd, Cudd_ReadOne(cudd_mgr), var_index); - Cudd_Ref(bdd); - break; - default: - break; + case LogicValue::zero: + bdd = Cudd_bddCompose(cudd_mgr, bdd, Cudd_ReadLogicZero(cudd_mgr), + var_index); + Cudd_Ref(bdd); + break; + case LogicValue::one: + bdd = Cudd_bddCompose(cudd_mgr, bdd, Cudd_ReadOne(cudd_mgr), var_index); + Cudd_Ref(bdd); + break; + default: + break; } } } @@ -243,16 +240,14 @@ bool Sim::isConstant(const Vertex *vertex) const { LogicValue value = simValue(vertex); - return value == LogicValue::zero - || value == LogicValue::one; + return value == LogicValue::zero || value == LogicValue::one; } bool Sim::isConstant(const Pin *pin) const { LogicValue value = simValue(pin); - return value == LogicValue::zero - || value == LogicValue::one; + return value == LogicValue::zero || value == LogicValue::one; } TimingSense @@ -283,8 +278,7 @@ Sim::setSimTimingSense(Edge *edge, bool Sim::isDisabledCond(const Edge *edge) const { - return edge->hasDisabledCond() - && edge_disabled_cond_set_.contains(edge); + return edge->hasDisabledCond() && edge_disabled_cond_set_.contains(edge); } //////////////////////////////////////////////////////////////// @@ -356,13 +350,12 @@ Sim::propagateFromInvalidDrvrsToLoads() { for (const Pin *drvr_pin : invalid_drvr_pins_) { LogicValue value = const_func_pins_.contains(drvr_pin) - ? pinConstFuncValue(drvr_pin) - : simValue(drvr_pin); - PinConnectedPinIterator *load_iter=network_->connectedPinIterator(drvr_pin); + ? pinConstFuncValue(drvr_pin) + : simValue(drvr_pin); + PinConnectedPinIterator *load_iter = network_->connectedPinIterator(drvr_pin); while (load_iter->hasNext()) { const Pin *load_pin = load_iter->next(); - if (load_pin != drvr_pin - && network_->isLoad(load_pin)) + if (load_pin != drvr_pin && network_->isLoad(load_pin)) setPinValue(load_pin, value); } delete load_iter; @@ -413,8 +406,7 @@ Sim::recordConstPinFunc(const Pin *pin) if (expr // Tristate outputs do not force the output to be constant. && port->tristateEnable() == nullptr - && (expr->op() == FuncExpr::Op::zero - || expr->op() == FuncExpr::Op::one)) + && (expr->op() == FuncExpr::Op::zero || expr->op() == FuncExpr::Op::one)) const_func_pins_.insert(pin); } } @@ -507,17 +499,15 @@ void Sim::setConstraintConstPins(const LogicValueMap &value_map) { for (const auto [pin, value] : value_map) { - debugPrint(debug_, "sim", 2, "case pin %s = %c", - network_->pathName(pin), + debugPrint(debug_, "sim", 2, "case pin {} = {}", network_->pathName(pin), logicValueString(value)); if (network_->isHierarchical(pin)) { // Set the logic value on pins inside the instance of a hierarchical pin. bool pin_is_output = network_->direction(pin)->isAnyOutput(); - PinConnectedPinIterator *pin_iter=network_->connectedPinIterator(pin); + PinConnectedPinIterator *pin_iter = network_->connectedPinIterator(pin); while (pin_iter->hasNext()) { const Pin *pin1 = pin_iter->next(); - if (network_->isLeaf(pin1) - && network_->direction(pin1)->isAnyInput() + if (network_->isLeaf(pin1) && network_->direction(pin1)->isAnyInput() && ((pin_is_output && !network_->isInside(pin1, pin)) || (!pin_is_output && network_->isInside(pin1, pin)))) setPinValue(pin1, value); @@ -537,8 +527,7 @@ Sim::setConstFuncPins() for (const Pin *pin : const_func_pins_) { LogicValue value = pinConstFuncValue(pin); setPinValue(pin, value); - debugPrint(debug_, "sim", 2, "func pin %s = %c", - network_->pathName(pin), + debugPrint(debug_, "sim", 2, "func pin {} = {}", network_->pathName(pin), logicValueString(value)); } } @@ -565,9 +554,8 @@ Sim::enqueueConstantPinInputs() LogicValue value; const Pin *pin; const_iter->next(pin, value); - debugPrint(debug_, "sim", 2, "network constant pin %s = %c", - network_->pathName(pin), - logicValueString(value)); + debugPrint(debug_, "sim", 2, "network constant pin {} = {}", + network_->pathName(pin), logicValueString(value)); setPinValue(pin, value); } delete const_iter; @@ -587,7 +575,7 @@ Sim::removePropagatedValue(const Pin *pin) if (!exists) { sdc->logicValue(pin, constraint_value, exists); if (!exists) { - debugPrint(debug_, "sim", 2, "pin %s remove prop constant", + debugPrint(debug_, "sim", 2, "pin {} remove prop constant", network_->pathName(pin)); setSimValue(pin, LogicValue::unknown); } @@ -604,17 +592,16 @@ Sim::setPinValue(const Pin *pin, sdc->caseLogicValue(pin, constraint_value, exists); if (!exists) sdc->logicValue(pin, constraint_value, exists); - if (exists - && value != constraint_value) { + if (exists && value != constraint_value) { if (value != LogicValue::unknown) - report_->warn(1521, "propagated logic value %c differs from constraint value of %c on pin %s.", - logicValueString(value), - logicValueString(constraint_value), - sdc_network_->pathName(pin)); + report_->warn( + 1521, + "propagated logic value {} differs from constraint value of {} on pin {}.", + logicValueString(value), logicValueString(constraint_value), + sdc_network_->pathName(pin)); } else { - debugPrint(debug_, "sim", 3, "pin %s = %c", - network_->pathName(pin), + debugPrint(debug_, "sim", 3, "pin {} = {}", network_->pathName(pin), logicValueString(value)); bool value_changed = false; value_changed |= value != simValue(pin); @@ -623,19 +610,16 @@ Sim::setPinValue(const Pin *pin, Instance *inst = network_->instance(pin); instances_to_annotate_.insert(inst); - if (network_->isLeaf(inst) - && network_->direction(pin)->isAnyInput()) { - if (eval_queue_.empty() - || (eval_queue_.back() != inst)) + if (network_->isLeaf(inst) && network_->direction(pin)->isAnyInput()) { + if (eval_queue_.empty() || (eval_queue_.back() != inst)) eval_queue_.push(inst); } else if (network_->isDriver(pin)) { // Enqueue instances with input pins connected to net. - PinConnectedPinIterator *pin_iter=network_->connectedPinIterator(pin); + PinConnectedPinIterator *pin_iter = network_->connectedPinIterator(pin); while (pin_iter->hasNext()) { const Pin *pin1 = pin_iter->next(); - if (pin1 != pin - && network_->isLoad(pin1)) + if (pin1 != pin && network_->isLoad(pin1)) setPinValue(pin1, value); } delete pin_iter; @@ -648,7 +632,7 @@ void Sim::evalInstance(const Instance *inst, bool thru_sequentials) { - debugPrint(debug_, "sim", 2, "eval %s", network_->pathName(inst)); + debugPrint(debug_, "sim", 2, "eval {}", network_->pathName(inst)); InstancePinIterator *pin_iter = network_->pinIterator(inst); while (pin_iter->hasNext()) { Pin *pin = pin_iter->next(); @@ -664,39 +648,32 @@ Sim::evalInstance(const Instance *inst, if (tri_en_expr) { if (evalExpr(tri_en_expr, inst) == LogicValue::one) { value = evalExpr(expr, inst); - debugPrint(debug_, "sim", 2, " %s tri_en=1 %s = %c", - port->name(), - expr->to_string().c_str(), - logicValueString(value)); + debugPrint(debug_, "sim", 2, " {} tri_en=1 {} = {}", port->name(), + expr->to_string(), logicValueString(value)); } } else { LibertyPort *expr_port = expr->port(); - Sequential *sequential = (thru_sequentials && expr_port) - ? cell->outputPortSequential(expr_port) - : nullptr; + Sequential *sequential = (thru_sequentials && expr_port) + ? cell->outputPortSequential(expr_port) + : nullptr; if (sequential) { value = evalExpr(sequential->data(), inst); if (expr_port == sequential->outputInv()) value = logicNot(value); - debugPrint(debug_, "sim", 2, " %s seq %s = %c", - port->name(), - expr->to_string().c_str(), - logicValueString(value)); + debugPrint(debug_, "sim", 2, " {} seq {} = {}", port->name(), + expr->to_string(), logicValueString(value)); } else { value = evalExpr(expr, inst); - debugPrint(debug_, "sim", 2, " %s %s = %c", - port->name(), - expr->to_string().c_str(), - logicValueString(value)); + debugPrint(debug_, "sim", 2, " {} {} = {}", port->name(), + expr->to_string(), logicValueString(value)); } } } else if (port->isClockGateOut()) { value = clockGateOutValue(inst); - debugPrint(debug_, "sim", 2, " %s gated_clk = %c", - port->name(), + debugPrint(debug_, "sim", 2, " {} gated_clk = {}", port->name(), logicValueString(value)); } if (value != simValue(pin)) @@ -714,11 +691,9 @@ Sim::clockGateOutValue(const Instance *inst) LibertyCellPortIterator port_iter(cell); while (port_iter.hasNext()) { LibertyPort *port = port_iter.next(); - if (port->isClockGateClock() - || port->isClockGateEnable()) { + if (port->isClockGateClock() || port->isClockGateEnable()) { Pin *gclk_pin = network_->findPin(inst, port); - if (gclk_pin - && simValue(gclk_pin) == LogicValue::zero) + if (gclk_pin && simValue(gclk_pin) == LogicValue::zero) return LogicValue::zero; } } @@ -932,15 +907,15 @@ Sim::isDisabledMode(Edge *edge, void Sim::findDisabledEdges() { - for (const Instance *inst : instances_to_annotate_) - findDisabledEdges(inst); - instances_to_annotate_.clear(); + for (const Instance *inst : instances_to_annotate_) + findDisabledEdges(inst); + instances_to_annotate_.clear(); } void Sim::findDisabledEdges(const Instance *inst) { - debugPrint(debug_, "sim", 4, "annotate %s", network_->pathName(inst)); + debugPrint(debug_, "sim", 4, "annotate {}", network_->pathName(inst)); InstancePinIterator *pin_iter = network_->pinIterator(inst); while (pin_iter->hasNext()) { Pin *pin = pin_iter->next(); @@ -974,9 +949,9 @@ Sim::findDisabledEdges(const Instance *inst, if (sense != TimingSense::none) // Disable conditional timing edges based on constant pins. is_disabled_cond = isDisabledCond(edge, inst, from_pin, pin) - // Disable mode conditional timing - // edges based on constant pins. - || isDisabledMode(edge,inst); + // Disable mode conditional timing + // edges based on constant pins. + || isDisabledMode(edge, inst); bool disables_changed = false; if (sense != simTimingSense(edge)) { @@ -997,4 +972,4 @@ Sim::findDisabledEdges(const Instance *inst, observer_->faninEdgesChangeAfter(vertex->pin()); } -} // namespace +} // namespace sta diff --git a/search/Sta.cc b/search/Sta.cc index e6d7de67..12645170 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "Sta.hh" @@ -29,6 +29,7 @@ #include #include "Machine.hh" +#include "Format.hh" #include "ContainerHelpers.hh" #include "DispatchQueue.hh" #include "ReportTcl.hh" @@ -87,18 +88,21 @@ #include "MakeTimingModel.hh" #include "parasitics/ConcreteParasitics.hh" #include "spice/WritePathSpice.hh" +#include "DelayScalar.hh" +#include "DelayNormal.hh" +#include "DelaySkewNormal.hh" namespace sta { static bool libertyPortCapsEqual(const LibertyPort *port1, - const LibertyPort *port2); + const LibertyPort *port2); static bool hasDisabledArcs(Edge *edge, const Mode *mode); static InstanceSet pinInstances(PinSet &pins, - const Network *network); + const Network *network); //////////////////////////////////////////////////////////////// // @@ -198,7 +202,8 @@ StaSimObserver::fanoutEdgesChangeAfter(const Pin *pin) class StaLevelizeObserver : public LevelizeObserver { public: - StaLevelizeObserver(Search *search, GraphDelayCalc *graph_delay_calc); + StaLevelizeObserver(Search *search, + GraphDelayCalc *graph_delay_calc); void levelsChangedBefore() override; void levelChangedBefore(Vertex *vertex) override; @@ -300,6 +305,7 @@ Sta::makeComponents() makePower(); makeClkSkews(); makeCheckTiming(); + delay_ops_ = new DelayOpsScalar(); setCmdNamespace1(CmdNamespace::sdc); setThreadCount1(defaultThreadCount()); @@ -526,6 +532,7 @@ Sta::~Sta() delete equiv_cells_; delete dispatch_queue_; delete variables_; + delete delay_ops_; deleteContents(parasitics_name_map_); deleteContents(modes_); deleteContents(scenes_); @@ -578,8 +585,7 @@ Sta::setCmdMode(const std::string &mode_name) { if (!mode_name.empty()) { if (!mode_name_map_.contains(mode_name)) { - if (modes_.size() == 1 - && modes_[0]->name() == "default") { + if (modes_.size() == 1 && modes_[0]->name() == "default") { // No need for default mode if one is defined. delete modes_[0]; mode_name_map_.clear(); @@ -591,8 +597,7 @@ Sta::setCmdMode(const std::string &mode_name) mode->sim()->setMode(mode); mode->sim()->setObserver(new StaSimObserver(this)); - if (scenes_.size() == 1 - && scenes_[0]->name() == "default") + if (scenes_.size() == 1 && scenes_[0]->name() == "default") scenes_[0]->setMode(mode); updateComponentsState(); } @@ -660,12 +665,12 @@ Sta::setCmdNamespace1(CmdNamespace namespc) { cmd_namespace_ = namespc; switch (cmd_namespace_) { - case CmdNamespace::sta: - cmd_network_ = network_; - break; - case CmdNamespace::sdc: - cmd_network_ = sdc_network_; - break; + case CmdNamespace::sta: + cmd_network_ = network_; + break; + case CmdNamespace::sdc: + cmd_network_ = sdc_network_; + break; } } @@ -689,12 +694,11 @@ Sta::setCurrentInstance(Instance *inst) LibertyLibrary * Sta::readLiberty(const char *filename, Scene *scene, - const MinMaxAll *min_max, - bool infer_latches) + const MinMaxAll *min_max, + bool infer_latches) { Stats stats(debug_, report_); - LibertyLibrary *library = readLibertyFile(filename, scene, min_max, - infer_latches); + LibertyLibrary *library = readLibertyFile(filename, scene, min_max, infer_latches); if (library // The default library is the first library read. // This corresponds to a link_path of '*'. @@ -710,11 +714,10 @@ Sta::readLiberty(const char *filename, LibertyLibrary * Sta::readLibertyFile(const char *filename, Scene *scene, - const MinMaxAll *min_max, - bool infer_latches) + const MinMaxAll *min_max, + bool infer_latches) { - LibertyLibrary *liberty = sta::readLibertyFile(filename, infer_latches, - network_); + LibertyLibrary *liberty = sta::readLibertyFile(filename, infer_latches, network_); if (liberty) { // Don't map liberty cells if they are redefined by reading another // library with the same cell names. @@ -731,7 +734,7 @@ Sta::readLibertyFile(const char *filename, LibertyLibrary * Sta::readLibertyFile(const char *filename, - bool infer_latches) + bool infer_latches) { return sta::readLibertyFile(filename, infer_latches, network_); } @@ -739,11 +742,11 @@ Sta::readLibertyFile(const char *filename, void Sta::readLibertyAfter(LibertyLibrary *liberty, Scene *scene, - const MinMax *min_max) + const MinMax *min_max) { scene->addLiberty(liberty, min_max); - LibertyLibrary::makeSceneMap(liberty, scene->libertyIndex(min_max), - network_, report_); + LibertyLibrary::makeSceneMap(liberty, scene->libertyIndex(min_max), network_, + report_); } bool @@ -775,9 +778,7 @@ Sta::linkDesign(const char *top_cell_name, { clear(); Stats stats(debug_, report_); - bool status = network_->linkNetwork(top_cell_name, - make_black_boxes, - report_); + bool status = network_->linkNetwork(top_cell_name, make_black_boxes, report_); stats.report("Link"); return status; } @@ -786,7 +787,7 @@ Sta::linkDesign(const char *top_cell_name, void Sta::setDebugLevel(const char *what, - int level) + int level) { debug_->setLevel(what, level); } @@ -832,9 +833,9 @@ Sta::pvt(Instance *inst, void Sta::setPvt(Instance *inst, - const MinMaxAll *min_max, - float process, - float voltage, + const MinMaxAll *min_max, + float process, + float voltage, float temperature, Sdc *sdc) { @@ -844,7 +845,7 @@ Sta::setPvt(Instance *inst, void Sta::setPvt(const Instance *inst, - const MinMaxAll *min_max, + const MinMaxAll *min_max, const Pvt &pvt, Sdc *sdc) { @@ -871,9 +872,9 @@ Sta::setVoltage(const Net *net, void Sta::setTimingDerate(TimingDerateType type, - PathClkOrData clk_data, - const RiseFallBoth *rf, - const EarlyLate *early_late, + PathClkOrData clk_data, + const RiseFallBoth *rf, + const EarlyLate *early_late, float derate, Sdc *sdc) { @@ -885,9 +886,9 @@ Sta::setTimingDerate(TimingDerateType type, void Sta::setTimingDerate(const Net *net, - PathClkOrData clk_data, - const RiseFallBoth *rf, - const EarlyLate *early_late, + PathClkOrData clk_data, + const RiseFallBoth *rf, + const EarlyLate *early_late, float derate, Sdc *sdc) { @@ -899,10 +900,10 @@ Sta::setTimingDerate(const Net *net, void Sta::setTimingDerate(const Instance *inst, - TimingDerateCellType type, - PathClkOrData clk_data, - const RiseFallBoth *rf, - const EarlyLate *early_late, + TimingDerateCellType type, + PathClkOrData clk_data, + const RiseFallBoth *rf, + const EarlyLate *early_late, float derate, Sdc *sdc) { @@ -914,10 +915,10 @@ Sta::setTimingDerate(const Instance *inst, void Sta::setTimingDerate(const LibertyCell *cell, - TimingDerateCellType type, - PathClkOrData clk_data, - const RiseFallBoth *rf, - const EarlyLate *early_late, + TimingDerateCellType type, + PathClkOrData clk_data, + const RiseFallBoth *rf, + const EarlyLate *early_late, float derate, Sdc *sdc) { @@ -938,8 +939,8 @@ Sta::unsetTimingDerate(Sdc *sdc) void Sta::setInputSlew(const Port *port, - const RiseFallBoth *rf, - const MinMaxAll *min_max, + const RiseFallBoth *rf, + const MinMaxAll *min_max, float slew, Sdc *sdc) { @@ -949,24 +950,24 @@ Sta::setInputSlew(const Port *port, void Sta::setDriveCell(const LibertyLibrary *library, - const LibertyCell *cell, - const Port *port, - const LibertyPort *from_port, - float *from_slews, - const LibertyPort *to_port, - const RiseFallBoth *rf, + const LibertyCell *cell, + const Port *port, + const LibertyPort *from_port, + float *from_slews, + const LibertyPort *to_port, + const RiseFallBoth *rf, const MinMaxAll *min_max, Sdc *sdc) { - sdc->setDriveCell(library, cell, port, from_port, from_slews, to_port, - rf, min_max); + sdc->setDriveCell(library, cell, port, from_port, from_slews, to_port, rf, + min_max); delaysInvalidFrom(port); } void Sta::setDriveResistance(const Port *port, - const RiseFallBoth *rf, - const MinMaxAll *min_max, + const RiseFallBoth *rf, + const MinMaxAll *min_max, float res, Sdc *sdc) { @@ -1011,7 +1012,7 @@ Sta::setMinPulseWidth(const RiseFallBoth *rf, void Sta::setMinPulseWidth(const Pin *pin, - const RiseFallBoth *rf, + const RiseFallBoth *rf, float min_width, Sdc *sdc) { @@ -1020,7 +1021,7 @@ Sta::setMinPulseWidth(const Pin *pin, void Sta::setMinPulseWidth(const Instance *inst, - const RiseFallBoth *rf, + const RiseFallBoth *rf, float min_width, Sdc *sdc) { @@ -1029,7 +1030,7 @@ Sta::setMinPulseWidth(const Instance *inst, void Sta::setMinPulseWidth(const Clock *clk, - const RiseFallBoth *rf, + const RiseFallBoth *rf, float min_width, Sdc *sdc) { @@ -1064,9 +1065,9 @@ Sta::setWireloadSelection(WireloadSelection *selection, void Sta::setSlewLimit(Clock *clk, - const RiseFallBoth *rf, - const PathClkOrData clk_data, - const MinMax *min_max, + const RiseFallBoth *rf, + const PathClkOrData clk_data, + const MinMax *min_max, float slew, Sdc *sdc) { @@ -1075,7 +1076,7 @@ Sta::setSlewLimit(Clock *clk, void Sta::setSlewLimit(Port *port, - const MinMax *min_max, + const MinMax *min_max, float slew, Sdc *sdc) { @@ -1084,7 +1085,7 @@ Sta::setSlewLimit(Port *port, void Sta::setSlewLimit(Cell *cell, - const MinMax *min_max, + const MinMax *min_max, float slew, Sdc *sdc) { @@ -1093,7 +1094,7 @@ Sta::setSlewLimit(Cell *cell, void Sta::setCapacitanceLimit(Cell *cell, - const MinMax *min_max, + const MinMax *min_max, float cap, Sdc *sdc) { @@ -1102,7 +1103,7 @@ Sta::setCapacitanceLimit(Cell *cell, void Sta::setCapacitanceLimit(Port *port, - const MinMax *min_max, + const MinMax *min_max, float cap, Sdc *sdc) { @@ -1111,7 +1112,7 @@ Sta::setCapacitanceLimit(Port *port, void Sta::setCapacitanceLimit(Pin *pin, - const MinMax *min_max, + const MinMax *min_max, float cap, Sdc *sdc) { @@ -1120,7 +1121,7 @@ Sta::setCapacitanceLimit(Pin *pin, void Sta::setFanoutLimit(Cell *cell, - const MinMax *min_max, + const MinMax *min_max, float fanout, Sdc *sdc) { @@ -1129,7 +1130,7 @@ Sta::setFanoutLimit(Cell *cell, void Sta::setFanoutLimit(Port *port, - const MinMax *min_max, + const MinMax *min_max, float fanout, Sdc *sdc) { @@ -1145,10 +1146,10 @@ Sta::setMaxArea(float area, void Sta::makeClock(const char *name, - PinSet *pins, - bool add_to_pins, - float period, - FloatSeq *waveform, + PinSet *pins, + bool add_to_pins, + float period, + FloatSeq *waveform, char *comment, const Mode *mode) { @@ -1161,25 +1162,23 @@ Sta::makeClock(const char *name, void Sta::makeGeneratedClock(const char *name, - PinSet *pins, - bool add_to_pins, - Pin *src_pin, - Clock *master_clk, - int divide_by, - int multiply_by, - float duty_cycle, - bool invert, - bool combinational, - IntSeq *edges, - FloatSeq *edge_shifts, + PinSet *pins, + bool add_to_pins, + Pin *src_pin, + Clock *master_clk, + int divide_by, + int multiply_by, + float duty_cycle, + bool invert, + bool combinational, + IntSeq *edges, + FloatSeq *edge_shifts, char *comment, const Mode *mode) { - mode->sdc()->makeGeneratedClock(name, pins, add_to_pins, - src_pin, master_clk, - divide_by, multiply_by, duty_cycle, - invert, combinational, - edges, edge_shifts, comment); + mode->sdc()->makeGeneratedClock(name, pins, add_to_pins, src_pin, master_clk, + divide_by, multiply_by, duty_cycle, invert, + combinational, edges, edge_shifts, comment); update_genclks_ = true; search_->arrivalsInvalid(); power_->activitiesInvalid(); @@ -1240,8 +1239,8 @@ Sta::removePropagatedClock(Pin *pin, void Sta::setClockSlew(Clock *clk, - const RiseFallBoth *rf, - const MinMaxAll *min_max, + const RiseFallBoth *rf, + const MinMaxAll *min_max, float slew, Sdc *sdc) { @@ -1267,9 +1266,9 @@ Sta::clockSlewChanged(Clock *clk) void Sta::setClockLatency(Clock *clk, - Pin *pin, - const RiseFallBoth *rf, - const MinMaxAll *min_max, + Pin *pin, + const RiseFallBoth *rf, + const MinMaxAll *min_max, float delay, Sdc *sdc) { @@ -1288,10 +1287,10 @@ Sta::removeClockLatency(const Clock *clk, void Sta::setClockInsertion(const Clock *clk, - const Pin *pin, - const RiseFallBoth *rf, - const MinMaxAll *min_max, - const EarlyLateAll *early_late, + const Pin *pin, + const RiseFallBoth *rf, + const MinMaxAll *min_max, + const EarlyLateAll *early_late, float delay, Sdc *sdc) { @@ -1310,8 +1309,8 @@ Sta::removeClockInsertion(const Clock *clk, void Sta::setClockUncertainty(Clock *clk, - const SetupHoldAll *setup_hold, - float uncertainty) + const SetupHoldAll *setup_hold, + float uncertainty) { clk->setUncertainty(setup_hold, uncertainty); search_->arrivalsInvalid(); @@ -1319,7 +1318,7 @@ Sta::setClockUncertainty(Clock *clk, void Sta::removeClockUncertainty(Clock *clk, - const SetupHoldAll *setup_hold) + const SetupHoldAll *setup_hold) { clk->removeUncertainty(setup_hold); search_->arrivalsInvalid(); @@ -1327,7 +1326,7 @@ Sta::removeClockUncertainty(Clock *clk, void Sta::setClockUncertainty(Pin *pin, - const SetupHoldAll *setup_hold, + const SetupHoldAll *setup_hold, float uncertainty, Sdc *sdc) { @@ -1346,23 +1345,23 @@ Sta::removeClockUncertainty(Pin *pin, void Sta::setClockUncertainty(Clock *from_clk, - const RiseFallBoth *from_rf, - Clock *to_clk, - const RiseFallBoth *to_rf, - const SetupHoldAll *setup_hold, + const RiseFallBoth *from_rf, + Clock *to_clk, + const RiseFallBoth *to_rf, + const SetupHoldAll *setup_hold, float uncertainty, Sdc *sdc) { - sdc->setClockUncertainty(from_clk, from_rf, to_clk, to_rf, - setup_hold, uncertainty); + sdc->setClockUncertainty(from_clk, from_rf, to_clk, to_rf, setup_hold, + uncertainty); search_->arrivalsInvalid(); } void Sta::removeClockUncertainty(Clock *from_clk, - const RiseFallBoth *from_rf, - Clock *to_clk, - const RiseFallBoth *to_rf, + const RiseFallBoth *from_rf, + Clock *to_clk, + const RiseFallBoth *to_rf, const SetupHoldAll *setup_hold, Sdc *sdc) { @@ -1371,26 +1370,31 @@ Sta::removeClockUncertainty(Clock *from_clk, } ClockGroups * -Sta::makeClockGroups(const char *name, - bool logically_exclusive, - bool physically_exclusive, - bool asynchronous, - bool allow_paths, +Sta::makeClockGroups(const std::string &name, + bool logically_exclusive, + bool physically_exclusive, + bool asynchronous, + bool allow_paths, const char *comment, Sdc *sdc) { - ClockGroups *groups = sdc->makeClockGroups(name, - logically_exclusive, - physically_exclusive, - asynchronous, - allow_paths, - comment); + ClockGroups *groups = sdc->makeClockGroups(name, logically_exclusive, + physically_exclusive, + asynchronous, allow_paths, + comment); search_->requiredsInvalid(); return groups; } void -Sta::removeClockGroupsLogicallyExclusive(const char *name, +Sta::removeClockGroupsLogicallyExclusive(Sdc *sdc) +{ + sdc->removeClockGroupsLogicallyExclusive(); + search_->requiredsInvalid(); +} + +void +Sta::removeClockGroupsLogicallyExclusive(const std::string &name, Sdc *sdc) { sdc->removeClockGroupsLogicallyExclusive(name); @@ -1398,7 +1402,14 @@ Sta::removeClockGroupsLogicallyExclusive(const char *name, } void -Sta::removeClockGroupsPhysicallyExclusive(const char *name, +Sta::removeClockGroupsPhysicallyExclusive(Sdc *sdc) +{ + sdc->removeClockGroupsPhysicallyExclusive(); + search_->requiredsInvalid(); +} + +void +Sta::removeClockGroupsPhysicallyExclusive(const std::string &name, Sdc *sdc) { sdc->removeClockGroupsPhysicallyExclusive(name); @@ -1406,7 +1417,14 @@ Sta::removeClockGroupsPhysicallyExclusive(const char *name, } void -Sta::removeClockGroupsAsynchronous(const char *name, +Sta::removeClockGroupsAsynchronous(Sdc *sdc) +{ + sdc->removeClockGroupsAsynchronous(); + search_->requiredsInvalid(); +} + +void +Sta::removeClockGroupsAsynchronous(const std::string &name, Sdc *sdc) { sdc->removeClockGroupsAsynchronous(name); @@ -1423,7 +1441,7 @@ Sta::makeClockGroup(ClockGroups *clk_groups, void Sta::setClockSense(PinSet *pins, - ClockSet *clks, + ClockSet *clks, ClockSense sense, Sdc *sdc) { @@ -1435,7 +1453,7 @@ Sta::setClockSense(PinSet *pins, void Sta::setClockGatingCheck(const RiseFallBoth *rf, - const SetupHold *setup_hold, + const SetupHold *setup_hold, float margin, Sdc *sdc) { @@ -1445,8 +1463,8 @@ Sta::setClockGatingCheck(const RiseFallBoth *rf, void Sta::setClockGatingCheck(Clock *clk, - const RiseFallBoth *rf, - const SetupHold *setup_hold, + const RiseFallBoth *rf, + const SetupHold *setup_hold, float margin, Sdc *sdc) { @@ -1456,48 +1474,48 @@ Sta::setClockGatingCheck(Clock *clk, void Sta::setClockGatingCheck(Instance *inst, - const RiseFallBoth *rf, - const SetupHold *setup_hold, - float margin, + const RiseFallBoth *rf, + const SetupHold *setup_hold, + float margin, LogicValue active_value, Sdc *sdc) { - sdc->setClockGatingCheck(inst, rf, setup_hold, margin,active_value); + sdc->setClockGatingCheck(inst, rf, setup_hold, margin, active_value); search_->arrivalsInvalid(); } void Sta::setClockGatingCheck(Pin *pin, - const RiseFallBoth *rf, - const SetupHold *setup_hold, - float margin, + const RiseFallBoth *rf, + const SetupHold *setup_hold, + float margin, LogicValue active_value, Sdc *sdc) { - sdc->setClockGatingCheck(pin, rf, setup_hold, margin,active_value); + sdc->setClockGatingCheck(pin, rf, setup_hold, margin, active_value); search_->arrivalsInvalid(); } void Sta::setDataCheck(Pin *from, - const RiseFallBoth *from_rf, - Pin *to, - const RiseFallBoth *to_rf, - Clock *clk, - const SetupHoldAll *setup_hold, + const RiseFallBoth *from_rf, + Pin *to, + const RiseFallBoth *to_rf, + Clock *clk, + const SetupHoldAll *setup_hold, float margin, Sdc *sdc) { - sdc->setDataCheck(from, from_rf, to, to_rf, clk, setup_hold,margin); + sdc->setDataCheck(from, from_rf, to, to_rf, clk, setup_hold, margin); search_->requiredInvalid(to); } void Sta::removeDataCheck(Pin *from, - const RiseFallBoth *from_rf, - Pin *to, - const RiseFallBoth *to_rf, - Clock *clk, + const RiseFallBoth *from_rf, + Pin *to, + const RiseFallBoth *to_rf, + Clock *clk, const SetupHoldAll *setup_hold, Sdc *sdc) { @@ -1528,7 +1546,7 @@ Sta::removeDisable(Pin *pin, void Sta::disable(Instance *inst, - LibertyPort *from, + LibertyPort *from, LibertyPort *to, Sdc *sdc) { @@ -1554,7 +1572,7 @@ Sta::disable(Instance *inst, void Sta::removeDisable(Instance *inst, - LibertyPort *from, + LibertyPort *from, LibertyPort *to, Sdc *sdc) { @@ -1580,7 +1598,7 @@ Sta::removeDisable(Instance *inst, void Sta::disable(LibertyCell *cell, - LibertyPort *from, + LibertyPort *from, LibertyPort *to, Sdc *sdc) { @@ -1590,7 +1608,7 @@ Sta::disable(LibertyCell *cell, void Sta::removeDisable(LibertyCell *cell, - LibertyPort *from, + LibertyPort *from, LibertyPort *to, Sdc *sdc) { @@ -1682,18 +1700,15 @@ Sta::disabledEdges(const Mode *mode) VertexOutEdgeIterator edge_iter(vertex, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); - if (isDisabledConstant(edge, mode) - || isDisabledCondDefault(edge) - || isDisabledConstraint(edge, sdc) - || edge->isDisabledLoop() - || isDisabledPresetClr(edge)) - disabled_edges.push_back(edge); + if (isDisabledConstant(edge, mode) || isDisabledCondDefault(edge) + || isDisabledConstraint(edge, sdc) || edge->isDisabledLoop() + || isDisabledPresetClr(edge)) + disabled_edges.push_back(edge); } } return disabled_edges; } - EdgeSeq Sta::disabledEdgesSorted(const Mode *mode) { @@ -1708,9 +1723,8 @@ Sta::isDisabledConstraint(Edge *edge, { Pin *from_pin = edge->from(graph_)->pin(); Pin *to_pin = edge->to(graph_)->pin(); - return sdc->isDisabledConstraint(from_pin) - || sdc->isDisabledConstraint(to_pin) - || sdc->isDisabledConstraint(edge); + return sdc->isDisabledConstraint(from_pin) || sdc->isDisabledConstraint(to_pin) + || sdc->isDisabledConstraint(edge); } bool @@ -1734,12 +1748,10 @@ Sta::isDisabledConstant(Edge *edge, Vertex *to_vertex = edge->to(graph_); Pin *to_pin = to_vertex->pin(); const Instance *inst = network_->instance(from_pin); - return sim->isConstant(from_vertex) - || sim->isConstant(to_vertex) - || (!role->isWire() - && (sim->isDisabledCond(edge, inst, from_pin, to_pin) - || sim->isDisabledMode(edge, inst) - || hasDisabledArcs(edge, mode))); + return sim->isConstant(from_vertex) || sim->isConstant(to_vertex) + || (!role->isWire() + && (sim->isDisabledCond(edge, inst, from_pin, to_pin) + || sim->isDisabledMode(edge, inst) || hasDisabledArcs(edge, mode))); } static bool @@ -1781,8 +1793,7 @@ Sta::disabledConstantPins(Edge *edge, const Instance *inst = network_->instance(to_pin); bool is_disabled; FuncExpr *disable_cond; - sim->isDisabledCond(edge, inst, from_pin, to_pin, - is_disabled, disable_cond); + sim->isDisabledCond(edge, inst, from_pin, to_pin, is_disabled, disable_cond); if (is_disabled) exprConstantPins(disable_cond, inst, mode, pins); sim->isDisabledMode(edge, inst, is_disabled, disable_cond); @@ -1791,9 +1802,8 @@ Sta::disabledConstantPins(Edge *edge, if (hasDisabledArcs(edge, mode)) { LibertyPort *to_port = network_->libertyPort(to_pin); if (to_port) { - FuncExpr *func = to_port->function(); - if (func - && sim->functionSense(inst, from_pin, to_pin) != edge->sense()) + FuncExpr *func = to_port->function(); + if (func && sim->functionSense(inst, from_pin, to_pin) != edge->sense()) exprConstantPins(func, inst, mode, pins); } } @@ -1824,7 +1834,7 @@ Sta::exprConstantPins(FuncExpr *expr, if (pin) { LogicValue value = mode->sim()->simValue(pin); if (value != LogicValue::unknown) - pins.insert(pin); + pins.insert(pin); } } } @@ -1832,15 +1842,14 @@ Sta::exprConstantPins(FuncExpr *expr, bool Sta::isDisabledBidirectInstPath(Edge *edge) const { - return !variables_->bidirectInstPathsEnabled() - && edge->isBidirectInstPath(); + return !variables_->bidirectInstPathsEnabled() && edge->isBidirectInstPath(); } bool Sta::isDisabledPresetClr(Edge *edge) const { return !variables_->presetClrArcsEnabled() - && edge->role() == TimingRole::regSetClr(); + && edge->role() == TimingRole::regSetClr(); } void @@ -1925,29 +1934,28 @@ Sta::removeCaseAnalysis(Pin *pin, void Sta::setInputDelay(const Pin *pin, - const RiseFallBoth *rf, - const Clock *clk, - const RiseFall *clk_rf, - const Pin *ref_pin, - bool source_latency_included, - bool network_latency_included, - const MinMaxAll *min_max, - bool add, + const RiseFallBoth *rf, + const Clock *clk, + const RiseFall *clk_rf, + const Pin *ref_pin, + bool source_latency_included, + bool network_latency_included, + const MinMaxAll *min_max, + bool add, float delay, Sdc *sdc) { - sdc->setInputDelay(pin, rf, clk, clk_rf, ref_pin, - source_latency_included, network_latency_included, - min_max, add, delay); + sdc->setInputDelay(pin, rf, clk, clk_rf, ref_pin, source_latency_included, + network_latency_included, min_max, add, delay); search_->arrivalInvalid(pin); } -void +void Sta::removeInputDelay(const Pin *pin, - const RiseFallBoth *rf, - const Clock *clk, - const RiseFall *clk_rf, + const RiseFallBoth *rf, + const Clock *clk, + const RiseFall *clk_rf, const MinMaxAll *min_max, Sdc *sdc) { @@ -1957,28 +1965,27 @@ Sta::removeInputDelay(const Pin *pin, void Sta::setOutputDelay(const Pin *pin, - const RiseFallBoth *rf, - const Clock *clk, - const RiseFall *clk_rf, - const Pin *ref_pin, - bool source_latency_included, - bool network_latency_included, - const MinMaxAll *min_max, - bool add, + const RiseFallBoth *rf, + const Clock *clk, + const RiseFall *clk_rf, + const Pin *ref_pin, + bool source_latency_included, + bool network_latency_included, + const MinMaxAll *min_max, + bool add, float delay, Sdc *sdc) { - sdc->setOutputDelay(pin, rf, clk, clk_rf, ref_pin, - source_latency_included,network_latency_included, - min_max, add, delay); + sdc->setOutputDelay(pin, rf, clk, clk_rf, ref_pin, source_latency_included, + network_latency_included, min_max, add, delay); search_->requiredInvalid(pin); } -void +void Sta::removeOutputDelay(const Pin *pin, - const RiseFallBoth *rf, - const Clock *clk, - const RiseFall *clk_rf, + const RiseFallBoth *rf, + const Clock *clk, + const RiseFall *clk_rf, const MinMaxAll *min_max, Sdc *sdc) { @@ -1988,9 +1995,9 @@ Sta::removeOutputDelay(const Pin *pin, void Sta::makeFalsePath(ExceptionFrom *from, - ExceptionThruSeq *thrus, - ExceptionTo *to, - const MinMaxAll *min_max, + ExceptionThruSeq *thrus, + ExceptionTo *to, + const MinMaxAll *min_max, const char *comment, Sdc *sdc) { @@ -2000,42 +2007,40 @@ Sta::makeFalsePath(ExceptionFrom *from, void Sta::makeMulticyclePath(ExceptionFrom *from, - ExceptionThruSeq *thrus, - ExceptionTo *to, - const MinMaxAll *min_max, - bool use_end_clk, - int path_multiplier, + ExceptionThruSeq *thrus, + ExceptionTo *to, + const MinMaxAll *min_max, + bool use_end_clk, + int path_multiplier, const char *comment, Sdc *sdc) { - sdc->makeMulticyclePath(from, thrus, to, min_max, - use_end_clk, path_multiplier, - comment); + sdc->makeMulticyclePath(from, thrus, to, min_max, use_end_clk, path_multiplier, + comment); search_->arrivalsInvalid(); } void Sta::makePathDelay(ExceptionFrom *from, - ExceptionThruSeq *thrus, - ExceptionTo *to, - const MinMax *min_max, - bool ignore_clk_latency, + ExceptionThruSeq *thrus, + ExceptionTo *to, + const MinMax *min_max, + bool ignore_clk_latency, bool break_path, - float delay, + float delay, const char *comment, Sdc *sdc) { - sdc->makePathDelay(from, thrus, to, min_max, - ignore_clk_latency, break_path, - delay, comment); + sdc->makePathDelay(from, thrus, to, min_max, ignore_clk_latency, break_path, delay, + comment); search_->endpointsInvalid(); search_->arrivalsInvalid(); } void Sta::resetPath(ExceptionFrom *from, - ExceptionThruSeq *thrus, - ExceptionTo *to, + ExceptionThruSeq *thrus, + ExceptionTo *to, const MinMaxAll *min_max, Sdc *sdc) { @@ -2044,11 +2049,11 @@ Sta::resetPath(ExceptionFrom *from, } void -Sta::makeGroupPath(const char *name, - bool is_default, - ExceptionFrom *from, - ExceptionThruSeq *thrus, - ExceptionTo *to, +Sta::makeGroupPath(const std::string &name, + bool is_default, + ExceptionFrom *from, + ExceptionThruSeq *thrus, + ExceptionTo *to, const char *comment, Sdc *sdc) { @@ -2067,12 +2072,11 @@ bool Sta::isPathGroupName(const char *group_name, const Sdc *sdc) const { - return sdc->findClock(group_name) - || sdc->isGroupPathName(group_name) - || stringEq(group_name, PathGroups::asyncPathGroupName()) - || stringEq(group_name, PathGroups::pathDelayGroupName()) - || stringEq(group_name, PathGroups::gatedClkGroupName()) - || stringEq(group_name, PathGroups::unconstrainedGroupName()); + return sdc->findClock(group_name) || sdc->isGroupPathName(group_name) + || stringEq(group_name, PathGroups::asyncPathGroupName()) + || stringEq(group_name, PathGroups::pathDelayGroupName()) + || stringEq(group_name, PathGroups::gatedClkGroupName()) + || stringEq(group_name, PathGroups::unconstrainedGroupName()); } StringSeq @@ -2094,8 +2098,8 @@ Sta::pathGroupNames(const Sdc *sdc) const ExceptionFrom * Sta::makeExceptionFrom(PinSet *from_pins, - ClockSet *from_clks, - InstanceSet *from_insts, + ClockSet *from_clks, + InstanceSet *from_insts, const RiseFallBoth *from_rf, const Sdc *sdc) { @@ -2104,7 +2108,7 @@ Sta::makeExceptionFrom(PinSet *from_pins, void Sta::checkExceptionFromPins(ExceptionFrom *from, - const char *file, + const char *file, int line, const Sdc *sdc) const { @@ -2113,16 +2117,16 @@ Sta::checkExceptionFromPins(ExceptionFrom *from, if (pins) { for (const Pin *pin : *pins) { if (!sdc->isExceptionStartpoint(pin)) { - if (line) - report_->fileWarn(1554, file, line, "'%s' is not a valid start point.", - cmd_network_->pathName(pin)); - else - report_->warn(1550, "'%s' is not a valid start point.", - cmd_network_->pathName(pin)); + if (line) + report_->fileWarn(1554, file, line, "'{}' is not a valid start point.", + cmd_network_->pathName(pin)); + else + report_->warn(1550, "'{}' is not a valid start point.", + cmd_network_->pathName(pin)); + } } } } - } } void @@ -2133,8 +2137,8 @@ Sta::deleteExceptionFrom(ExceptionFrom *from) ExceptionThru * Sta::makeExceptionThru(PinSet *pins, - NetSet *nets, - InstanceSet *insts, + NetSet *nets, + InstanceSet *insts, const RiseFallBoth *rf, const Sdc *sdc) { @@ -2149,9 +2153,9 @@ Sta::deleteExceptionThru(ExceptionThru *thru) ExceptionTo * Sta::makeExceptionTo(PinSet *to_pins, - ClockSet *to_clks, - InstanceSet *to_insts, - const RiseFallBoth *rf, + ClockSet *to_clks, + InstanceSet *to_insts, + const RiseFallBoth *rf, const RiseFallBoth *end_rf, const Sdc *sdc) { @@ -2166,7 +2170,7 @@ Sta::deleteExceptionTo(ExceptionTo *to) void Sta::checkExceptionToPins(ExceptionTo *to, - const char *file, + const char *file, int line, const Sdc *sdc) const { @@ -2175,30 +2179,30 @@ Sta::checkExceptionToPins(ExceptionTo *to, if (pins) { for (const Pin *pin : *pins) { if (!sdc->isExceptionEndpoint(pin)) { - if (line) - report_->fileWarn(1551, file, line, "'%s' is not a valid endpoint.", - cmd_network_->pathName(pin)); - else - report_->warn(1552, "'%s' is not a valid endpoint.", - cmd_network_->pathName(pin)); + if (line) + report_->fileWarn(1551, file, line, "'{}' is not a valid endpoint.", + cmd_network_->pathName(pin)); + else + report_->warn(1552, "'{}' is not a valid endpoint.", + cmd_network_->pathName(pin)); + } } } } - } } void Sta::writeSdc(const Sdc *sdc, const char *filename, - bool leaf, - bool native, - int digits, + bool leaf, + bool native, + int digits, bool gzip, - bool no_timestamp) + bool no_timestamp) { ensureLibLinked(); - sta::writeSdc(sdc, network_->topInstance(), filename, "write_sdc", - leaf, native, digits, gzip, no_timestamp); + sta::writeSdc(sdc, network_->topInstance(), filename, "write_sdc", leaf, native, + digits, gzip, no_timestamp); } //////////////////////////////////////////////////////////////// @@ -2206,12 +2210,12 @@ Sta::writeSdc(const Sdc *sdc, CheckErrorSeq & Sta::checkTiming(const Mode *mode, bool no_input_delay, - bool no_output_delay, - bool reg_multiple_clks, - bool reg_no_clks, - bool unconstrained_endpoints, - bool loops, - bool generated_clks) + bool no_output_delay, + bool reg_multiple_clks, + bool reg_no_clks, + bool unconstrained_endpoints, + bool loops, + bool generated_clks) { if (unconstrained_endpoints) { // Only need non-clock arrivals to find unconstrained_endpoints. @@ -2225,9 +2229,8 @@ Sta::checkTiming(const Mode *mode, mode->clkNetwork()->ensureClkNetwork(); } return check_timing_->check(mode, no_input_delay, no_output_delay, - reg_multiple_clks, reg_no_clks, - unconstrained_endpoints, - loops, generated_clks); + reg_multiple_clks, reg_no_clks, + unconstrained_endpoints, loops, generated_clks); } //////////////////////////////////////////////////////////////// @@ -2256,31 +2259,52 @@ void Sta::setCrprMode(CrprMode mode) { // Pessimism is only relevant for on_chip_variation analysis. - if (variables_->crprEnabled() - && variables_->crprMode() != mode) + if (variables_->crprEnabled() && variables_->crprMode() != mode) search_->arrivalsInvalid(); variables_->setCrprMode(mode); } -bool -Sta::pocvEnabled() const +PocvMode +Sta::pocvMode() const { - return variables_->pocvEnabled(); + return variables_->pocvMode(); } void -Sta::setPocvEnabled(bool enabled) +Sta::setPocvMode(PocvMode mode) { - if (enabled != variables_->pocvEnabled()) + if (mode != variables_->pocvMode()) { + variables_->setPocvMode(mode); + + delete delay_ops_; + switch (mode) { + case PocvMode::scalar: + default: + delay_ops_ = new DelayOpsScalar(); + break; + case PocvMode::normal: + delay_ops_ = new DelayOpsNormal(); + break; + case PocvMode::skew_normal: + delay_ops_ = new DelayOpsSkewNormal(); + break; + } + updateComponentsState(); delaysInvalid(); - variables_->setPocvEnabled(enabled); + } +} + +float +Sta::pocvQuantile() +{ + return variables_->pocvQuantile(); } void -Sta::setSigmaFactor(float factor) +Sta::setPocvQuantile(float quantile) { - if (!fuzzyEqual(factor, sigma_factor_)) { - sigma_factor_ = factor; + if (!fuzzyEqual(quantile, variables_->pocvQuantile())) { + variables_->setPocvQuantile(quantile); search_->arrivalsInvalid(); updateComponentsState(); } @@ -2351,7 +2375,7 @@ bool Sta::recoveryRemovalChecksEnabled() const { return variables_->recoveryRemovalChecksEnabled(); -} +} void Sta::setRecoveryRemovalChecksEnabled(bool enabled) @@ -2502,10 +2526,9 @@ Sta::makeScene(const std::string &name, parasitics_min = findParasitics(spef_min_file); parasitics_max = findParasitics(spef_max_file); if (parasitics_min == nullptr) - report_->error(1558, "Spef file %s not found.", spef_min_file.c_str()); - if (parasitics_max == nullptr - && spef_max_file != spef_min_file) - report_->error(1559, "Spef file %s not found.", spef_max_file.c_str()); + report_->error(1558, "Spef file {} not found.", spef_min_file); + if (parasitics_max == nullptr && spef_max_file != spef_min_file) + report_->error(1559, "Spef file {} not found.", spef_max_file); } mode->sdc()->makeSceneBefore(); @@ -2517,7 +2540,7 @@ Sta::makeScene(const std::string &name, cmd_scene_ = scene; } else - report_->error(1572, "mode %s not found.", mode_name.c_str()); + report_->error(1572, "mode {} not found.", mode_name); } Scene * @@ -2549,12 +2572,11 @@ Sta::makeScene(const std::string &name, Parasitics *parasitics_min, Parasitics *parasitics_max) { - if (scenes_.size() == 1 - && findScene("default")) + if (scenes_.size() == 1 && findScene("default")) deleteScenes(); - Scene *scene = new Scene(name, scenes_.size(), mode, - parasitics_min, parasitics_max); + Scene *scene = + new Scene(name, scenes_.size(), mode, parasitics_min, parasitics_max); scene_name_map_[name] = scene; scenes_.push_back(scene); mode->addScene(scene); @@ -2601,18 +2623,17 @@ Sta::updateSceneLiberty(Scene *scene, { StringSet warned_files; for (const MinMax *min_max : MinMax::range()) { - const StringSeq &liberty_files = min_max == MinMax::min() - ? liberty_min_files - : liberty_max_files; + const StringSeq &liberty_files = + min_max == MinMax::min() ? liberty_min_files : liberty_max_files; for (const std::string &lib_file : liberty_files) { LibertyLibrary *lib = network_->findLiberty(lib_file.c_str()); - if (lib == nullptr) + if (lib == nullptr) lib = network_->findLibertyFilename(lib_file.c_str()); if (lib) - LibertyLibrary::makeSceneMap(lib, scene->libertyIndex(min_max), - network_, report_); + LibertyLibrary::makeSceneMap(lib, scene->libertyIndex(min_max), network_, + report_); else if (!warned_files.contains(lib_file)) { - report_->warn(1555, "liberty name/filename %s not found.", lib_file.c_str()); + report_->warn(1555, "liberty name/filename {} not found.", lib_file); warned_files.insert(lib_file); } } @@ -2627,8 +2648,8 @@ Sta::updateLibertyScenes() while (iter->hasNext()) { LibertyLibrary *lib = iter->next(); for (const MinMax *min_max : MinMax::range()) { - LibertyLibrary::makeSceneMap(lib, scene->libertyIndex(min_max), - network_, report_); + LibertyLibrary::makeSceneMap(lib, scene->libertyIndex(min_max), network_, + report_); } } } @@ -2664,36 +2685,33 @@ Sta::makeSceneSeq(Scene *scene) const // PathEnds are owned by Search PathGroups and deleted on next call. PathEndSeq Sta::findPathEnds(ExceptionFrom *from, - ExceptionThruSeq *thrus, - ExceptionTo *to, - bool unconstrained, + ExceptionThruSeq *thrus, + ExceptionTo *to, + bool unconstrained, const SceneSeq &scenes, - const MinMaxAll *min_max, - int group_path_count, - int endpoint_path_count, - bool unique_pins, - bool unique_edges, - float slack_min, - float slack_max, - bool sort_by_slack, + const MinMaxAll *min_max, + int group_path_count, + int endpoint_path_count, + bool unique_pins, + bool unique_edges, + float slack_min, + float slack_max, + bool sort_by_slack, StringSeq &group_names, - bool setup, - bool hold, - bool recovery, - bool removal, - bool clk_gating_setup, - bool clk_gating_hold) + bool setup, + bool hold, + bool recovery, + bool removal, + bool clk_gating_setup, + bool clk_gating_hold) { searchPreamble(); clk_skews_->clear(); - return search_->findPathEnds(from, thrus, to, unconstrained, - scenes, min_max, group_path_count, - endpoint_path_count, - unique_pins, unique_edges, slack_min, slack_max, - sort_by_slack, group_names, - setup, hold, - recovery, removal, - clk_gating_setup, clk_gating_hold); + return search_->findPathEnds(from, thrus, to, unconstrained, scenes, min_max, + group_path_count, endpoint_path_count, unique_pins, + unique_edges, slack_min, slack_max, sort_by_slack, + group_names, setup, hold, recovery, removal, + clk_gating_setup, clk_gating_hold); } //////////////////////////////////////////////////////////////// @@ -2739,11 +2757,12 @@ Sta::setReportPathFields(bool report_input_pin, bool report_cap, bool report_slew, bool report_fanout, + bool report_variation, bool report_src_attr) { report_path_->setReportFields(report_input_pin, report_hier_pins, report_net, report_cap, report_slew, report_fanout, - report_src_attr); + report_variation, report_src_attr); } ReportField * @@ -2764,12 +2783,6 @@ Sta::setReportPathNoSplit(bool no_split) report_path_->setNoSplit(no_split); } -void -Sta::setReportPathSigmas(bool report_sigmas) -{ - report_path_->setReportSigmas(report_sigmas); -} - void Sta::reportPathEnd(PathEnd *end) { @@ -2802,23 +2815,21 @@ Sta::updateTiming(bool full) void Sta::reportClkSkew(ConstClockSeq &clks, const SceneSeq &scenes, - const SetupHold *setup_hold, + const SetupHold *setup_hold, bool include_internal_latency, - int digits) + int digits) { clkSkewPreamble(); - clk_skews_->reportClkSkew(clks, scenes, setup_hold, - include_internal_latency, digits); + clk_skews_->reportClkSkew(clks, scenes, setup_hold, include_internal_latency, + digits); } -float +Delay Sta::findWorstClkSkew(const SetupHold *setup_hold, bool include_internal_latency) { - clkSkewPreamble(); - return clk_skews_->findWorstClkSkew(scenes_, setup_hold, - include_internal_latency); + return clk_skews_->findWorstClkSkew(scenes_, setup_hold, include_internal_latency); } void @@ -2922,15 +2933,15 @@ Sta::findRequireds() Path * Sta::vertexWorstArrivalPath(Vertex *vertex, - const MinMax *min_max) + const MinMax *min_max) { return vertexWorstArrivalPath(vertex, nullptr, min_max); } Path * Sta::vertexWorstArrivalPath(Vertex *vertex, - const RiseFall *rf, - const MinMax *min_max) + const RiseFall *rf, + const MinMax *min_max) { Path *worst_path = nullptr; Arrival worst_arrival = min_max->initValue(); @@ -2939,7 +2950,7 @@ Sta::vertexWorstArrivalPath(Vertex *vertex, Path *path = path_iter.next(); Arrival arrival = path->arrival(); if (!path->tag(this)->isGenClkSrcPath() - && delayGreater(arrival, worst_arrival, min_max, this)) { + && delayGreater(arrival, worst_arrival, min_max, this)) { worst_arrival = arrival; worst_path = path; } @@ -2967,7 +2978,7 @@ Sta::vertexWorstRequiredPath(Vertex *vertex, Path *path = path_iter.next(); const Required path_req = path->required(); if (!path->tag(this)->isGenClkSrcPath() - && delayGreater(path_req, worst_req, req_min_max, this)) { + && delayGreater(path_req, worst_req, req_min_max, this)) { worst_req = path_req; worst_path = path; } @@ -2977,8 +2988,8 @@ Sta::vertexWorstRequiredPath(Vertex *vertex, Path * Sta::vertexWorstSlackPath(Vertex *vertex, - const RiseFall *rf, - const MinMax *min_max) + const RiseFall *rf, + const MinMax *min_max) { Path *worst_path = nullptr; Slack min_slack = MinMax::min()->initValue(); @@ -2986,8 +2997,7 @@ Sta::vertexWorstSlackPath(Vertex *vertex, while (path_iter.hasNext()) { Path *path = path_iter.next(); Slack slack = path->slack(this); - if (!path->tag(this)->isGenClkSrcPath() - && delayLess(slack, min_slack, this)) { + if (!path->tag(this)->isGenClkSrcPath() && delayLess(slack, min_slack, this)) { min_slack = slack; worst_path = path; } @@ -2997,7 +3007,7 @@ Sta::vertexWorstSlackPath(Vertex *vertex, Path * Sta::vertexWorstSlackPath(Vertex *vertex, - const MinMax *min_max) + const MinMax *min_max) { return vertexWorstSlackPath(vertex, nullptr, min_max); @@ -3006,7 +3016,7 @@ Sta::vertexWorstSlackPath(Vertex *vertex, Arrival Sta::arrival(const Pin *pin, const RiseFallBoth *rf, - const MinMax *min_max) + const MinMax *min_max) { Vertex *vertex, *bidirect_vertex; graph_->pinVertices(pin, vertex, bidirect_vertex); @@ -3025,7 +3035,7 @@ Arrival Sta::arrival(Vertex *vertex, const RiseFallBoth *rf, const SceneSeq &scenes, - const MinMax *min_max) + const MinMax *min_max) { searchPreamble(); search_->findArrivals(vertex->level()); @@ -3039,9 +3049,8 @@ Sta::arrival(Vertex *vertex, if (!clk_info->isGenClkSrcPath() && (rf == RiseFallBoth::riseFall() || path->transition(this)->asRiseFallBoth() == rf) - && path->minMax(this) == min_max - && scenes_set.contains(path->scene(this)) - && delayGreater(path->arrival(), arrival, min_max, this)) + && path->minMax(this) == min_max && scenes_set.contains(path->scene(this)) + && delayGreater(path->arrival(), arrival, min_max, this)) arrival = path_arrival; } return arrival; @@ -3076,7 +3085,7 @@ Required Sta::required(Vertex *vertex, const RiseFallBoth *rf, const SceneSeq &scenes, - const MinMax *min_max) + const MinMax *min_max) { findRequired(vertex); const SceneSet scenes_set = Scene::sceneSet(scenes); @@ -3088,9 +3097,8 @@ Sta::required(Vertex *vertex, const Required path_required = path->required(); if ((rf == RiseFallBoth::riseFall() || path->transition(this)->asRiseFallBoth() == rf) - && path->minMax(this) == min_max - && scenes_set.contains(path->scene(this)) - && delayGreater(path_required, required, req_min_max, this)) + && path->minMax(this) == min_max && scenes_set.contains(path->scene(this)) + && delayGreater(path_required, required, req_min_max, this)) required = path_required; } return required; @@ -3147,8 +3155,8 @@ Sta::slack(Vertex *vertex, Slack Sta::slack(Vertex *vertex, - const RiseFall *rf, - const MinMax *min_max) + const RiseFall *rf, + const MinMax *min_max) { return slack(vertex, rf->asRiseFallBoth(), scenes_, min_max); } @@ -3169,8 +3177,7 @@ Sta::slack(Vertex *vertex, Slack path_slack = path->slack(this); if ((rf == RiseFallBoth::riseFall() || path->transition(this)->asRiseFallBoth() == rf) - && path->minMax(this) == min_max - && scenes_set.contains(path->scene(this)) + && path->minMax(this) == min_max && scenes_set.contains(path->scene(this)) && delayLess(path_slack, slack, this)) slack = path_slack; } @@ -3240,9 +3247,9 @@ EndpointPathEndVisitor::visit(PathEnd *path_end) StringSeq group_names = PathGroups::pathGroupNames(path_end, sta_); for (std::string &group_name : group_names) { if (group_name == path_group_name_) { - Slack end_slack = path_end->slack(sta_); - if (delayLess(end_slack, slack_, sta_)) - slack_ = end_slack; + Slack end_slack = path_end->slack(sta_); + if (delayLess(end_slack, slack_, sta_)) + slack_ = end_slack; } } } @@ -3271,10 +3278,11 @@ Sta::endpointSlack(const Pin *pin, void Sta::reportArrivalWrtClks(const Pin *pin, const Scene *scene, + bool report_variance, int digits) { searchPreamble(); - reportDelaysWrtClks(pin, scene, digits, false, + reportDelaysWrtClks(pin, scene, report_variance, digits, false, [] (const Path *path) { return path->arrival(); }); @@ -3283,9 +3291,10 @@ Sta::reportArrivalWrtClks(const Pin *pin, void Sta::reportRequiredWrtClks(const Pin *pin, const Scene *scene, + bool report_variance, int digits) { - reportDelaysWrtClks(pin, scene, digits, true, + reportDelaysWrtClks(pin, scene, report_variance, digits, true, [] (const Path *path) { return path->required(); }); @@ -3294,9 +3303,10 @@ Sta::reportRequiredWrtClks(const Pin *pin, void Sta::reportSlackWrtClks(const Pin *pin, const Scene *scene, + bool report_variance, int digits) { - reportDelaysWrtClks(pin, scene, digits, true, + reportDelaysWrtClks(pin, scene, report_variance, digits, true, [this] (const Path *path) { return path->slack(this); }); @@ -3305,6 +3315,7 @@ Sta::reportSlackWrtClks(const Pin *pin, void Sta::reportDelaysWrtClks(const Pin *pin, const Scene *scene, + bool report_variance, int digits, bool find_required, PathDelayFunc get_path_delay) @@ -3313,14 +3324,17 @@ Sta::reportDelaysWrtClks(const Pin *pin, Vertex *vertex, *bidir_vertex; graph_->pinVertices(pin, vertex, bidir_vertex); if (vertex) - reportDelaysWrtClks(vertex, scene, digits, find_required, get_path_delay); + reportDelaysWrtClks(vertex, scene, report_variance, digits, + find_required, get_path_delay); if (bidir_vertex) - reportDelaysWrtClks(vertex, scene, digits, find_required, get_path_delay); + reportDelaysWrtClks(vertex, scene, report_variance, digits, + find_required, get_path_delay); } void Sta::reportDelaysWrtClks(Vertex *vertex, const Scene *scene, + bool report_variance, int digits, bool find_required, PathDelayFunc get_path_delay) @@ -3330,13 +3344,15 @@ Sta::reportDelaysWrtClks(Vertex *vertex, else search_->findArrivals(vertex->level()); const Sdc *sdc = scene->sdc(); - reportDelaysWrtClks(vertex, nullptr, scene, digits, get_path_delay); + reportDelaysWrtClks(vertex, nullptr, scene, report_variance, digits, get_path_delay); const ClockEdge *default_clk_edge = sdc->defaultArrivalClock()->edge(RiseFall::rise()); - reportDelaysWrtClks(vertex, default_clk_edge, scene, digits, get_path_delay); + reportDelaysWrtClks(vertex, default_clk_edge, scene, report_variance, + digits, get_path_delay); for (const Clock *clk : sdc->sortedClocks()) { for (const RiseFall *rf : RiseFall::range()) { const ClockEdge *clk_edge = clk->edge(rf); - reportDelaysWrtClks(vertex, clk_edge, scene, digits, get_path_delay); + reportDelaysWrtClks(vertex, clk_edge, scene, report_variance, digits, + get_path_delay); } } } @@ -3345,28 +3361,25 @@ void Sta::reportDelaysWrtClks(Vertex *vertex, const ClockEdge *clk_edge, const Scene *scene, + bool report_variance, int digits, PathDelayFunc get_path_delay) { - RiseFallMinMaxDelay delays = findDelaysWrtClks(vertex, clk_edge, scene, - get_path_delay); + RiseFallMinMaxDelay delays = + findDelaysWrtClks(vertex, clk_edge, scene, get_path_delay); if (!delays.empty()) { std::string clk_name; - if (clk_edge) { - clk_name = " ("; - clk_name += clk_edge->name(); - clk_name += ')'; - } - report_->reportLine("%s r %s:%s f %s:%s", - clk_name.c_str(), - formatDelay(RiseFall::rise(), MinMax::min(), - delays, digits).c_str(), - formatDelay(RiseFall::rise(), MinMax::max(), - delays, digits).c_str(), - formatDelay(RiseFall::fall(), MinMax::min(), - delays, digits).c_str(), - formatDelay(RiseFall::fall(), MinMax::max(), - delays, digits).c_str()); + if (clk_edge) + clk_name = sta::format("({})", clk_edge->name()); + report_->report("{} r {}:{} f {}:{}", clk_name, + formatDelay(RiseFall::rise(), MinMax::min(), + delays, report_variance, digits).c_str(), + formatDelay(RiseFall::rise(), MinMax::max(), + delays, report_variance, digits).c_str(), + formatDelay(RiseFall::fall(), MinMax::min(), + delays, report_variance, digits).c_str(), + formatDelay(RiseFall::fall(), MinMax::max(), + delays, report_variance, digits).c_str()); } } @@ -3385,7 +3398,7 @@ Sta::findDelaysWrtClks(Vertex *vertex, const MinMax *min_max = path->minMax(this); const ClockEdge *path_clk_edge = path->clkEdge(this); if (path_clk_edge == clk_edge - && !delayInf(delay)) + && !delayInf(delay, this)) delays.mergeValue(rf, min_max, delay, this); } return delays; @@ -3395,13 +3408,14 @@ std::string Sta::formatDelay(const RiseFall *rf, const MinMax *min_max, const RiseFallMinMaxDelay &delays, + bool report_variance, int digits) { Delay delay; bool exists; delays.value(rf, min_max, delay, exists); if (exists) - return delayAsString(delay, this, digits); + return delayAsString(delay, min_max, report_variance, digits, this); else return "---"; } @@ -3452,10 +3466,8 @@ MinPeriodEndVisitor::visit(PathEnd *path_end) const ClockEdge *src_edge = path_end->sourceClkEdge(sta_); const ClockEdge *tgt_edge = path_end->targetClkEdge(sta_); PathEnd::Type end_type = path_end->type(); - if ((end_type == PathEnd::Type::check - || end_type == PathEnd::Type::output_delay) - && path->minMax(sta_) == MinMax::max() - && src_edge->clock() == clk_ + if ((end_type == PathEnd::Type::check || end_type == PathEnd::Type::output_delay) + && path->minMax(sta_) == MinMax::max() && src_edge->clock() == clk_ && tgt_edge->clock() == clk_ // Only consider rise/rise and fall/fall paths. && src_edge->transition() == tgt_edge->transition() @@ -3464,7 +3476,7 @@ MinPeriodEndVisitor::visit(PathEnd *path_end) || !(network->isTopLevelPort(path->pin(sta_)) || pathIsFromInputPort(path_end)))) { Slack slack = path_end->slack(sta_); - float period = clk_->period() - delayAsFloat(slack); + float period = clk_->period() - delayAsFloat(slack, MinMax::min(), sta_); min_period_ = std::max(min_period_, period); } } @@ -3519,7 +3531,7 @@ Sta::totalNegativeSlack(const MinMax *min_max) Slack Sta::totalNegativeSlack(const Scene *scene, - const MinMax *min_max) + const MinMax *min_max) { searchPreamble(); return search_->totalNegativeSlack(scene, min_max); @@ -3537,9 +3549,9 @@ Sta::worstSlack(const MinMax *min_max) void Sta::worstSlack(const MinMax *min_max, - // Return values. - Slack &worst_slack, - Vertex *&worst_vertex) + // Return values. + Slack &worst_slack, + Vertex *&worst_vertex) { searchPreamble(); search_->worstSlack(min_max, worst_slack, worst_vertex); @@ -3547,10 +3559,10 @@ Sta::worstSlack(const MinMax *min_max, void Sta::worstSlack(const Scene *scene, - const MinMax *min_max, - // Return values. - Slack &worst_slack, - Vertex *&worst_vertex) + const MinMax *min_max, + // Return values. + Slack &worst_slack, + Vertex *&worst_vertex) { searchPreamble(); return search_->worstSlack(scene, min_max, worst_slack, worst_vertex); @@ -3614,9 +3626,9 @@ Sta::setIncrementalDelayTolerance(float tol) graph_delay_calc_->setIncrementalDelayTolerance(tol); } -ArcDelay +const ArcDelay Sta::arcDelay(Edge *edge, - TimingArc *arc, + TimingArc *arc, DcalcAPIndex ap_index) { findDelays(edge->to(graph_)); @@ -3625,7 +3637,7 @@ Sta::arcDelay(Edge *edge, bool Sta::arcDelayAnnotated(Edge *edge, - TimingArc *arc, + TimingArc *arc, const Scene *scene, const MinMax *min_max) { @@ -3635,10 +3647,10 @@ Sta::arcDelayAnnotated(Edge *edge, void Sta::setArcDelayAnnotated(Edge *edge, - TimingArc *arc, + TimingArc *arc, const Scene *scene, const MinMax *min_max, - bool annotated) + bool annotated) { DcalcAPIndex ap_index = scene->dcalcAnalysisPtIndex(min_max); graph_->setArcDelayAnnotated(edge, arc, ap_index, annotated); @@ -3653,7 +3665,7 @@ Slew Sta::slew(Vertex *vertex, const RiseFallBoth *rf, const SceneSeq &scenes, - const MinMax *min_max) + const MinMax *min_max) { findDelays(vertex); Slew mm_slew = min_max->initValue(); @@ -3709,7 +3721,7 @@ Sta::ensureGraph() void Sta::makeGraph() { - graph_ = new Graph(this, 2, dcalcAnalysisPtCount()); + graph_ = new Graph(this, dcalcAnalysisPtCount()); graph_->makeGraph(); } @@ -3728,22 +3740,22 @@ Sta::updateGeneratedClks() for (Mode *mode : modes_) { Genclks *genclks = mode->genclks(); Sdc *sdc = mode->sdc(); - bool gen_clk_changed = true; - while (gen_clk_changed) { - gen_clk_changed = false; + bool gen_clk_changed = true; + while (gen_clk_changed) { + gen_clk_changed = false; for (Clock *clk : sdc->clocks()) { - if (clk->isGenerated() && !clk->waveformValid()) { + if (clk->isGenerated() && !clk->waveformValid()) { genclks->ensureMaster(clk, sdc); - Clock *master_clk = clk->masterClk(); - if (master_clk && master_clk->waveformValid()) { - clk->generate(master_clk); - gen_clk_changed = true; - } - } + Clock *master_clk = clk->masterClk(); + if (master_clk && master_clk->waveformValid()) { + clk->generate(master_clk); + gen_clk_changed = true; + } + } + } } } } - } update_genclks_ = false; } @@ -3779,7 +3791,7 @@ Sta::maxPathCountVertex() const } int -Sta::vertexPathCount(Vertex *vertex) const +Sta::vertexPathCount(Vertex *vertex) const { TagGroup *tag_group = search_->tagGroup(vertex); if (tag_group) @@ -3820,10 +3832,10 @@ Sta::clkInfoCount() const void Sta::setArcDelay(Edge *edge, - TimingArc *arc, + TimingArc *arc, const Scene *scene, - const MinMaxAll *min_max, - ArcDelay delay) + const MinMaxAll *min_max, + ArcDelay delay) { ensureGraph(); for (const MinMax *mm : min_max->range()) { @@ -3843,9 +3855,9 @@ Sta::setArcDelay(Edge *edge, void Sta::setAnnotatedSlew(Vertex *vertex, const Scene *scene, - const MinMaxAll *min_max, - const RiseFallBoth *rf, - float slew) + const MinMaxAll *min_max, + const RiseFallBoth *rf, + float slew) { ensureGraph(); for (const MinMax *mm : min_max->range()) { @@ -3862,16 +3874,16 @@ Sta::setAnnotatedSlew(Vertex *vertex, void Sta::writeSdf(const char *filename, const Scene *scene, - char divider, - bool include_typ, + char divider, + bool include_typ, int digits, - bool gzip, - bool no_timestamp, - bool no_version) + bool gzip, + bool no_timestamp, + bool no_version) { findDelays(); - sta::writeSdf(filename, scene, divider, include_typ, digits, gzip, - no_timestamp, no_version, this); + sta::writeSdf(filename, scene, divider, include_typ, digits, gzip, no_timestamp, + no_version, this); } void @@ -3917,8 +3929,8 @@ Sta::clearLogicConstants() void Sta::setPortExtPinCap(const Port *port, - const RiseFallBoth *rf, - const MinMaxAll *min_max, + const RiseFallBoth *rf, + const MinMaxAll *min_max, float cap, Sdc *sdc) { @@ -3947,10 +3959,8 @@ Sta::portExtCaps(const Port *port, float pin_cap1, wire_cap1; int fanout1; bool pin_exists1, wire_exists1, fanout_exists1; - sdc->portExtCap(port, rf, min_max, - pin_cap1, pin_exists1, - wire_cap1, wire_exists1, - fanout1, fanout_exists1); + sdc->portExtCap(port, rf, min_max, pin_cap1, pin_exists1, wire_cap1, + wire_exists1, fanout1, fanout_exists1); if (pin_exists1) { pin_cap = min_max->minMax(pin_cap, pin_cap1); pin_exists = true; @@ -3974,8 +3984,8 @@ Sta::portExtCaps(const Port *port, void Sta::setPortExtWireCap(const Port *port, - const RiseFallBoth *rf, - const MinMaxAll *min_max, + const RiseFallBoth *rf, + const MinMaxAll *min_max, float cap, Sdc *sdc) { @@ -3995,7 +4005,7 @@ Sta::removeNetLoadCaps(Sdc *sdc) const void Sta::setPortExtFanout(const Port *port, - int fanout, + int fanout, const MinMaxAll *min_max, Sdc *sdc) { @@ -4006,8 +4016,8 @@ Sta::setPortExtFanout(const Port *port, void Sta::setNetWireCap(const Net *net, - bool subtract_pin_cap, - const MinMaxAll *min_max, + bool subtract_pin_cap, + const MinMaxAll *min_max, float cap, Sdc *sdc) { @@ -4018,22 +4028,21 @@ Sta::setNetWireCap(const Net *net, void Sta::connectedCap(const Pin *drvr_pin, - const RiseFall *rf, + const RiseFall *rf, const Scene *scene, - const MinMax *min_max, - float &pin_cap, - float &wire_cap) const + const MinMax *min_max, + float &pin_cap, + float &wire_cap) const { - graph_delay_calc_->loadCap(drvr_pin, rf, scene, min_max, - pin_cap, wire_cap); + graph_delay_calc_->loadCap(drvr_pin, rf, scene, min_max, pin_cap, wire_cap); } void Sta::connectedCap(const Net *net, Scene *scene, - const MinMax *min_max, - float &pin_cap, - float &wire_cap) const + const MinMax *min_max, + float &pin_cap, + float &wire_cap) const { const Pin *drvr_pin = findNetParasiticDrvrPin(net); if (drvr_pin) { @@ -4065,7 +4074,8 @@ Sta::capacitance(const LibertyPort *port, OperatingConditions *op_cond = operatingConditions(min_max, sdc); const LibertyPort *scene_port = port->scenePort(scene, min_max); for (const RiseFall *rf : RiseFall::range()) - cap = min_max->minMax(cap, scene_port->capacitance(rf, min_max, op_cond, op_cond)); + cap = min_max->minMax(cap, + scene_port->capacitance(rf, min_max, op_cond, op_cond)); } return cap; } @@ -4092,7 +4102,7 @@ Sta::findNetParasiticDrvrPin(const Net *net) const void Sta::setResistance(const Net *net, - const MinMaxAll *min_max, + const MinMaxAll *min_max, float res, Sdc *sdc) { @@ -4105,7 +4115,7 @@ bool Sta::readSpef(const std::string &name, const std::string &filename, Instance *instance, - Scene *scene, // -scene deprecated 11/20/2025 + Scene *scene, // -scene deprecated 11/20/2025 const MinMaxAll *min_max, bool pin_cap_included, bool keep_coupling_caps, @@ -4117,8 +4127,7 @@ Sta::readSpef(const std::string &name, // Use -name to distinguish rel 2.7 args for compatibility. if (name.empty()) { std::string spef_name = "default"; - if (scene - || min_max != MinMaxAll::minMax()) { + if (scene || min_max != MinMaxAll::minMax()) { if (scene) spef_name = scene->name(); if (min_max != MinMaxAll::minMax()) { @@ -4143,10 +4152,9 @@ Sta::readSpef(const std::string &name, parasitics = makeConcreteParasitics(name, filename); } - bool success = readSpefFile(filename.c_str(), instance, - pin_cap_included, keep_coupling_caps, - coupling_cap_factor, reduce, - scene, min_max, parasitics, this); + bool success = + readSpefFile(filename.c_str(), instance, pin_cap_included, keep_coupling_caps, + coupling_cap_factor, reduce, scene, min_max, parasitics, this); delaysInvalid(); return success; } @@ -4167,22 +4175,21 @@ Sta::reportParasiticAnnotation(const std::string &spef_name, if (!spef_name.empty()) { parasitics = findParasitics(spef_name); if (parasitics == nullptr) - report_->error(1560, "spef %s not found.", spef_name.c_str()); + report_->error(1560, "spef {} not found.", spef_name); } else parasitics = cmd_scene_->parasitics(MinMax::max()); - sta::reportParasiticAnnotation(parasitics, report_unannotated, - cmd_scene_, this); + sta::reportParasiticAnnotation(parasitics, report_unannotated, cmd_scene_, this); } void Sta::findPiElmore(Pin *drvr_pin, - const RiseFall *rf, - const MinMax *min_max, - float &c2, - float &rpi, - float &c1, - bool &exists) const + const RiseFall *rf, + const MinMax *min_max, + float &c2, + float &rpi, + float &c1, + bool &exists) const { Scene *scene = cmd_scene_; const Parasitics *parasitics = scene->parasitics(min_max); @@ -4197,11 +4204,11 @@ Sta::findPiElmore(Pin *drvr_pin, void Sta::makePiElmore(Pin *drvr_pin, - const RiseFall *rf, - const MinMaxAll *min_max, - float c2, - float rpi, - float c1) + const RiseFall *rf, + const MinMaxAll *min_max, + float c2, + float rpi, + float c1) { const Scene *scene = cmd_scene_; for (const MinMax *mm : min_max->range()) { @@ -4213,11 +4220,11 @@ Sta::makePiElmore(Pin *drvr_pin, void Sta::findElmore(Pin *drvr_pin, - Pin *load_pin, - const RiseFall *rf, - const MinMax *min_max, - float &elmore, - bool &exists) const + Pin *load_pin, + const RiseFall *rf, + const MinMax *min_max, + float &elmore, + bool &exists) const { Scene *scene = cmd_scene_; const Parasitics *parasitics = scene->parasitics(min_max); @@ -4230,10 +4237,10 @@ Sta::findElmore(Pin *drvr_pin, void Sta::setElmore(Pin *drvr_pin, - Pin *load_pin, - const RiseFall *rf, - const MinMaxAll *min_max, - float elmore) + Pin *load_pin, + const RiseFall *rf, + const MinMaxAll *min_max, + float elmore) { const Scene *scene = cmd_scene_; for (const MinMax *mm : min_max->range()) { @@ -4300,13 +4307,13 @@ Sta::makeParasiticNetwork(const Net *net, NetworkEdit * Sta::networkCmdEdit() { - return dynamic_cast(cmd_network_); + return dynamic_cast(cmd_network_); } Instance * Sta::makeInstance(const char *name, - LibertyCell *cell, - Instance *parent) + LibertyCell *cell, + Instance *parent) { NetworkEdit *network = networkCmdEdit(); Instance *inst = network->makeInstance(cell, name, parent); @@ -4325,7 +4332,7 @@ Sta::deleteInstance(Instance *inst) void Sta::replaceCell(Instance *inst, - LibertyCell *to_lib_cell) + LibertyCell *to_lib_cell) { Cell *to_cell = network_->cell(to_lib_cell); replaceCell(inst, to_cell, to_lib_cell); @@ -4333,7 +4340,7 @@ Sta::replaceCell(Instance *inst, void Sta::replaceCell(Instance *inst, - Cell *to_cell) + Cell *to_cell) { LibertyCell *to_lib_cell = network_->libertyCell(to_cell); replaceCell(inst, to_cell, to_lib_cell); @@ -4341,8 +4348,8 @@ Sta::replaceCell(Instance *inst, void Sta::replaceCell(Instance *inst, - Cell *to_cell, - LibertyCell *to_lib_cell) + Cell *to_cell, + LibertyCell *to_lib_cell) { NetworkEdit *network = networkCmdEdit(); LibertyCell *from_lib_cell = network->libertyCell(inst); @@ -4362,7 +4369,7 @@ Sta::replaceCell(Instance *inst, Net * Sta::makeNet(const char *name, - Instance *parent) + Instance *parent) { NetworkEdit *network = networkCmdEdit(); Net *net = network->makeNet(name, parent); @@ -4380,8 +4387,8 @@ Sta::deleteNet(Net *net) void Sta::connectPin(Instance *inst, - Port *port, - Net *net) + Port *port, + Net *net) { NetworkEdit *network = networkCmdEdit(); Pin *pin = network->connect(inst, port, net); @@ -4390,8 +4397,8 @@ Sta::connectPin(Instance *inst, void Sta::connectPin(Instance *inst, - LibertyPort *port, - Net *net) + LibertyPort *port, + Net *net) { NetworkEdit *network = networkCmdEdit(); Pin *pin = network->connect(inst, port, net); @@ -4411,7 +4418,7 @@ Sta::makePortPin(const char *port_name, PortDirection *dir) { ensureLinked(); - NetworkReader *network = dynamic_cast(network_); + NetworkReader *network = dynamic_cast(network_); Instance *top_inst = network->topInstance(); Cell *top_cell = network->cell(top_inst); Port *port = network->makePort(top_cell, port_name); @@ -4419,7 +4426,7 @@ Sta::makePortPin(const char *port_name, Pin *pin = network->makePin(top_inst, port, nullptr); makePortPinAfter(pin); } - + //////////////////////////////////////////////////////////////// // // Network edit before/after methods. @@ -4429,7 +4436,7 @@ Sta::makePortPin(const char *port_name, void Sta::makeInstanceAfter(const Instance *inst) { - debugPrint(debug_, "network_edit", 1, "make instance %s", + debugPrint(debug_, "network_edit", 1, "make instance {}", sdc_network_->pathName(inst)); if (graph_) { LibertyCell *lib_cell = network_->libertyCell(inst); @@ -4442,7 +4449,6 @@ Sta::makeInstanceAfter(const Instance *inst) if (pin) { Vertex *vertex, *bidir_drvr_vertex; graph_->makePinVertices(pin, vertex, bidir_drvr_vertex); - } } graph_->makeInstanceEdges(inst); @@ -4462,7 +4468,7 @@ Sta::makePortPinAfter(Pin *pin) void Sta::replaceEquivCellBefore(const Instance *inst, - const LibertyCell *to_cell) + const LibertyCell *to_cell) { if (graph_) { InstancePinIterator *pin_iter = network_->pinIterator(inst); @@ -4486,15 +4492,16 @@ Sta::replaceEquivCellBefore(const Instance *inst, if (to_set) edge->setTimingArcSet(to_set); else - report_->critical(1556, "corresponding timing arc set not found in equiv cells"); + report_->critical( + 1556, "corresponding timing arc set not found in equiv cells"); } } } else { // Force delay calculation on output pins. Vertex *vertex = graph_->pinDrvrVertex(pin); - if (vertex) - graph_delay_calc_->delayInvalid(vertex); + if (vertex) + graph_delay_calc_->delayInvalid(vertex); } } } @@ -4522,16 +4529,15 @@ Sta::replaceEquivCellAfter(const Instance *inst) void Sta::replaceCellPinInvalidate(const LibertyPort *from_port, - Vertex *vertex, - const LibertyCell *to_cell) + Vertex *vertex, + const LibertyCell *to_cell) { LibertyPort *to_port = to_cell->findLibertyPort(from_port->name()); if (to_port == nullptr || (!libertyPortCapsEqual(to_port, from_port) // If this is an ideal clock pin, do not invalidate // arrivals and delay calc on the clock pin driver. - && !(to_port->isClock() - && idealClockMode()))) + && !(to_port->isClock() && idealClockMode()))) // Input port capacitance changed, so invalidate delay // calculation from input driver. delaysInvalidFromFanin(vertex); @@ -4545,30 +4551,30 @@ Sta::idealClockMode() for (Mode *mode : modes_) { Sdc *sdc = mode->sdc(); for (Clock *clk : sdc->clocks()) { - if (clk->isPropagated()) - return false; - } + if (clk->isPropagated()) + return false; + } } return true; } static bool libertyPortCapsEqual(const LibertyPort *port1, - const LibertyPort *port2) + const LibertyPort *port2) { return port1->capacitance(RiseFall::rise(), MinMax::min()) - == port2->capacitance(RiseFall::rise(), MinMax::min()) - && port1->capacitance(RiseFall::rise(), MinMax::max()) - == port2->capacitance(RiseFall::rise(), MinMax::max()) - && port1->capacitance(RiseFall::fall(), MinMax::min()) - == port2->capacitance(RiseFall::fall(), MinMax::min()) - && port1->capacitance(RiseFall::fall(), MinMax::max()) - == port2->capacitance(RiseFall::fall(), MinMax::max()); + == port2->capacitance(RiseFall::rise(), MinMax::min()) + && port1->capacitance(RiseFall::rise(), MinMax::max()) + == port2->capacitance(RiseFall::rise(), MinMax::max()) + && port1->capacitance(RiseFall::fall(), MinMax::min()) + == port2->capacitance(RiseFall::fall(), MinMax::min()) + && port1->capacitance(RiseFall::fall(), MinMax::max()) + == port2->capacitance(RiseFall::fall(), MinMax::max()); } void Sta::replaceCellBefore(const Instance *inst, - const LibertyCell *to_cell) + const LibertyCell *to_cell) { if (graph_) { // Delete all graph edges between instance pins. @@ -4577,16 +4583,16 @@ Sta::replaceCellBefore(const Instance *inst, Pin *pin = pin_iter->next(); LibertyPort *port = network_->libertyPort(pin); if (port->direction()->isAnyInput()) { - Vertex *vertex = graph_->pinLoadVertex(pin); - replaceCellPinInvalidate(port, vertex, to_cell); + Vertex *vertex = graph_->pinLoadVertex(pin); + replaceCellPinInvalidate(port, vertex, to_cell); - VertexOutEdgeIterator edge_iter(vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - Vertex *to_vertex = edge->to(graph_); - if (network_->instance(to_vertex->pin()) == inst) - deleteEdge(edge); - } + VertexOutEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + Vertex *to_vertex = edge->to(graph_); + if (network_->instance(to_vertex->pin()) == inst) + deleteEdge(edge); + } } } delete pin_iter; @@ -4615,7 +4621,7 @@ Sta::replaceCellAfter(const Instance *inst) void Sta::connectPinAfter(const Pin *pin) { - debugPrint(debug_, "network_edit", 1, "connect %s to %s", + debugPrint(debug_, "network_edit", 1, "connect {} to {}", sdc_network_->pathName(pin), sdc_network_->pathName(network_->net(pin))); if (graph_) { @@ -4623,11 +4629,11 @@ Sta::connectPinAfter(const Pin *pin) graph_->makeWireEdgesThruPin(pin); EdgesThruHierPinIterator edge_iter(pin, network_, graph_); while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->role()->isWire()) { - connectDrvrPinAfter(edge->from(graph_)); - connectLoadPinAfter(edge->to(graph_)); - } + Edge *edge = edge_iter.next(); + if (edge->role()->isWire()) { + connectDrvrPinAfter(edge->from(graph_)); + connectLoadPinAfter(edge->to(graph_)); + } } } else { @@ -4716,7 +4722,7 @@ Sta::connectLoadPinAfter(Vertex *vertex) void Sta::disconnectPinBefore(const Pin *pin) { - debugPrint(debug_, "network_edit", 1, "disconnect %s from %s", + debugPrint(debug_, "network_edit", 1, "disconnect {} from {}", sdc_network_->pathName(pin), sdc_network_->pathName(network_->net(pin))); @@ -4734,37 +4740,37 @@ Sta::disconnectPinBefore(const Pin *pin) Vertex *vertex = graph_->pinDrvrVertex(pin); // Delete wire edges from pin. if (vertex) { - VertexOutEdgeIterator edge_iter(vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->role()->isWire()) - deleteEdge(edge); - } + VertexOutEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->role()->isWire()) + deleteEdge(edge); + } } } if (network_->isLoad(pin)) { // Delete wire edges to pin. Vertex *vertex = graph_->pinLoadVertex(pin); if (vertex) { - VertexInEdgeIterator edge_iter(vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->role()->isWire()) - deleteEdge(edge); - } + VertexInEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->role()->isWire()) + deleteEdge(edge); + } } } if (is_hierarchical) { // Delete wire edges thru pin. EdgesThruHierPinIterator edge_iter(pin, network_, graph_); while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->role()->isWire()) { - deleteEdge(edge); + Edge *edge = edge_iter.next(); + if (edge->role()->isWire()) { + deleteEdge(edge); const Pin *from_pin = edge->from(graph_)->pin(); for (Mode *mode : modes_) mode->clkNetwork()->disconnectPinBefore(from_pin); - } + } } } clk_skews_->clear(); @@ -4775,7 +4781,7 @@ Sta::disconnectPinBefore(const Pin *pin) void Sta::deleteEdge(Edge *edge) { - debugPrint(debug_, "network_edit", 2, "delete edge %s -> %s", + debugPrint(debug_, "network_edit", 2, "delete edge {} -> {}", edge->from(graph_)->name(sdc_network_), edge->to(graph_)->name(sdc_network_)); Vertex *to = edge->to(graph_); @@ -4793,24 +4799,24 @@ Sta::deleteEdge(Edge *edge) void Sta::deleteNetBefore(const Net *net) { - debugPrint(debug_, "network_edit", 1, "delete net %s", + debugPrint(debug_, "network_edit", 1, "delete net {}", sdc_network_->pathName(net)); if (graph_) { NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net); while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); if (!network_->isHierarchical(pin)) { - disconnectPinBefore(pin); - // Delete wire edges on net pins. - Vertex *vertex = graph_->pinDrvrVertex(pin); - if (vertex) { - VertexOutEdgeIterator edge_iter(vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->role()->isWire()) - deleteEdge(edge); - } - } + disconnectPinBefore(pin); + // Delete wire edges on net pins. + Vertex *vertex = graph_->pinDrvrVertex(pin); + if (vertex) { + VertexOutEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->role()->isWire()) + deleteEdge(edge); + } + } } } delete pin_iter; @@ -4824,7 +4830,7 @@ Sta::deleteNetBefore(const Net *net) void Sta::deleteInstanceBefore(const Instance *inst) { - debugPrint(debug_, "network_edit", 1, "delete instance %s", + debugPrint(debug_, "network_edit", 1, "delete instance {}", sdc_network_->pathName(inst)); if (network_->isLeaf(inst)) { deleteInstancePinsBefore(inst); @@ -4867,8 +4873,8 @@ void Sta::deletePinBefore(const Pin *pin) { if (graph_) { - debugPrint(debug_, "network_edit", 1, "delete pin %s", - sdc_network_->pathName(pin)); + debugPrint(debug_, "network_edit", 1, "delete pin {}", + sdc_network_->pathName(pin)); if (network_->isLoad(pin)) { Vertex *vertex = graph_->pinLoadVertex(pin); if (vertex) { @@ -4886,7 +4892,7 @@ Sta::deletePinBefore(const Pin *pin) } levelize_->deleteEdgeBefore(edge); } - // Deletes edges to/from vertex also. + // Deletes edges to/from vertex also. graph_->deleteVertex(vertex); } } @@ -4909,7 +4915,7 @@ Sta::deletePinBefore(const Pin *pin) } levelize_->deleteEdgeBefore(edge); } - // Deletes edges to/from vertex also. + // Deletes edges to/from vertex also. graph_->deleteVertex(vertex); } } @@ -5010,12 +5016,12 @@ Sta::delaysInvalidFromFanin(const Net *net) while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); if (!network_->isHierarchical(pin)) { - Vertex *vertex, *bidirect_drvr_vertex; - graph_->pinVertices(pin, vertex, bidirect_drvr_vertex); - if (vertex) - delaysInvalidFrom(vertex); - if (bidirect_drvr_vertex) - delaysInvalidFrom(bidirect_drvr_vertex); + Vertex *vertex, *bidirect_drvr_vertex; + graph_->pinVertices(pin, vertex, bidirect_drvr_vertex); + if (vertex) + delaysInvalidFrom(vertex); + if (bidirect_drvr_vertex) + delaysInvalidFrom(bidirect_drvr_vertex); } } delete pin_iter; @@ -5057,62 +5063,57 @@ Sta::clockDomains(const Pin *pin, InstanceSet Sta::findRegisterInstances(ClockSet *clks, - const RiseFallBoth *clk_rf, - bool edge_triggered, + const RiseFallBoth *clk_rf, + bool edge_triggered, bool latches, const Mode *mode) { findRegisterPreamble(mode); - return findRegInstances(clks, clk_rf, edge_triggered, latches, - mode, this); + return findRegInstances(clks, clk_rf, edge_triggered, latches, mode, this); } PinSet Sta::findRegisterDataPins(ClockSet *clks, - const RiseFallBoth *clk_rf, - bool edge_triggered, + const RiseFallBoth *clk_rf, + bool edge_triggered, bool latches, const Mode *mode) { findRegisterPreamble(mode); - return findRegDataPins(clks, clk_rf, edge_triggered, latches, - mode, this); + return findRegDataPins(clks, clk_rf, edge_triggered, latches, mode, this); } PinSet Sta::findRegisterClkPins(ClockSet *clks, - const RiseFallBoth *clk_rf, - bool edge_triggered, + const RiseFallBoth *clk_rf, + bool edge_triggered, bool latches, const Mode *mode) { findRegisterPreamble(mode); - return findRegClkPins(clks, clk_rf, edge_triggered, latches, - mode, this); + return findRegClkPins(clks, clk_rf, edge_triggered, latches, mode, this); } PinSet Sta::findRegisterAsyncPins(ClockSet *clks, - const RiseFallBoth *clk_rf, - bool edge_triggered, + const RiseFallBoth *clk_rf, + bool edge_triggered, bool latches, const Mode *mode) { findRegisterPreamble(mode); - return findRegAsyncPins(clks, clk_rf, edge_triggered, latches, - mode, this); + return findRegAsyncPins(clks, clk_rf, edge_triggered, latches, mode, this); } PinSet Sta::findRegisterOutputPins(ClockSet *clks, - const RiseFallBoth *clk_rf, - bool edge_triggered, + const RiseFallBoth *clk_rf, + bool edge_triggered, bool latches, const Mode *mode) { findRegisterPreamble(mode); - return findRegOutputPins(clks, clk_rf, edge_triggered, latches, - mode, this); + return findRegOutputPins(clks, clk_rf, edge_triggered, latches, mode, this); } void @@ -5129,8 +5130,8 @@ class FanInOutSrchPred : public SearchPred { public: FanInOutSrchPred(bool thru_disabled, - bool thru_constants, - const StaState *sta); + bool thru_constants, + const StaState *sta); bool searchFrom(const Vertex *from_vertex, const Mode *mode) const override; bool searchThru(Edge *edge, @@ -5148,8 +5149,8 @@ protected: }; FanInOutSrchPred::FanInOutSrchPred(bool thru_disabled, - bool thru_constants, - const StaState *sta) : + bool thru_constants, + const StaState *sta) : SearchPred(sta), thru_disabled_(thru_disabled), thru_constants_(thru_constants), @@ -5163,10 +5164,8 @@ FanInOutSrchPred::searchFrom(const Vertex *from_vertex, { const Pin *from_pin = from_vertex->pin(); const Sdc *sdc = mode->sdc(); - return (thru_disabled_ - || !sdc->isDisabledConstraint(from_pin)) - && (thru_constants_ - || !mode->sim()->isConstant(from_vertex)); + return (thru_disabled_ || !sdc->isDisabledConstraint(from_pin)) + && (thru_constants_ || !mode->sim()->isConstant(from_vertex)); } bool @@ -5176,22 +5175,19 @@ FanInOutSrchPred::searchThru(Edge *edge, const Sdc *sdc = mode->sdc(); const Sim *sim = mode->sim(); return searchThruRole(edge) - && (thru_disabled_ - || !(sdc->isDisabledConstraint(edge) - || sim->isDisabledCond(edge) - || sta_->isDisabledCondDefault(edge))) - && (thru_constants_ - || sim->simTimingSense(edge) != TimingSense::none); + && (thru_disabled_ + || !(sdc->isDisabledConstraint(edge) || sim->isDisabledCond(edge) + || sta_->isDisabledCondDefault(edge))) + && (thru_constants_ || sim->simTimingSense(edge) != TimingSense::none); } bool FanInOutSrchPred::searchThruRole(Edge *edge) const { const TimingRole *role = edge->role(); - return role == TimingRole::wire() - || role == TimingRole::combinational() - || role == TimingRole::tristateEnable() - || role == TimingRole::tristateDisable(); + return role == TimingRole::wire() || role == TimingRole::combinational() + || role == TimingRole::tristateEnable() + || role == TimingRole::tristateDisable(); } bool @@ -5212,27 +5208,27 @@ FanInOutSrchPred::searchTo(const Vertex *to_vertex, { const Pin *to_pin = to_vertex->pin(); const Sdc *sdc = mode->sdc(); - return (thru_disabled_ - || !sdc->isDisabledConstraint(to_pin)) - && (thru_constants_ - || !mode->sim()->isConstant(to_vertex)); + return (thru_disabled_ || !sdc->isDisabledConstraint(to_pin)) + && (thru_constants_ || !mode->sim()->isConstant(to_vertex)); } class FaninSrchPred : public FanInOutSrchPred { public: FaninSrchPred(bool thru_disabled, - bool thru_constants, - const StaState *sta); + bool thru_constants, + const StaState *sta); protected: bool searchThruRole(Edge *edge) const override; }; FaninSrchPred::FaninSrchPred(bool thru_disabled, - bool thru_constants, - const StaState *sta) : - FanInOutSrchPred(thru_disabled, thru_constants, sta) + bool thru_constants, + const StaState *sta) : + FanInOutSrchPred(thru_disabled, + thru_constants, + sta) { } @@ -5240,21 +5236,19 @@ bool FaninSrchPred::searchThruRole(Edge *edge) const { const TimingRole *role = edge->role(); - return role == TimingRole::wire() - || role == TimingRole::combinational() - || role == TimingRole::tristateEnable() - || role == TimingRole::tristateDisable() - || role == TimingRole::regClkToQ() - || role == TimingRole::latchEnToQ(); + return role == TimingRole::wire() || role == TimingRole::combinational() + || role == TimingRole::tristateEnable() + || role == TimingRole::tristateDisable() || role == TimingRole::regClkToQ() + || role == TimingRole::latchEnToQ(); } PinSet Sta::findFaninPins(PinSeq *to, - bool flat, - bool startpoints_only, - int inst_levels, - int pin_levels, - bool thru_disabled, + bool flat, + bool startpoints_only, + int inst_levels, + int pin_levels, + bool thru_disabled, bool thru_constants, const Mode *mode) { @@ -5267,15 +5261,15 @@ Sta::findFaninPins(PinSeq *to, if (network_->isHierarchical(pin)) { EdgesThruHierPinIterator edge_iter(pin, network_, graph_); while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - findFaninPins(edge->from(graph_), flat, startpoints_only, - inst_levels, pin_levels, fanin, pred, mode); + Edge *edge = edge_iter.next(); + findFaninPins(edge->from(graph_), flat, startpoints_only, inst_levels, + pin_levels, fanin, pred, mode); } } else { Vertex *vertex = graph_->pinLoadVertex(pin); - findFaninPins(vertex, flat, startpoints_only, - inst_levels, pin_levels, fanin, pred, mode); + findFaninPins(vertex, flat, startpoints_only, inst_levels, pin_levels, fanin, + pred, mode); } } return fanin; @@ -5283,21 +5277,19 @@ Sta::findFaninPins(PinSeq *to, void Sta::findFaninPins(Vertex *vertex, - bool flat, - bool startpoints_only, - int inst_levels, - int pin_levels, - PinSet &fanin, + bool flat, + bool startpoints_only, + int inst_levels, + int pin_levels, + PinSet &fanin, SearchPred &pred, const Mode *mode) { VertexSet visited = makeVertexSet(this); - findFaninPins(vertex, flat, inst_levels, - pin_levels, visited, &pred, 0, 0, mode); + findFaninPins(vertex, flat, inst_levels, pin_levels, visited, &pred, 0, 0, mode); for (Vertex *visited_vertex : visited) { Pin *visited_pin = visited_vertex->pin(); - if (!startpoints_only - || network_->isRegClkPin(visited_pin) + if (!startpoints_only || network_->isRegClkPin(visited_pin) || !hasFanin(visited_vertex, &pred, graph_, mode)) fanin.insert(visited_pin); } @@ -5305,40 +5297,32 @@ Sta::findFaninPins(Vertex *vertex, void Sta::findFaninPins(Vertex *to, - bool flat, - int inst_levels, - int pin_levels, - VertexSet &visited, - SearchPred *pred, - int inst_level, + bool flat, + int inst_levels, + int pin_levels, + VertexSet &visited, + SearchPred *pred, + int inst_level, int pin_level, const Mode *mode) { - debugPrint(debug_, "fanin", 1, "%s", - to->to_string(this).c_str()); + debugPrint(debug_, "fanin", 1, "{}", to->to_string(this)); if (!visited.contains(to)) { visited.insert(to); Pin *to_pin = to->pin(); bool is_reg_clk_pin = network_->isRegClkPin(to_pin); - if (!is_reg_clk_pin - && (inst_levels <= 0 - || inst_level < inst_levels) - && (pin_levels <= 0 - || pin_level < pin_levels) - && pred->searchTo(to, mode)) { + if (!is_reg_clk_pin && (inst_levels <= 0 || inst_level < inst_levels) + && (pin_levels <= 0 || pin_level < pin_levels) && pred->searchTo(to, mode)) { VertexInEdgeIterator edge_iter(to, graph_); while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - Vertex *from_vertex = edge->from(graph_); - if (pred->searchThru(edge, mode) - && (flat - || !crossesHierarchy(edge)) + Edge *edge = edge_iter.next(); + Vertex *from_vertex = edge->from(graph_); + if (pred->searchThru(edge, mode) && (flat || !crossesHierarchy(edge)) && pred->searchFrom(from_vertex, mode)) { - findFaninPins(from_vertex, flat, inst_levels, - pin_levels, visited, pred, - edge->role()->isWire() ? inst_level : inst_level+1, - pin_level+1, mode); - } + findFaninPins(from_vertex, flat, inst_levels, pin_levels, visited, pred, + edge->role()->isWire() ? inst_level : inst_level + 1, + pin_level + 1, mode); + } } } } @@ -5346,26 +5330,26 @@ Sta::findFaninPins(Vertex *to, InstanceSet Sta::findFaninInstances(PinSeq *to, - bool flat, - bool startpoints_only, - int inst_levels, - int pin_levels, - bool thru_disabled, + bool flat, + bool startpoints_only, + int inst_levels, + int pin_levels, + bool thru_disabled, bool thru_constants, const Mode *mode) { - PinSet pins = findFaninPins(to, flat, startpoints_only, inst_levels, - pin_levels, thru_disabled, thru_constants, mode); + PinSet pins = findFaninPins(to, flat, startpoints_only, inst_levels, pin_levels, + thru_disabled, thru_constants, mode); return pinInstances(pins, network_); } PinSet Sta::findFanoutPins(PinSeq *from, - bool flat, - bool endpoints_only, - int inst_levels, - int pin_levels, - bool thru_disabled, + bool flat, + bool endpoints_only, + int inst_levels, + int pin_levels, + bool thru_disabled, bool thru_constants, const Mode *mode) { @@ -5378,15 +5362,15 @@ Sta::findFanoutPins(PinSeq *from, if (network_->isHierarchical(pin)) { EdgesThruHierPinIterator edge_iter(pin, network_, graph_); while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - findFanoutPins(edge->to(graph_), flat, endpoints_only, - inst_levels, pin_levels, fanout, pred, mode); + Edge *edge = edge_iter.next(); + findFanoutPins(edge->to(graph_), flat, endpoints_only, inst_levels, + pin_levels, fanout, pred, mode); } } else { Vertex *vertex = graph_->pinDrvrVertex(pin); - findFanoutPins(vertex, flat, endpoints_only, - inst_levels, pin_levels, fanout, pred, mode); + findFanoutPins(vertex, flat, endpoints_only, inst_levels, pin_levels, fanout, + pred, mode); } } return fanout; @@ -5394,21 +5378,19 @@ Sta::findFanoutPins(PinSeq *from, void Sta::findFanoutPins(Vertex *vertex, - bool flat, - bool endpoints_only, - int inst_levels, - int pin_levels, - PinSet &fanout, + bool flat, + bool endpoints_only, + int inst_levels, + int pin_levels, + PinSet &fanout, SearchPred &pred, const Mode *mode) { VertexSet visited = makeVertexSet(this); - findFanoutPins(vertex, flat, inst_levels, - pin_levels, visited, &pred, 0, 0, mode); + findFanoutPins(vertex, flat, inst_levels, pin_levels, visited, &pred, 0, 0, mode); for (Vertex *visited_vertex : visited) { Pin *visited_pin = visited_vertex->pin(); - if (!endpoints_only - || search_->isEndpoint(visited_vertex, &pred, mode)) + if (!endpoints_only || search_->isEndpoint(visited_vertex, &pred, mode)) fanout.insert(visited_pin); } } @@ -5416,38 +5398,32 @@ Sta::findFanoutPins(Vertex *vertex, // DFS to support level limits. void Sta::findFanoutPins(Vertex *from, - bool flat, - int inst_levels, - int pin_levels, - VertexSet &visited, - SearchPred *pred, - int inst_level, + bool flat, + int inst_levels, + int pin_levels, + VertexSet &visited, + SearchPred *pred, + int inst_level, int pin_level, const Mode *mode) { - debugPrint(debug_, "fanout", 1, "%s", - from->to_string(this).c_str()); + debugPrint(debug_, "fanout", 1, "{}", from->to_string(this)); if (!visited.contains(from)) { visited.insert(from); if (!search_->isEndpoint(from, pred, mode) - && (inst_levels <= 0 - || inst_level < inst_levels) - && (pin_levels <= 0 - || pin_level < pin_levels) + && (inst_levels <= 0 || inst_level < inst_levels) + && (pin_levels <= 0 || pin_level < pin_levels) && pred->searchFrom(from, mode)) { VertexOutEdgeIterator edge_iter(from, graph_); while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - Vertex *to_vertex = edge->to(graph_); - if (pred->searchThru(edge, mode) - && (flat - || !crossesHierarchy(edge)) + Edge *edge = edge_iter.next(); + Vertex *to_vertex = edge->to(graph_); + if (pred->searchThru(edge, mode) && (flat || !crossesHierarchy(edge)) && pred->searchTo(to_vertex, mode)) { - findFanoutPins(to_vertex, flat, inst_levels, - pin_levels, visited, pred, - edge->role()->isWire() ? inst_level : inst_level+1, - pin_level+1, mode); - } + findFanoutPins(to_vertex, flat, inst_levels, pin_levels, visited, pred, + edge->role()->isWire() ? inst_level : inst_level + 1, + pin_level + 1, mode); + } } } } @@ -5455,22 +5431,22 @@ Sta::findFanoutPins(Vertex *from, InstanceSet Sta::findFanoutInstances(PinSeq *from, - bool flat, - bool endpoints_only, - int inst_levels, - int pin_levels, - bool thru_disabled, + bool flat, + bool endpoints_only, + int inst_levels, + int pin_levels, + bool thru_disabled, bool thru_constants, const Mode *mode) { - PinSet pins = findFanoutPins(from, flat, endpoints_only, inst_levels, - pin_levels, thru_disabled, thru_constants, mode); + PinSet pins = findFanoutPins(from, flat, endpoints_only, inst_levels, pin_levels, + thru_disabled, thru_constants, mode); return pinInstances(pins, network_); } static InstanceSet pinInstances(PinSet &pins, - const Network *network) + const Network *network) { InstanceSet insts(network); for (const Pin *pin : pins) @@ -5490,11 +5466,11 @@ Sta::crossesHierarchy(Edge *edge) const // Treat input/output port pins as "inside". if (network_->isTopInstance(from_inst)) from_parent = from_inst; - else + else from_parent = network_->parent(from_inst); if (network_->isTopInstance(to_inst)) to_parent = to_inst; - else + else to_parent = network_->parent(to_inst); return from_parent != to_parent; } @@ -5513,8 +5489,8 @@ instMaxSlew(const Instance *inst, Pin *pin = pin_iter->next(); if (network->isDriver(pin)) { Vertex *vertex = graph->pinDrvrVertex(pin); - Slew slew = sta->slew(vertex, RiseFallBoth::riseFall(), - sta->scenes(), MinMax::max()); + Slew slew = + sta->slew(vertex, RiseFallBoth::riseFall(), sta->scenes(), MinMax::max()); if (delayGreater(slew, max_slew, sta)) max_slew = slew; } @@ -5528,11 +5504,8 @@ Sta::slowDrivers(int count) { findDelays(); InstanceSeq insts = network_->leafInstances(); - sort(insts, [this] (const Instance *inst1, - const Instance *inst2) { - return delayGreater(instMaxSlew(inst1, this), - instMaxSlew(inst2, this), - this); + sort(insts, [this](const Instance *inst1, const Instance *inst2) { + return delayGreater(instMaxSlew(inst1, this), instMaxSlew(inst2, this), this); }); insts.resize(count); return insts; @@ -5549,10 +5522,11 @@ Sta::reportSlewChecks(const Net *net, const MinMax *min_max) { checkSlewsPreamble(); - SlewCheckSeq &checks = check_slews_->check(net, max_count, violators, scenes, min_max); + SlewCheckSeq &checks = + check_slews_->check(net, max_count, violators, scenes, min_max); if (!checks.empty()) { - report_->reportLine("%s slew", min_max->to_string().c_str()); - report_->reportLine(""); + report_->report("{} slew", min_max->to_string()); + report_->report(""); if (!verbose) report_path_->reportLimitShortHeader(report_path_->fieldSlew()); @@ -5560,15 +5534,15 @@ Sta::reportSlewChecks(const Net *net, if (verbose) report_path_->reportLimitVerbose(report_path_->fieldSlew(), check.pin(), check.edge(), - delayAsFloat(check.slew()), + delayAsFloat(check.slew(), min_max, this), check.limit(), check.slack(), check.scene(), min_max); else report_path_->reportLimitShort(report_path_->fieldSlew(), check.pin(), - delayAsFloat(check.slew()), + delayAsFloat(check.slew(), min_max, this), check.limit(), check.slack()); } - report_->reportLine(""); + report_->report(""); } } @@ -5581,7 +5555,7 @@ Sta::checkSlewsPreamble() if (mode->sdc()->haveClkSlewLimits()) have_clk_slew_limits = true; mode->clkNetwork()->ensureClkNetwork(); - } + } if (have_clk_slew_limits) // Arrivals are needed to know pin clock domains. updateTiming(false); @@ -5594,17 +5568,17 @@ Sta::checkSlewsPreamble() void Sta::checkSlew(const Pin *pin, const SceneSeq &scenes, - const MinMax *min_max, - bool check_clks, - // Return values. - Slew &slew, - float &limit, + const MinMax *min_max, + bool check_clks, + // Return values. + Slew &slew, + float &limit, float &slack, const RiseFall *&rf, const Scene *&scene) { - check_slews_->check(pin, scenes, min_max, check_clks, - slew, limit, slack, rf, scene); + check_slews_->check(pin, scenes, min_max, check_clks, slew, limit, slack, rf, + scene); } size_t @@ -5615,14 +5589,15 @@ Sta::maxSlewViolationCount() } void -Sta::maxSlewCheck(// Return values. - const Pin *&pin, - Slew &slew, - float &slack, - float &limit) +Sta::maxSlewCheck( // Return values. + const Pin *&pin, + Slew &slew, + float &slack, + float &limit) { checkSlewsPreamble(); - SlewCheckSeq &checks = check_slews_->check(nullptr, 1, false, scenes_, MinMax::max()); + SlewCheckSeq &checks = + check_slews_->check(nullptr, 1, false, scenes_, MinMax::max()); if (!checks.empty()) { SlewCheck &check = checks[0]; pin = check.pin(); @@ -5631,9 +5606,9 @@ Sta::maxSlewCheck(// Return values. limit = check.limit(); } else { - pin = nullptr; - slew = 0.0; - slack = INF; + pin = nullptr; + slew = 0.0; + slack = INF; } } @@ -5647,8 +5622,7 @@ Sta::findSlewLimit(const LibertyPort *port, { if (check_slews_ == nullptr) makeCheckSlews(); - check_slews_->findLimit(port, scene, min_max, - limit, exists); + check_slews_->findLimit(port, scene, min_max, limit, exists); } ////////////////////////////////////////////////////////////////' @@ -5656,34 +5630,32 @@ Sta::findSlewLimit(const LibertyPort *port, void Sta::reportFanoutChecks(const Net *net, size_t max_count, - bool violators, + bool violators, bool verbose, const SceneSeq &scenes, - const MinMax *min_max) + const MinMax *min_max) { checkFanoutPreamble(); - const ModeSeq modes = Scene::modesSorted(scenes); - FanoutCheckSeq &checks = check_fanouts_->check(net, max_count, violators, - modes, min_max); + const ModeSeq modes = Scene::modesSorted(scenes); + FanoutCheckSeq &checks = + check_fanouts_->check(net, max_count, violators, modes, min_max); if (!checks.empty()) { - report_->reportLine("%s fanout", min_max->to_string().c_str()); - report_->reportLine(""); + report_->report("{} fanout", min_max->to_string()); + report_->report(""); if (!verbose) - report_path_->reportLimitShortHeader(report_path_->fieldFanout()); + report_path_->reportLimitShortHeader(report_path_->fieldFanout()); for (const FanoutCheck &check : checks) { if (verbose) - report_path_->reportLimitVerbose(report_path_->fieldFanout(), - check.pin(), nullptr, check.fanout(), - check.limit(), check.slack(), nullptr, - min_max); + report_path_->reportLimitVerbose(report_path_->fieldFanout(), check.pin(), + nullptr, check.fanout(), check.limit(), + check.slack(), nullptr, min_max); else - report_path_->reportLimitShort(report_path_->fieldFanout(), - check.pin(), check.fanout(), - check.limit(), check.slack()); + report_path_->reportLimitShort(report_path_->fieldFanout(), check.pin(), + check.fanout(), check.limit(), check.slack()); } - report_->reportLine(""); + report_->report(""); } } @@ -5710,11 +5682,11 @@ Sta::fanoutViolationCount(const MinMax *min_max, void Sta::checkFanout(const Pin *pin, const Mode *mode, - const MinMax *min_max, - // Return values. - float &fanout, - float &limit, - float &slack) + const MinMax *min_max, + // Return values. + float &fanout, + float &limit, + float &slack) { FanoutCheck check = check_fanouts_->check(pin, mode, min_max); pin = check.pin(); @@ -5726,15 +5698,15 @@ Sta::checkFanout(const Pin *pin, void Sta::maxFanoutMinSlackPin(const ModeSeq &modes, // Return values. - const Pin *&pin, - float &fanout, + const Pin *&pin, + float &fanout, float &limit, - float &slack, + float &slack, const Mode *&mode) { checkFanoutPreamble(); - FanoutCheckSeq &checks = check_fanouts_->check(nullptr, 1, false, - modes, MinMax::max()); + FanoutCheckSeq &checks = + check_fanouts_->check(nullptr, 1, false, modes, MinMax::max()); if (!checks.empty()) { FanoutCheck &check = checks[0]; pin = check.pin(); @@ -5744,9 +5716,9 @@ Sta::maxFanoutMinSlackPin(const ModeSeq &modes, mode = check.mode(); } else { - pin = nullptr; - fanout = 0; - limit = INF; + pin = nullptr; + fanout = 0; + limit = INF; slack = INF; mode = nullptr; } @@ -5757,32 +5729,31 @@ Sta::maxFanoutMinSlackPin(const ModeSeq &modes, void Sta::reportCapacitanceChecks(const Net *net, size_t max_count, - bool violators, + bool violators, bool verbose, const SceneSeq &scenes, - const MinMax *min_max) + const MinMax *min_max) { checkCapacitancesPreamble(scenes); - CapacitanceCheckSeq &checks = check_capacitances_->check(net, max_count, - violators, - scenes, min_max); + CapacitanceCheckSeq &checks = + check_capacitances_->check(net, max_count, violators, scenes, min_max); if (!checks.empty()) { - report_->reportLine("%s capacitance", min_max->to_string().c_str()); - report_->reportLine(""); + report_->report("{} capacitance", min_max->to_string()); + report_->report(""); if (!verbose) - report_path_->reportLimitShortHeader(report_path_->fieldCapacitance()); + report_path_->reportLimitShortHeader(report_path_->fieldCapacitance()); for (CapacitanceCheck &check : checks) { if (verbose) - report_path_->reportLimitVerbose(report_path_->fieldCapacitance(), - check.pin(), check.rf(), check.capacitance(), - check.limit(), check.slack(), check.scene(), - min_max); + report_path_->reportLimitVerbose(report_path_->fieldCapacitance(), + check.pin(), check.rf(), + check.capacitance(), check.limit(), + check.slack(), check.scene(), min_max); else - report_path_->reportLimitShort(report_path_->fieldCapacitance(), - check.pin(), check.capacitance(), - check.limit(), check.slack()); - report_->reportLine(""); + report_path_->reportLimitShort(report_path_->fieldCapacitance(), check.pin(), + check.capacitance(), check.limit(), + check.slack()); + report_->report(""); } } } @@ -5802,10 +5773,10 @@ Sta::checkCapacitancesPreamble(const SceneSeq &scenes) void Sta::checkCapacitance(const Pin *pin, const SceneSeq &scenes, - const MinMax *min_max, - // Return values. - float &capacitance, - float &limit, + const MinMax *min_max, + // Return values. + float &capacitance, + float &limit, float &slack, const RiseFall *&rf, const Scene *&scene) @@ -5823,21 +5794,19 @@ size_t Sta::maxCapacitanceViolationCount() { checkCapacitancesPreamble(scenes_); - return check_capacitances_->check(nullptr, 1, true, scenes_, - MinMax::max()).size(); + return check_capacitances_->check(nullptr, 1, true, scenes_, MinMax::max()).size(); } void -Sta::maxCapacitanceCheck(// Return values. - const Pin *&pin, - float &capacitance, - float &slack, - float &limit) +Sta::maxCapacitanceCheck( // Return values. + const Pin *&pin, + float &capacitance, + float &slack, + float &limit) { checkCapacitancesPreamble(scenes_); - CapacitanceCheckSeq &checks = check_capacitances_->check(nullptr, 1, false, - scenes_, - MinMax::max()); + CapacitanceCheckSeq &checks = + check_capacitances_->check(nullptr, 1, false, scenes_, MinMax::max()); pin = nullptr; capacitance = 0.0; slack = INF; @@ -5864,7 +5833,7 @@ Sta::reportMinPulseWidthChecks(const Net *net, if (check_min_pulse_widths_ == nullptr) makeCheckMinPulseWidths(); MinPulseWidthCheckSeq &checks = - check_min_pulse_widths_->check(net, max_count, violators, scenes); + check_min_pulse_widths_->check(net, max_count, violators, scenes); report_path_->reportMpwChecks(checks, verbose); } @@ -5881,8 +5850,8 @@ Sta::reportMinPeriodChecks(const Net *net, ensureClkArrivals(); if (check_min_periods_ == nullptr) makeCheckMinPeriods(); - MinPeriodCheckSeq &checks = check_min_periods_->check(net, max_count, - violators, scenes); + MinPeriodCheckSeq &checks = + check_min_periods_->check(net, max_count, violators, scenes); report_path_->reportChecks(checks, verbose); } @@ -5896,7 +5865,8 @@ Sta::reportMaxSkewChecks(const Net *net, const SceneSeq &scenes) { maxSkewPreamble(); - MaxSkewCheckSeq &checks = check_max_skews_->check(net, max_count, violators, scenes); + MaxSkewCheckSeq &checks = + check_max_skews_->check(net, max_count, violators, scenes); report_path_->reportChecks(checks, verbose); } @@ -5912,7 +5882,7 @@ Sta::maxSkewPreamble() void Sta::makeEquivCells(LibertyLibrarySeq *equiv_libs, - LibertyLibrarySeq *map_libs) + LibertyLibrarySeq *map_libs) { delete equiv_cells_; equiv_cells_ = new EquivCells(equiv_libs, map_libs); @@ -5937,8 +5907,8 @@ Sta::writeTimingModel(const char *lib_name, { ensureLibLinked(); ensureGraph(); - LibertyLibrary *library = makeTimingModel(lib_name, cell_name, filename, - scene, this); + LibertyLibrary *library = + makeTimingModel(lib_name, cell_name, filename, scene, this); writeLiberty(library, filename, this); } @@ -6004,13 +5974,13 @@ Sta::powerPreamble(const Scene *scene) void Sta::power(const Scene *scene, - // Return values. - PowerResult &total, - PowerResult &sequential, - PowerResult &combinational, - PowerResult &clock, - PowerResult ¯o, - PowerResult &pad) + // Return values. + PowerResult &total, + PowerResult &sequential, + PowerResult &combinational, + PowerResult &clock, + PowerResult ¯o, + PowerResult &pad) { powerPreamble(scene); power_->power(scene, total, sequential, combinational, clock, macro, pad); @@ -6045,9 +6015,8 @@ Sta::writePathSpice(const Path *path, CircuitSim ckt_sim) { ensureLibLinked(); - sta::writePathSpice(path, spice_filename, subckt_filename, - lib_subckt_filename, model_filename, - power_name, gnd_name, ckt_sim, this); + sta::writePathSpice(path, spice_filename, subckt_filename, lib_subckt_filename, + model_filename, power_name, gnd_name, ckt_sim, this); } //////////////////////////////////////////////////////////////// @@ -6105,4 +6074,4 @@ Sta::clkPinsInvalid(const Mode *mode) mode->clkNetwork()->clkPinsInvalid(); } -} // namespace +} // namespace sta diff --git a/search/StaState.cc b/search/StaState.cc index 6ba49123..661c02c9 100644 --- a/search/StaState.cc +++ b/search/StaState.cc @@ -49,11 +49,11 @@ StaState::StaState() : arc_delay_calc_(nullptr), graph_delay_calc_(nullptr), search_(nullptr), + delay_ops_(nullptr), latches_(nullptr), variables_(nullptr), thread_count_(1), - dispatch_queue_(nullptr), - sigma_factor_(1.0) + dispatch_queue_(nullptr) { } diff --git a/search/Tag.cc b/search/Tag.cc index a242be9c..9e5113e4 100644 --- a/search/Tag.cc +++ b/search/Tag.cc @@ -160,10 +160,10 @@ Tag::to_string(bool report_index, for (ExceptionState *state : *states_) { ExceptionPath *exception = state->exception(); result += " "; - result += exception->asString(network); + result += exception->to_string(network); if (state->nextThru()) { result += " (next thru "; - result += state->nextThru()->asString(network); + result += state->nextThru()->to_string(network); result += ")"; } else { diff --git a/search/TagGroup.cc b/search/TagGroup.cc index 67d0d5eb..85fc29a5 100644 --- a/search/TagGroup.cc +++ b/search/TagGroup.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "TagGroup.hh" @@ -43,7 +43,8 @@ TagGroup::TagGroup(TagGroupIndex index, bool has_loop_tag, const StaState *sta) : path_index_map_(path_index_map), - hash_(hash(path_index_map, sta)), + hash_(hash(path_index_map, + sta)), ref_count_(0), index_(index), has_clk_tag_(has_clk_tag), @@ -57,7 +58,8 @@ TagGroup::TagGroup(TagGroupIndex index, TagGroup::TagGroup(TagGroupBldr *tag_bldr, const StaState *sta) : path_index_map_(&tag_bldr->pathIndexMap()), - hash_(hash(path_index_map_, sta)), + hash_(hash(path_index_map_, + sta)), ref_count_(0), own_path_map_(false) { @@ -121,7 +123,7 @@ void TagGroup::report(const StaState *sta) const { Report *report = sta->report(); - report->reportLine("Group %u hash = %zu", index_, hash_); + report->report("Group {} hash = {}", index_, hash_); pathIndexMapReport(path_index_map_, sta); } @@ -137,9 +139,7 @@ pathIndexMapReport(const PathIndexMap *path_index_map, { Report *report = sta->report(); for (auto const [tag, path_index] : *path_index_map) - report->reportLine(" %2zu %s", - path_index, - tag->to_string(sta).c_str()); + report->report(" {:2} {}", path_index, tag->to_string(sta)); report->reportBlankLine(); } @@ -147,10 +147,10 @@ pathIndexMapReport(const PathIndexMap *path_index_map, TagGroupBldr::TagGroupBldr(bool match_crpr_clk_pin, const StaState *sta) : - default_path_count_(sta->scenes().size() - * RiseFall::index_count + default_path_count_(sta->scenes().size() * RiseFall::index_count * MinMax::index_count), - path_index_map_(TagMatchLess(match_crpr_clk_pin, sta)), + path_index_map_(TagMatchLess(match_crpr_clk_pin, + sta)), paths_(default_path_count_), has_clk_tag_(false), has_genclk_src_tag_(false), @@ -213,7 +213,7 @@ TagGroupBldr::tagMatchPath(Tag *tag, } } -Arrival +Arrival TagGroupBldr::arrival(size_t path_index) const { return paths_[path_index].arrival(); @@ -247,8 +247,8 @@ TagGroupBldr::setMatchPath(Path *match, path_index_map_.erase(tag_match); path_index_map_[tag] = path_index; } - paths_[path_index].init(vertex_, tag, arrival, prev_path, - prev_edge, prev_arc, sta_); + paths_[path_index].init(vertex_, tag, arrival, prev_path, prev_edge, prev_arc, + sta_); } else insertPath(tag, arrival, prev_path, prev_edge, prev_arc); @@ -264,15 +264,13 @@ TagGroupBldr::insertPath(Tag *tag, { size_t path_index = paths_.size(); path_index_map_[tag] = path_index; - paths_.emplace_back(vertex_, tag, arrival, prev_path, - prev_edge, prev_arc, sta_); + paths_.emplace_back(vertex_, tag, arrival, prev_path, prev_edge, prev_arc, sta_); if (tag->isClock()) has_clk_tag_ = true; if (tag->isGenClkSrcPath()) has_genclk_src_tag_ = true; - if (tag->isFilter() - || tag->clkInfo()->crprPathRefsFilter()) + if (tag->isFilter() || tag->clkInfo()->crprPathRefsFilter()) has_filter_tag_ = true; if (tag->isLoop()) has_loop_tag_ = true; @@ -283,18 +281,16 @@ TagGroupBldr::insertPath(Tag *tag, void TagGroupBldr::insertPath(const Path &path) { - insertPath(path.tag(sta_), path.arrival(), path.prevPath(), - path.prevEdge(sta_), path.prevArc(sta_)); + insertPath(path.tag(sta_), path.arrival(), path.prevPath(), path.prevEdge(sta_), + path.prevArc(sta_)); } TagGroup * TagGroupBldr::makeTagGroup(TagGroupIndex index, const StaState *sta) { - return new TagGroup(index, makePathIndexMap(sta), - has_clk_tag_, has_genclk_src_tag_, has_filter_tag_, - has_loop_tag_, sta); - + return new TagGroup(index, makePathIndexMap(sta), has_clk_tag_, + has_genclk_src_tag_, has_filter_tag_, has_loop_tag_, sta); } PathIndexMap * @@ -352,9 +348,9 @@ TagGroupEqual::operator()(const TagGroup *tag_group1, const TagGroup *tag_group2) const { return tag_group1 == tag_group2 - || (tag_group1->hash() == tag_group2->hash() - && pathIndexMapEqual(tag_group1->pathIndexMap(), - tag_group2->pathIndexMap())); + || (tag_group1->hash() == tag_group2->hash() + && pathIndexMapEqual(tag_group1->pathIndexMap(), + tag_group2->pathIndexMap())); } -} // namespace +} // namespace sta diff --git a/search/VisitPathEnds.cc b/search/VisitPathEnds.cc index 0c414c86..4a668d9b 100644 --- a/search/VisitPathEnds.cc +++ b/search/VisitPathEnds.cc @@ -67,8 +67,8 @@ VisitPathEnds::visitPathEnds(Vertex *vertex, // Ignore slack on bidirect driver vertex. The load vertex gets the slack. if (!vertex->isBidirectDriver()) { const Pin *pin = vertex->pin(); - debugPrint(debug_, "search", 2, "find end slack %s", - vertex->to_string(this).c_str()); + debugPrint(debug_, "search", 2, "find end slack {}", + vertex->to_string(this)); visitor->vertexBegin(vertex); bool is_constrained = false; visitClkedPathEnds(pin, vertex, scenes, min_max, filtered, visitor, diff --git a/search/WorstSlack.cc b/search/WorstSlack.cc index d2e6d5ce..a58efb64 100644 --- a/search/WorstSlack.cc +++ b/search/WorstSlack.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "WorstSlack.hh" @@ -37,7 +37,8 @@ namespace sta { WorstSlacks::WorstSlacks(StaState *sta) : - worst_slacks_(sta->scenePathCount(), sta), + worst_slacks_(sta->scenePathCount(), + sta), sta_(sta) { } @@ -54,8 +55,8 @@ WorstSlacks::worstSlack(const MinMax *min_max, PathAPIndex path_ap_index = scene->pathIndex(min_max); Slack worst_slack1; Vertex *worst_vertex1; - worst_slacks_[path_ap_index].worstSlack(path_ap_index, - worst_slack1, worst_vertex1); + worst_slacks_[path_ap_index].worstSlack(path_ap_index, worst_slack1, + worst_vertex1); if (delayLess(worst_slack1, worst_slack, sta_)) { worst_slack = worst_slack1; worst_vertex = worst_vertex1; @@ -71,8 +72,7 @@ WorstSlacks::worstSlack(const Scene *scene, Vertex *&worst_vertex) { PathAPIndex path_ap_index = scene->pathIndex(min_max); - worst_slacks_[path_ap_index].worstSlack(path_ap_index, - worst_slack, worst_vertex); + worst_slacks_[path_ap_index].worstSlack(path_ap_index, worst_slack, worst_vertex); } void @@ -105,10 +105,7 @@ WorstSlack::WorstSlack(StaState *sta) : { } -WorstSlack::~WorstSlack() -{ - delete queue_; -} +WorstSlack::~WorstSlack() { delete queue_; } WorstSlack::WorstSlack(const WorstSlack &worst_slack) : StaState(worst_slack), @@ -164,9 +161,9 @@ WorstSlack::initQueue(PathAPIndex path_ap_index) worst_vertex_ = nullptr; worst_slack_ = slack_init_; slack_threshold_ = slack_init_; - for(Vertex *vertex : search_->endpoints()) { + for (Vertex *vertex : search_->endpoints()) { Slack slack = search_->wnsSlack(vertex, path_ap_index); - if (!delayEqual(slack, slack_init_)) { + if (!delayEqual(slack, slack_init_, this)) { if (delayLess(slack, worst_slack_, this)) setWorstSlack(vertex, slack); if (delayLessEqual(slack, slack_threshold_, this)) @@ -176,9 +173,9 @@ WorstSlack::initQueue(PathAPIndex path_ap_index) sortQueue(path_ap_index); } } - debugPrint(debug_, "wns", 3, "threshold %s", - delayAsString(slack_threshold_, this)); -// checkQueue(); + debugPrint(debug_, "wns", 3, "threshold {}", + delayAsString(slack_threshold_, MinMax::max(), this)); + //checkQueue(); } void @@ -198,8 +195,8 @@ WorstSlack::sortQueue(PathAPIndex path_ap_index) int threshold_index = std::min(min_queue_size_, vertex_count - 1); Vertex *threshold_vertex = vertices[threshold_index]; slack_threshold_ = search_->wnsSlack(threshold_vertex, path_ap_index); - debugPrint(debug_, "wns", 3, "threshold %s", - delayAsString(slack_threshold_, this)); + debugPrint(debug_, "wns", 3, "threshold {}", + delayAsString(slack_threshold_, MinMax::max(), this)); // Reinsert vertices with slack < threshold. queue_->clear(); @@ -234,9 +231,9 @@ void WorstSlack::checkQueue(PathAPIndex path_ap_index) { VertexSeq ends; - for(Vertex *end : search_->endpoints()) { - if (delayLessEqual(search_->wnsSlack(end, path_ap_index), - slack_threshold_, this)) + for (Vertex *end : search_->endpoints()) { + if (delayLessEqual(search_->wnsSlack(end, path_ap_index), slack_threshold_, + this)) ends.push_back(end); } WnsSlackLess slack_less(path_ap_index, this); @@ -246,20 +243,18 @@ WorstSlack::checkQueue(PathAPIndex path_ap_index) for (Vertex *end : ends) { end_set.insert(end); if (!queue_->contains(end) - && delayLessEqual(search_->wnsSlack(end, path_ap_index), - slack_threshold_, this)) - report_->reportLine("WorstSlack queue missing %s %s < %s", - end->to_string(this).c_str(), - delayAsString(search_->wnsSlack(end, path_ap_index), this), - delayAsString(slack_threshold_, this)); + && delayLessEqual(search_->wnsSlack(end, path_ap_index), slack_threshold_, + this)) + report_->report("WorstSlack queue missing {} {} < {}", end->to_string(this), + delayAsString(search_->wnsSlack(end, path_ap_index), this), + delayAsString(slack_threshold_, this)); } for (Vertex *end : *queue_) { if (!end_set.contains(end)) - report_->reportLine("WorstSlack queue extra %s %s > %s", - end->to_string(this).c_str(), - delayAsString(search_->wnsSlack(end, path_ap_index), this), - delayAsString(slack_threshold_, this)); + report_->report("WorstSlack queue extra {} {} > {}", end->to_string(this), + delayAsString(search_->wnsSlack(end, path_ap_index), this), + delayAsString(slack_threshold_, this)); } } @@ -274,27 +269,24 @@ WorstSlack::updateWorstSlack(Vertex *vertex, // Locking is required because ArrivalVisitor is called by multiple // threads. LockGuard lock(lock_); - if (worst_vertex_ - && delayLess(slack, worst_slack_, this)) + if (worst_vertex_ && delayLess(slack, worst_slack_, this)) setWorstSlack(vertex, slack); else if (vertex == worst_vertex_) // Mark worst slack as unknown (updated by findWorstSlack(). worst_vertex_ = nullptr; - if (!delayEqual(slack, slack_init_) + if (!delayEqual(slack, slack_init_, this) && delayLessEqual(slack, slack_threshold_, this)) { - debugPrint(debug_, "wns", 3, "insert %s %s", - vertex->to_string(this).c_str(), + debugPrint(debug_, "wns", 3, "insert {} {}", vertex->to_string(this), delayAsString(slack, this)); queue_->insert(vertex); } else { - debugPrint(debug_, "wns", 3, "delete %s %s", - vertex->to_string(this).c_str(), + debugPrint(debug_, "wns", 3, "delete {} {}", vertex->to_string(this), delayAsString(slack, this)); queue_->erase(vertex); } - //checkQueue(path_ap_index); + // checkQueue(path_ap_index); } } @@ -302,8 +294,7 @@ void WorstSlack::setWorstSlack(Vertex *vertex, Slack slack) { - debugPrint(debug_, "wns", 3, "%s %s", - vertex->to_string(this).c_str(), + debugPrint(debug_, "wns", 3, "{} {}", vertex->to_string(this), delayAsString(slack, this)); worst_vertex_ = vertex; worst_slack_ = slack; @@ -323,8 +314,7 @@ WnsSlackLess::operator()(Vertex *vertex1, Vertex *vertex2) { return delayLess(search_->wnsSlack(vertex1, path_ap_index_), - search_->wnsSlack(vertex2, path_ap_index_), - search_); + search_->wnsSlack(vertex2, path_ap_index_), search_); } -} // namespace +} // namespace sta diff --git a/spice/WritePathSpice.cc b/spice/WritePathSpice.cc index 95fabc42..e5c019bd 100644 --- a/spice/WritePathSpice.cc +++ b/spice/WritePathSpice.cc @@ -30,6 +30,7 @@ #include "Debug.hh" #include "Error.hh" #include "Report.hh" +#include "Format.hh" #include "StringUtil.hh" #include "FuncExpr.hh" #include "Units.hh" @@ -203,7 +204,7 @@ WritePathSpice::writeSpice() writeInputSource(); writeStageInstances(); writeStageSubckts(); - streamPrint(spice_stream_, ".end\n"); + sta::print(spice_stream_, ".end\n"); spice_stream_.close(); } else @@ -214,11 +215,11 @@ void WritePathSpice::writeHeader() { const Path *start_path = path_expanded_.startPath(); - std::string title = stdstrPrint("Path from %s %s to %s %s", - network_->pathName(start_path->pin(this)), - start_path->transition(this)->shortName(), - network_->pathName(path_->pin(this)), - path_->transition(this)->shortName()); + std::string title = sta::format("Path from {} {} to {} {}", + network_->pathName(start_path->pin(this)), + start_path->transition(this)->shortName(), + network_->pathName(path_->pin(this)), + path_->transition(this)->shortName()); float max_time = maxTime(); float time_step = 1e-13; writeHeader(title, max_time, time_step); @@ -281,37 +282,37 @@ WritePathSpice::pathMaxTime() void WritePathSpice::writeStageInstances() { - streamPrint(spice_stream_, "*****************\n"); - streamPrint(spice_stream_, "* Stage instances\n"); - streamPrint(spice_stream_, "*****************\n\n"); + sta::print(spice_stream_, "*****************\n"); + sta::print(spice_stream_, "* Stage instances\n"); + sta::print(spice_stream_, "*****************\n\n"); for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { std::string stage_name = stageName(stage); const char *stage_cname = stage_name.c_str(); if (stage == stageFirst()) - streamPrint(spice_stream_, "x%s %s %s %s\n", - stage_cname, - stageDrvrPinName(stage), - stageLoadPinName(stage), - stage_cname); + sta::print(spice_stream_, "x{} {} {} {}\n", + stage_cname, + stageDrvrPinName(stage), + stageLoadPinName(stage), + stage_cname); else { - streamPrint(spice_stream_, "x%s %s %s %s %s\n", - stage_cname, - stageGateInputPinName(stage), - stageDrvrPinName(stage), - stageLoadPinName(stage), - stage_cname); + sta::print(spice_stream_, "x{} {} {} {} {}\n", + stage_cname, + stageGateInputPinName(stage), + stageDrvrPinName(stage), + stageLoadPinName(stage), + stage_cname); } } - streamPrint(spice_stream_, "\n"); + sta::print(spice_stream_, "\n"); } void WritePathSpice::writeInputSource() { - streamPrint(spice_stream_, "**************\n"); - streamPrint(spice_stream_, "* Input source\n"); - streamPrint(spice_stream_, "**************\n\n"); + sta::print(spice_stream_, "**************\n"); + sta::print(spice_stream_, "* Input source\n"); + sta::print(spice_stream_, "**************\n\n"); Stage input_stage = stageFirst(); const Path *input_path = stageDrvrPath(input_stage); @@ -319,7 +320,7 @@ WritePathSpice::writeInputSource() writeClkWaveform(); else writeInputWaveform(); - streamPrint(spice_stream_, "\n"); + sta::print(spice_stream_, "\n"); } void @@ -372,17 +373,17 @@ WritePathSpice::writeClkWaveform() } float slew0 = findSlew(input_path, rf0, next_arc); float slew1 = findSlew(input_path, rf1, next_arc); - streamPrint(spice_stream_, "v1 %s 0 pwl(\n", - stageDrvrPinName(input_stage)); - streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0); + sta::print(spice_stream_, "v1 {} 0 pwl(\n", + stageDrvrPinName(input_stage)); + sta::print(spice_stream_, "+{:.3e} {:.3e}\n", 0.0, volt0); for (int cycle = 0; cycle < clk_cycle_count_; cycle++) { float time0 = time_offset + cycle * period; float time1 = time0 + period / 2.0; writeWaveformEdge(rf0, time0, slew0); writeWaveformEdge(rf1, time1, slew1); } - streamPrint(spice_stream_, "+%.3e %.3e\n", max_time_, volt0); - streamPrint(spice_stream_, "+)\n"); + sta::print(spice_stream_, "+{:.3e} {:.3e}\n", max_time_, volt0); + sta::print(spice_stream_, "+)\n"); } float @@ -407,9 +408,9 @@ WritePathSpice::findSlew(const Path *path, void WritePathSpice::writeMeasureStmts() { - streamPrint(spice_stream_, "********************\n"); - streamPrint(spice_stream_, "* Measure statements\n"); - streamPrint(spice_stream_, "********************\n\n"); + sta::print(spice_stream_, "********************\n"); + sta::print(spice_stream_, "* Measure statements\n"); + sta::print(spice_stream_, "********************\n\n"); for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { const Path *gate_input_path = stageGateInputPath(stage); @@ -426,7 +427,7 @@ WritePathSpice::writeMeasureStmts() if (stage == stageLast()) writeMeasureSlewStmt(stage, load_path); } - streamPrint(spice_stream_, "\n"); + sta::print(spice_stream_, "\n"); } void @@ -452,9 +453,9 @@ WritePathSpice::writeMeasureSlewStmt(Stage stage, void WritePathSpice::writeStageSubckts() { - streamPrint(spice_stream_, "***************\n"); - streamPrint(spice_stream_, "* Stage subckts\n"); - streamPrint(spice_stream_, "***************\n\n"); + sta::print(spice_stream_, "***************\n"); + sta::print(spice_stream_, "* Stage subckts\n"); + sta::print(spice_stream_, "***************\n\n"); for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { cap_index_ = 1; @@ -476,12 +477,12 @@ WritePathSpice::writeInputStage(Stage stage) const char *drvr_pin_name = stageDrvrPinName(stage); const char *load_pin_name = stageLoadPinName(stage); std::string prefix = stageName(stage); - streamPrint(spice_stream_, ".subckt %s %s %s\n", - prefix.c_str(), - drvr_pin_name, - load_pin_name); + sta::print(spice_stream_, ".subckt {} {} {}\n", + prefix, + drvr_pin_name, + load_pin_name); writeStageParasitics(stage); - streamPrint(spice_stream_, ".ends\n\n"); + sta::print(spice_stream_, ".ends\n\n"); } // Gate and load parasitics. @@ -500,17 +501,17 @@ WritePathSpice::writeGateStage(Stage stage) const LibertyPort *input_port = stageGateInputPort(stage); const LibertyPort *drvr_port = stageDrvrPort(stage); - streamPrint(spice_stream_, ".subckt %s %s %s %s\n", - subckt_name.c_str(), - input_pin_name, - drvr_pin_name, - load_pin_name); + sta::print(spice_stream_, ".subckt {} {} {} {}\n", + subckt_name, + input_pin_name, + drvr_pin_name, + load_pin_name); // Driver subckt call. - streamPrint(spice_stream_, "* Gate %s %s -> %s\n", - network_->pathName(inst), - input_port->name(), - drvr_port->name()); + sta::print(spice_stream_, "* Gate {} {} -> {}\n", + network_->pathName(inst), + input_port->name(), + drvr_port->name()); writeSubcktInst(inst); const Path *drvr_path = stageDrvrPath(stage); @@ -525,7 +526,7 @@ WritePathSpice::writeGateStage(Stage stage) PinSet inputs(network_); inputs.insert(input_pin); writeSubcktInstVoltSrcs(inst, port_values, inputs); - streamPrint(spice_stream_, "\n"); + sta::print(spice_stream_, "\n"); PinSet drvr_loads(network_); PinConnectedPinIterator *pin_iter = network_->connectedPinIterator(drvr_pin); @@ -537,7 +538,7 @@ WritePathSpice::writeGateStage(Stage stage) writeSubcktInstLoads(drvr_pin, load_pin, drvr_loads, written_insts_); writeStageParasitics(stage); - streamPrint(spice_stream_, ".ends\n\n"); + sta::print(spice_stream_, ".ends\n\n"); } void @@ -575,7 +576,7 @@ WritePathSpice::findPathCellNames() if (arc) { LibertyCell *cell = arc->set()->libertyCell(); if (cell) { - debugPrint(debug_, "write_spice", 2, "cell %s", cell->name()); + debugPrint(debug_, "write_spice", 2, "cell {}", cell->name()); path_cell_names.insert(cell->name()); } // Include side receivers. @@ -612,9 +613,7 @@ WritePathSpice::stageLast() std::string WritePathSpice::stageName(Stage stage) { - std::string name; - stringPrint(name, "stage%d", stage); - return name; + return sta::format("stage{}", stage); } int diff --git a/spice/WriteSpice.cc b/spice/WriteSpice.cc index 3e646bea..6a62785c 100644 --- a/spice/WriteSpice.cc +++ b/spice/WriteSpice.cc @@ -1,30 +1,30 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "spice/WriteSpice.hh" -#include // swap +#include // swap #include #include #include @@ -60,7 +60,7 @@ class SubcktEndsMissing : public Exception { public: SubcktEndsMissing(const char *cell_name, - const char *subckt_filename); + const char *subckt_filename); const char *what() const noexcept; protected: @@ -68,7 +68,7 @@ protected: }; SubcktEndsMissing::SubcktEndsMissing(const char *cell_name, - const char *subckt_filename) : + const char *subckt_filename) : Exception() { what_ = "spice subckt for cell "; @@ -122,7 +122,7 @@ WriteSpice::initPowerGnd() default_library_->supplyVoltage(power_name_, power_voltage_, exists); if (!exists) { const OperatingConditions *op_cond = - scene_->sdc()->operatingConditions(min_max_); + scene_->sdc()->operatingConditions(min_max_); if (op_cond == nullptr) op_cond = network_->defaultLibertyLibrary()->defaultOperatingConditions(); power_voltage_ = op_cond->voltage(); @@ -137,31 +137,31 @@ WriteSpice::writeHeader(std::string &title, float max_time, float time_step) { - streamPrint(spice_stream_, "* %s\n", title.c_str()); - streamPrint(spice_stream_, ".include \"%s\"\n", model_filename_); - std::filesystem::path subckt_filename - = std::filesystem::path(subckt_filename_).filename(); - streamPrint(spice_stream_, ".include \"%s\"\n", subckt_filename.c_str()); - streamPrint(spice_stream_, ".tran %.3g %.3g\n", time_step, max_time); + sta::print(spice_stream_, "* {}\n", title); + sta::print(spice_stream_, ".include \"{}\"\n", model_filename_); + std::filesystem::path subckt_filename = + std::filesystem::path(subckt_filename_).filename(); + sta::print(spice_stream_, ".include \"{}\"\n", subckt_filename.string()); + sta::print(spice_stream_, ".tran {:.3g} {:.3g}\n", time_step, max_time); // Suppress printing model parameters. if (ckt_sim_ == CircuitSim::hspice) - streamPrint(spice_stream_, ".options nomod\n"); - streamPrint(spice_stream_, "\n"); + sta::print(spice_stream_, ".options nomod\n"); + sta::print(spice_stream_, "\n"); max_time_ = max_time; } void WriteSpice::writePrintStmt(StringSeq &node_names) { - streamPrint(spice_stream_, ".print tran"); + sta::print(spice_stream_, ".print tran"); if (ckt_sim_ == CircuitSim::xyce) { std::string csv_filename = replaceFileExt(spice_filename_, "csv"); - streamPrint(spice_stream_, " format=csv file=%s", csv_filename.c_str()); + sta::print(spice_stream_, " format=csv file={}", csv_filename); writeGnuplotFile(node_names); } for (std::string &name : node_names) - streamPrint(spice_stream_, " v(%s)", name.c_str()); - streamPrint(spice_stream_, "\n\n"); + sta::print(spice_stream_, " v({})", name); + sta::print(spice_stream_, "\n\n"); } std::string @@ -183,17 +183,16 @@ WriteSpice::writeGnuplotFile(StringSeq &node_nanes) std::ofstream gnuplot_stream; gnuplot_stream.open(gnuplot_filename); if (gnuplot_stream.is_open()) { - streamPrint(gnuplot_stream, "set datafile separator ','\n"); - streamPrint(gnuplot_stream, "set key autotitle columnhead\n"); - streamPrint(gnuplot_stream, "plot\\\n"); - streamPrint(gnuplot_stream, "\"%s\" using 1:2 with lines", - csv_filename.c_str()); + sta::print(gnuplot_stream, "set datafile separator ','\n"); + sta::print(gnuplot_stream, "set key autotitle columnhead\n"); + sta::print(gnuplot_stream, "plot\\\n"); + sta::print(gnuplot_stream, "\"{}\" using 1:2 with lines", csv_filename); for (size_t i = 3; i <= node_nanes.size() + 1; i++) { - streamPrint(gnuplot_stream, ",\\\n"); - streamPrint(gnuplot_stream, "'' using 1:%zu with lines", i); + sta::print(gnuplot_stream, ",\\\n"); + sta::print(gnuplot_stream, "'' using 1:{} with lines", i); } - streamPrint(gnuplot_stream, "\n"); - streamPrint(gnuplot_stream, "pause mouse close\n"); + sta::print(gnuplot_stream, "\n"); + sta::print(gnuplot_stream, "pause mouse close\n"); gnuplot_stream.close(); } } @@ -208,28 +207,27 @@ WriteSpice::writeSubckts(StringSet &cell_names) if (subckts_stream.is_open()) { std::string line; while (std::getline(lib_subckts_stream, line)) { - // .subckt [args..] - StringSeq tokens = parseTokens(line, ' '); - if (tokens.size() >= 2 - && stringEqual(tokens[0].c_str(), ".subckt")) { - const char *cell_name = tokens[1].c_str(); + // .subckt [args..] + StringSeq tokens = parseTokens(line, ' '); + if (tokens.size() >= 2 && stringEqual(tokens[0].c_str(), ".subckt")) { + const char *cell_name = tokens[1].c_str(); if (cell_names.contains(cell_name)) { - subckts_stream << line << "\n"; - bool found_ends = false; - while (std::getline(lib_subckts_stream, line)) { - subckts_stream << line << "\n"; - if (stringBeginEqual(line.c_str(), ".ends")) { - subckts_stream << "\n"; - found_ends = true; - break; - } - } - if (!found_ends) - throw SubcktEndsMissing(cell_name, lib_subckt_filename_); - cell_names.erase(cell_name); - } - recordSpicePortNames(cell_name, tokens); - } + subckts_stream << line << "\n"; + bool found_ends = false; + while (std::getline(lib_subckts_stream, line)) { + subckts_stream << line << "\n"; + if (stringBeginEqual(line.c_str(), ".ends")) { + subckts_stream << "\n"; + found_ends = true; + break; + } + } + if (!found_ends) + throw SubcktEndsMissing(cell_name, lib_subckt_filename_); + cell_names.erase(cell_name); + } + recordSpicePortNames(cell_name, tokens); + } } subckts_stream.close(); lib_subckts_stream.close(); @@ -240,9 +238,8 @@ WriteSpice::writeSubckts(StringSet &cell_names) missing_cells += "\n"; missing_cells += cell_name; } - report_->error(1605, "The subkct file %s is missing definitions for %s", - lib_subckt_filename_, - missing_cells.c_str()); + report_->error(1605, "The subkct file {} is missing definitions for {}", + lib_subckt_filename_, missing_cells); } } else { @@ -265,12 +262,13 @@ WriteSpice::recordSpicePortNames(const char *cell_name, const char *port_name = tokens[i].c_str(); LibertyPort *port = cell->findLibertyPort(port_name); LibertyPort *pg_port = cell->findLibertyPort(port_name); - if (port == nullptr - && pg_port == nullptr - && !stringEqual(port_name, power_name_) - && !stringEqual(port_name, gnd_name_)) - report_->error(1606, "subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground.", - cell_name, port_name); + if (port == nullptr && pg_port == nullptr + && !stringEqual(port_name, power_name_) + && !stringEqual(port_name, gnd_name_)) + report_->error(1606, + "subckt {} port {} has no corresponding liberty port, " + "pg_port and is not power or ground.", + cell_name, port_name); spice_port_names.push_back(port_name); } } @@ -286,8 +284,7 @@ WriteSpice::findCellSubckts(StringSet &cell_names) while (std::getline(lib_subckts_stream, line)) { // .subckt [args..] StringSeq tokens = parseTokens(line, ' '); - if (tokens.size() >= 2 - && stringEqual(tokens[0].c_str(), ".subckt")) { + if (tokens.size() >= 2 && stringEqual(tokens[0].c_str(), ".subckt")) { const char *cell_name = tokens[1].c_str(); if (cell_names.contains(cell_name)) { // Scan the subckt definition for subckt calls. @@ -324,7 +321,7 @@ WriteSpice::writeSubcktInst(const Instance *inst) LibertyCell *cell = network_->libertyCell(inst); const char *cell_name = cell->name(); StringSeq &spice_port_names = cell_spice_port_names_[cell_name]; - streamPrint(spice_stream_, "x%s", inst_name); + sta::print(spice_stream_, "x{}", inst_name); for (std::string subckt_port_name : spice_port_names) { const char *subckt_port_cname = subckt_port_name.c_str(); Pin *pin = network_->findPin(inst, subckt_port_cname); @@ -332,15 +329,15 @@ WriteSpice::writeSubcktInst(const Instance *inst) const char *pin_name; if (pin) { pin_name = network_->pathName(pin); - streamPrint(spice_stream_, " %s", pin_name); + sta::print(spice_stream_, " {}", pin_name); } else if (pg_port) - streamPrint(spice_stream_, " %s/%s", inst_name, subckt_port_cname); + sta::print(spice_stream_, " {}/{}", inst_name, subckt_port_cname); else if (stringEq(subckt_port_cname, power_name_) - || stringEq(subckt_port_cname, gnd_name_)) - streamPrint(spice_stream_, " %s/%s", inst_name, subckt_port_cname); + || stringEq(subckt_port_cname, gnd_name_)) + sta::print(spice_stream_, " {}/{}", inst_name, subckt_port_cname); } - streamPrint(spice_stream_, " %s\n", cell_name); + sta::print(spice_stream_, " {}\n", cell_name); } // Power/ground and input voltage sources. @@ -354,24 +351,21 @@ WriteSpice::writeSubcktInstVoltSrcs(const Instance *inst, StringSeq &spice_port_names = cell_spice_port_names_[cell_name]; const char *inst_name = network_->pathName(inst); - debugPrint(debug_, "write_spice", 2, "subckt %s", cell->name()); + debugPrint(debug_, "write_spice", 2, "subckt {}", cell->name()); for (std::string subckt_port_sname : spice_port_names) { const char *subckt_port_name = subckt_port_sname.c_str(); LibertyPort *port = cell->findLibertyPort(subckt_port_name); const Pin *pin = port ? network_->findPin(inst, port) : nullptr; bool is_pg_port = port && port->isPwrGnd(); - debugPrint(debug_, "write_spice", 2, " port %s%s", - subckt_port_name, + debugPrint(debug_, "write_spice", 2, " port {}{}", subckt_port_name, is_pg_port ? " pwr/gnd" : ""); if (is_pg_port) - writeVoltageSource(inst_name, subckt_port_name, - pgPortVoltage(port)); + writeVoltageSource(inst_name, subckt_port_name, pgPortVoltage(port)); else if (stringEq(subckt_port_name, power_name_)) writeVoltageSource(inst_name, subckt_port_name, power_voltage_); else if (stringEq(subckt_port_name, gnd_name_)) writeVoltageSource(inst_name, subckt_port_name, gnd_voltage_); - else if (port - && !excluded_input_pins.contains(pin) + else if (port && !excluded_input_pins.contains(pin) && port->direction()->isAnyInput()) { // Input voltage to sensitize path from gate input to output. // Look for tie high/low or propagated constant values. @@ -384,20 +378,18 @@ WriteSpice::writeSubcktInstVoltSrcs(const Instance *inst, port_value = value; } switch (port_value) { - case LogicValue::zero: - case LogicValue::unknown: - writeVoltageSource(cell, inst_name, subckt_port_name, - port->relatedGroundPin(), - gnd_voltage_); - break; - case LogicValue::one: - writeVoltageSource(cell, inst_name, subckt_port_name, - port->relatedPowerPin(), - power_voltage_); - break; - case LogicValue::rise: - case LogicValue::fall: - break; + case LogicValue::zero: + case LogicValue::unknown: + writeVoltageSource(cell, inst_name, subckt_port_name, + port->relatedGroundPin(), gnd_voltage_); + break; + case LogicValue::one: + writeVoltageSource(cell, inst_name, subckt_port_name, + port->relatedPowerPin(), power_voltage_); + break; + case LogicValue::rise: + case LogicValue::fall: + break; } } } @@ -426,10 +418,7 @@ WriteSpice::writeVoltageSource(LibertyCell *cell, if (pg_port) voltage = pgPortVoltage(pg_port); else - report_->error(1603, "%s pg_port %s not found,", - cell->name(), - pg_port_name); - + report_->error(1603, "{} pg_port {} not found,", cell->name(), pg_port_name); } writeVoltageSource(inst_name, subckt_port_name, voltage); } @@ -445,20 +434,18 @@ WriteSpice::pgPortVoltage(LibertyPort *pg_port) liberty->supplyVoltage(voltage_name, voltage, exists); if (!exists) { if (stringEqual(voltage_name, power_name_)) - voltage = power_voltage_; + voltage = power_voltage_; else if (stringEqual(voltage_name, gnd_name_)) - voltage = gnd_voltage_; + voltage = gnd_voltage_; else - report_->error(1601 , "pg_pin %s/%s voltage %s not found,", - pg_port->libertyCell()->name(), - pg_port->name(), - voltage_name); + report_->error(1601, "pg_pin {}/{} voltage {} not found,", + pg_port->libertyCell()->name(), pg_port->name(), + voltage_name); } } else - report_->error(1602, "Liberty pg_port %s/%s missing voltage_name attribute,", - pg_port->libertyCell()->name(), - pg_port->name()); + report_->error(1602, "Liberty pg_port {}/{} missing voltage_name attribute,", + pg_port->libertyCell()->name(), pg_port->name()); return voltage; } @@ -484,23 +471,23 @@ WriteSpice::slewAxisMinValue(const TimingArc *arc) { GateTableModel *gate_model = arc->gateTableModel(scene_, min_max_); if (gate_model) { - const TableModel *model = gate_model->delayModel(); + const TableModel *model = gate_model->delayModels()->model(); const TableAxis *axis1 = model->axis1(); TableAxisVariable var1 = axis1->variable(); if (var1 == TableAxisVariable::input_transition_time - || var1 == TableAxisVariable::input_net_transition) + || var1 == TableAxisVariable::input_net_transition) return axis1->axisValue(0); const TableAxis *axis2 = model->axis2(); TableAxisVariable var2 = axis2->variable(); if (var2 == TableAxisVariable::input_transition_time - || var2 == TableAxisVariable::input_net_transition) + || var2 == TableAxisVariable::input_net_transition) return axis2->axisValue(0); const TableAxis *axis3 = model->axis3(); TableAxisVariable var3 = axis3->variable(); if (var3 == TableAxisVariable::input_transition_time - || var3 == TableAxisVariable::input_net_transition) + || var3 == TableAxisVariable::input_net_transition) return axis3->axisValue(0); } return 0.0; @@ -514,15 +501,16 @@ WriteSpice::writeDrvrParasitics(const Pin *drvr_pin, const NetSet &coupling_nets) { Net *net = network_->net(drvr_pin); - const char *net_name = net ? network_->pathName(net) : network_->pathName(drvr_pin); - streamPrint(spice_stream_, "* Net %s\n", net_name); + const char *net_name = + net ? network_->pathName(net) : network_->pathName(drvr_pin); + sta::print(spice_stream_, "* Net {}\n", net_name); if (parasitics_->isParasiticNetwork(parasitic)) writeParasiticNetwork(drvr_pin, parasitic, coupling_nets); else if (parasitics_->isPiElmore(parasitic)) writePiElmore(drvr_pin, parasitic); else { - streamPrint(spice_stream_, "* Net has no parasitics.\n"); + sta::print(spice_stream_, "* Net has no parasitics.\n"); writeNullParasitic(drvr_pin); } } @@ -532,22 +520,18 @@ WriteSpice::writeParasiticNetwork(const Pin *drvr_pin, const Parasitic *parasitic, const NetSet &coupling_nets) { - std::set reachable_pins; + std::set reachable_pins; // Sort resistors for consistent regression results. ParasiticResistorSeq resistors = parasitics_->resistors(parasitic); - sort(resistors, [this] (const ParasiticResistor *r1, - const ParasiticResistor *r2) { - return parasitics_->id(r1) < parasitics_->id(r2); - }); + sort(resistors, [this](const ParasiticResistor *r1, const ParasiticResistor *r2) { + return parasitics_->id(r1) < parasitics_->id(r2); + }); for (ParasiticResistor *resistor : resistors) { float resistance = parasitics_->value(resistor); ParasiticNode *node1 = parasitics_->node1(resistor); ParasiticNode *node2 = parasitics_->node2(resistor); - streamPrint(spice_stream_, "R%d %s %s %.3e\n", - res_index_++, - parasitics_->name(node1), - parasitics_->name(node2), - resistance); + sta::print(spice_stream_, "R{} {} {} {:.3e}\n", res_index_++, + parasitics_->name(node1), parasitics_->name(node2), resistance); // Necessary but not sufficient. Need a DFS. const Pin *pin1 = parasitics_->pin(node1); @@ -562,15 +546,11 @@ WriteSpice::writeParasiticNetwork(const Pin *drvr_pin, auto pin_iter = network_->connectedPinIterator(drvr_pin); while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); - if (pin != drvr_pin - && network_->isLoad(pin) - && !network_->isHierarchical(pin) + if (pin != drvr_pin && network_->isLoad(pin) && !network_->isHierarchical(pin) && !reachable_pins.contains(pin)) { - streamPrint(spice_stream_, "R%d %s %s %.3e\n", - res_index_++, - network_->pathName(drvr_pin), - network_->pathName(pin), - short_ckt_resistance_); + sta::print(spice_stream_, "R{} {} {} {:.3e}\n", res_index_++, + network_->pathName(drvr_pin), network_->pathName(pin), + short_ckt_resistance_); } } delete pin_iter; @@ -578,28 +558,25 @@ WriteSpice::writeParasiticNetwork(const Pin *drvr_pin, // Grounded node capacitors. // Sort nodes for consistent regression results. ParasiticNodeSeq nodes = parasitics_->nodes(parasitic); - sort(nodes, [this] (const ParasiticNode *node1, - const ParasiticNode *node2) { - const char *name1 = parasitics_->name(node1); - const char *name2 = parasitics_->name(node2); - return stringLess(name1, name2); - }); + sort(nodes, [this](const ParasiticNode *node1, const ParasiticNode *node2) { + const char *name1 = parasitics_->name(node1); + const char *name2 = parasitics_->name(node2); + return stringLess(name1, name2); + }); for (ParasiticNode *node : nodes) { float cap = parasitics_->nodeGndCap(node); // Spice has a cow over zero value caps. if (cap > 0.0) { - streamPrint(spice_stream_, "C%d %s 0 %.3e\n", - cap_index_++, - parasitics_->name(node), - cap); + sta::print(spice_stream_, "C{} {} 0 {:.3e}\n", cap_index_++, + parasitics_->name(node), cap); } } // Sort coupling capacitors for consistent regression results. ParasiticCapacitorSeq capacitors = parasitics_->capacitors(parasitic); - sort(capacitors, [this] (const ParasiticCapacitor *c1, - const ParasiticCapacitor *c2) { + sort(capacitors, + [this](const ParasiticCapacitor *c1, const ParasiticCapacitor *c2) { return parasitics_->id(c1) < parasitics_->id(c2); }); const Net *net = pinNet(drvr_pin, network_); @@ -615,16 +592,11 @@ WriteSpice::writeParasiticNetwork(const Pin *drvr_pin, } if (net2 && coupling_nets.contains(net2)) // Write half the capacitance because the coupled net will do the same. - streamPrint(spice_stream_, "C%d %s %s %.3e\n", - cap_index_++, - parasitics_->name(node1), - parasitics_->name(node2), - cap * .5); + sta::print(spice_stream_, "C{} {} {} {:.3e}\n", cap_index_++, + parasitics_->name(node1), parasitics_->name(node2), cap * .5); else - streamPrint(spice_stream_, "C%d %s 0 %.3e\n", - cap_index_++, - parasitics_->name(node1), - cap); + sta::print(spice_stream_, "C{} {} 0 {:.3e}\n", cap_index_++, + parasitics_->name(node1), cap); } } @@ -650,50 +622,35 @@ WriteSpice::writePiElmore(const Pin *drvr_pin, float c2, rpi, c1; parasitics_->piModel(parasitic, c2, rpi, c1); const char *c1_node = "n1"; - streamPrint(spice_stream_, "RPI %s %s %.3e\n", - network_->pathName(drvr_pin), - c1_node, - rpi); + sta::print(spice_stream_, "RPI {} {} {:.3e}\n", network_->pathName(drvr_pin), + c1_node, rpi); if (c2 > 0.0) - streamPrint(spice_stream_, "C2 %s 0 %.3e\n", - network_->pathName(drvr_pin), - c2); + sta::print(spice_stream_, "C2 {} 0 {:.3e}\n", network_->pathName(drvr_pin), c2); if (c1 > 0.0) - streamPrint(spice_stream_, "C1 %s 0 %.3e\n", - c1_node, - c1); - + sta::print(spice_stream_, "C1 {} 0 {:.3e}\n", c1_node, c1); + int load_index = 3; auto pin_iter = network_->connectedPinIterator(drvr_pin); while (pin_iter->hasNext()) { const Pin *load_pin = pin_iter->next(); - if (load_pin != drvr_pin - && network_->isLoad(load_pin) - && !network_->isHierarchical(load_pin)) { + if (load_pin != drvr_pin && network_->isLoad(load_pin) + && !network_->isHierarchical(load_pin)) { float elmore; bool exists; parasitics_->findElmore(parasitic, load_pin, elmore, exists); if (exists) { - streamPrint(spice_stream_, "E%d el%d 0 %s 0 1.0\n", - load_index, - load_index, - network_->pathName(drvr_pin)); - streamPrint(spice_stream_, "R%d el%d %s 1.0\n", - load_index, - load_index, - network_->pathName(load_pin)); - streamPrint(spice_stream_, "C%d %s 0 %.3e\n", - load_index, - network_->pathName(load_pin), - elmore); + sta::print(spice_stream_, "E{} el{} 0 {} 0 1.0\n", load_index, load_index, + network_->pathName(drvr_pin)); + sta::print(spice_stream_, "R{} el{} {} 1.0\n", load_index, load_index, + network_->pathName(load_pin)); + sta::print(spice_stream_, "C{} {} 0 {:.3e}\n", load_index, + network_->pathName(load_pin), elmore); } else // Add resistor from drvr to load for missing elmore. - streamPrint(spice_stream_, "R%d %s %s %.3e\n", - load_index, - network_->pathName(drvr_pin), - network_->pathName(load_pin), - short_ckt_resistance_); + sta::print(spice_stream_, "R{} {} {} {:.3e}\n", load_index, + network_->pathName(drvr_pin), network_->pathName(load_pin), + short_ckt_resistance_); load_index++; } } @@ -707,14 +664,11 @@ WriteSpice::writeNullParasitic(const Pin *drvr_pin) auto pin_iter = network_->connectedPinIterator(drvr_pin); while (pin_iter->hasNext()) { const Pin *load_pin = pin_iter->next(); - if (load_pin != drvr_pin - && network_->isLoad(load_pin) - && !network_->isHierarchical(load_pin)) { - streamPrint(spice_stream_, "R%d %s %s %.3e\n", - res_index_++, - network_->pathName(drvr_pin), - network_->pathName(load_pin), - short_ckt_resistance_); + if (load_pin != drvr_pin && network_->isLoad(load_pin) + && !network_->isHierarchical(load_pin)) { + sta::print(spice_stream_, "R{} {} {} {:.3e}\n", res_index_++, + network_->pathName(drvr_pin), network_->pathName(load_pin), + short_ckt_resistance_); } } delete pin_iter; @@ -726,10 +680,7 @@ void WriteSpice::writeVoltageSource(const char *node_name, float voltage) { - streamPrint(spice_stream_, "v%d %s 0 %.3f\n", - volt_index_++, - node_name, - voltage); + sta::print(spice_stream_, "v{} {} 0 {:.3f}\n", volt_index_++, node_name, voltage); } void @@ -750,20 +701,19 @@ WriteSpice::writeWaveformVoltSource(const Pin *pin, volt1 = gnd_voltage_; volt_factor = -power_voltage_; } - streamPrint(spice_stream_, "v%d %s 0 pwl(\n", - volt_index_++, - network_->pathName(pin)); - streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0); + sta::print(spice_stream_, "v{} {} 0 pwl(\n", volt_index_++, + network_->pathName(pin)); + sta::print(spice_stream_, "+{:.3e} {:.3e}\n", 0.0, volt0); Table waveform = drvr_waveform->waveform(slew); const TableAxis *time_axis = waveform.axis1(); - for (size_t time_index = 0; time_index < time_axis->size(); time_index++) { + for (size_t time_index = 0; time_index < time_axis->size(); time_index++) { float time = delay + time_axis->axisValue(time_index); float wave_volt = waveform.value(time_index); float volt = volt0 + wave_volt * volt_factor; - streamPrint(spice_stream_, "+%.3e %.3e\n", time, volt); + sta::print(spice_stream_, "+{:.3e} {:.3e}\n", time, volt); } - streamPrint(spice_stream_, "+%.3e %.3e\n", max_time_, volt1); - streamPrint(spice_stream_, "+)\n"); + sta::print(spice_stream_, "+{:.3e} {:.3e}\n", max_time_, volt1); + sta::print(spice_stream_, "+)\n"); } void @@ -781,13 +731,12 @@ WriteSpice::writeRampVoltSource(const Pin *pin, volt0 = power_voltage_; volt1 = gnd_voltage_; } - streamPrint(spice_stream_, "v%d %s 0 pwl(\n", - volt_index_++, - network_->pathName(pin)); - streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0); + sta::print(spice_stream_, "v{} {} 0 pwl(\n", volt_index_++, + network_->pathName(pin)); + sta::print(spice_stream_, "+{:.3e} {:.3e}\n", 0.0, volt0); writeWaveformEdge(rf, time, slew); - streamPrint(spice_stream_, "+%.3e %.3e\n", max_time_, volt1); - streamPrint(spice_stream_, "+)\n"); + sta::print(spice_stream_, "+{:.3e} {:.3e}\n", max_time_, volt1); + sta::print(spice_stream_, "+)\n"); } // Write PWL rise/fall edge that crosses threshold at time. @@ -810,8 +759,8 @@ WriteSpice::writeWaveformEdge(const RiseFall *rf, float time0 = time - dt * threshold; float time1 = time0 + dt; if (time0 > 0.0) - streamPrint(spice_stream_, "+%.3e %.3e\n", time0, volt0); - streamPrint(spice_stream_, "+%.3e %.3e\n", time1, volt1); + sta::print(spice_stream_, "+{:.3e} {:.3e}\n", time0, volt0); + sta::print(spice_stream_, "+{:.3e} {:.3e}\n", time1, volt1); } float @@ -841,10 +790,8 @@ WriteSpice::gatePortValues(const Pin *input_pin, const LibertyPort *drvr_port = network_->libertyPort(drvr_pin); const FuncExpr *drvr_func = drvr_port->function(); if (drvr_func) { - if (gate_edge - && gate_edge->role()->genericRole() == TimingRole::regClkToQ()) - regPortValues(input_pin, drvr_rf, drvr_port, drvr_func, - port_values, is_clked); + if (gate_edge && gate_edge->role()->genericRole() == TimingRole::regClkToQ()) + regPortValues(input_pin, drvr_rf, drvr_port, drvr_func, port_values, is_clked); else gatePortValues(inst, drvr_func, input_port, port_values); } @@ -873,16 +820,16 @@ WriteSpice::gatePortValues(const Instance *, int var_index = Cudd_NodeReadIndex(port_node); LogicValue value; switch (cube[var_index]) { - case 0: - value = LogicValue::zero; - break; - case 1: - value = LogicValue::one; - break; - case 2: - default: - value = LogicValue::unknown; - break; + case 0: + value = LogicValue::zero; + break; + case 1: + value = LogicValue::one; + break; + case 2: + default: + value = LogicValue::unknown; + break; } port_values[port] = value; } @@ -914,9 +861,8 @@ WriteSpice::regPortValues(const Pin *input_pin, } else { const LibertyPort *input_port = network_->libertyPort(input_pin); - report_->error(1604, "no register/latch found for path from %s to %s,", - input_port->name(), - drvr_port->name()); + report_->error(1604, "no register/latch found for path from {} to {},", + input_port->name(), drvr_port->name()); } } } @@ -934,23 +880,23 @@ WriteSpice::seqPortValues(Sequential *seq, if (port) { TimingSense sense = data->portTimingSense(port); switch (sense) { - case TimingSense::positive_unate: - if (rf == RiseFall::rise()) - port_values[port] = LogicValue::one; - else - port_values[port] = LogicValue::zero; - break; - case TimingSense::negative_unate: - if (rf == RiseFall::rise()) - port_values[port] = LogicValue::zero; - else - port_values[port] = LogicValue::one; - break; - case TimingSense::non_unate: - case TimingSense::none: - case TimingSense::unknown: - default: - break; + case TimingSense::positive_unate: + if (rf == RiseFall::rise()) + port_values[port] = LogicValue::one; + else + port_values[port] = LogicValue::zero; + break; + case TimingSense::negative_unate: + if (rf == RiseFall::rise()) + port_values[port] = LogicValue::zero; + else + port_values[port] = LogicValue::one; + break; + case TimingSense::non_unate: + case TimingSense::none: + case TimingSense::unknown: + default: + break; } } } @@ -963,21 +909,21 @@ WriteSpice::onePort(FuncExpr *expr) FuncExpr *right = expr->right(); LibertyPort *port; switch (expr->op()) { - case FuncExpr::Op::port: - return expr->port(); - case FuncExpr::Op::not_: - return onePort(left); - case FuncExpr::Op::or_: - case FuncExpr::Op::and_: - case FuncExpr::Op::xor_: - port = onePort(left); - if (port == nullptr) - port = onePort(right); - return port; - case FuncExpr::Op::one: - case FuncExpr::Op::zero: - default: - return nullptr; + case FuncExpr::Op::port: + return expr->port(); + case FuncExpr::Op::not_: + return onePort(left); + case FuncExpr::Op::or_: + case FuncExpr::Op::and_: + case FuncExpr::Op::xor_: + port = onePort(left); + if (port == nullptr) + port = onePort(right); + return port; + case FuncExpr::Op::one: + case FuncExpr::Op::zero: + default: + return nullptr; } } @@ -1006,20 +952,18 @@ WriteSpice::writeSubcktInstLoads(const Pin *drvr_pin, const PinSet &excluded_input_pins, InstanceSet &written_insts) { - streamPrint(spice_stream_, "* Load pins\n"); + sta::print(spice_stream_, "* Load pins\n"); PinSeq drvr_loads = drvrLoads(drvr_pin); // Do not sensitize side load gates. LibertyPortLogicValues port_values; for (const Pin *load_pin : drvr_loads) { const Instance *load_inst = network_->instance(load_pin); - if (load_pin != path_load - && network_->direction(load_pin)->isAnyInput() - && !network_->isHierarchical(load_pin) - && !network_->isTopLevelPort(load_pin) + if (load_pin != path_load && network_->direction(load_pin)->isAnyInput() + && !network_->isHierarchical(load_pin) && !network_->isTopLevelPort(load_pin) && !written_insts.contains(load_inst)) { writeSubcktInst(load_inst); writeSubcktInstVoltSrcs(load_inst, port_values, excluded_input_pins); - streamPrint(spice_stream_, "\n"); + sta::print(spice_stream_, "\n"); written_insts.insert(load_inst); } } @@ -1038,21 +982,12 @@ WriteSpice::writeMeasureDelayStmt(const Pin *from_pin, float from_threshold = power_voltage_ * default_library_->inputThreshold(from_rf); const char *to_pin_name = network_->pathName(to_pin); float to_threshold = power_voltage_ * default_library_->inputThreshold(to_rf); - streamPrint(spice_stream_, - ".measure tran %s_%s_delay_%s\n", - prefix.c_str(), - from_pin_name, - to_pin_name); - streamPrint(spice_stream_, - "+trig v(%s) val=%.3f %s=last\n", - from_pin_name, - from_threshold, - spiceTrans(from_rf)); - streamPrint(spice_stream_, - "+targ v(%s) val=%.3f %s=last\n", - to_pin_name, - to_threshold, - spiceTrans(to_rf)); + sta::print(spice_stream_, ".measure tran {}_{}_delay_{}\n", prefix, + from_pin_name, to_pin_name); + sta::print(spice_stream_, "+trig v({}) val={:.3f} {}=last\n", from_pin_name, + from_threshold, spiceTrans(from_rf)); + sta::print(spice_stream_, "+targ v({}) val={:.3f} {}=last\n", to_pin_name, + to_threshold, spiceTrans(to_rf)); } void @@ -1073,25 +1008,15 @@ WriteSpice::writeMeasureSlewStmt(const Pin *pin, threshold1 = upper; threshold2 = lower; } - streamPrint(spice_stream_, - ".measure tran %s_%s_slew\n", - prefix.c_str(), - pin_name); - streamPrint(spice_stream_, - "+trig v(%s) val=%.3f %s=last\n", - pin_name, - threshold1, - spice_rf); - streamPrint(spice_stream_, - "+targ v(%s) val=%.3f %s=last\n", - pin_name, - threshold2, - spice_rf); + sta::print(spice_stream_, ".measure tran {}_{}_slew\n", prefix, pin_name); + sta::print(spice_stream_, "+trig v({}) val={:.3f} {}=last\n", pin_name, threshold1, + spice_rf); + sta::print(spice_stream_, "+targ v({}) val={:.3f} {}=last\n", pin_name, threshold2, + spice_rf); } //////////////////////////////////////////////////////////////// - const char * WriteSpice::spiceTrans(const RiseFall *rf) { @@ -1101,23 +1026,6 @@ WriteSpice::spiceTrans(const RiseFall *rf) return "FALL"; } -// fprintf for c++ streams. -// Yes, I hate formatted output to ostream THAT much. -void -streamPrint(std::ofstream &stream, - const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - char *result = nullptr; - if (vasprintf(&result, fmt, args) == -1) - criticalError(267, "out of memory"); - stream << result; - free(result); - va_end(args); -} - //////////////////////////////////////////////////////////////// // Unused @@ -1139,4 +1047,4 @@ WriteSpice::clkWaveformTimeOffset(const Clock *clk) return clk->period() / 10; } -} // namespace +} // namespace sta diff --git a/spice/WriteSpice.hh b/spice/WriteSpice.hh index ace2b78b..74fecf00 100644 --- a/spice/WriteSpice.hh +++ b/spice/WriteSpice.hh @@ -29,6 +29,7 @@ #include #include +#include "Format.hh" #include "StaState.hh" #include "StringUtil.hh" #include "Liberty.hh" @@ -186,9 +187,4 @@ protected: Parasitics *parasitics_; }; -void -streamPrint(std::ofstream &stream, - const char *fmt, - ...) __attribute__((format (printf, 2, 3))); - -} // namespace +} // namespace sta diff --git a/tcl/StaTclTypes.i b/tcl/StaTclTypes.i index e29d5a6b..b01986a2 100644 --- a/tcl/StaTclTypes.i +++ b/tcl/StaTclTypes.i @@ -444,7 +444,7 @@ using namespace sta; const char *arg = Tcl_GetStringFromObj($input, &length); Transition *tr = Transition::find(arg); if (tr == nullptr) { - tclArgError(interp, 2150, "Unknown transition '%s'.", arg); + tclArgError(interp, 2150, "Unknown transition '{}'.", arg); return TCL_ERROR; } else @@ -464,7 +464,7 @@ using namespace sta; const char *arg = Tcl_GetStringFromObj($input, &length); const RiseFall *rf = RiseFall::find(arg); if (rf == nullptr) { - tclArgError(interp, 2151, "Unknown rise/fall edge '%s'.", arg); + tclArgError(interp, 2151, "Unknown rise/fall edge '{}'.", arg); return TCL_ERROR; } // Swig is retarded and drops const on args. @@ -484,7 +484,7 @@ using namespace sta; const char *arg = Tcl_GetStringFromObj($input, &length); const RiseFallBoth *rf = RiseFallBoth::find(arg); if (rf == nullptr) { - tclArgError(interp, 2152, "Unknown transition name '%s'.", arg); + tclArgError(interp, 2152, "Unknown transition name '{}'.", arg); return TCL_ERROR; } // Swig is retarded and drops const on args. @@ -504,7 +504,7 @@ using namespace sta; const char *arg = Tcl_GetStringFromObj($input, &length); PortDirection *dir = PortDirection::find(arg); if (dir == nullptr) { - tclArgError(interp, 2153, "Unknown port direction '%s'.", arg); + tclArgError(interp, 2153, "Unknown port direction '{}'.", arg); return TCL_ERROR; } else @@ -519,7 +519,7 @@ using namespace sta; // Swig is retarded and drops const on args. $1 = const_cast(TimingRole::find(arg)); else { - tclArgError(interp, 2154, "Unknown timing role '%s'.", arg); + tclArgError(interp, 2154, "Unknown timing role '{}'.", arg); return TCL_ERROR; } } @@ -542,7 +542,7 @@ using namespace sta; else if (stringEq(arg, "fall") || stringEq(arg, "falling")) $1 = LogicValue::fall; else { - tclArgError(interp, 2155, "Unknown logic value '%s'.", arg); + tclArgError(interp, 2155, "Unknown logic value '{}'.", arg); return TCL_ERROR; } } @@ -557,7 +557,7 @@ using namespace sta; else if (stringEq(arg, "on_chip_variation")) $1 = AnalysisType::ocv; else { - tclArgError(interp, 2156, "Unknown analysis type '%s'.", arg); + tclArgError(interp, 2156, "Unknown analysis type '{}'.", arg); return TCL_ERROR; } } @@ -762,7 +762,7 @@ using namespace sta; floats->push_back(static_cast(value)); else { delete floats; - tclArgError(interp, 2157, "%s is not a floating point number.", arg); + tclArgError(interp, 2157, "{} is not a floating point number.", arg); return TCL_ERROR; } } @@ -807,7 +807,7 @@ using namespace sta; ints->push_back(value); else { delete ints; - tclArgError(interp, 2158, "%s is not an integer.", arg); + tclArgError(interp, 2158, "{} is not an integer.", arg); return TCL_ERROR; } } @@ -869,7 +869,7 @@ using namespace sta; if (min_max) $1 = min_max; else { - tclArgError(interp, 2159, "%s not min or max.", arg); + tclArgError(interp, 2159, "{} not min or max.", arg); return TCL_ERROR; } } @@ -890,7 +890,7 @@ using namespace sta; if (min_max) $1 = min_max; else { - tclArgError(interp, 2160, "%s not min, max or min_max.", arg); + tclArgError(interp, 2160, "{} not min, max or min_max.", arg); return TCL_ERROR; } } @@ -906,7 +906,7 @@ using namespace sta; if (min_max) $1 = min_max; else { - tclArgError(interp, 2161, "%s not min, max or min_max.", arg); + tclArgError(interp, 2161, "{} not min, max or min_max.", arg); return TCL_ERROR; } } @@ -928,7 +928,7 @@ using namespace sta; || stringEqual(arg, "max")) $1 = const_cast(MinMax::max()); else { - tclArgError(interp, 2162, "%s not setup, hold, min or max.", arg); + tclArgError(interp, 2162, "{} not setup, hold, min or max.", arg); return TCL_ERROR; } } @@ -948,7 +948,7 @@ using namespace sta; || stringEqual(arg, "min_max")) $1 = const_cast(SetupHoldAll::all()); else { - tclArgError(interp, 2163, "%s not setup, hold, setup_hold, min, max or min_max.", + tclArgError(interp, 2163, "{} not setup, hold, setup_hold, min, max or min_max.", arg); return TCL_ERROR; } @@ -963,7 +963,7 @@ using namespace sta; if (early_late) $1 = early_late; else { - tclArgError(interp, 2164, "%s not early/min, late/max or early_late/min_max.", arg); + tclArgError(interp, 2164, "{} not early/min, late/max or early_late/min_max.", arg); return TCL_ERROR; } } @@ -977,7 +977,7 @@ using namespace sta; if (early_late) $1 = early_late; else { - tclArgError(interp, 2165, "%s not early/min, late/max or early_late/min_max.", arg); + tclArgError(interp, 2165, "{} not early/min, late/max or early_late/min_max.", arg); return TCL_ERROR; } } @@ -992,7 +992,7 @@ using namespace sta; else if (stringEq(arg, "cell_check")) $1 = TimingDerateType::cell_check; else { - tclArgError(interp, 2166, "%s not net_delay, cell_delay or cell_check.", arg); + tclArgError(interp, 2166, "{} not net_delay, cell_delay or cell_check.", arg); return TCL_ERROR; } } @@ -1005,7 +1005,7 @@ using namespace sta; else if (stringEq(arg, "cell_check")) $1 = TimingDerateCellType::cell_check; else { - tclArgError(interp, 2167, "%s not cell_delay or cell_check.", arg); + tclArgError(interp, 2167, "{} not cell_delay or cell_check.", arg); return TCL_ERROR; } } @@ -1018,7 +1018,7 @@ using namespace sta; else if (stringEq(arg, "data")) $1 = PathClkOrData::data; else { - tclArgError(interp, 2168, "%s not clk or data.", arg); + tclArgError(interp, 2168, "{} not clk or data.", arg); return TCL_ERROR; } } @@ -1031,7 +1031,7 @@ using namespace sta; else if (stringEq(arg, "slack")) $1 = sort_by_slack; else { - tclArgError(interp, 2169, "%s not group or slack.", arg); + tclArgError(interp, 2169, "{} not group or slack.", arg); return TCL_ERROR; } } @@ -1056,7 +1056,7 @@ using namespace sta; else if (stringEq(arg, "json")) $1 = ReportPathFormat::json; else { - tclArgError(interp, 2170, "unknown path type %s.", arg); + tclArgError(interp, 2170, "unknown path type {}.", arg); return TCL_ERROR; } } @@ -1198,32 +1198,8 @@ using namespace sta; Tcl_SetObjResult(interp, obj); } -%typemap(out) Delay { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); -} - -%typemap(out) Arrival { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); -} - -%typemap(out) Required { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); -} - -%typemap(out) Slack { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); -} - -%typemap(out) ArcDelay { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); -} - -%typemap(out) Slew { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); -} - -%typemap(out) Crpr { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); +%typemap(in) StringSet* { + $1 = tclListSetConstChar($input, interp); } %typemap(out) Mode* { @@ -1249,7 +1225,7 @@ using namespace sta; if (mode) seq.push_back(mode); else { - tclArgError(interp, 2174, "mode %s not found.", mode_name); + tclArgError(interp, 2174, "mode {} not found.", mode_name); return TCL_ERROR; } } @@ -1280,7 +1256,7 @@ using namespace sta; if (scene) $1 = scene; else { - tclArgError(interp, 2173, "scene %s not found.", scene_name); + tclArgError(interp, 2173, "scene {} not found.", scene_name); return TCL_ERROR; } } @@ -1309,7 +1285,7 @@ using namespace sta; if (scene) seq.push_back(scene); else { - tclArgError(interp, 2172, "scene %s not found.", scene_name); + tclArgError(interp, 2172, "scene {} not found.", scene_name); return TCL_ERROR; } } @@ -1345,8 +1321,8 @@ using namespace sta; break; case PropertyValue::Type::float_: { const Unit *unit = value.unit(); - const char *float_string = unit->asString(value.floatValue(), 6); - Tcl_SetResult(interp, const_cast(float_string), TCL_VOLATILE); + std::string float_string = unit->asString(value.floatValue(), 6); + Tcl_SetResult(interp, const_cast(float_string.c_str()), TCL_VOLATILE); } break; case PropertyValue::Type::bool_: { @@ -1446,18 +1422,17 @@ using namespace sta; PwrActivity activity = value.pwrActivity(); Tcl_Obj *list = Tcl_NewListObj(0, nullptr); Tcl_Obj *obj; - const char *str; - str = stringPrintTmp("%.5e", activity.density()); - obj = Tcl_NewStringObj(str, strlen(str)); + std::string density = sta::format("{:.5e}", activity.density()); + obj = Tcl_NewStringObj(density.c_str(), density.size()); Tcl_ListObjAppendElement(interp, list, obj); - str = stringPrintTmp("%.3f", activity.duty()); - obj = Tcl_NewStringObj(str, strlen(str)); + std::string duty = sta::format("{:.3f}", activity.duty()); + obj = Tcl_NewStringObj(duty.c_str(), duty.size()); Tcl_ListObjAppendElement(interp, list, obj); - str = activity.originName(); - obj = Tcl_NewStringObj(str, strlen(str)); + std::string name = activity.originName(); + obj = Tcl_NewStringObj(name.c_str(), name.size()); Tcl_ListObjAppendElement(interp, list, obj); Tcl_SetObjResult(interp, list); @@ -1476,7 +1451,7 @@ using namespace sta; else if (stringEq(arg, "xyce")) $1 = CircuitSim::xyce; else { - tclArgError(interp, 2171, "unknown circuit simulator %s.", arg); + tclArgError(interp, 2171, "unknown circuit simulator {}.", arg); return TCL_ERROR; } } diff --git a/tcl/TclTypeHelpers.cc b/tcl/TclTypeHelpers.cc index 8667048b..66dc529c 100644 --- a/tcl/TclTypeHelpers.cc +++ b/tcl/TclTypeHelpers.cc @@ -170,8 +170,8 @@ tclArcDcalcArg(ArcDcalcArg &gate, obj = Tcl_NewStringObj(to_edge, strlen(to_edge)); Tcl_ListObjAppendElement(interp, list, obj); - const char *input_delay = delayAsString(gate.inputDelay(), sta, 3); - obj = Tcl_NewStringObj(input_delay, strlen(input_delay)); + std::string input_delay = delayAsString(gate.inputDelay(), sta); + obj = Tcl_NewStringObj(input_delay.c_str(), input_delay.size()); Tcl_ListObjAppendElement(interp, list, obj); return list; diff --git a/tcl/Util.tcl b/tcl/Util.tcl index 15443529..3236cb93 100644 --- a/tcl/Util.tcl +++ b/tcl/Util.tcl @@ -267,6 +267,7 @@ define_cmd_args "user_run_time" {} # Write run time statistics to filename. proc write_stats { filename } { +puts "stats $filename" if { ![catch {open $filename w} stream] } { puts $stream "[elapsed_run_time] [user_run_time] [memory_usage]" close $stream diff --git a/tcl/Variables.tcl b/tcl/Variables.tcl index e37f7396..ba8f37b3 100644 --- a/tcl/Variables.tcl +++ b/tcl/Variables.tcl @@ -152,16 +152,42 @@ proc trace_propagate_gated_clock_enable { name1 name2 op } { propagate_gated_clock_enable set_propagate_gated_clock_enable } -trace variable ::sta_pocv_enabled "rw" \ - sta::trace_pocv_enabled +trace variable ::sta_pocv_mode "rw" \ + sta::trace_pocv_mode -proc trace_pocv_enabled { name1 name2 op } { - trace_boolean_var $op ::sta_pocv_enabled \ - pocv_enabled set_pocv_enabled +proc trace_pocv_mode { name1 name2 op } { + global sta_pocv_mode + + if { $op == "r" } { + set sta_pocv_mode [pocv_mode] + } elseif { $op == "w" } { + if { $sta_pocv_mode == "scalar" \ + || $sta_pocv_mode == "normal" \ + || $sta_pocv_mode == "skew_normal" } { + set_pocv_mode $sta_pocv_mode + } else { + sta_error 593 "sta_pocv_mode must be scalar, normal, or skew_normal." + } + } } -# Report path numeric field width is digits + extra. -set report_path_field_width_extra 5 +trace variable ::sta_pocv_quantile "rw" \ + sta::trace_pocv_quantile + +proc trace_pocv_quantile { name1 name2 op } { + global sta_pocv_quantile + + if { $op == "r" } { + set sta_pocv_quantile [pocv_quantile] + } elseif { $op == "w" } { + if { [string is double $sta_pocv_quantile] \ + && $sta_pocv_quantile >= 0.0 } { + set_pocv_quantile $sta_pocv_quantile + } else { + sta_error 594 "sta_pocv_quantile must be a positive floating point number." + } + } +} ################################################################ diff --git a/util/Debug.cc b/util/Debug.cc index c2429db4..917e40fa 100644 --- a/util/Debug.cc +++ b/util/Debug.cc @@ -81,19 +81,4 @@ Debug::setLevel(const char *what, } } -void -Debug::reportLine(const char *what, - const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - std::unique_lock lock(buffer_lock_); - report_->printToBuffer("%s", what); - report_->printToBufferAppend(": "); - report_->printToBufferAppend(fmt, args); - report_->printBufferLine(); - va_end(args); -} - } // namespace diff --git a/util/Error.cc b/util/Error.cc index aa4b85e5..88914f26 100644 --- a/util/Error.cc +++ b/util/Error.cc @@ -27,6 +27,7 @@ #include #include +#include "Format.hh" #include "StringUtil.hh" namespace sta { @@ -36,7 +37,7 @@ Exception::Exception() : { } -ExceptionMsg::ExceptionMsg(const char *msg, +ExceptionMsg::ExceptionMsg(const std::string &msg, const bool suppressed) : Exception(), msg_(msg), @@ -50,7 +51,7 @@ ExceptionMsg::what() const noexcept return msg_.c_str(); } -ExceptionLine::ExceptionLine(const char *filename, +ExceptionLine::ExceptionLine(const std::string &filename, int line) : Exception(), filename_(filename), @@ -58,26 +59,28 @@ ExceptionLine::ExceptionLine(const char *filename, { } -FileNotReadable::FileNotReadable(const char *filename) : - filename_(filename) +FileNotReadable::FileNotReadable(std::string filename) : + filename_(std::move(filename)), + msg_(sta::format("cannot read file {}.", filename_)) { } const char * FileNotReadable::what() const noexcept { - return stringPrintTmp("cannot read file %s.", filename_); + return msg_.c_str(); } -FileNotWritable::FileNotWritable(const char *filename) : - filename_(filename) +FileNotWritable::FileNotWritable(std::string filename) : + filename_(std::move(filename)), + msg_(sta::format("cannot write file {}.", filename_)) { } const char * FileNotWritable::what() const noexcept { - return stringPrintTmp("cannot write file %s.", filename_); + return msg_.c_str(); } } // namespace diff --git a/util/MachineLinux.cc b/util/MachineLinux.cc index 261d143f..7be581f6 100644 --- a/util/MachineLinux.cc +++ b/util/MachineLinux.cc @@ -33,6 +33,7 @@ #include "StaConfig.hh" #include "StringUtil.hh" +#include "Format.hh" namespace sta { @@ -81,8 +82,7 @@ systemRunTime() size_t memoryUsage() { - std::string proc_filename; - stringPrint(proc_filename, "/proc/%d/status", getpid()); + std::string proc_filename = sta::format("/proc/{}/status", getpid()); size_t memory = 0; FILE *status = fopen(proc_filename.c_str(), "r"); if (status) { diff --git a/util/Report.cc b/util/Report.cc index 4a6e6bf8..d8a6a04d 100644 --- a/util/Report.cc +++ b/util/Report.cc @@ -1,35 +1,36 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "Report.hh" -#include // min -#include // exit -#include // strlen +#include // min +#include // exit +#include // strlen -#include "Machine.hh" #include "Error.hh" +#include "Machine.hh" +#include "Format.hh" namespace sta { @@ -46,10 +47,7 @@ Report::Report() : default_ = this; } -Report::~Report() -{ - delete [] buffer_; -} +Report::~Report() { delete[] buffer_; } size_t Report::printConsole(const char *buffer, @@ -85,17 +83,6 @@ Report::printString(const char *buffer, return ret; } -void -Report::reportLine(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - std::unique_lock lock(buffer_lock_); - printToBuffer(fmt, args); - printBufferLine(); - va_end(args); -} - void Report::reportBlankLine() { @@ -103,13 +90,7 @@ Report::reportBlankLine() } void -Report::reportLineString(const char *line) -{ - printLine(line, strlen(line)); -} - -void -Report::reportLineString(const std::string &line) +Report::reportLine(const std::string &line) { printLine(line.c_str(), line.length()); } @@ -151,16 +132,16 @@ Report::printToBufferAppend(const char *fmt, // Copy args in case we need to grow the buffer. va_list args_copy; va_copy(args_copy, args); - size_t length = vsnprint(buffer_ + buffer_length_, buffer_size_- buffer_length_, - fmt, args); + size_t length = + vsnprint(buffer_ + buffer_length_, buffer_size_ - buffer_length_, fmt, args); if (length >= buffer_size_ - buffer_length_) { buffer_size_ = buffer_length_ + length * 2; char *new_buffer = new char[buffer_size_]; strncpy(new_buffer, buffer_, buffer_length_); - delete [] buffer_; + delete[] buffer_; buffer_ = new_buffer; - length = vsnprint(buffer_ + buffer_length_, buffer_size_ - buffer_length_, - fmt, args_copy); + length = vsnprint(buffer_ + buffer_length_, buffer_size_ - buffer_length_, fmt, + args_copy); } buffer_length_ += length; va_end(args_copy); @@ -175,152 +156,10 @@ Report::printBufferLine() //////////////////////////////////////////////////////////////// void -Report::warn(int id, - const char *fmt, - ...) +reportThrowExceptionMsg(const std::string &msg, + bool suppressed) { - // Skip suppressed messages. - if (!isSuppressed(id)) { - va_list args; - va_start(args, fmt); - printToBuffer("Warning %d: ", id); - printToBufferAppend(fmt, args); - printBufferLine(); - va_end(args); - } -} - -void -Report::vwarn(int id, - const char *fmt, - va_list args) -{ - // Skip suppressed messages. - if (!isSuppressed(id)) { - printToBuffer("Warning %d: ", id); - printToBufferAppend(fmt, args); - printBufferLine(); - } -} - -void -Report::fileWarn(int id, - const char *filename, - int line, - const char *fmt, - ...) -{ - // Skip suppressed messages. - if (!isSuppressed(id)) { - va_list args; - va_start(args, fmt); - printToBuffer("Warning %d: %s line %d, ", id, filename, line); - printToBufferAppend(fmt, args); - printBufferLine(); - va_end(args); - } -} - -void -Report::vfileWarn(int id, - const char *filename, - int line, - const char *fmt, - va_list args) -{ - // Skip suppressed messages. - if (!isSuppressed(id)) { - printToBuffer("Warning %d: %s line %d, ", id, filename, line); - printToBufferAppend(fmt, args); - printBufferLine(); - } -} - -//////////////////////////////////////////////////////////////// - -void -Report::error(int id, - const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - // No prefix msg, no \n. - printToBuffer("%d ", id); - printToBufferAppend(fmt, args); - va_end(args); - throw ExceptionMsg(buffer_, isSuppressed(id)); -} - -void -Report::verror(int id, - const char *fmt, - va_list args) -{ - // No prefix msg, no \n. - printToBuffer("%d ", id); - printToBufferAppend(fmt, args); - throw ExceptionMsg(buffer_, isSuppressed(id)); -} - -void -Report::fileError(int id, - const char *filename, - int line, - const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - // No prefix msg, no \n. - printToBuffer("%d %s line %d, ", id, filename, line); - printToBufferAppend(fmt, args); - va_end(args); - throw ExceptionMsg(buffer_, isSuppressed(id)); -} - -void -Report::vfileError(int id, - const char *filename, - int line, - const char *fmt, - va_list args) -{ - // No prefix msg, no \n. - printToBuffer("%d %s line %d, ", id, filename, line); - printToBufferAppend(fmt, args); - throw ExceptionMsg(buffer_, isSuppressed(id)); -} - -//////////////////////////////////////////////////////////////// - -void -Report::critical(int id, - const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - printToBuffer("Critical %d: ", id); - printToBufferAppend(fmt, args); - printBufferLine(); - va_end(args); - exit(1); -} - -void -Report::fileCritical(int id, - const char *filename, - int line, - const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - printToBuffer("Critical %d: %s line %d, ", id, filename, line); - printToBufferAppend(fmt, args); - printBufferLine(); - va_end(args); - exit(1); + throw ExceptionMsg(msg, suppressed); } //////////////////////////////////////////////////////////////// @@ -346,11 +185,11 @@ Report::isSuppressed(int id) //////////////////////////////////////////////////////////////// void -Report::logBegin(const char *filename) +Report::logBegin(std::string filename) { - log_stream_ = fopen(filename, "w"); + log_stream_ = fopen(filename.c_str(), "w"); if (log_stream_ == nullptr) - throw FileNotWritable(filename); + throw FileNotWritable(std::move(filename)); } void @@ -362,19 +201,19 @@ Report::logEnd() } void -Report::redirectFileBegin(const char *filename) +Report::redirectFileBegin(std::string filename) { - redirect_stream_ = fopen(filename, "w"); + redirect_stream_ = fopen(filename.c_str(), "w"); if (redirect_stream_ == nullptr) - throw FileNotWritable(filename); + throw FileNotWritable(std::move(filename)); } void -Report::redirectFileAppendBegin(const char *filename) +Report::redirectFileAppendBegin(std::string filename) { - redirect_stream_ = fopen(filename, "a"); + redirect_stream_ = fopen(filename.c_str(), "a"); if (redirect_stream_ == nullptr) - throw FileNotWritable(filename); + throw FileNotWritable(std::move(filename)); } void @@ -406,4 +245,4 @@ Report::redirectStringPrint(const char *buffer, redirect_string_.append(buffer, length); } -} // namespace +} // namespace sta diff --git a/util/ReportTcl.cc b/util/ReportTcl.cc index d3e07048..97eef4af 100644 --- a/util/ReportTcl.cc +++ b/util/ReportTcl.cc @@ -183,7 +183,7 @@ ReportTcl::flush() // Tcl_Main can eval multiple commands before the flushing the command // output, so the log/redirect commands must force a flush. void -ReportTcl::logBegin(const char *filename) +ReportTcl::logBegin(std::string filename) { flush(); Report::logBegin(filename); @@ -197,14 +197,14 @@ ReportTcl::logEnd() } void -ReportTcl::redirectFileBegin(const char *filename) +ReportTcl::redirectFileBegin(std::string filename) { flush(); Report::redirectFileBegin(filename); } void -ReportTcl::redirectFileAppendBegin(const char *filename) +ReportTcl::redirectFileAppendBegin(std::string filename) { flush(); Report::redirectFileAppendBegin(filename); diff --git a/util/StaConfig.hh.cmake b/util/StaConfig.hh.cmake index 78d2e304..2efd9720 100644 --- a/util/StaConfig.hh.cmake +++ b/util/StaConfig.hh.cmake @@ -6,6 +6,4 @@ #cmakedefine ZLIB_FOUND -#define SSTA ${SSTA} - #define TCL_READLINE ${TCL_READLINE} diff --git a/util/Stats.cc b/util/Stats.cc index ac6d98dd..07fb62a1 100644 --- a/util/Stats.cc +++ b/util/Stats.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "Stats.hh" @@ -57,12 +57,11 @@ Stats::report(const char *step) double memory_begin = static_cast(memory_begin_); double memory_end = static_cast(memoryUsage()); double memory_delta = memory_end - memory_begin; - report_->reportLine("stats: %5.1f/%5.1fe %5.1f/%5.1fu %5.1f/%5.1fMB %s", - elapsed_end - elapsed_begin_, elapsed_end, - user_end - user_begin_, user_end, - memory_delta * 1e-6, memory_end * 1e-6, - step); + report_->report("stats: {:5.1f}/{:5.1f}e {:5.1f}/{:5.1f}u {:5.1f}/{:5.1f}MB {}", + elapsed_end - elapsed_begin_, elapsed_end, + user_end - user_begin_, user_end, memory_delta * 1e-6, + memory_end * 1e-6, step); } } -} // namespace +} // namespace sta diff --git a/util/StringUtil.cc b/util/StringUtil.cc index 2b93704c..cc77196c 100644 --- a/util/StringUtil.cc +++ b/util/StringUtil.cc @@ -32,20 +32,10 @@ #include "Machine.hh" #include "Mutex.hh" +#include "Error.hh" namespace sta { -static void -stringPrintTmp(const char *fmt, - va_list args, - // Return values. - char *&str, - size_t &length); -static void -getTmpString(// Return values. - char *&str, - size_t &length); - char * stringCopy(const char *str) { @@ -70,112 +60,6 @@ isDigits(const char *str) //////////////////////////////////////////////////////////////// -// print for c++ strings. -void -stringPrint(std::string &str, - const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - char *tmp; - size_t tmp_length; - stringPrintTmp(fmt, args, tmp, tmp_length); - va_end(args); - str = tmp; -} - -void -stringAppend(std::string &str, - const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - char *tmp; - size_t tmp_length; - stringPrintTmp(fmt, args, tmp, tmp_length); - va_end(args); - str += tmp; -} - -std::string -stdstrPrint(const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - char *tmp; - size_t tmp_length; - stringPrintTmp(fmt, args, tmp, tmp_length); - va_end(args); - return tmp; -} - -char * -stringPrint(const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - char *result = stringPrintArgs(fmt, args); - va_end(args); - return result; -} - -char * -stringPrintArgs(const char *fmt, - va_list args) -{ - char *tmp; - size_t tmp_length; - stringPrintTmp(fmt, args, tmp, tmp_length); - char *result = new char[tmp_length + 1]; - strcpy(result, tmp); - return result; -} - -char * -stringPrintTmp(const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - char *tmp; - size_t tmp_length; - stringPrintTmp(fmt, args, tmp, tmp_length); - va_end(args); - return tmp; -} - -static void -stringPrintTmp(const char *fmt, - va_list args, - // Return values. - char *&tmp, - // strlen(tmp), not including terminating '\0'. - size_t &tmp_length) -{ - size_t tmp_length1; - getTmpString(tmp, tmp_length1); - - va_list args_copy; - va_copy(args_copy, args); - // Returned length does NOT include trailing '\0'. - tmp_length = vsnprint(tmp, tmp_length1, fmt, args_copy); - va_end(args_copy); - - if (tmp_length >= tmp_length1) { - tmp_length1 = tmp_length + 1; - tmp = makeTmpString(tmp_length1); - va_copy(args_copy, args); - tmp_length = vsnprint(tmp, tmp_length1, fmt, args_copy); - va_end(args_copy); - } -} - -//////////////////////////////////////////////////////////////// - static constexpr size_t tmp_string_count = 256; static constexpr size_t tmp_string_initial_length = 256; thread_local static std::array tmp_strings; @@ -193,22 +77,6 @@ deleteTmpStrings() tmp_string_next = 0; } -static void -getTmpString(// Return values. - char *&str, - size_t &length) -{ - if (tmp_string_next == tmp_string_count) - tmp_string_next = 0; - str = tmp_strings[tmp_string_next]; - length = tmp_string_lengths[tmp_string_next]; - if (str == nullptr) { - str = tmp_strings[tmp_string_next] = new char[tmp_string_initial_length]; - length = tmp_string_lengths[tmp_string_next] = tmp_string_initial_length; - } - tmp_string_next++; -} - char * makeTmpString(size_t length) { @@ -239,10 +107,8 @@ makeTmpString(std::string &str) void stringDeleteCheck(const char *str) { - if (isTmpString(str)) { - printf("Critical error: stringDelete for tmp string."); - exit(1); - } + if (isTmpString(str)) + criticalError(2600, "stringDelete for tmp string."); } bool diff --git a/util/Util.i b/util/Util.i index 32d9e0c1..e68de5ef 100644 --- a/util/Util.i +++ b/util/Util.i @@ -115,7 +115,7 @@ report_error(int id, const char *msg) { Report *report = Sta::sta()->report(); - report->error(id, "%s", msg); + report->error(id, "{}", msg); } void @@ -125,7 +125,7 @@ report_file_error(int id, const char *msg) { Report *report = Sta::sta()->report(); - report->error(id, filename, line, "%s", msg); + report->error(id, filename, line, "{}", msg); } void @@ -133,7 +133,7 @@ report_warn(int id, const char *msg) { Report *report = Sta::sta()->report(); - report->warn(id, "%s", msg); + report->warn(id, "{}", msg); } void @@ -143,7 +143,7 @@ report_file_warn(int id, const char *msg) { Report *report = Sta::sta()->report(); - report->fileWarn(id, filename, line, "%s", msg); + report->fileWarn(id, filename, line, "{}", msg); } void @@ -151,9 +151,9 @@ report_line(const char *msg) { Sta *sta = Sta::sta(); if (sta) - sta->report()->reportLineString(msg); + sta->report()->reportLine(msg); else - // After sta::delete_all_memory souce -echo prints the cmd file line + // After sta::delete_all_memory include -echo prints the cmd file line. printf("%s\n", msg); } @@ -471,7 +471,7 @@ unit_scale(const char *unit_name) // format_unit functions print with fixed digits and suffix. // Pass value arg as string to support NaNs. -const char * +std::string format_time(const char *value, int digits) { @@ -479,7 +479,7 @@ format_time(const char *value, return Sta::sta()->units()->timeUnit()->asString(value1, digits); } -const char * +std::string format_capacitance(const char *value, int digits) { @@ -487,7 +487,7 @@ format_capacitance(const char *value, return Sta::sta()->units()->capacitanceUnit()->asString(value1, digits); } -const char * +std::string format_resistance(const char *value, int digits) { @@ -495,7 +495,7 @@ format_resistance(const char *value, return Sta::sta()->units()->resistanceUnit()->asString(value1, digits); } -const char * +std::string format_voltage(const char *value, int digits) { @@ -503,7 +503,7 @@ format_voltage(const char *value, return Sta::sta()->units()->voltageUnit()->asString(value1, digits); } -const char * +std::string format_current(const char *value, int digits) { @@ -511,7 +511,7 @@ format_current(const char *value, return Sta::sta()->units()->currentUnit()->asString(value1, digits); } -const char * +std::string format_power(const char *value, int digits) { @@ -519,7 +519,7 @@ format_power(const char *value, return Sta::sta()->units()->powerUnit()->asString(value1, digits); } -const char * +std::string format_distance(const char *value, int digits) { @@ -528,7 +528,7 @@ format_distance(const char *value, return dist_unit->asString(value1, digits); } -const char * +std::string format_area(const char *value, int digits) { diff --git a/verilog/VerilogParse.yy b/verilog/VerilogParse.yy index 71f056ad..5888f993 100644 --- a/verilog/VerilogParse.yy +++ b/verilog/VerilogParse.yy @@ -44,8 +44,7 @@ void sta::VerilogParse::error(const location_type &loc, const std::string &msg) { - reader->report()->fileError(164,reader->filename(),loc.begin.line, - "%s",msg.c_str()); + reader->report()->fileError(171,reader->filename(),loc.begin.line, "{}",msg); } %} diff --git a/verilog/VerilogReader.cc b/verilog/VerilogReader.cc index 3d402e79..a539a311 100644 --- a/verilog/VerilogReader.cc +++ b/verilog/VerilogReader.cc @@ -1,25 +1,25 @@ // OpenSTA, Static Timing Analyzer // Copyright (c) 2026, Parallax Software, Inc. -// +// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// +// // The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. -// +// // Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. -// +// // This notice may not be removed or altered from any source distribution. #include "VerilogReader.hh" @@ -73,35 +73,10 @@ deleteVerilogReader(VerilogReader *verilog_reader) //////////////////////////////////////////////////////////////// -class VerilogError -{ -public: - VerilogError(int id, - const char *filename, - int line, - const char *msg, - bool warn); - ~VerilogError(); - const char *msg() const { return msg_; } - const char *filename() const { return filename_; } - int id() const { return id_; } - int line() const { return line_; } - bool warn() const { return warn_; } - -private: - int id_; - const char *filename_; - int line_; - const char *msg_; - bool warn_; - - friend class VerilogErrorCmp; -}; - VerilogError::VerilogError(int id, - const char *filename, + std::string_view filename, int line, - const char *msg, + std::string_view msg, bool warn) : id_(id), filename_(filename), @@ -111,22 +86,16 @@ VerilogError::VerilogError(int id, { } -VerilogError::~VerilogError() -{ - // filename is owned by VerilogReader. - stringDelete(msg_); -} - class VerilogErrorCmp { public: bool operator()(const VerilogError *error1, const VerilogError *error2) const { - int file_cmp = strcmp(error1->filename_, error2->filename_); + int file_cmp = error1->filename_.compare(error2->filename_); if (file_cmp == 0) { if (error1->line_ == error2->line_) - return strcmp(error1->msg_, error2->msg_) < 0; + return error1->msg_ < error2->msg_; else return error1->line_ < error2->line_; } @@ -146,17 +115,14 @@ VerilogReader::VerilogReader(NetworkReader *network) : zero_net_name_("zero_"), one_net_name_("one_") { - network->setLinkFunc([this] (const char *top_cell_name, - bool make_black_boxes) -> Instance* { - return linkNetwork(top_cell_name, make_black_boxes, true); - }); - constant10_max_ = stdstrPrint("%llu", std::numeric_limits::max()); + network->setLinkFunc( + [this](const char *top_cell_name, bool make_black_boxes) -> Instance * { + return linkNetwork(top_cell_name, make_black_boxes, true); + }); + constant10_max_ = std::to_string(std::numeric_limits::max()); } -VerilogReader::~VerilogReader() -{ - deleteModules(); -} +VerilogReader::~VerilogReader() { deleteModules(); } void VerilogReader::deleteModules() @@ -232,7 +198,7 @@ VerilogReader::makeModule(const std::string *module_vname, VerilogAttrStmtSeq *attr_stmts, int line) { - const std::string module_name = moduleVerilogToSta(module_vname); + const std::string module_name = moduleVerilogToSta(*module_vname); Cell *cell = network_->findCell(library_, module_name.c_str()); if (cell) { VerilogModule *module = module_map_[cell]; @@ -267,7 +233,7 @@ VerilogReader::makeModule(const std::string *module_name, // Pull the port names out of the port declarations. for (VerilogStmt *dcl : *port_dcls) { if (dcl->isDeclaration()) { - VerilogDcl *dcl1 = dynamic_cast(dcl); + VerilogDcl *dcl1 = dynamic_cast(dcl); for (VerilogDclArg *arg : *dcl1->args()) { VerilogNetNamed *port = new VerilogNetScalar(arg->netName()); ports->push_back(port); @@ -299,8 +265,7 @@ VerilogReader::makeCellPorts(Cell *cell, } else warn(165, module->filename(), module->line(), - "module %s repeated port name %s.", - module->name().c_str(), + "module {} repeated port name {}.", module->name().c_str(), port_name.c_str()); } checkModuleDcls(module, port_names); @@ -314,18 +279,17 @@ VerilogReader::makeCellPort(Cell *cell, VerilogDcl *dcl = module->declaration(port_name.c_str()); if (dcl) { PortDirection *dir = dcl->direction(); - VerilogDclBus *dcl_bus = dynamic_cast(dcl); + VerilogDclBus *dcl_bus = dynamic_cast(dcl); Port *port = dcl->isBus() - ? network_->makeBusPort(cell, port_name.c_str(), dcl_bus->fromIndex(), - dcl_bus->toIndex()) - : network_->makePort(cell, port_name.c_str()); + ? network_->makeBusPort(cell, port_name.c_str(), dcl_bus->fromIndex(), + dcl_bus->toIndex()) + : network_->makePort(cell, port_name.c_str()); network_->setDirection(port, dir); return port; } else { warn(166, module->filename(), module->line(), - "module %s missing declaration for port %s.", - module->name().c_str(), + "module {} missing declaration for port {}.", module->name().c_str(), port_name.c_str()); return network_->makePort(cell, port_name.c_str()); } @@ -338,7 +302,7 @@ VerilogReader::makeNamedPortRefCellPorts(Cell *cell, StringSet &port_names) { PortSeq *member_ports = new PortSeq; - VerilogNetNameIterator *net_name_iter = mod_port->nameIterator(module,this); + VerilogNetNameIterator *net_name_iter = mod_port->nameIterator(module, this); while (net_name_iter->hasNext()) { const std::string &net_name = net_name_iter->next(); port_names.insert(net_name); @@ -355,16 +319,13 @@ void VerilogReader::checkModuleDcls(VerilogModule *module, std::set &port_names) { - for (auto const & [port_name, dcl] : *module->declarationMap()) { + for (auto const &[port_name, dcl] : *module->declarationMap()) { PortDirection *dir = dcl->direction(); - if (dir->isInput() - || dir->isOutput() - || dir->isBidirect()) { + if (dir->isInput() || dir->isOutput() || dir->isBidirect()) { if (!port_names.contains(port_name)) linkWarn(197, module->filename(), module->line(), - "module %s declared signal %s is not in the port list.", - module->name().c_str(), - port_name.c_str()); + "module {} declared signal {} is not in the port list.", + module->name(), port_name); } } } @@ -425,8 +386,7 @@ VerilogReader::makeDclBus(PortDirection *dir, int line) { dcl_bus_count_++; - return new VerilogDclBus(dir, from_index, to_index, arg, attr_stmts, - line); + return new VerilogDclBus(dir, from_index, to_index, arg, attr_stmts, line); } VerilogDclBus * @@ -438,16 +398,15 @@ VerilogReader::makeDclBus(PortDirection *dir, int line) { dcl_bus_count_++; - return new VerilogDclBus(dir, from_index, to_index, args, attr_stmts, - line); + return new VerilogDclBus(dir, from_index, to_index, args, attr_stmts, line); } VerilogDclArg * VerilogReader::makeDclArg(const std::string *net_vname) { dcl_arg_count_++; - const std::string net_name = netVerilogToSta(net_vname); - VerilogDclArg *dcl =new VerilogDclArg(net_name); + const std::string net_name = netVerilogToSta(*net_vname); + VerilogDclArg *dcl = new VerilogDclArg(net_name); delete net_vname; return dcl; } @@ -467,10 +426,9 @@ VerilogReader::makeNetPartSelect(const std::string *net_vname, net_part_select_count_++; if (report_stmt_stats_) net_bus_names_ += net_vname->size() + 1; - const std::string net_name = netVerilogToSta(net_vname); - VerilogNetPartSelect *select = new VerilogNetPartSelect(net_name, - from_index, - to_index); + const std::string net_name = netVerilogToSta(*net_vname); + VerilogNetPartSelect *select = + new VerilogNetPartSelect(net_name, from_index, to_index); delete net_vname; return select; } @@ -489,7 +447,7 @@ VerilogReader::makeNetScalar(const std::string *net_vname) net_scalar_count_++; if (report_stmt_stats_) net_scalar_names_ += net_vname->size() + 1; - const std::string net_name = netVerilogToSta(net_vname); + const std::string net_name = netVerilogToSta(*net_vname); VerilogNetScalar *scalar = new VerilogNetScalar(net_name); delete net_vname; return scalar; @@ -502,7 +460,7 @@ VerilogReader::makeNetBitSelect(const std::string *net_vname, net_bit_select_count_++; if (report_stmt_stats_) net_bus_names_ += net_vname->size() + 1; - const std::string net_name = netVerilogToSta(net_vname); + const std::string net_name = netVerilogToSta(*net_vname); VerilogNetBitSelect *select = new VerilogNetBitSelect(net_name, index); delete net_vname; return select; @@ -524,21 +482,20 @@ VerilogReader::makeModuleInst(const std::string *module_vname, VerilogAttrStmtSeq *attr_stmts, const int line) { - const std::string module_name = moduleVerilogToSta(module_vname); - const std::string inst_name = instanceVerilogToSta(inst_vname); + const std::string module_name = moduleVerilogToSta(*module_vname); + const std::string inst_name = instanceVerilogToSta(*inst_vname); Cell *cell = network_->findAnyCell(module_name.c_str()); LibertyCell *liberty_cell = nullptr; if (cell) liberty_cell = network_->libertyCell(cell); // Instances of liberty with scalar ports are special cased // to reduce the memory footprint of the verilog parser. - if (liberty_cell - && hasScalarNamedPortRefs(liberty_cell, pins)) { + if (liberty_cell && hasScalarNamedPortRefs(liberty_cell, pins)) { const int port_count = liberty_cell->portBitCount(); StringSeq net_names(port_count); for (VerilogNet *vnet : *pins) { VerilogNetPortRefScalarNet *vpin = - dynamic_cast(vnet); + dynamic_cast(vnet); const char *port_name = vpin->name().c_str(); const std::string &net_name = vpin->netName(); Port *port = network_->findPort(cell, port_name); @@ -552,8 +509,8 @@ VerilogReader::makeModuleInst(const std::string *module_vname, delete vpin; net_port_ref_scalar_net_count_--; } - VerilogInst *inst = new VerilogLibertyInst(liberty_cell, inst_name, - net_names, attr_stmts, line); + VerilogInst *inst = + new VerilogLibertyInst(liberty_cell, inst_name, net_names, attr_stmts, line); delete pins; if (report_stmt_stats_) { inst_names_ += inst_name.size() + 1; @@ -565,11 +522,8 @@ VerilogReader::makeModuleInst(const std::string *module_vname, return inst; } else { - VerilogInst *inst = new VerilogModuleInst(module_name.c_str(), - inst_name.c_str(), - pins, - attr_stmts, - line); + VerilogInst *inst = new VerilogModuleInst(module_name.c_str(), inst_name.c_str(), + pins, attr_stmts, line); if (report_stmt_stats_) { inst_module_names_ += module_name.size() + 1; inst_names_ += inst_name.size() + 1; @@ -585,15 +539,12 @@ bool VerilogReader::hasScalarNamedPortRefs(LibertyCell *liberty_cell, VerilogNetSeq *pins) { - if (pins - && pins->size() > 0 - && (*pins)[0]->isNamedPortRef()) { + if (pins && pins->size() > 0 && (*pins)[0]->isNamedPortRef()) { for (VerilogNet *vpin : *pins) { const char *port_name = vpin->name().c_str(); LibertyPort *port = liberty_cell->findLibertyPort(port_name); if (port) { - if (!(port->size() == 1 - && (vpin->isNamedPortRefScalarNet()))) + if (!(port->size() == 1 && (vpin->isNamedPortRefScalarNet()))) return false; } else @@ -611,7 +562,7 @@ VerilogReader::makeNetNamedPortRefScalarNet(const std::string *port_vname) net_port_ref_scalar_net_count_++; if (report_stmt_stats_) port_names_ += port_vname->size() + 1; - const std::string port_name = portVerilogToSta(port_vname); + const std::string port_name = portVerilogToSta(*port_vname); VerilogNetPortRef *ref = new VerilogNetPortRefScalarNet(port_name.c_str()); delete port_vname; return ref; @@ -627,10 +578,10 @@ VerilogReader::makeNetNamedPortRefScalarNet(const std::string *port_vname, net_scalar_names_ += net_vname->size() + 1; port_names_ += port_vname->size() + 1; } - const std::string port_name = portVerilogToSta(port_vname); - const std::string net_name = netVerilogToSta(net_vname); - VerilogNetPortRef *ref = new VerilogNetPortRefScalarNet(port_name.c_str(), - net_name.c_str()); + const std::string port_name = portVerilogToSta(*port_vname); + const std::string net_name = netVerilogToSta(*net_vname); + VerilogNetPortRef *ref = + new VerilogNetPortRefScalarNet(port_name.c_str(), net_name.c_str()); delete port_vname; delete net_vname; return ref; @@ -642,15 +593,15 @@ VerilogReader::makeNetNamedPortRefBitSelect(const std::string *port_vname, int index) { net_port_ref_scalar_net_count_++; - const std::string bus_name = portVerilogToSta(bus_vname); + const std::string bus_name = portVerilogToSta(*bus_vname); const std::string net_name = verilogBusBitName(bus_name, index); if (report_stmt_stats_) { net_scalar_names_ += net_name.length() + 1; port_names_ += port_vname->size() + 1; } - const std::string port_name = portVerilogToSta(port_vname); - VerilogNetPortRef *ref = new VerilogNetPortRefScalarNet(port_name.c_str(), - net_name.c_str()); + const std::string port_name = portVerilogToSta(*port_vname); + VerilogNetPortRef *ref = + new VerilogNetPortRefScalarNet(port_name.c_str(), net_name.c_str()); delete port_vname; delete bus_vname; return ref; @@ -663,7 +614,7 @@ VerilogReader::makeNetNamedPortRefScalar(const std::string *port_vname, net_port_ref_scalar_count_++; if (report_stmt_stats_) port_names_ += port_vname->size() + 1; - const std::string port_name = portVerilogToSta(port_vname); + const std::string port_name = portVerilogToSta(*port_vname); VerilogNetPortRef *ref = new VerilogNetPortRefScalar(port_name.c_str(), net); delete port_vname; return ref; @@ -675,9 +626,8 @@ VerilogReader::makeNetNamedPortRefBit(const std::string *port_vname, VerilogNet *net) { net_port_ref_bit_count_++; - const std::string port_name = portVerilogToSta(port_vname); - VerilogNetPortRef *ref = new VerilogNetPortRefBit(port_name.c_str(), - index, net); + const std::string port_name = portVerilogToSta(*port_vname); + VerilogNetPortRef *ref = new VerilogNetPortRefBit(port_name.c_str(), index, net); delete port_vname; return ref; } @@ -689,10 +639,9 @@ VerilogReader::makeNetNamedPortRefPart(const std::string *port_vname, VerilogNet *net) { net_port_ref_part_count_++; - const std::string port_name = portVerilogToSta(port_vname); - VerilogNetPortRef *ref = new VerilogNetPortRefPart(port_name, - from_index, - to_index, net); + const std::string port_name = portVerilogToSta(*port_vname); + VerilogNetPortRef *ref = + new VerilogNetPortRefPart(port_name, from_index, to_index, net); delete port_vname; return ref; } @@ -704,21 +653,18 @@ VerilogReader::makeNetConcat(VerilogNetSeq *nets) return new VerilogNetConcat(nets); } -#define printClassMemory(name, class_name, count) \ - report_->reportLine(" %-20s %9d * %3zu = %6.1fMb\n", \ - name, \ - count, \ - sizeof(class_name), \ - (count * sizeof(class_name) * 1e-6)) +#define printClassMemory(name, class_name, count) \ + report_->report(" {:<20} {:9} * {:3} = {:6.1f}Mb\n", name, count, \ + sizeof(class_name), (count * sizeof(class_name) * 1e-6)) -#define printStringMemory(name, count) \ - report_->reportLine(" %-20s %6.1fMb", name, count * 1e-6) +#define printStringMemory(name, count) \ + report_->report(" {:<20} {:6.1f}Mb", name, count * 1e-6) void VerilogReader::reportStmtCounts() { if (debug_->check("verilog", 1)) { - report_->reportLine("Verilog stats"); + report_->report("Verilog stats"); printClassMemory("modules", VerilogModule, module_count_); printClassMemory("module insts", VerilogModuleInst, inst_mod_count_); printClassMemory("liberty insts", VerilogLibertyInst, inst_lib_count_); @@ -730,14 +676,12 @@ VerilogReader::reportStmtCounts() net_port_ref_scalar_count_); printClassMemory("port ref scalar net", VerilogNetPortRefScalarNet, net_port_ref_scalar_net_count_); - printClassMemory("port ref bit", VerilogNetPortRefBit, - net_port_ref_bit_count_); + printClassMemory("port ref bit", VerilogNetPortRefBit, net_port_ref_bit_count_); printClassMemory("port ref part", VerilogNetPortRefPart, net_port_ref_part_count_); printClassMemory("scalar nets", VerilogNetScalar, net_scalar_count_); - printClassMemory("bus bit nets",VerilogNetBitSelect,net_bit_select_count_); - printClassMemory("bus range nets", VerilogNetPartSelect, - net_part_select_count_); + printClassMemory("bus bit nets", VerilogNetBitSelect, net_bit_select_count_); + printClassMemory("bus range nets", VerilogNetPartSelect, net_part_select_count_); printClassMemory("constant nets", VerilogNetConstant, net_constant_count_); printClassMemory("concats", VerilogNetConcat, concat_count_); printClassMemory("assigns", VerilogAssign, assign_count_); @@ -749,30 +693,6 @@ VerilogReader::reportStmtCounts() } } -void -VerilogReader::error(int id, - const char *filename, - int line, - const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - report_->vfileError(id, filename, line, fmt, args); - va_end(args); -} - -void -VerilogReader::warn(int id, - const char *filename, - int line, - const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - report_->vfileWarn(id, filename, line, fmt, args); - va_end(args); -} - //////////////////////////////////////////////////////////////// VerilogModule::VerilogModule(const std::string &name, @@ -808,10 +728,9 @@ VerilogModule::parseStmts(VerilogReader *reader) StringSet inst_names; for (VerilogStmt *stmt : *stmts_) { if (stmt->isDeclaration()) - parseDcl(dynamic_cast(stmt), reader); + parseDcl(dynamic_cast(stmt), reader); else if (stmt->isInstance()) - checkInstanceName(dynamic_cast(stmt), inst_names, - reader); + checkInstanceName(dynamic_cast(stmt), inst_names, reader); } } @@ -837,18 +756,16 @@ VerilogModule::parseDcl(VerilogDcl *dcl, dcl_map_[net_name.c_str()] = dcl; } else if (dcl->direction()->isPowerGround() - && (existing_dir->isOutput() - || existing_dir->isInput() + && (existing_dir->isOutput() || existing_dir->isInput() || existing_dir->isBidirect())) // supply0/supply1 dcl can be used as modifier for // input/output/inout dcls. dcl_map_[net_name.c_str()] = dcl; else if (!dcl->direction()->isInternal()) { std::string net_vname = netVerilogName(net_name.c_str()); - reader->warn(1395, filename_.c_str(), dcl->line(), - "signal %s previously declared on line %d.", - net_vname.c_str(), - existing_dcl->line()); + reader->warn(1395, filename_, dcl->line(), + "signal {} previously declared on line {}.", + net_vname, existing_dcl->line()); } } else @@ -869,13 +786,12 @@ VerilogModule::checkInstanceName(VerilogInst *inst, int i = 1; std::string replacement_name; do { - replacement_name = stdstrPrint("%s_%d", inst_name.c_str(), i++); + replacement_name = sta::format("{}_{}", inst_name, i++); } while (inst_names.contains(replacement_name)); std::string inst_vname = instanceVerilogName(inst_name.c_str()); - reader->warn(1396, filename_.c_str(), inst->line(), - "instance name %s duplicated - renamed to %s.", - inst_vname.c_str(), - replacement_name.c_str()); + reader->warn(1396, filename_, inst->line(), + "instance name {} duplicated - renamed to {}.", inst_vname, + replacement_name); inst_name = replacement_name; inst->setInstanceName(inst_name); } @@ -921,7 +837,9 @@ VerilogModuleInst::VerilogModuleInst(const std::string &module_name, VerilogNetSeq *pins, VerilogAttrStmtSeq *attr_stmts, int line) : - VerilogInst(inst_name, attr_stmts, line), + VerilogInst(inst_name, + attr_stmts, + line), module_name_(module_name), pins_(pins) { @@ -938,17 +856,13 @@ VerilogModuleInst::~VerilogModuleInst() bool VerilogModuleInst::hasPins() { - return pins_ - && pins_->size() > 0; - + return pins_ && pins_->size() > 0; } bool VerilogModuleInst::namedPins() { - return pins_ - && pins_->size() > 0 - && (*pins_)[0]->isNamedPortRef(); + return pins_ && pins_->size() > 0 && (*pins_)[0]->isNamedPortRef(); } VerilogLibertyInst::VerilogLibertyInst(LibertyCell *cell, @@ -956,7 +870,9 @@ VerilogLibertyInst::VerilogLibertyInst(LibertyCell *cell, const StringSeq &net_names, VerilogAttrStmtSeq *attr_stmts, const int line) : - VerilogInst(inst_name, attr_stmts, line), + VerilogInst(inst_name, + attr_stmts, + line), cell_(cell), net_names_(net_names) { @@ -1011,7 +927,10 @@ VerilogDclBus::VerilogDclBus(PortDirection *dir, VerilogDclArgSeq *args, VerilogAttrStmtSeq *attr_stmts, int line) : - VerilogDcl(dir, args, attr_stmts, line), + VerilogDcl(dir, + args, + attr_stmts, + line), from_index_(from_index), to_index_(to_index) { @@ -1023,7 +942,10 @@ VerilogDclBus::VerilogDclBus(PortDirection *dir, VerilogDclArg *arg, VerilogAttrStmtSeq *attr_stmts, int line) : - VerilogDcl(dir, arg, attr_stmts, line), + VerilogDcl(dir, + arg, + attr_stmts, + line), from_index_(from_index), to_index_(to_index) { @@ -1032,7 +954,7 @@ VerilogDclBus::VerilogDclBus(PortDirection *dir, int VerilogDclBus::size() const { - return abs(to_index_ - from_index_) + 1; + return std::abs(to_index_ - from_index_) + 1; } VerilogDclArg::VerilogDclArg(const std::string &net_name) : @@ -1046,10 +968,7 @@ VerilogDclArg::VerilogDclArg(VerilogAssign *assign) : { } -VerilogDclArg::~VerilogDclArg() -{ - delete assign_; -} +VerilogDclArg::~VerilogDclArg() { delete assign_; } const std::string & VerilogDclArg::netName() @@ -1152,10 +1071,8 @@ VerilogBusNetNameIterator::VerilogBusNetNameIterator(const std::string bus_name, bool VerilogBusNetNameIterator::hasNext() { - return (to_index_ > from_index_ - && index_ <= to_index_) - || (to_index_ <= from_index_ - && index_ >= to_index_); + return (to_index_ > from_index_ && index_ <= to_index_) + || (to_index_ <= from_index_ && index_ >= to_index_); } const std::string & @@ -1173,7 +1090,7 @@ static std::string verilogBusBitName(const std::string &bus_name, int index) { - return stdstrPrint("%s[%d]", bus_name.c_str(), index); + return sta::format("{}[{}]", bus_name.c_str(), index); } class VerilogConstantNetNameIterator : public VerilogNetNameIterator @@ -1192,10 +1109,10 @@ private: int bit_index_; }; -VerilogConstantNetNameIterator:: -VerilogConstantNetNameIterator(VerilogConstantValue *value, - const std::string &zero, - const std::string &one) : +VerilogConstantNetNameIterator::VerilogConstantNetNameIterator( + VerilogConstantValue *value, + const std::string &zero, + const std::string &one) : value_(value), zero_(zero), one_(one), @@ -1233,10 +1150,9 @@ private: VerilogNetNameIterator *net_name_iter_; }; -VerilogNetConcatNameIterator:: -VerilogNetConcatNameIterator(VerilogNetSeq *nets, - VerilogModule *module, - VerilogReader *reader) : +VerilogNetConcatNameIterator::VerilogNetConcatNameIterator(VerilogNetSeq *nets, + VerilogModule *module, + VerilogReader *reader) : module_(module), reader_(reader), nets_(nets), @@ -1257,8 +1173,7 @@ VerilogNetConcatNameIterator::~VerilogNetConcatNameIterator() bool VerilogNetConcatNameIterator::hasNext() { - return (net_name_iter_ && net_name_iter_->hasNext()) - || net_iter_ != nets_->end(); + return (net_name_iter_ && net_name_iter_->hasNext()) || net_iter_ != nets_->end(); } const std::string & @@ -1289,9 +1204,7 @@ VerilogNetNamed::VerilogNetNamed(const std::string &name) : { } -VerilogNetNamed::~VerilogNetNamed() -{ -} +VerilogNetNamed::~VerilogNetNamed() {} VerilogNetScalar::VerilogNetScalar(const std::string &name) : VerilogNetNamed(name) @@ -1340,7 +1253,8 @@ VerilogNetScalar::nameIterator(VerilogModule *module, VerilogNetBitSelect::VerilogNetBitSelect(const std::string &name, int index) : - VerilogNetNamed(verilogBusBitName(name, index)), + VerilogNetNamed(verilogBusBitName(name, + index)), index_(index) { } @@ -1360,7 +1274,7 @@ VerilogNetBitSelect::nameIterator(VerilogModule *, VerilogNetPartSelect::VerilogNetPartSelect(const std::string &name, int from_index, - int to_index): + int to_index) : VerilogNetNamed(name), from_index_(from_index), to_index_(to_index) @@ -1407,27 +1321,27 @@ VerilogNetConstant::parseConstant(const std::string *constant, size_t base_idx = csize_end + 1; char base = constant->at(base_idx); switch (base) { - case 'b': - case 'B': - parseConstant(constant, base_idx, 2, 1); - break; - case 'o': - case 'O': - parseConstant(constant, base_idx, 8, 3); - break; - case 'h': - case 'H': - parseConstant(constant, base_idx, 16, 4); - break; - case 'd': - case 'D': - parseConstant10(constant, base_idx, reader, line); - break; - default: - case '\0': - reader->report()->fileWarn(1861, reader->filename(), line, - "unknown constant base."); - break; + case 'b': + case 'B': + parseConstant(constant, base_idx, 2, 1); + break; + case 'o': + case 'O': + parseConstant(constant, base_idx, 8, 3); + break; + case 'h': + case 'H': + parseConstant(constant, base_idx, 16, 4); + break; + case 'd': + case 'D': + parseConstant10(constant, base_idx, reader, line); + break; + default: + case '\0': + reader->report()->fileWarn(1861, reader->filename(), line, + "unknown constant base."); + break; } delete constant; } @@ -1472,19 +1386,17 @@ VerilogNetConstant::parseConstant10(const std::string *constant, for (size_t i = base_idx + 1; i < constant->size(); i++) { char ch = constant->at(i); if (ch != '_') - tmp += ch; + tmp += ch; } size_t size = value_->size(); size_t length = tmp.size(); const std::string &constant10_max = reader->constant10Max(); size_t max_length = constant10_max.size(); - if (length > max_length - || (length == max_length - && tmp > constant10_max)) + if (length > max_length || (length == max_length && tmp > constant10_max)) reader->warn(1397, reader->filename(), line, - "base 10 constant greater than %s not supported.", - constant10_max.c_str()); + "base 10 constant greater than {} not supported.", + constant10_max); else { size_t *end = nullptr; VerilogConstant10 value = std::stoull(tmp, end, 10); @@ -1496,28 +1408,22 @@ VerilogNetConstant::parseConstant10(const std::string *constant, } } -VerilogNetConstant::~VerilogNetConstant() -{ - delete value_; -} +VerilogNetConstant::~VerilogNetConstant() { delete value_; } VerilogNetNameIterator * VerilogNetConstant::nameIterator(VerilogModule *, VerilogReader *reader) { - return new VerilogConstantNetNameIterator(value_, - reader->zeroNetName(), + return new VerilogConstantNetNameIterator(value_, reader->zeroNetName(), reader->oneNetName()); } - int VerilogNetConstant::size(VerilogModule *) { return value_->size(); } - VerilogNetConcat::VerilogNetConcat(VerilogNetSeq *nets) : nets_(nets) { @@ -1590,10 +1496,7 @@ VerilogNetPortRefScalar::VerilogNetPortRefScalar(const std::string &name, { } -VerilogNetPortRefScalar::~VerilogNetPortRefScalar() -{ - delete net_; -} +VerilogNetPortRefScalar::~VerilogNetPortRefScalar() { delete net_; } int VerilogNetPortRefScalar::size(VerilogModule *module) @@ -1617,8 +1520,10 @@ VerilogNetPortRefScalar::nameIterator(VerilogModule *module, VerilogNetPortRefBit::VerilogNetPortRefBit(const std::string &name, int index, VerilogNet *net) : - VerilogNetPortRefScalar(name, net), - bit_name_(verilogBusBitName(name, index)) + VerilogNetPortRefScalar(name, + net), + bit_name_(verilogBusBitName(name, + index)) { } @@ -1626,7 +1531,9 @@ VerilogNetPortRefPart::VerilogNetPortRefPart(const std::string &name, int from_index, int to_index, VerilogNet *net) : - VerilogNetPortRefBit(name, from_index, net), + VerilogNetPortRefBit(name, + from_index, + net), to_index_(to_index) { } @@ -1656,8 +1563,8 @@ VerilogAttrEntry::value() return value_; } -VerilogAttrStmt::VerilogAttrStmt(VerilogAttrEntrySeq *attrs): - attrs_(attrs) +VerilogAttrStmt::VerilogAttrStmt(VerilogAttrEntrySeq *attrs) : + attrs_(attrs) { } @@ -1667,13 +1574,12 @@ VerilogAttrStmt::~VerilogAttrStmt() delete attrs_; } -VerilogAttrEntrySeq* +VerilogAttrEntrySeq * VerilogAttrStmt::attrs() { return attrs_; } - //////////////////////////////////////////////////////////////// // // Link verilog network @@ -1681,7 +1587,7 @@ VerilogAttrStmt::attrs() //////////////////////////////////////////////////////////////// // Verilog net name to network net map. -using BindingMap = std::map; +using BindingMap = std::map; class VerilogBindingTbl { @@ -1712,15 +1618,16 @@ VerilogReader::linkNetwork(const char *top_cell_name, VerilogModule *module = this->module(top_cell); if (module) { // Seed the recursion for expansion with the top level instance. - Instance *top_instance = network_->makeInstance(top_cell, top_cell_name, nullptr); + Instance *top_instance = + network_->makeInstance(top_cell, top_cell_name, nullptr); VerilogBindingTbl bindings(zero_net_name_, one_net_name_); for (VerilogNet *mod_port : *module->ports()) { - VerilogNetNameIterator *net_name_iter = mod_port->nameIterator(module, - this); + VerilogNetNameIterator *net_name_iter = mod_port->nameIterator(module, this); while (net_name_iter->hasNext()) { const std::string &net_name = net_name_iter->next(); Port *port = network_->findPort(top_cell, net_name.c_str()); - Net *net = bindings.ensureNetBinding(net_name.c_str(), top_instance, network_); + Net *net = + bindings.ensureNetBinding(net_name.c_str(), top_instance, network_); // Guard against repeated port name. if (network_->findPin(top_instance, port) == nullptr) { Pin *pin = network_->makePin(top_instance, port, nullptr); @@ -1741,12 +1648,12 @@ VerilogReader::linkNetwork(const char *top_cell_name, return top_instance; } else { - report_->error(1398, "%s is not a verilog module.", top_cell_name); + report_->error(1398, "{} is not a verilog module.", top_cell_name); return nullptr; } } else { - report_->error(1399, "%s is not a verilog module.", top_cell_name); + report_->error(1399, "{} is not a verilog module.", top_cell_name); return nullptr; } } @@ -1759,31 +1666,32 @@ VerilogReader::makeModuleInstBody(VerilogModule *module, { for (VerilogStmt *stmt : *module->stmts()) { if (stmt->isModuleInst()) - makeModuleInstNetwork(dynamic_cast(stmt), - inst, module, bindings, make_black_boxes); + makeModuleInstNetwork(dynamic_cast(stmt), inst, module, + bindings, make_black_boxes); else if (stmt->isLibertyInst()) - makeLibertyInst(dynamic_cast(stmt), - inst, module, bindings); + makeLibertyInst(dynamic_cast(stmt), inst, module, + bindings); else if (stmt->isDeclaration()) { - VerilogDcl *dcl = dynamic_cast(stmt); + VerilogDcl *dcl = dynamic_cast(stmt); PortDirection *dir = dcl->direction(); for (VerilogDclArg *arg : *dcl->args()) { VerilogAssign *assign = arg->assign(); if (assign) mergeAssignNet(assign, module, inst, bindings); if (dir->isGround()) { - Net *net = bindings->ensureNetBinding(arg->netName().c_str(),inst,network_); + Net *net = + bindings->ensureNetBinding(arg->netName().c_str(), inst, network_); network_->addConstantNet(net, LogicValue::zero); } if (dir->isPower()) { - Net *net = bindings->ensureNetBinding(arg->netName().c_str(),inst,network_); + Net *net = + bindings->ensureNetBinding(arg->netName().c_str(), inst, network_); network_->addConstantNet(net, LogicValue::one); } } } else if (stmt->isAssign()) - mergeAssignNet(dynamic_cast(stmt), module, inst, - bindings); + mergeAssignNet(dynamic_cast(stmt), module, inst, bindings); } } @@ -1801,22 +1709,20 @@ VerilogReader::makeModuleInstNetwork(VerilogModuleInst *mod_inst, if (make_black_boxes) { cell = makeBlackBox(mod_inst, parent_module); linkWarn(198, parent_module->filename(), mod_inst->line(), - "module %s not found. Creating black box for %s.", - mod_inst->moduleName().c_str(), - inst_vname.c_str()); + "module {} not found. Creating black box for {}.", + mod_inst->moduleName(), inst_vname); } else linkError(199, parent_module->filename(), mod_inst->line(), - "module %s not found for instance %s.", - mod_inst->moduleName().c_str(), - inst_vname.c_str()); + "module {} not found for instance {}.", + mod_inst->moduleName(), inst_vname); } if (cell) { LibertyCell *lib_cell = network_->libertyCell(cell); if (lib_cell) cell = network_->cell(lib_cell); - Instance *inst = network_->makeInstance(cell, mod_inst->instanceName().c_str(), - parent); + Instance *inst = + network_->makeInstance(cell, mod_inst->instanceName().c_str(), parent); VerilogAttrStmtSeq *attr_stmts = mod_inst->attrStmts(); for (VerilogAttrStmt *stmt : *attr_stmts) { for (VerilogAttrEntry *entry : *stmt->attrs()) { @@ -1835,11 +1741,11 @@ VerilogReader::makeModuleInstNetwork(VerilogModuleInst *mod_inst, VerilogBindingTbl bindings(zero_net_name_, one_net_name_); if (mod_inst->hasPins()) { if (mod_inst->namedPins()) - makeNamedInstPins(cell, inst, mod_inst, &bindings, parent, - parent_module, parent_bindings, is_leaf); + makeNamedInstPins(cell, inst, mod_inst, &bindings, parent, parent_module, + parent_bindings, is_leaf); else - makeOrderedInstPins(cell, inst, mod_inst, &bindings, parent, - parent_module, parent_bindings, is_leaf); + makeOrderedInstPins(cell, inst, mod_inst, &bindings, parent, parent_module, + parent_bindings, is_leaf); } if (!is_leaf) { VerilogModule *module = this->module(cell); @@ -1861,43 +1767,38 @@ VerilogReader::makeNamedInstPins(Cell *cell, { std::string inst_vname = instanceVerilogName(mod_inst->instanceName().c_str()); for (auto mpin : *mod_inst->pins()) { - VerilogNetPortRef *vpin = dynamic_cast(mpin); + VerilogNetPortRef *vpin = dynamic_cast(mpin); const char *port_name = vpin->name().c_str(); Port *port = network_->findPort(cell, port_name); if (port) { - if (vpin->hasNet() - && network_->size(port) != vpin->size(parent_module)) { + if (vpin->hasNet() && network_->size(port) != vpin->size(parent_module)) { linkWarn(200, parent_module->filename(), mod_inst->line(), - "instance %s port %s size %d does not match net size %d.", - inst_vname.c_str(), - network_->name(port), - network_->size(port), + "instance {} port {} size {} does not match net size {}.", + inst_vname, network_->name(port), network_->size(port), vpin->size(parent_module)); } else { VerilogNetNameIterator *net_name_iter = - vpin->nameIterator(parent_module, this); + vpin->nameIterator(parent_module, this); if (network_->hasMembers(port)) { PortMemberIterator *port_iter = network_->memberIterator(port); while (port_iter->hasNext()) { Port *port = port_iter->next(); - makeInstPin(inst, port, net_name_iter, bindings, - parent, parent_bindings, is_leaf); + makeInstPin(inst, port, net_name_iter, bindings, parent, parent_bindings, + is_leaf); } delete port_iter; } else { - makeInstPin(inst, port, net_name_iter, bindings, - parent, parent_bindings, is_leaf); + makeInstPin(inst, port, net_name_iter, bindings, parent, parent_bindings, + is_leaf); } delete net_name_iter; } } else linkWarn(201, parent_module->filename(), mod_inst->line(), - "instance %s port %s not found.", - inst_vname.c_str(), - port_name); + "instance {} port {} not found.", inst_vname, port_name); } } @@ -1914,34 +1815,30 @@ VerilogReader::makeOrderedInstPins(Cell *cell, CellPortIterator *port_iter = network_->portIterator(cell); VerilogNetSeq *mod_pins = mod_inst->pins(); VerilogNetSeq::iterator pin_iter = mod_pins->begin(); - while (pin_iter != mod_pins->end() - && port_iter->hasNext()) { + while (pin_iter != mod_pins->end() && port_iter->hasNext()) { VerilogNet *net = *pin_iter++; Port *port = port_iter->next(); if (network_->size(port) != net->size(parent_module)) { std::string inst_vname = instanceVerilogName(mod_inst->instanceName().c_str()); linkWarn(202, parent_module->filename(), mod_inst->line(), - "instance %s port %s size %d does not match net size %d.", - inst_vname.c_str(), - network_->name(port), - network_->size(port), + "instance {} port {} size {} does not match net size {}.", + inst_vname, network_->name(port), network_->size(port), net->size(parent_module)); } else { - VerilogNetNameIterator *net_name_iter=net->nameIterator(parent_module, - this); + VerilogNetNameIterator *net_name_iter = net->nameIterator(parent_module, this); if (network_->isBus(port)) { PortMemberIterator *member_iter = network_->memberIterator(port); while (member_iter->hasNext() && net_name_iter->hasNext()) { Port *port = member_iter->next(); - makeInstPin(inst, port, net_name_iter, bindings, - parent, parent_bindings, is_leaf); + makeInstPin(inst, port, net_name_iter, bindings, parent, parent_bindings, + is_leaf); } delete member_iter; } else - makeInstPin(inst, port, net_name_iter, bindings, - parent, parent_bindings, is_leaf); + makeInstPin(inst, port, net_name_iter, bindings, parent, parent_bindings, + is_leaf); delete net_name_iter; } } @@ -1960,8 +1857,7 @@ VerilogReader::makeInstPin(Instance *inst, std::string net_name; if (net_name_iter->hasNext()) net_name = net_name_iter->next(); - makeInstPin(inst, port, net_name, bindings, parent, parent_bindings, - is_leaf); + makeInstPin(inst, port, net_name, bindings, parent, parent_bindings, is_leaf); } void @@ -2001,9 +1897,9 @@ VerilogReader::makeLibertyInst(VerilogLibertyInst *lib_inst, VerilogBindingTbl *parent_bindings) { LibertyCell *lib_cell = lib_inst->cell(); - Cell *cell = reinterpret_cast(lib_cell); - Instance *inst = network_->makeInstance(cell, lib_inst->instanceName().c_str(), - parent); + Cell *cell = reinterpret_cast(lib_cell); + Instance *inst = + network_->makeInstance(cell, lib_inst->instanceName().c_str(), parent); VerilogAttrStmtSeq *attr_stmts = lib_inst->attrStmts(); for (VerilogAttrStmt *stmt : *attr_stmts) { for (VerilogAttrEntry *entry : *stmt->attrs()) { @@ -2029,11 +1925,11 @@ VerilogReader::makeLibertyInst(VerilogLibertyInst *lib_inst, } else net = parent_bindings->ensureNetBinding(net_name.c_str(), parent, network_); - network_->makePin(inst, reinterpret_cast(port), net); + network_->makePin(inst, reinterpret_cast(port), net); } else // Make unconnected pin. - network_->makePin(inst, reinterpret_cast(port), nullptr); + network_->makePin(inst, reinterpret_cast(port), nullptr); } } @@ -2059,12 +1955,11 @@ VerilogReader::makeBlackBoxNamedPorts(Cell *cell, VerilogModule *parent_module) { for (VerilogNet *mpin : *mod_inst->pins()) { - VerilogNetNamed *vpin = dynamic_cast(mpin); + VerilogNetNamed *vpin = dynamic_cast(mpin); const char *port_name = vpin->name().c_str(); size_t size = vpin->size(parent_module); - Port *port = (size == 1) - ? network_->makePort(cell, port_name) - : network_->makeBusPort(cell, port_name, 0, size - 1); + Port *port = (size == 1) ? network_->makePort(cell, port_name) + : network_->makeBusPort(cell, port_name, 0, size - 1); network_->setDirection(port, PortDirection::unknown()); } } @@ -2079,11 +1974,10 @@ VerilogReader::makeBlackBoxOrderedPorts(Cell *cell, if (nets) { for (VerilogNet *net : *nets) { size_t size = net->size(parent_module); - char *port_name = stringPrint("p_%d", port_index); + std::string port_name = format("p_{}", port_index); Port *port = (size == 1) - ? network_->makePort(cell, port_name) - : network_->makeBusPort(cell, port_name, size - 1, 0); - stringDelete(port_name); + ? network_->makePort(cell, port_name.c_str()) + : network_->makeBusPort(cell, port_name.c_str(), size - 1, 0); network_->setDirection(port, PortDirection::unknown()); port_index++; } @@ -2117,7 +2011,7 @@ VerilogReader::mergeAssignNet(VerilogAssign *assign, // Merge lower level net into higher level net so that deleting // instances from the bottom up does not reference deleted nets // by referencing the mergedInto field. - if (hierarchyLevel(lhs_net,network_) >= hierarchyLevel(rhs_net,network_)) + if (hierarchyLevel(lhs_net, network_) >= hierarchyLevel(rhs_net, network_)) network_->mergeInto(lhs_net, rhs_net); else network_->mergeInto(rhs_net, lhs_net); @@ -2129,9 +2023,8 @@ VerilogReader::mergeAssignNet(VerilogAssign *assign, } else linkWarn(203, module->filename(), assign->line(), - "assign left hand side size %d not equal right hand size %d.", - lhs->size(module), - rhs->size(module)); + "assign left hand side size {} not equal right hand size {}.", + lhs->size(module), rhs->size(module)); } static int @@ -2160,7 +2053,8 @@ VerilogBindingTbl::VerilogBindingTbl(const std::string &zero_net_name, // binding tables up the call tree when nodes are merged // because the name changes up the hierarchy. Net * -VerilogBindingTbl::find(const char *name, NetworkReader *network) +VerilogBindingTbl::find(const char *name, + NetworkReader *network) { Net *net = findKey(map_, name); while (net && network->mergedInto(net)) @@ -2194,34 +2088,6 @@ VerilogBindingTbl::ensureNetBinding(const char *net_name, //////////////////////////////////////////////////////////////// -void -VerilogReader::linkWarn(int id, - const char *filename, - int line, - const char *msg, ...) -{ - va_list args; - va_start(args, msg); - char *msg_str = stringPrintArgs(msg, args); - VerilogError *error = new VerilogError(id, filename, line, msg_str, true); - link_errors_.push_back(error); - va_end(args); -} - -void -VerilogReader::linkError(int id, - const char *filename, - int line, - const char *msg, ...) -{ - va_list args; - va_start(args, msg); - char *msg_str = stringPrintArgs(msg, args); - VerilogError *error = new VerilogError(id, filename, line, msg_str, false); - link_errors_.push_back(error); - va_end(args); -} - bool VerilogReader::reportLinkErrors() { @@ -2231,7 +2097,8 @@ VerilogReader::reportLinkErrors() bool errors = false; for (VerilogError *error : link_errors_) { // Report as warnings to avoid throwing. - report_->fileWarn(error->id(), error->filename(), error->line(), "%s", error->msg()); + report_->fileWarn(error->id(), error->filename(), error->line(), "{}", + error->msg()); errors |= !error->warn(); delete error; } @@ -2253,7 +2120,7 @@ VerilogScanner::VerilogScanner(std::istream *stream, void VerilogScanner::error(const char *msg) { - report_->fileError(1870, filename_, lineno(), "%s", msg); + report_->fileError(1870, filename_, lineno(), "{}", msg); } -} // namespace +} // namespace sta diff --git a/verilog/VerilogWriter.cc b/verilog/VerilogWriter.cc index d8ee7c6f..3531b865 100644 --- a/verilog/VerilogWriter.cc +++ b/verilog/VerilogWriter.cc @@ -30,6 +30,7 @@ #include #include "Error.hh" +#include "Format.hh" #include "Liberty.hh" #include "PortDirection.hh" #include "Network.hh" @@ -173,15 +174,15 @@ VerilogWriter::writeModule(const Instance *inst) { Cell *cell = network_->cell(inst); std::string cell_vname = cellVerilogName(network_->name(cell)); - fprintf(stream_, "module %s (", cell_vname.c_str()); + sta::print(stream_, "module {} (", cell_vname); writePorts(cell); writePortDcls(cell); - fprintf(stream_, "\n"); + sta::print(stream_, "\n"); writeWireDcls(inst); - fprintf(stream_, "\n"); + sta::print(stream_, "\n"); writeChildren(inst); writeAssigns(inst); - fprintf(stream_, "endmodule\n"); + sta::print(stream_, "endmodule\n"); } void @@ -194,14 +195,14 @@ VerilogWriter::writePorts(const Cell *cell) if (include_pwr_gnd_ || !network_->direction(port)->isPowerGround()) { if (!first) - fprintf(stream_, ",\n "); + sta::print(stream_, ",\n "); std::string verilog_name = portVerilogName(network_->name(port)); - fprintf(stream_, "%s", verilog_name.c_str()); + sta::print(stream_, "{}", verilog_name); first = false; } } delete port_iter; - fprintf(stream_, ");\n"); + sta::print(stream_, ");\n"); } void @@ -216,19 +217,19 @@ VerilogWriter::writePortDcls(const Cell *cell) std::string port_vname = portVerilogName(network_->name(port)); const char *vtype = verilogPortDir(dir); if (vtype) { - fprintf(stream_, " %s", vtype); + sta::print(stream_, " {}", vtype); if (network_->isBus(port)) - fprintf(stream_, " [%d:%d]", - network_->fromIndex(port), - network_->toIndex(port)); - fprintf(stream_, " %s;\n", port_vname.c_str()); - if (dir->isTristate()) { - fprintf(stream_, " tri"); - if (network_->isBus(port)) - fprintf(stream_, " [%d:%d]", + sta::print(stream_, " [{}:{}]", network_->fromIndex(port), network_->toIndex(port)); - fprintf(stream_, " %s;\n", port_vname.c_str()); + sta::print(stream_, " {};\n", port_vname); + if (dir->isTristate()) { + sta::print(stream_, " tri"); + if (network_->isBus(port)) + sta::print(stream_, " [{}:{}]", + network_->fromIndex(port), + network_->toIndex(port)); + sta::print(stream_, " {};\n", port_vname); } } } @@ -286,7 +287,7 @@ VerilogWriter::writeWireDcls(const Instance *inst) } else { std::string net_vname = netVerilogName(net_name); - fprintf(stream_, " wire %s;\n", net_vname.c_str());; + sta::print(stream_, " wire {};\n", net_vname); } } } @@ -296,16 +297,16 @@ VerilogWriter::writeWireDcls(const Instance *inst) for (const auto& [bus_name1, range] : bus_ranges) { const char *bus_name = bus_name1.c_str(); std::string net_vname = netVerilogName(bus_name); - fprintf(stream_, " wire [%d:%d] %s;\n", - range.first, - range.second, - net_vname.c_str());; + sta::print(stream_, " wire [{}:{}] {};\n", + range.first, + range.second, + net_vname); } // Wire net dcls for writeInstBusPinBit. int nc_count = findUnconnectedNetCount(inst); for (int i = 1; i < nc_count + 1; i++) - fprintf(stream_, " wire _NC%d;\n", i); + sta::print(stream_, " wire _NC{};\n", i); } void @@ -336,9 +337,9 @@ VerilogWriter::writeChild(const Instance *child) const char *child_name = network_->name(child); std::string child_vname = instanceVerilogName(child_name); std::string child_cell_vname = cellVerilogName(network_->name(child_cell)); - fprintf(stream_, " %s %s (", - child_cell_vname.c_str(), - child_vname.c_str()); + sta::print(stream_, " {} {} (", + child_cell_vname, + child_vname); bool first_port = true; CellPortIterator *port_iter = network_->portIterator(child_cell); while (port_iter->hasNext()) { @@ -352,7 +353,7 @@ VerilogWriter::writeChild(const Instance *child) } } delete port_iter; - fprintf(stream_, ");\n"); + sta::print(stream_, ");\n"); } } @@ -368,11 +369,11 @@ VerilogWriter::writeInstPin(const Instance *inst, const char *net_name = network_->name(net); std::string net_vname = netVerilogName(net_name); if (!first_port) - fprintf(stream_, ",\n "); + sta::print(stream_, ",\n "); std::string port_vname = portVerilogName(network_->name(port)); - fprintf(stream_, ".%s(%s)", - port_vname.c_str(), - net_vname.c_str()); + sta::print(stream_, ".{}({})", + port_vname, + net_vname); first_port = false; } } @@ -384,10 +385,10 @@ VerilogWriter::writeInstBusPin(const Instance *inst, bool &first_port) { if (!first_port) - fprintf(stream_, ",\n "); + sta::print(stream_, ",\n "); std::string port_vname = portVerilogName(network_->name(port)); - fprintf(stream_, ".%s({", port_vname.c_str()); + sta::print(stream_, ".{}({{", port_vname); first_port = false; bool first_member = true; @@ -410,7 +411,7 @@ VerilogWriter::writeInstBusPin(const Instance *inst, } delete member_iter; } - fprintf(stream_, "})"); + sta::print(stream_, "}})"); } void @@ -420,16 +421,15 @@ VerilogWriter::writeInstBusPinBit(const Instance *inst, { Pin *pin = network_->findPin(inst, port); Net *net = pin ? network_->net(pin) : nullptr; - std::string net_name; - if (net) - net_name = network_->name(net); - else + std::string net_name = net + ? network_->name(net) // There is no verilog syntax to "skip" a bit in the concatentation. - stringPrint(net_name, "_NC%d", unconnected_net_index_++); + : sta::format("_NC{}", unconnected_net_index_++); + std::string net_vname = netVerilogName(net_name.c_str()); if (!first_member) - fprintf(stream_, ",\n "); - fprintf(stream_, "%s", net_vname.c_str()); + sta::print(stream_, ",\n "); + sta::print(stream_, "{}", net_vname); first_member = false; } @@ -455,9 +455,9 @@ VerilogWriter::writeAssigns(const Instance *inst) // Port name is different from net name. std::string port_vname = netVerilogName(network_->name(port)); std::string net_vname = netVerilogName(network_->name(net)); - fprintf(stream_, " assign %s = %s;\n", - port_vname.c_str(), - net_vname.c_str()); + sta::print(stream_, " assign {} = {};\n", + port_vname, + net_vname); } } }