diff --git a/CMakeLists.txt b/CMakeLists.txt index de2a90c7..e9e84a87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,13 +24,13 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14) cmake_policy(SET CMP0086 NEW) endif() -project(STA VERSION 2.5.0 +project(STA VERSION 2.6.0 LANGUAGES CXX ) -option(USE_CUDD "Use CUDD BDD package") +option(USE_CUDD "Use CUDD BDD package" ON) option(CUDD_DIR "CUDD BDD package directory") -option(USE_TCL_READLINE "Use TCL readliine package") +option(USE_TCL_READLINE "Use TCL readliine package" ON) option(USE_SANITIZE "Compile with santize address enabled") # Turn on to debug compiler args. @@ -195,8 +195,10 @@ set(STA_SOURCE search/VisitPathEnds.cc search/VisitPathGroupVertices.cc search/WorstSlack.cc - search/WritePathSpice.cc - search/WriteSpice.cc + + spice/WritePathSpice.cc + spice/WriteSpice.cc + spice/Xyce.cc power/Power.cc power/ReadVcdActivities.cc @@ -244,11 +246,11 @@ set(STA_TCL_FILES tcl/Sta.tcl tcl/Splash.tcl tcl/Variables.tcl - tcl/WritePathSpice.tcl dcalc/DelayCalc.tcl parasitics/Parasitics.tcl power/Power.tcl sdf/Sdf.tcl + spice/WriteSpice.tcl verilog/Verilog.tcl ) @@ -258,8 +260,7 @@ set(STA_TCL_FILES # ################################################################ -# Earlier versions of flex use 'register' declarations that are deprecated -# in c++11 and illegal in c++17. +# Earlier versions of flex use 'register' declarations that are illegal in c++17. #find_package(FLEX 2.6.4) find_package(FLEX) find_package(BISON) @@ -431,6 +432,7 @@ set_property(SOURCE ${STA_SWIG_FILE} -I${STA_HOME}/dcalc -I${STA_HOME}/parasitics -I${STA_HOME}/power + -I${STA_HOME}/spice -I${STA_HOME}/verilog ) @@ -439,6 +441,7 @@ set(SWIG_FILES ${STA_HOME}/parasitics/Parasitics.i ${STA_HOME}/power/Power.i ${STA_HOME}/sdf/Sdf.i + ${STA_HOME}/spice/WriteSpice.i ${STA_HOME}/tcl/Exception.i ${STA_HOME}/tcl/StaTcl.i ${STA_HOME}/tcl/StaTclTypes.i @@ -559,7 +562,7 @@ target_compile_options(OpenSTA # Disable compiler specific extensions like gnu++11. set_target_properties(OpenSTA PROPERTIES CXX_EXTENSIONS OFF) -target_compile_features(OpenSTA PUBLIC cxx_std_11) +target_compile_features(OpenSTA PUBLIC cxx_std_17) ########################################################### # Executable diff --git a/README.md b/README.md index db16c0f0..33533b75 100644 --- a/README.md +++ b/README.md @@ -85,15 +85,15 @@ The build dependency versions are show below. Other versions may work, but these are the versions used for development. ``` - from Ubuntu Macos - 22.04.2 14.4.1 -cmake 3.10.2 3.24.2 3.29.2 -clang 9.1.0 15.0.0 -gcc 3.3.2 11.4.0 -tcl 8.4 8.6 8.6.6 -swig 1.3.28 4.1.0 4.2.1 -bison 1.35 3.8.2 3.8.2 -flex 2.5.4 2.6.4 2.6.4 + Ubuntu Macos + 22.04.2 14.5 +cmake 3.24.2 3.29.2 +clang 15.0.0 +gcc 11.4.0 +tcl 8.6 8.6.6 +swig 4.1.0 4.1.1 +bison 3.8.2 3.8.2 +flex 2.6.4 2.6.4 ``` Note that flex versions before 2.6.4 contain 'register' declarations that @@ -101,38 +101,47 @@ are illegal in c++17. External library dependencies: ``` - from Ubuntu Macos -eigen 3.4 .0 3.4.0 required -tclreadline 2.3.8 optional -libz 1.1.4 1.2.5 1.2.8 optional -cudd 2.4.1 3.0.0 optional + Ubuntu Macos +eigen 3.4.0 3.4.0 required +tclreadline 2.3.8 2.3.8 optional +libz 1.2.5 1.2.8 optional +cudd 3.0.0 3.0.0 optional ``` The [TCL readline library](https://tclreadline.sourceforge.net/tclreadline.html) links the GNU readline library to the TCL interpreter for command line editing On OSX, Homebrew does not support tclreadline, but the macports system does (see https://www.macports.org). To enable TCL readline support use the following -Cmake option: +Cmake option: See (https://tclreadline.sourceforge.net/) for TCL readline +documentation. To change the overly verbose default prompt, add something this +to your ~/.sta init file: ``` -cmake .. -DUSE_TCL_READLINE=ON +if { ![catch {package require tclreadline}] } { + proc tclreadline::prompt1 {} { + return "> " + } +} ``` The Zlib library is an optional. If CMake finds libz, OpenSTA can -read Verilog, SDF, SPF, and SPEF files compressed with gzip. +read Liberty, Verilog, SDF, SPF, and SPEF files compressed with gzip. CUDD is a binary decision diageram (BDD) package that is used to improve conditional timing arc handling. OpenSTA does not require it -to be installed. It is available +to be installed, but it improves constant propagation, power activity propagation +and spice netlist generation if it is installed. + +CUDD is available [here](https://www.davidkebo.com/source/cudd_versions/cudd-3.0.0.tar.gz) or [here](https://sourceforge.net/projects/cudd-mirror/). -Note that the file hierarchy of the CUDD installation changed with version 3.0. -Some changes to CMakeLists.txt are required to support older versions. +Use the CUDD_DIR option to set the install directory of the CUDD +library if it is not in one of the normal system install directories. -Use the USE_CUDD option to look for the cudd library. -Use the CUDD_DIR option to set the install directory if it is not in -one of the normal install directories. +``` +cmake -DCUDD_DIR=$HOME/stax/cudd-3.0.0 .." +``` When building CUDD you may use the `--prefix ` option to `configure` to install in a location other than the default (`/usr/local/lib`). diff --git a/app/Main.cc b/app/Main.cc index 9b45ae21..1a15e6c9 100644 --- a/app/Main.cc +++ b/app/Main.cc @@ -19,6 +19,7 @@ #include #include // exit +#include #include #if TCL_READLINE #include @@ -39,7 +40,6 @@ using sta::evalTclInit; using sta::sourceTclFile; using sta::parseThreadsArg; using sta::tcl_inits; -using sta::is_regular_file; // Swig uses C linkage for init functions. extern "C" { @@ -133,15 +133,15 @@ staTclAppInit(int argc, string init_path = home; init_path += "/"; init_path += init_filename; - if (is_regular_file(init_path.c_str())) + if (std::filesystem::is_regular_file(init_path.c_str())) sourceTclFile(init_path.c_str(), true, true, interp); } } bool exit_after_cmd_file = findCmdLineFlag(argc, argv, "-exit"); - if (argc > 2 || - (argc > 1 && argv[1][0] == '-')) { + if (argc > 2 + || (argc > 1 && argv[1][0] == '-')) { showUsage(argv[0], init_filename); exit(1); } diff --git a/app/StaApp.i b/app/StaApp.i index fde2e64d..a7594988 100644 --- a/app/StaApp.i +++ b/app/StaApp.i @@ -23,5 +23,6 @@ %include "NetworkEdit.i" %include "Sdf.i" %include "DelayCalc.i" +%include "WriteSpice.i" %include "Parasitics.i" %include "Power.i" diff --git a/app/StaMain.cc b/app/StaMain.cc index f78dfa3e..2805afbe 100644 --- a/app/StaMain.cc +++ b/app/StaMain.cc @@ -51,10 +51,11 @@ findCmdLineFlag(int &argc, for (int i = 1; i < argc; i++) { char *arg = argv[i]; if (stringEq(arg, flag)) { - // remove flag from argv. + // Remove flag from argv. for (int j = i + 1; j < argc; j++, i++) argv[i] = argv[j]; argc--; + argv[argc] = nullptr; return true; } } @@ -70,10 +71,11 @@ findCmdLineKey(int &argc, char *arg = argv[i]; if (stringEq(arg, key) && i + 1 < argc) { char *value = argv[i + 1]; - // remove key and value from argv. + // Remove key and value from argv. for (int j = i + 2; j < argc; j++, i++) argv[i] = argv[j]; argc -= 2; + argv[argc] = nullptr; return value; } } @@ -138,12 +140,4 @@ unencode(const char *inits[]) return unencoded; } -// Hack until c++17 filesystem is better supported. -bool -is_regular_file(const char *filename) -{ - struct stat sb; - return stat(filename, &sb) == 0 && S_ISREG(sb.st_mode); -} - } // namespace diff --git a/dcalc/ArcDcalcWaveforms.cc b/dcalc/ArcDcalcWaveforms.cc index 90f83b9c..02f14479 100644 --- a/dcalc/ArcDcalcWaveforms.cc +++ b/dcalc/ArcDcalcWaveforms.cc @@ -14,30 +14,64 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include + #include "ArcDcalcWaveforms.hh" +#include "Report.hh" +#include "Liberty.hh" +#include "Network.hh" +#include "Graph.hh" +#include "ArcDelayCalc.hh" +#include "DcalcAnalysisPt.hh" +#include "GraphDelayCalc.hh" namespace sta { -Table1 -ArcDcalcWaveforms::inputWaveform(const Pin *, - const RiseFall *, - const Corner *, - const MinMax *) -{ - return Table1(); -} +using std::make_shared; -Table1 -ArcDcalcWaveforms::drvrRampWaveform(const Pin *, - const RiseFall *, - const Pin *, - const RiseFall *, - const Pin *, - const Corner *, - const MinMax *) +Waveform +ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg, + const DcalcAnalysisPt *dcalc_ap, + const StaState *sta) { - return Table1(); + const Network *network = sta->network(); + Graph *graph = sta->graph(); + Report *report = sta->report(); + const Pin *in_pin = dcalc_arg.inPin(); + LibertyPort *port = network->libertyPort(in_pin); + if (port) { + const RiseFall *in_rf = dcalc_arg.inEdge(); + DriverWaveform *driver_waveform = port->driverWaveform(in_rf); + if (driver_waveform) { + const Vertex *in_vertex = graph->pinLoadVertex(in_pin); + GraphDelayCalc *graph_dcalc = sta->graphDelayCalc(); + Slew in_slew = graph_dcalc->edgeFromSlew(in_vertex, in_rf, + dcalc_arg.arc()->role(), dcalc_ap); + LibertyLibrary *library = port->libertyLibrary(); + float vdd; + 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(in_slew); + // Delay time axis. + FloatSeq *time_values = new FloatSeq; + for (float time : *in_waveform.axis1()->values()) + time_values->push_back(time + dcalc_arg.inputDelay()); + TableAxisPtr time_axis = make_shared(TableAxisVariable::time, time_values); + // Scale the waveform from 0:vdd. + FloatSeq *scaled_values = new FloatSeq; + for (float value : *in_waveform.values()) { + float scaled_value = (in_rf == RiseFall::rise()) + ? value * vdd + : (1.0 - value) * vdd; + scaled_values->push_back(scaled_value); + } + return Waveform(scaled_values, time_axis); + } + } + return Waveform(); } } // namespace diff --git a/dcalc/ArcDcalcWaveforms.hh b/dcalc/ArcDcalcWaveforms.hh index 7015a27a..62343183 100644 --- a/dcalc/ArcDcalcWaveforms.hh +++ b/dcalc/ArcDcalcWaveforms.hh @@ -22,37 +22,25 @@ namespace sta { +class StaState; class Corner; class DcalcAnalysisPt; +class ArcDcalcArg; -// Abstract class for the graph delay calculator traversal to interface +// Abstract class for delay calculation waveforms for ploting. class ArcDcalcWaveforms { public: - virtual Table1 inputWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Corner *corner, - const MinMax *min_max); - virtual Table1 drvrWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Corner *corner, - const MinMax *min_max) = 0; - virtual Table1 loadWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) = 0; - virtual Table1 drvrRampWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max); + // Record waveform for drvr/load pin. + virtual void watchPin(const Pin *pin) = 0; + virtual void clearWatchPins() = 0; + virtual PinSeq watchPins() const = 0; + virtual Waveform watchWaveform(const Pin *pin) = 0; + +protected: + Waveform inputWaveform(ArcDcalcArg &dcalc_arg, + const DcalcAnalysisPt *dcalc_ap, + const StaState *sta); }; } // namespace diff --git a/dcalc/ArcDelayCalc.cc b/dcalc/ArcDelayCalc.cc index ee94eee0..e318fa56 100644 --- a/dcalc/ArcDelayCalc.cc +++ b/dcalc/ArcDelayCalc.cc @@ -16,9 +16,11 @@ #include "ArcDelayCalc.hh" +#include "Units.hh" #include "Liberty.hh" #include "TimingArc.hh" #include "Network.hh" +#include "Graph.hh" namespace sta { @@ -48,12 +50,67 @@ ArcDelayCalc::gateDelay(const TimingArc *arc, //////////////////////////////////////////////////////////////// +ArcDcalcArg +makeArcDcalcArg(const char *inst_name, + const char *in_port_name, + const char *in_rf_name, + const char *drvr_port_name, + const char *drvr_rf_name, + const char *input_delay_str, + const StaState *sta) +{ + Report *report = sta->report(); + const Network *network = sta->sdcNetwork(); + const Instance *inst = network->findInstance(inst_name); + if (inst) { + const Pin *in_pin = network->findPin(inst, in_port_name); + if (in_pin) { + const RiseFall *in_rf = RiseFall::find(in_rf_name); + if (in_rf) { + const Pin *drvr_pin = network->findPin(inst, drvr_port_name); + if (drvr_pin) { + const RiseFall *drvr_rf = RiseFall::find(drvr_rf_name); + if (drvr_rf) { + float input_delay = strtof(input_delay_str, nullptr); + input_delay = sta->units()->timeUnit()->userToSta(input_delay); + + const Graph *graph = sta->graph(); + Edge *edge; + const TimingArc *arc; + graph->gateEdgeArc(in_pin, in_rf, drvr_pin, drvr_rf, edge, arc); + if (edge) + return ArcDcalcArg(in_pin, drvr_pin, edge, arc, input_delay); + else { + const Network *network = sta->network(); + const Instance *inst = network->instance(in_pin); + report->warn(2100, "no timing arc for %s input/driver pins.", + network->pathName(inst)); + } + } + else + report->warn(2101, "%s not a valid rise/fall.", drvr_rf_name); + } + else + report->warn(2102, "Pin %s/%s not found.", inst_name, drvr_port_name); + } + else + report->warn(2103, "%s not a valid rise/fall.", in_rf_name); + } + else + report->warn(2104, "Pin %s/%s not found.", inst_name, in_port_name); + } + else + report->warn(2105, "Instance %s not found.", inst_name); + return ArcDcalcArg(); +} + ArcDcalcArg::ArcDcalcArg() : in_pin_(nullptr), drvr_pin_(nullptr), edge_(nullptr), arc_(nullptr), in_slew_(0.0), + load_cap_(0.0), parasitic_(nullptr), input_delay_(0.0) { @@ -64,12 +121,14 @@ ArcDcalcArg::ArcDcalcArg(const Pin *in_pin, Edge *edge, const TimingArc *arc, const Slew in_slew, + float load_cap, const Parasitic *parasitic) : in_pin_(in_pin), drvr_pin_(drvr_pin), edge_(edge), arc_(arc), in_slew_(in_slew), + load_cap_(load_cap), parasitic_(parasitic), input_delay_(0.0) { @@ -85,6 +144,7 @@ ArcDcalcArg::ArcDcalcArg(const Pin *in_pin, edge_(edge), arc_(arc), in_slew_(0.0), + load_cap_(0.0), parasitic_(nullptr), input_delay_(input_delay) { @@ -96,6 +156,7 @@ ArcDcalcArg::ArcDcalcArg(const ArcDcalcArg &arg) : edge_(arg.edge_), arc_(arg.arc_), in_slew_(arg.in_slew_), + load_cap_(arg.load_cap_), parasitic_(arg.parasitic_), input_delay_(arg.input_delay_) { @@ -107,6 +168,12 @@ ArcDcalcArg::inEdge() const return arc_->fromEdge()->asRiseFall(); } +Vertex * +ArcDcalcArg::drvrVertex(const Graph *graph) const +{ + return edge_->to(graph); +} + LibertyCell * ArcDcalcArg::drvrCell() const { @@ -150,6 +217,18 @@ ArcDcalcArg::setParasitic(const Parasitic *parasitic) parasitic_ = parasitic; } +void +ArcDcalcArg::setLoadCap(float load_cap) +{ + load_cap_ = load_cap; +} + +void +ArcDcalcArg::setInputDelay(float input_delay) +{ + input_delay_ = input_delay; +} + //////////////////////////////////////////////////////////////// ArcDcalcResult::ArcDcalcResult() : diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc index 20f8d9e5..38e976e2 100644 --- a/dcalc/ArnoldiDelayCalc.cc +++ b/dcalc/ArnoldiDelayCalc.cc @@ -115,6 +115,7 @@ public: ArnoldiDelayCalc(StaState *sta); virtual ~ArnoldiDelayCalc(); ArcDelayCalc *copy() override; + const char *name() const override { return "arnoldi"; } Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; @@ -382,7 +383,7 @@ ArnoldiDelayCalc::gateDelay(const Pin *drvr_pin, ConcreteParasitic *cparasitic = reinterpret_cast(const_cast(parasitic)); rcmodel_ = dynamic_cast(cparasitic); - GateTableModel *table_model = gateTableModel(arc, dcalc_ap); + GateTableModel *table_model = arc->gateTableModel(dcalc_ap); if (table_model && rcmodel_) { const Pvt *pvt = pinPvt(drvr_pin, dcalc_ap); return gateDelaySlew(drvr_cell, arc, table_model, in_slew, load_pin_index_map, pvt); diff --git a/dcalc/CcsCeffDelayCalc.cc b/dcalc/CcsCeffDelayCalc.cc index a9680b49..45fe8fff 100644 --- a/dcalc/CcsCeffDelayCalc.cc +++ b/dcalc/CcsCeffDelayCalc.cc @@ -52,6 +52,7 @@ CcsCeffDelayCalc::CcsCeffDelayCalc(StaState *sta) : // Includes the Vh:Vdd region. region_count_(0), vl_fail_(false), + watch_pin_values_(network_), capacitance_unit_(units_->capacitanceUnit()), table_dcalc_(makeDmpCeffElmoreDelayCalc(sta)) { @@ -82,7 +83,7 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin, parasitic_ = parasitic; output_waveforms_ = nullptr; - GateTableModel *table_model = gateTableModel(arc, dcalc_ap); + GateTableModel *table_model = arc->gateTableModel(dcalc_ap); if (table_model && parasitic) { OutputWaveforms *output_waveforms = table_model->outputWaveforms(); parasitics_->piModel(parasitic, c2_, rpi_, c1_); @@ -95,25 +96,25 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin, bool vdd_exists; LibertyCell *drvr_cell = arc->to()->libertyCell(); const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); - const RiseFall *rf = arc->toEdge()->asRiseFall(); + 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()); - vth_ = drvr_library->outputThreshold(rf) * vdd_; - vl_ = drvr_library->slewLowerThreshold(rf) * vdd_; - vh_ = drvr_library->slewUpperThreshold(rf) * vdd_; + vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_; + vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_; + vh_ = drvr_library->slewUpperThreshold(drvr_rf_) * vdd_; - drvr_cell->ensureVoltageWaveforms(); + drvr_cell->ensureVoltageWaveforms(dcalc_ap); 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(), - rf->asString()); + drvr_rf_->asString()); ArcDelay gate_delay; Slew drvr_slew; - gateDelaySlew(drvr_library, rf, gate_delay, drvr_slew); - return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map); + gateDelaySlew(drvr_library, drvr_rf_, gate_delay, drvr_slew); + 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, @@ -312,9 +313,7 @@ CcsCeffDelayCalc::makeResult(const LibertyLibrary *drvr_library, dcalc_result.setGateDelay(gate_delay); dcalc_result.setDrvrSlew(drvr_slew); - 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; + for (const auto [load_pin, load_idx] : load_pin_index_map) { ArcDelay wire_delay; Slew load_slew; loadDelaySlew(load_pin, drvr_library, rf, drvr_slew, wire_delay, load_slew); @@ -466,69 +465,75 @@ CcsCeffDelayCalc::findVlTime(double v, // Waveform accessors for swig/tcl. -Table1 -CcsCeffDelayCalc::drvrWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Corner *corner, - const MinMax *min_max) +void +CcsCeffDelayCalc::watchPin(const Pin *pin) { - bool dcalc_success = makeWaveformPreamble(in_pin, in_rf, drvr_pin, - drvr_rf, corner, min_max); - if (dcalc_success) - return drvrWaveform(in_slew_, drvr_rf); + watch_pin_values_[pin] = FloatSeq(); +} + +void +CcsCeffDelayCalc::clearWatchPins() +{ + watch_pin_values_.clear(); +} + +PinSeq +CcsCeffDelayCalc::watchPins() const +{ + PinSeq pins; + for (const auto& [pin, values] : watch_pin_values_) + pins.push_back(pin); + return pins; +} + +Waveform +CcsCeffDelayCalc::watchWaveform(const Pin *pin) +{ + if (pin == drvr_pin_) + return drvrWaveform(); + else + return loadWaveform(pin); +} + +Waveform +CcsCeffDelayCalc::drvrWaveform() +{ + if (output_waveforms_) { + // Stitch together the ccs waveforms for each region. + FloatSeq *drvr_times = new FloatSeq; + FloatSeq *drvr_volts = new FloatSeq; + for (size_t i = 0; i < region_count_; i++) { + double t1 = region_begin_times_[i]; + double t2 = region_end_times_[i]; + size_t time_steps = 10; + double time_step = (t2 - t1) / time_steps; + double time_offset = region_time_offsets_[i]; + for (size_t s = 0; s <= time_steps; s++) { + double t = t1 + s * time_step; + drvr_times->push_back(t - time_offset); + double v = output_waveforms_->timeVoltage(in_slew_, region_ceff_[i], t); + if (drvr_rf_ == RiseFall::fall()) + v = vdd_ - v; + drvr_volts->push_back(v); + } + } + TableAxisPtr drvr_time_axis = make_shared(TableAxisVariable::time, + drvr_times); + Table1 drvr_table(drvr_volts, drvr_time_axis); + return drvr_table; + } else return Table1(); } -Table1 -CcsCeffDelayCalc::drvrWaveform(const Slew &in_slew, - const RiseFall *drvr_rf) +Waveform +CcsCeffDelayCalc::loadWaveform(const Pin *load_pin) { - // Stitch together the ccs waveforms for each region. - FloatSeq *drvr_times = new FloatSeq; - FloatSeq *drvr_volts = new FloatSeq; - for (size_t i = 0; i < region_count_; i++) { - double t1 = region_begin_times_[i]; - double t2 = region_end_times_[i]; - size_t time_steps = 10; - double time_step = (t2 - t1) / time_steps; - double time_offset = region_time_offsets_[i]; - for (size_t s = 0; s <= time_steps; s++) { - double t = t1 + s * time_step; - drvr_times->push_back(t - time_offset); - double v = output_waveforms_->timeVoltage(delayAsFloat(in_slew), - region_ceff_[i], t); - if (drvr_rf == RiseFall::fall()) - v = vdd_ - v; - drvr_volts->push_back(v); - } - } - TableAxisPtr drvr_time_axis = make_shared(TableAxisVariable::time, - drvr_times); - Table1 drvr_table(drvr_volts, drvr_time_axis); - return drvr_table; -} - -// For debugging -Table1 -CcsCeffDelayCalc::loadWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) -{ - bool elmore_exists = false; - float elmore = 0.0; - if (parasitic_) { + if (output_waveforms_) { + bool elmore_exists = false; + float elmore = 0.0; parasitics_->findElmore(parasitic_, load_pin, elmore, elmore_exists); - bool dcalc_success = makeWaveformPreamble(in_pin, in_rf, drvr_pin, - drvr_rf, corner, min_max); - if (dcalc_success - && elmore_exists) { + if (elmore_exists) { FloatSeq *load_times = new FloatSeq; FloatSeq *load_volts = new FloatSeq; double t_vh = findVlTime(vh_, elmore); @@ -540,7 +545,7 @@ CcsCeffDelayCalc::loadWaveform(const Pin *in_pin, double ignore; vl(t, elmore, v, ignore); - double v1 = (drvr_rf == RiseFall::rise()) ? v : vdd_ - v; + double v1 = (drvr_rf_ == RiseFall::rise()) ? v : vdd_ - v; load_volts->push_back(v1); } TableAxisPtr load_time_axis = make_shared(TableAxisVariable::time, @@ -552,7 +557,7 @@ CcsCeffDelayCalc::loadWaveform(const Pin *in_pin, return Table1(); } -Table1 +Waveform CcsCeffDelayCalc::drvrRampWaveform(const Pin *in_pin, const RiseFall *in_rf, const Pin *drvr_pin, diff --git a/dcalc/CcsCeffDelayCalc.hh b/dcalc/CcsCeffDelayCalc.hh index 35094007..924cbd5a 100644 --- a/dcalc/CcsCeffDelayCalc.hh +++ b/dcalc/CcsCeffDelayCalc.hh @@ -23,15 +23,19 @@ namespace sta { using std::vector; +typedef map WatchPinValuesMap; + ArcDelayCalc * makeCcsCeffDelayCalc(StaState *sta); -class CcsCeffDelayCalc : public LumpedCapDelayCalc, public ArcDcalcWaveforms +class CcsCeffDelayCalc : public LumpedCapDelayCalc, + public ArcDcalcWaveforms { public: CcsCeffDelayCalc(StaState *sta); virtual ~CcsCeffDelayCalc(); ArcDelayCalc *copy() override; + const char *name() const override { return "ccs_ceff"; } ArcDcalcResult gateDelay(const Pin *drvr_pin, const TimingArc *arc, @@ -49,26 +53,11 @@ public: const DcalcAnalysisPt *dcalc_ap, int digits) override; - Table1 drvrWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Corner *corner, - const MinMax *min_max) override; - Table1 loadWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) override; - Table1 drvrRampWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) override; + // Record waveform for drvr/load pin. + void watchPin(const Pin *pin) override; + void clearWatchPins() override; + PinSeq watchPins() const override; + Waveform watchWaveform(const Pin *pin) override; protected: typedef vector Region; @@ -99,14 +88,23 @@ protected: // Return values. ArcDelay &delay, Slew &slew); + double findVlTime(double v, + double elmore); bool makeWaveformPreamble(const Pin *in_pin, const RiseFall *in_rf, const Pin *drvr_pin, const RiseFall *drvr_rf, const Corner *corner, const MinMax *min_max); - double findVlTime(double v, - double elmore); + Waveform drvrWaveform(); + Waveform loadWaveform(const Pin *load_pin); + Waveform drvrRampWaveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Pin *load_pin, + const Corner *corner, + const MinMax *min_max); void vl(double t, double elmore, // Return values. @@ -114,11 +112,10 @@ protected: double &dvl_dt); double vl(double t, double elmore); - Table1 drvrWaveform(const Slew &in_slew, - const RiseFall *drvr_rf); void fail(const char *reason); const Pin *drvr_pin_; + const RiseFall *drvr_rf_; double in_slew_; double load_cap_; const Parasitic *parasitic_; @@ -148,6 +145,8 @@ protected: Region region_ramp_times_; Region region_ramp_slopes_; bool vl_fail_; + // Waveform recording. + WatchPinValuesMap watch_pin_values_; const Unit *capacitance_unit_; // Delay calculator to use when ccs waveforms are missing from liberty. diff --git a/dcalc/CcsSimDelayCalc.cc b/dcalc/CcsSimDelayCalc.cc index 6b1de326..c6cf5c2d 100644 --- a/dcalc/CcsSimDelayCalc.cc +++ b/dcalc/CcsSimDelayCalc.cc @@ -23,7 +23,6 @@ #include "TimingArc.hh" #include "Liberty.hh" #include "Sdc.hh" -#include "Parasitics.hh" #include "DcalcAnalysisPt.hh" #include "Network.hh" #include "Corner.hh" @@ -31,14 +30,14 @@ #include "GraphDelayCalc.hh" #include "DmpDelayCalc.hh" +// Lawrence Pillage - “Electronic Circuit & System Simulation Methods” 1998 +// McGraw-Hill, Inc. New York, NY. + namespace sta { using std::abs; using std::make_shared; -// Lawrence Pillage - “Electronic Circuit & System Simulation Methods” 1998 -// McGraw-Hill, Inc. New York, NY. - ArcDelayCalc * makeCcsSimDelayCalc(StaState *sta) { @@ -51,9 +50,8 @@ CcsSimDelayCalc::CcsSimDelayCalc(StaState *sta) : load_pin_index_map_(network_), dcalc_failed_(false), pin_node_map_(network_), - make_waveforms_(false), - waveform_drvr_pin_(nullptr), - waveform_load_pin_(nullptr), + node_index_map_(ParasiticNodeLess(parasitics_, network_)), + watch_pin_values_(network_), table_dcalc_(makeDmpCeffElmoreDelayCalc(sta)) { } @@ -114,9 +112,7 @@ CcsSimDelayCalc::inputPortDelay(const Pin *drvr_pin, pi_elmore = parasitics_->findPiElmore(drvr_pin, rf, ap); } - 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; + for (const auto [load_pin, load_idx] : load_pin_index_map) { ArcDelay wire_delay = 0.0; Slew load_slew = in_slew; bool elmore_exists = false; @@ -143,22 +139,19 @@ CcsSimDelayCalc::gateDelay(const Pin *drvr_pin, const DcalcAnalysisPt *dcalc_ap) { ArcDcalcArgSeq dcalc_args; - dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, parasitic); - ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_cap, - load_pin_index_map, dcalc_ap); + dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, load_cap, parasitic); + ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_pin_index_map, dcalc_ap); return dcalc_results[0]; } ArcDcalcResultSeq CcsSimDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, - float load_cap, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) { dcalc_args_ = &dcalc_args; load_pin_index_map_ = load_pin_index_map; drvr_count_ = dcalc_args.size(); - load_cap_ = load_cap; dcalc_ap_ = dcalc_ap; drvr_rf_ = dcalc_args[0].arc()->toEdge()->asRiseFall(); dcalc_failed_ = false; @@ -171,14 +164,14 @@ CcsSimDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, for (size_t drvr_idx = 0; drvr_idx < dcalc_args.size(); drvr_idx++) { ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx]; - GateTableModel *table_model = gateTableModel(dcalc_arg.arc(), dcalc_ap); + GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(dcalc_ap); if (table_model && dcalc_arg.parasitic()) { OutputWaveforms *output_waveforms = table_model->outputWaveforms(); - float in_slew = delayAsFloat(dcalc_arg.inSlew()); + float in_slew = dcalc_arg.inSlewFlt(); if (output_waveforms // Bounds check because extrapolating waveforms does not work for shit. && output_waveforms->slewAxis()->inBounds(in_slew) - && output_waveforms->capAxis()->inBounds(load_cap)) { + && output_waveforms->capAxis()->inBounds(dcalc_arg.loadCap())) { output_waveforms_[drvr_idx] = output_waveforms; ref_time_[drvr_idx] = output_waveforms->referenceTime(in_slew); debugPrint(debug_, "ccs_dcalc", 1, "%s %s", @@ -191,7 +184,7 @@ CcsSimDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, drvr_library->supplyVoltage("VDD", vdd_, vdd_exists); if (!vdd_exists) report_->error(1720, "VDD not defined in library %s", drvr_library->name()); - drvr_cell->ensureVoltageWaveforms(); + drvr_cell->ensureVoltageWaveforms(dcalc_ap); if (drvr_idx == 0) { vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_; vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_; @@ -220,8 +213,7 @@ CcsSimDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, dcalc_arg.setParasitic(pi_elmore); } } - dcalc_results = table_dcalc_->gateDelays(dcalc_args, load_cap, - load_pin_index_map, dcalc_ap); + dcalc_results = table_dcalc_->gateDelays(dcalc_args, load_pin_index_map, dcalc_ap); } else { simulate(dcalc_args); @@ -245,9 +237,7 @@ CcsSimDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, delayAsString(drvr_slew, this)); dcalc_result.setLoadCount(load_pin_index_map.size()); - 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; + for (const auto [load_pin, load_idx] : load_pin_index_map) { size_t load_node = pin_node_map_[load_pin]; ThresholdTimes &wire_times = threshold_times_[load_node]; ThresholdTimes &drvr_times = threshold_times_[drvr_node]; @@ -291,10 +281,10 @@ CcsSimDelayCalc::simulate(ArcDcalcArgSeq &dcalc_args) for (size_t drvr_idx = 0; drvr_idx < dcalc_args.size(); drvr_idx++) { ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx]; // Find initial ceff. - ceff_[drvr_idx] = load_cap_; + ceff_[drvr_idx] = dcalc_arg.loadCap(); // voltageTime is always for a rising waveform so 0.0v is initial voltage. drvr_current_[drvr_idx] = - output_waveforms_[drvr_idx]->voltageCurrent(delayAsFloat(dcalc_arg.inSlew()), + output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(), ceff_[drvr_idx], 0.0); } // Initial time depends on ceff which impact delay, so use a sim step @@ -310,8 +300,7 @@ CcsSimDelayCalc::simulate(ArcDcalcArgSeq &dcalc_args) // Limit in case load voltage waveforms don't get to final value. double time_end = time_begin + maxTime(); - if (make_waveforms_) - recordWaveformStep(time_begin); + recordWaveformStep(time_begin); for (double time = time_begin; time <= time_end; time += time_step_) { stampConductances(); @@ -328,12 +317,10 @@ CcsSimDelayCalc::simulate(ArcDcalcArgSeq &dcalc_args) updateCeffIdrvr(); measureThresholds(time); - if (make_waveforms_) - recordWaveformStep(time); + recordWaveformStep(time); bool loads_finished = true; - for (auto load_node1 : pin_node_map_) { - size_t load_node = load_node1.second; + for (const auto [load, load_node] : pin_node_map_) { if ((drvr_rf_ == RiseFall::rise() && voltages_[load_node] < vh_ + (vdd_ - vh_) * .5) || (drvr_rf_ == RiseFall::fall() @@ -356,14 +343,14 @@ double CcsSimDelayCalc::timeStep() { // Needs to use LTE for time step dynamic control. - return drive_resistance_ * load_cap_ * .02; + return drive_resistance_ * (*dcalc_args_)[0].loadCap() * .02; } double CcsSimDelayCalc::maxTime() { return (*dcalc_args_)[0].inSlewFlt() - + (drive_resistance_ + resistance_sum_) * load_cap_ * 2; + + (drive_resistance_ + resistance_sum_) * (*dcalc_args_)[0].loadCap() * 2; } void @@ -383,9 +370,6 @@ CcsSimDelayCalc::initSim() // Reset waveform recording. times_.clear(); - drvr_voltages_.clear(); - load_voltages_.clear(); - measure_thresholds_ = {vl_, vth_, vh_}; } @@ -406,7 +390,7 @@ CcsSimDelayCalc::findNodeCount() const Pin *pin = parasitics_->pin(node); if (pin) { pin_node_map_[pin] = node_idx; - debugPrint(debug_, "ccs_dcalc", 1, "pin %s node %lu", + debugPrint(debug_, "ccs_dcalc", 1, "pin %s node %zu", network_->pathName(pin), node_idx); } @@ -660,10 +644,8 @@ CcsSimDelayCalc::updateCeffIdrvr() void CcsSimDelayCalc::measureThresholds(double time) { - for (auto pin_node1 : pin_node_map_) { - size_t pin_node = pin_node1.second; - measureThresholds(time, pin_node); - } + for (const auto [pin, node] : pin_node_map_) + measureThresholds(time, node); } void @@ -677,7 +659,7 @@ CcsSimDelayCalc::measureThresholds(double time, 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", + debugPrint(debug_, "ccs_measure", 1, "node %zu cross %.2f %s", n, th, delayAsString(t_cross, this)); @@ -689,12 +671,13 @@ CcsSimDelayCalc::measureThresholds(double time, void CcsSimDelayCalc::recordWaveformStep(double time) { - times_.push_back(time); - size_t drvr_node = pin_node_map_[waveform_drvr_pin_]; - drvr_voltages_.push_back(voltages_[drvr_node]); - if (waveform_load_pin_) { - size_t load_node = pin_node_map_[waveform_load_pin_]; - load_voltages_.push_back(voltages_[load_node]); + if (!watch_pin_values_.empty()) { + times_.push_back(time); + for (auto& [pin, waveform] : watch_pin_values_) { + size_t node = pin_node_map_[pin]; + double pin_v = voltages_[node]; + waveform.push_back(pin_v); + } } } @@ -710,7 +693,7 @@ CcsSimDelayCalc::reportGateDelay(const Pin *drvr_pin, const DcalcAnalysisPt *dcalc_ap, int digits) { - GateTimingModel *model = gateModel(arc, dcalc_ap); + GateTableModel *model = arc->gateTableModel(dcalc_ap); if (model) { float in_slew1 = delayAsFloat(in_slew); return model->reportGateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, load_cap, @@ -721,92 +704,39 @@ CcsSimDelayCalc::reportGateDelay(const Pin *drvr_pin, //////////////////////////////////////////////////////////////// -// Waveform accessors for swig/tcl. -Table1 -CcsSimDelayCalc::drvrWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Corner *corner, - const MinMax *min_max) +void +CcsSimDelayCalc::watchPin(const Pin *pin) { - makeWaveforms(in_pin, in_rf, drvr_pin, drvr_rf, nullptr, corner, min_max); - TableAxisPtr time_axis = make_shared(TableAxisVariable::time, - new FloatSeq(times_)); - Table1 waveform(new FloatSeq(drvr_voltages_), time_axis); - return waveform; -} - -Table1 -CcsSimDelayCalc::loadWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) -{ - makeWaveforms(in_pin, in_rf, drvr_pin, drvr_rf, load_pin, corner, min_max); - TableAxisPtr time_axis = make_shared(TableAxisVariable::time, - new FloatSeq(times_)); - Table1 waveform(new FloatSeq(load_voltages_), time_axis); - return waveform; -} - -Table1 -CcsSimDelayCalc::inputWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Corner *corner, - const MinMax *min_max) -{ - LibertyPort *port = network_->libertyPort(in_pin); - if (port) { - DriverWaveform *driver_waveform = port->driverWaveform(in_rf); - const Vertex *in_vertex = graph_->pinLoadVertex(in_pin); - DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); - float in_slew = delayAsFloat(graph_->slew(in_vertex, in_rf, dcalc_ap->index())); - LibertyLibrary *library = port->libertyLibrary(); - float vdd; - bool vdd_exists; - library->supplyVoltage("VDD", vdd, vdd_exists); - if (!vdd_exists) - report_->error(1721, "VDD not defined in library %s", library->name()); - Table1 in_waveform = driver_waveform->waveform(in_slew); - // Scale the waveform from 0:vdd. - FloatSeq *scaled_values = new FloatSeq; - for (float value : *in_waveform.values()) - scaled_values->push_back(value * vdd); - return Table1(scaled_values, in_waveform.axis1ptr()); - } - return Table1(); + watch_pin_values_[pin] = FloatSeq(); } void -CcsSimDelayCalc::makeWaveforms(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) +CcsSimDelayCalc::clearWatchPins() { - Edge *edge; - const TimingArc *arc; - graph_->gateEdgeArc(in_pin, in_rf, drvr_pin, drvr_rf, edge, arc); - if (arc) { - DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); - const Parasitic *parasitic = findParasitic(drvr_pin, drvr_rf, dcalc_ap); - if (parasitic) { - make_waveforms_ = true; - waveform_drvr_pin_ = drvr_pin; - waveform_load_pin_ = load_pin; - Vertex *drvr_vertex = graph_->pinDrvrVertex(drvr_pin); - graph_delay_calc_->findDriverArcDelays(drvr_vertex, edge, arc, dcalc_ap, this); - make_waveforms_ = false; - waveform_drvr_pin_ = nullptr; - waveform_load_pin_ = nullptr; - } + watch_pin_values_.clear(); +} + +PinSeq +CcsSimDelayCalc::watchPins() const +{ + PinSeq pins; + for (const auto& [pin, values] : watch_pin_values_) + pins.push_back(pin); + return pins; +} + +Waveform +CcsSimDelayCalc::watchWaveform(const Pin *pin) +{ + for (ArcDcalcArg &dcalc_arg : *dcalc_args_) { + if (dcalc_arg.inPin() == pin) + return inputWaveform(dcalc_arg, dcalc_ap_, this); } + FloatSeq &voltages = watch_pin_values_[pin]; + TableAxisPtr time_axis = make_shared(TableAxisVariable::time, + new FloatSeq(times_)); + Table1 waveform(new FloatSeq(voltages), time_axis); + return waveform; } //////////////////////////////////////////////////////////////// diff --git a/dcalc/CcsSimDelayCalc.hh b/dcalc/CcsSimDelayCalc.hh index 5f000472..da4cf51a 100644 --- a/dcalc/CcsSimDelayCalc.hh +++ b/dcalc/CcsSimDelayCalc.hh @@ -20,6 +20,7 @@ #include #include +#include "Parasitics.hh" #include "LumpedCapDelayCalc.hh" #include "ArcDcalcWaveforms.hh" @@ -39,19 +40,22 @@ using Eigen::Index; using Eigen::SparseLU; typedef Map PinNodeMap; -typedef Map NodeIndexMap; +typedef map NodeIndexMap; typedef Map PortIndexMap; typedef SparseMatrix MatrixSd; +typedef map WatchPinValuesMap; ArcDelayCalc * makeCcsSimDelayCalc(StaState *sta); -class CcsSimDelayCalc : public DelayCalcBase, public ArcDcalcWaveforms +class CcsSimDelayCalc : public DelayCalcBase, + public ArcDcalcWaveforms { public: CcsSimDelayCalc(StaState *sta); ~CcsSimDelayCalc(); ArcDelayCalc *copy() override; + const char *name() const override { return "ccs_sim"; } Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; @@ -73,7 +77,6 @@ public: const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) override; ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args, - float load_cap, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) override; string reportGateDelay(const Pin *drvr_pin, @@ -85,23 +88,11 @@ public: const DcalcAnalysisPt *dcalc_ap, int digits) override; - Table1 inputWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Corner *corner, - const MinMax *min_max) override; - Table1 drvrWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Corner *corner, - const MinMax *min_max) override; - Table1 loadWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) override; + // Record waveform for drvr/load pin. + void watchPin(const Pin *pin) override; + void clearWatchPins() override; + PinSeq watchPins() const override; + Waveform watchWaveform(const Pin *pin) override; protected: void simulate(ArcDcalcArgSeq &dcalc_args); @@ -145,13 +136,7 @@ protected: ArcDelay &delay, Slew &slew); void recordWaveformStep(double time); - void makeWaveforms(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max); + void reportMatrix(const char *name, MatrixSd &matrix); void reportMatrix(const char *name, @@ -167,7 +152,6 @@ protected: ArcDcalcArgSeq *dcalc_args_; size_t drvr_count_; - float load_cap_; const DcalcAnalysisPt *dcalc_ap_; const Parasitic *parasitic_network_; const RiseFall *drvr_rf_; @@ -205,11 +189,7 @@ protected: SparseLU solver_; // Waveform recording. - bool make_waveforms_; - const Pin *waveform_drvr_pin_; - const Pin *waveform_load_pin_; - FloatSeq drvr_voltages_; - FloatSeq load_voltages_; + WatchPinValuesMap watch_pin_values_; FloatSeq times_; size_t drvr_idx_; diff --git a/dcalc/DelayCalc.cc b/dcalc/DelayCalc.cc index b6ce0b50..9c6a1dda 100644 --- a/dcalc/DelayCalc.cc +++ b/dcalc/DelayCalc.cc @@ -82,10 +82,8 @@ StringSeq delayCalcNames() { StringSeq names; - for (auto name_dcalc : *delay_calcs) { - const char *name = name_dcalc.first; + for (const auto [name, make_dcalc] : *delay_calcs) names.push_back(name); - } return names; } diff --git a/dcalc/DelayCalc.i b/dcalc/DelayCalc.i index efd55ae0..c2dfe68b 100644 --- a/dcalc/DelayCalc.i +++ b/dcalc/DelayCalc.i @@ -62,88 +62,4 @@ report_delay_calc_cmd(Edge *edge, return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits); } -//////////////////////////////////////////////////////////////// - -Table1 -ccs_input_waveform(const Pin *in_pin, - const RiseFall *in_rf, - const Corner *corner, - const MinMax *min_max) -{ - cmdLinkedNetwork(); - Sta *sta = Sta::sta(); - ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc()); - if (arc_dcalc) - return arc_dcalc->inputWaveform(in_pin, in_rf, corner, min_max); - else - return Table1(); -} - -Table1 -ccs_driver_waveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Corner *corner, - const MinMax *min_max) -{ - cmdLinkedNetwork(); - Sta *sta = Sta::sta(); - ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc()); - if (arc_dcalc) - return arc_dcalc->drvrWaveform(in_pin, in_rf, drvr_pin, drvr_rf, corner, min_max); - else - return Table1(); -} - -Table1 -ccs_driver_ramp_waveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) -{ - cmdLinkedNetwork(); - Sta *sta = Sta::sta(); - ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc()); - if (arc_dcalc) - return arc_dcalc->drvrRampWaveform(in_pin, in_rf, drvr_pin, drvr_rf, - load_pin, corner, min_max); - else - return Table1(); -} - -Table1 -ccs_load_waveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) -{ - cmdLinkedNetwork(); - Sta *sta = Sta::sta(); - ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc()); - if (arc_dcalc) - return arc_dcalc->loadWaveform(in_pin, in_rf, drvr_pin, drvr_rf, - load_pin, corner, min_max); - else - return Table1(); -} - -void -set_prima_reduce_order(size_t order) -{ - cmdLinkedNetwork(); - Sta *sta = Sta::sta(); - PrimaDelayCalc *dcalc = dynamic_cast(sta->arcDelayCalc()); - if (dcalc) { - dcalc->setPrimaReduceOrder(order); - sta->delaysInvalid(); - } -} - %} // inline diff --git a/dcalc/DelayCalc.tcl b/dcalc/DelayCalc.tcl index 5ab60ff0..9709a85e 100644 --- a/dcalc/DelayCalc.tcl +++ b/dcalc/DelayCalc.tcl @@ -148,17 +148,17 @@ proc set_assigned_delay { args } { if [info exists keys(-from)] { set from_pins [get_port_pins_error "from_pins" $keys(-from)] } else { - sta_error 181 ""set_assigned_delay" missing -from argument." + sta_error 181 "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 182 "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 183 "set_assigned_delay delay is not a float." } set delay [time_ui_sta $delay] @@ -283,7 +283,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 192 "set_assigned_check check_value is not a float." } set check_value [time_ui_sta $check_value] diff --git a/dcalc/DelayCalcBase.cc b/dcalc/DelayCalcBase.cc index a878e551..074a506a 100644 --- a/dcalc/DelayCalcBase.cc +++ b/dcalc/DelayCalcBase.cc @@ -22,9 +22,11 @@ #include "TableModel.hh" #include "Network.hh" #include "Parasitics.hh" +#include "Graph.hh" #include "Sdc.hh" #include "Corner.hh" #include "DcalcAnalysisPt.hh" +#include "GraphDelayCalc.hh" namespace sta { @@ -64,36 +66,6 @@ DelayCalcBase::reduceParasitic(const Parasitic *parasitic_network, delete pin_iter; } -TimingModel * -DelayCalcBase::model(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const -{ - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); - const TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex()); - return corner_arc->model(op_cond); -} - -GateTimingModel * -DelayCalcBase::gateModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const -{ - return dynamic_cast(model(arc, dcalc_ap)); -} - -GateTableModel * -DelayCalcBase::gateTableModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const -{ - return dynamic_cast(model(arc, dcalc_ap)); -} - -CheckTimingModel * -DelayCalcBase::checkModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const -{ - return dynamic_cast(model(arc, dcalc_ap)); -} - void DelayCalcBase::finishDrvrPin() { @@ -182,7 +154,7 @@ DelayCalcBase::checkDelay(const Pin *check_pin, float related_out_cap, const DcalcAnalysisPt *dcalc_ap) { - CheckTimingModel *model = checkModel(arc, dcalc_ap); + CheckTimingModel *model = arc->checkModel(dcalc_ap); if (model) { float from_slew1 = delayAsFloat(from_slew); float to_slew1 = delayAsFloat(to_slew); @@ -203,7 +175,7 @@ DelayCalcBase::reportCheckDelay(const Pin *check_pin, const DcalcAnalysisPt *dcalc_ap, int digits) { - CheckTimingModel *model = checkModel(arc, dcalc_ap); + CheckTimingModel *model = arc->checkModel(dcalc_ap); if (model) { float from_slew1 = delayAsFloat(from_slew); float to_slew1 = delayAsFloat(to_slew); @@ -225,4 +197,33 @@ DelayCalcBase::pinPvt(const Pin *pin, return pvt; } +void +DelayCalcBase::setDcalcArgParasiticSlew(ArcDcalcArg &gate, + const DcalcAnalysisPt *dcalc_ap) +{ + const Pin *drvr_pin = gate.drvrPin(); + if (drvr_pin) { + const Parasitic *parasitic; + float load_cap; + graph_delay_calc_->parasiticLoad(drvr_pin, gate.drvrEdge(), dcalc_ap, + nullptr, this, load_cap, + parasitic); + gate.setLoadCap(load_cap); + gate.setParasitic(parasitic); + const Pin *in_pin = gate.inPin(); + const Vertex *in_vertex = graph_->pinLoadVertex(in_pin); + const Slew &in_slew = graph_delay_calc_->edgeFromSlew(in_vertex, gate.inEdge(), + gate.edge(), dcalc_ap); + gate.setInSlew(in_slew); + } +} + +void +DelayCalcBase::setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates, + const DcalcAnalysisPt *dcalc_ap) +{ + for (ArcDcalcArg &gate : gates) + setDcalcArgParasiticSlew(gate, dcalc_ap); +} + } // namespace diff --git a/dcalc/DelayCalcBase.hh b/dcalc/DelayCalcBase.hh index 76137d0b..1726d8b0 100644 --- a/dcalc/DelayCalcBase.hh +++ b/dcalc/DelayCalcBase.hh @@ -22,6 +22,7 @@ namespace sta { class GateTableModel; +// ArcDelayCalc helper functions. class DelayCalcBase : public ArcDelayCalc { public: @@ -32,7 +33,10 @@ public: const Net *net, const Corner *corner, const MinMaxAll *min_max) override; - + void setDcalcArgParasiticSlew(ArcDcalcArg &gate, + const DcalcAnalysisPt *dcalc_ap) override; + void setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates, + const DcalcAnalysisPt *dcalc_ap) override; ArcDelay checkDelay(const Pin *check_pin, const TimingArc *arc, const Slew &from_slew, @@ -50,14 +54,6 @@ public: int digits) override; protected: - GateTimingModel *gateModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const; - GateTableModel *gateTableModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const; - CheckTimingModel *checkModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const; - TimingModel *model(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const; // Find the liberty library to use for logic/slew thresholds. LibertyLibrary *thresholdLibrary(const Pin *load_pin); // Adjust load_delay and load_slew from driver thresholds to load thresholds. diff --git a/dcalc/DmpCeff.cc b/dcalc/DmpCeff.cc index 70cf302f..c75b4990 100644 --- a/dcalc/DmpCeff.cc +++ b/dcalc/DmpCeff.cc @@ -1501,7 +1501,7 @@ DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin, const LibertyCell *drvr_cell = arc->from()->libertyCell(); const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); - GateTableModel *table_model = gateTableModel(arc, dcalc_ap); + GateTableModel *table_model = arc->gateTableModel(dcalc_ap); if (table_model && parasitic) { float in_slew1 = delayAsFloat(in_slew); float c2, rpi, c1; @@ -1516,9 +1516,7 @@ DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin, dcalc_result.setGateDelay(gate_delay); dcalc_result.setDrvrSlew(drvr_slew); - 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; + for (const auto [load_pin, load_idx] : load_pin_index_map) { ArcDelay wire_delay; Slew load_slew; loadDelaySlew(load_pin, drvr_slew, rf, drvr_library, parasitic, @@ -1595,7 +1593,7 @@ DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin, int digits) { gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, load_pin_index_map, dcalc_ap); - GateTimingModel *model = gateModel(arc, dcalc_ap); + GateTableModel *model = arc->gateTableModel(dcalc_ap); float c_eff = 0.0; string result; if (parasitic && dmp_alg_) { diff --git a/dcalc/DmpDelayCalc.cc b/dcalc/DmpDelayCalc.cc index 8006a0f8..9745a0cc 100644 --- a/dcalc/DmpDelayCalc.cc +++ b/dcalc/DmpDelayCalc.cc @@ -36,6 +36,7 @@ class DmpCeffElmoreDelayCalc : public DmpCeffDelayCalc public: DmpCeffElmoreDelayCalc(StaState *sta); ArcDelayCalc *copy() override; + const char *name() const override { return "dmp_ceff_elmore"; } ArcDcalcResult inputPortDelay(const Pin *port_pin, float in_slew, const RiseFall *rf, @@ -81,9 +82,7 @@ DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *, { ArcDcalcResult dcalc_result(load_pin_index_map.size()); LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); - 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; + for (auto [load_pin, load_idx] : load_pin_index_map) { ArcDelay wire_delay = 0.0; Slew load_slew = in_slew; bool elmore_exists = false; @@ -130,6 +129,7 @@ class DmpCeffTwoPoleDelayCalc : public DmpCeffDelayCalc public: DmpCeffTwoPoleDelayCalc(StaState *sta); ArcDelayCalc *copy() override; + const char *name() const override { return "dmp_ceff_two_pole"; } Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; @@ -257,9 +257,7 @@ DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *, ArcDelay wire_delay = 0.0; Slew load_slew = in_slew; LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); - 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; + for (const auto [load_pin, load_idx] : load_pin_index_map) { if (parasitics_->isPiPoleResidue(parasitic)) { const Parasitic *pole_residue = parasitics_->findPoleResidue(parasitic, load_pin); if (pole_residue) { diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 159d868c..25405f34 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -366,12 +366,12 @@ GraphDelayCalc::seedNoDrvrCellSlew(Vertex *drvr_vertex, float drive_res; drive->driveResistance(rf, cnst_min_max, drive_res, exists); const Parasitic *parasitic; - float cap; + float load_cap; parasiticLoad(drvr_pin, rf, dcalc_ap, nullptr, arc_delay_calc, - cap, parasitic); + load_cap, parasitic); if (exists) { - drive_delay = cap * drive_res; - slew = cap * drive_res; + drive_delay = load_cap * drive_res; + slew = load_cap * drive_res; } const MinMax *slew_min_max = dcalc_ap->slewMinMax(); if (!drvr_vertex->slewAnnotated(rf, slew_min_max)) @@ -912,8 +912,7 @@ GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex, edge, arc, dcalc_ap, arc_delay_calc); ArcDcalcResultSeq dcalc_results = - arc_delay_calc->gateDelays(dcalc_args, load_cap, load_pin_index_map, - dcalc_ap); + arc_delay_calc->gateDelays(dcalc_args, load_pin_index_map, dcalc_ap); for (size_t drvr_idx = 0; drvr_idx < dcalc_args.size(); drvr_idx++) { ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx]; ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx]; @@ -963,9 +962,12 @@ GraphDelayCalc::makeArcDcalcArgs(Vertex *drvr_vertex, const RiseFall *drvr_rf = arc1->toEdge()->asRiseFall(); const Slew in_slew = edgeFromSlew(from_vertex, from_rf, edge1, dcalc_ap); const Pin *drvr_pin1 = drvr_vertex1->pin(); - Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin1, drvr_rf, - dcalc_ap); - dcalc_args.emplace_back(from_pin, drvr_pin1, edge1, arc1, in_slew, parasitic); + float load_cap; + const Parasitic *parasitic; + parasiticLoad(drvr_pin1, drvr_rf, dcalc_ap, multi_drvr, arc_delay_calc, + load_cap, parasitic); + dcalc_args.emplace_back(from_pin, drvr_pin1, edge1, arc1, in_slew, + load_cap, parasitic); } } return dcalc_args; @@ -1061,7 +1063,7 @@ GraphDelayCalc::annotateDelaySlew(Edge *edge, // Merge slews. const Slew &drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index); const MinMax *slew_min_max = dcalc_ap->slewMinMax(); - if (delayGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax(), this) + if (delayGreater(gate_slew, drvr_slew, slew_min_max, this) && !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max) && !edge->role()->isLatchDtoQ()) graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew); @@ -1380,14 +1382,23 @@ GraphDelayCalc::initWireDelays(Vertex *drvr_vertex) } } -// Use clock slew for register/latch clk->q edges. Slew GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex, const RiseFall *from_rf, const Edge *edge, const DcalcAnalysisPt *dcalc_ap) { - const TimingRole *role = edge->role(); + return edgeFromSlew(from_vertex, from_rf, edge->role(), dcalc_ap); +} + +// Use clock slew for register/latch clk->q edges. +Slew +GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex, + const RiseFall *from_rf, + const TimingRole *role, + const DcalcAnalysisPt *dcalc_ap) +{ + if (role->genericRole() == TimingRole::regClkToQ() && clk_network_->isIdealClock(from_vertex->pin())) return clk_network_->idealClkSlew(from_vertex->pin(), from_rf, diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc index 67cecec0..a06853bd 100644 --- a/dcalc/LumpedCapDelayCalc.cc +++ b/dcalc/LumpedCapDelayCalc.cc @@ -122,7 +122,7 @@ LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) { - GateTimingModel *model = gateModel(arc, dcalc_ap); + GateTimingModel *model = arc->gateModel(dcalc_ap); debugPrint(debug_, "delay_calc", 3, " in_slew = %s load_cap = %s lumped", delayAsString(in_slew, this), @@ -155,9 +155,7 @@ LumpedCapDelayCalc::makeResult(const LibertyLibrary *drvr_library, dcalc_result.setGateDelay(gate_delay); dcalc_result.setDrvrSlew(drvr_slew); - 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; + for (const auto [load_pin, load_idx] : load_pin_index_map) { ArcDelay wire_delay = 0.0; thresholdAdjust(load_pin, drvr_library, rf, wire_delay, drvr_slew); dcalc_result.setWireDelay(load_idx, wire_delay); @@ -176,7 +174,7 @@ LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin, const DcalcAnalysisPt *dcalc_ap, int digits) { - GateTimingModel *model = gateModel(arc, dcalc_ap); + GateTimingModel *model = arc->gateModel(dcalc_ap); if (model) { float in_slew1 = delayAsFloat(in_slew); return model->reportGateDelay(pinPvt(check_pin, dcalc_ap), in_slew1, load_cap, diff --git a/dcalc/LumpedCapDelayCalc.hh b/dcalc/LumpedCapDelayCalc.hh index b62a2faf..331d2e81 100644 --- a/dcalc/LumpedCapDelayCalc.hh +++ b/dcalc/LumpedCapDelayCalc.hh @@ -27,6 +27,7 @@ class LumpedCapDelayCalc : public ParallelDelayCalc public: LumpedCapDelayCalc(StaState *sta); ArcDelayCalc *copy() override; + const char *name() const override { return "lumped_cap"; } Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; diff --git a/dcalc/ParallelDelayCalc.cc b/dcalc/ParallelDelayCalc.cc index 732a239f..2648797c 100644 --- a/dcalc/ParallelDelayCalc.cc +++ b/dcalc/ParallelDelayCalc.cc @@ -33,26 +33,24 @@ ParallelDelayCalc::ParallelDelayCalc(StaState *sta): ArcDcalcResultSeq ParallelDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, - float load_cap, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) { if (dcalc_args.size() == 1) { ArcDcalcArg &dcalc_arg = dcalc_args[0]; ArcDcalcResult dcalc_result = gateDelay(dcalc_arg.drvrPin(), dcalc_arg.arc(), - dcalc_arg.inSlew(), - load_cap, dcalc_arg.parasitic(), + dcalc_arg.inSlew(), dcalc_arg.loadCap(), + dcalc_arg.parasitic(), load_pin_index_map, dcalc_ap); ArcDcalcResultSeq dcalc_results; dcalc_results.push_back(dcalc_result); return dcalc_results; } - return gateDelaysParallel(dcalc_args, load_cap, load_pin_index_map, dcalc_ap); + return gateDelaysParallel(dcalc_args, load_pin_index_map, dcalc_ap); } ArcDcalcResultSeq ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args, - float load_cap, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) { @@ -74,7 +72,7 @@ ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args, ArcDelay intrinsic_delay = intrinsic_result.gateDelay(); intrinsic_delays[drvr_idx] = intrinsic_result.gateDelay(); - ArcDcalcResult gate_result = gateDelay(drvr_pin, arc, in_slew, load_cap, + ArcDcalcResult gate_result = gateDelay(drvr_pin, arc, in_slew, dcalc_arg.loadCap(), dcalc_arg.parasitic(), load_pin_index_map, dcalc_ap); ArcDelay gate_delay = gate_result.gateDelay(); @@ -88,8 +86,7 @@ ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args, slew_sum += 1.0 / drvr_slew; dcalc_result.setLoadCount(load_pin_index_map.size()); - for (auto load_pin_index : load_pin_index_map) { - size_t load_idx = load_pin_index.second; + for (const auto [load_pin, load_idx] : load_pin_index_map) { dcalc_result.setWireDelay(load_idx, gate_result.wireDelay(load_idx)); dcalc_result.setLoadSlew(load_idx, gate_result.loadSlew(load_idx)); } diff --git a/dcalc/ParallelDelayCalc.hh b/dcalc/ParallelDelayCalc.hh index 7f361218..06ddbda7 100644 --- a/dcalc/ParallelDelayCalc.hh +++ b/dcalc/ParallelDelayCalc.hh @@ -29,12 +29,10 @@ class ParallelDelayCalc : public DelayCalcBase public: ParallelDelayCalc(StaState *sta); ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args, - float load_cap, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) override; protected: ArcDcalcResultSeq gateDelaysParallel(ArcDcalcArgSeq &dcalc_args, - float load_cap, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap); }; diff --git a/dcalc/PrimaDelayCalc.cc b/dcalc/PrimaDelayCalc.cc index 681bf3e3..32f6cf9a 100644 --- a/dcalc/PrimaDelayCalc.cc +++ b/dcalc/PrimaDelayCalc.cc @@ -57,6 +57,7 @@ PrimaDelayCalc::PrimaDelayCalc(StaState *sta) : dcalc_args_(nullptr), load_pin_index_map_(nullptr), pin_node_map_(network_), + node_index_map_(ParasiticNodeLess(parasitics_, network_)), prima_order_(3), make_waveforms_(false), waveform_drvr_pin_(nullptr), @@ -71,6 +72,7 @@ PrimaDelayCalc::PrimaDelayCalc(const PrimaDelayCalc &dcalc) : dcalc_args_(nullptr), load_pin_index_map_(nullptr), pin_node_map_(network_), + node_index_map_(ParasiticNodeLess(parasitics_, network_)), prima_order_(dcalc.prima_order_), make_waveforms_(false), waveform_drvr_pin_(nullptr), @@ -184,22 +186,19 @@ PrimaDelayCalc::gateDelay(const Pin *drvr_pin, const DcalcAnalysisPt *dcalc_ap) { ArcDcalcArgSeq dcalc_args; - dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, parasitic); - ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_cap, - load_pin_index_map, dcalc_ap); + dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, load_cap, parasitic); + ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_pin_index_map, dcalc_ap); return dcalc_results[0]; } ArcDcalcResultSeq PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, - float load_cap, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) { dcalc_args_ = &dcalc_args; load_pin_index_map_ = &load_pin_index_map; drvr_count_ = dcalc_args.size(); - load_cap_ = load_cap; dcalc_ap_ = dcalc_ap; drvr_rf_ = dcalc_args[0].arc()->toEdge()->asRiseFall(); parasitic_network_ = dcalc_args[0].parasitic(); @@ -208,14 +207,14 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, output_waveforms_.resize(drvr_count_); for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) { ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx]; - GateTableModel *table_model = gateTableModel(dcalc_arg.arc(), dcalc_ap); + GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(dcalc_ap); if (table_model && dcalc_arg.parasitic()) { OutputWaveforms *output_waveforms = table_model->outputWaveforms(); Slew in_slew = dcalc_arg.inSlew(); if (output_waveforms // Bounds check because extrapolating waveforms does not work for shit. && output_waveforms->slewAxis()->inBounds(in_slew) - && output_waveforms->capAxis()->inBounds(load_cap)) { + && output_waveforms->capAxis()->inBounds(dcalc_arg.loadCap())) { output_waveforms_[drvr_idx] = output_waveforms; debugPrint(debug_, "ccs_dcalc", 1, "%s %s", dcalc_arg.drvrCell()->name(), @@ -226,7 +225,7 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, drvr_library->supplyVoltage("VDD", vdd_, vdd_exists); if (!vdd_exists) report_->error(1720, "VDD not defined in library %s", drvr_library->name()); - drvr_cell->ensureVoltageWaveforms(); + drvr_cell->ensureVoltageWaveforms(dcalc_ap); if (drvr_idx == 0) { vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_; vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_; @@ -241,7 +240,7 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, } if (failed) - return tableDcalcResults(load_cap); + return tableDcalcResults(); else { simulate(); return dcalcResults(); @@ -249,7 +248,7 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, } ArcDcalcResultSeq -PrimaDelayCalc::tableDcalcResults(float load_cap) +PrimaDelayCalc::tableDcalcResults() { for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) { ArcDcalcArg &dcalc_arg = (*dcalc_args_)[drvr_idx]; @@ -260,8 +259,7 @@ PrimaDelayCalc::tableDcalcResults(float load_cap) dcalc_arg.setParasitic(parasitic); } } - return table_dcalc_->gateDelays(*dcalc_args_, load_cap, *load_pin_index_map_, - dcalc_ap_); + return table_dcalc_->gateDelays(*dcalc_args_, *load_pin_index_map_, dcalc_ap_); } void @@ -904,7 +902,7 @@ PrimaDelayCalc::reportGateDelay(const Pin *drvr_pin, const DcalcAnalysisPt *dcalc_ap, int digits) { - GateTimingModel *model = gateModel(arc, dcalc_ap); + GateTimingModel *model = arc->gateModel(dcalc_ap); if (model) { float in_slew1 = delayAsFloat(in_slew); return model->reportGateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, load_cap, @@ -952,96 +950,6 @@ PrimaDelayCalc::watchWaveform(const Pin *pin) //////////////////////////////////////////////////////////////// -// Waveform accessors for swig/tcl. -Table1 -PrimaDelayCalc::drvrWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Corner *corner, - const MinMax *min_max) -{ - makeWaveforms(in_pin, in_rf, drvr_pin, drvr_rf, nullptr, corner, min_max); - TableAxisPtr time_axis = make_shared(TableAxisVariable::time, - new FloatSeq(times_)); - Table1 waveform(new FloatSeq(drvr_voltages_), time_axis); - return waveform; -} - -Table1 -PrimaDelayCalc::loadWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) -{ - makeWaveforms(in_pin, in_rf, drvr_pin, drvr_rf, load_pin, corner, min_max); - TableAxisPtr time_axis = make_shared(TableAxisVariable::time, - new FloatSeq(times_)); - Table1 waveform(new FloatSeq(load_voltages_), time_axis); - return waveform; -} - -Table1 -PrimaDelayCalc::inputWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Corner *corner, - const MinMax *min_max) -{ - LibertyPort *port = network_->libertyPort(in_pin); - if (port) { - DriverWaveform *driver_waveform = port->driverWaveform(in_rf); - const Vertex *in_vertex = graph_->pinLoadVertex(in_pin); - DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); - Slew in_slew = graph_->slew(in_vertex, in_rf, dcalc_ap->index()); - LibertyLibrary *library = port->libertyLibrary(); - float vdd; - bool vdd_exists; - library->supplyVoltage("VDD", vdd, vdd_exists); - if (!vdd_exists) - report_->error(1751, "VDD not defined in library %s", library->name()); - Table1 in_waveform = driver_waveform->waveform(in_slew); - // Scale the waveform from 0:vdd. - FloatSeq *scaled_values = new FloatSeq; - for (float value : *in_waveform.values()) - scaled_values->push_back(value * vdd); - return Table1(scaled_values, in_waveform.axis1ptr()); - } - return Table1(); -} - -void -PrimaDelayCalc::makeWaveforms(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) -{ - Edge *edge; - const TimingArc *arc; - graph_->gateEdgeArc(in_pin, in_rf, drvr_pin, drvr_rf, edge, arc); - if (arc) { - DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); - const Parasitic *parasitic = findParasitic(drvr_pin, drvr_rf, dcalc_ap); - if (parasitic) { - make_waveforms_ = true; - waveform_drvr_pin_ = drvr_pin; - waveform_load_pin_ = load_pin; - Vertex *drvr_vertex = graph_->pinDrvrVertex(drvr_pin); - graph_delay_calc_->findDriverArcDelays(drvr_vertex, edge, arc, dcalc_ap, this); - make_waveforms_ = false; - waveform_drvr_pin_ = nullptr; - waveform_load_pin_ = nullptr; - } - } -} - -//////////////////////////////////////////////////////////////// - void PrimaDelayCalc::reportMatrix(const char *name, MatrixSd &matrix) diff --git a/dcalc/PrimaDelayCalc.hh b/dcalc/PrimaDelayCalc.hh index 3cf2a779..a17a1f27 100644 --- a/dcalc/PrimaDelayCalc.hh +++ b/dcalc/PrimaDelayCalc.hh @@ -24,6 +24,7 @@ #include "Map.hh" #include "LumpedCapDelayCalc.hh" #include "ArcDcalcWaveforms.hh" +#include "Parasitics.hh" namespace sta { @@ -41,7 +42,7 @@ using Eigen::Index; using std::map; typedef Map PinNodeMap; -typedef Map NodeIndexMap; +typedef map NodeIndexMap; typedef Map PortIndexMap; typedef SparseMatrix MatrixSd; typedef Map PinLMap; @@ -61,6 +62,7 @@ public: ~PrimaDelayCalc(); ArcDelayCalc *copy() override; void copyState(const StaState *sta) override; + const char *name() const override { return "prima"; } void setPrimaReduceOrder(size_t order); Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, @@ -83,7 +85,6 @@ public: const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) override; ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args, - float load_cap, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) override; string reportGateDelay(const Pin *drvr_pin, @@ -96,31 +97,13 @@ public: int digits) override; // Record waveform for drvr/load pin. - void watchPin(const Pin *pin); - void clearWatchPins(); - PinSeq watchPins() const; - Waveform watchWaveform(const Pin *pin); + void watchPin(const Pin *pin) override; + void clearWatchPins() override; + PinSeq watchPins() const override; + Waveform watchWaveform(const Pin *pin) override; - Waveform inputWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Corner *corner, - const MinMax *min_max) override; - Waveform drvrWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Corner *corner, - const MinMax *min_max) override; - Waveform loadWaveform(const Pin *in_pin, - const RiseFall *in_rf, - const Pin *drvr_pin, - const RiseFall *drvr_rf, - const Pin *load_pin, - const Corner *corner, - const MinMax *min_max) override; - protected: - ArcDcalcResultSeq tableDcalcResults(float load_cap); + ArcDcalcResultSeq tableDcalcResults(); void simulate(); void simulate1(const MatrixSd &G, const MatrixSd &C, diff --git a/dcalc/UnitDelayCalc.cc b/dcalc/UnitDelayCalc.cc index 39c02fb5..76fc4a9c 100644 --- a/dcalc/UnitDelayCalc.cc +++ b/dcalc/UnitDelayCalc.cc @@ -62,6 +62,18 @@ UnitDelayCalc::reduceParasitic(const Parasitic *, { } +void +UnitDelayCalc::setDcalcArgParasiticSlew(ArcDcalcArg &, + const DcalcAnalysisPt *) +{ +} + +void +UnitDelayCalc::setDcalcArgParasiticSlew(ArcDcalcArgSeq &, + const DcalcAnalysisPt *) +{ +} + ArcDcalcResult UnitDelayCalc::inputPortDelay(const Pin *, float, @@ -87,7 +99,6 @@ UnitDelayCalc::gateDelay(const Pin *, ArcDcalcResultSeq UnitDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, - float, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *) { diff --git a/dcalc/UnitDelayCalc.hh b/dcalc/UnitDelayCalc.hh index 8d247f5d..04fae163 100644 --- a/dcalc/UnitDelayCalc.hh +++ b/dcalc/UnitDelayCalc.hh @@ -26,6 +26,7 @@ class UnitDelayCalc : public ArcDelayCalc public: UnitDelayCalc(StaState *sta); ArcDelayCalc *copy() override; + const char *name() const override { return "unit"; } Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; @@ -37,6 +38,10 @@ public: const Net *net, const Corner *corner, const MinMaxAll *min_max) override; + void setDcalcArgParasiticSlew(ArcDcalcArg &gate, + const DcalcAnalysisPt *dcalc_ap) override; + void setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates, + const DcalcAnalysisPt *dcalc_ap) override; ArcDcalcResult inputPortDelay(const Pin *port_pin, float in_slew, const RiseFall *rf, @@ -52,7 +57,6 @@ public: const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) override; ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args, - float load_cap, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) override; ArcDelay checkDelay(const Pin *check_pin, diff --git a/doc/ChangeLog.txt b/doc/ChangeLog.txt index 214fc9c0..20f440a9 100644 --- a/doc/ChangeLog.txt +++ b/doc/ChangeLog.txt @@ -3,6 +3,13 @@ OpenSTA Timing Analyzer Release Notes This file summarizes user visible changes for each release. +Release 2.6.0 2024/07/?? +------------------------- + +The version of c++ used by OpenSTA is now 17. + +The USE_CUDD and USE_TCL_READLINE options default to ON. + Release 2.5.0 2024/01/17 ------------------------- diff --git a/graph/Graph.cc b/graph/Graph.cc index 2e21e0a4..d30c464c 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -757,10 +757,8 @@ Graph::makeArcDelayTables(DcalcAPIndex ap_count) { if (have_arc_delays_) { arc_delays_.resize(ap_count); - for (DcalcAPIndex i = 0; i < ap_count; i++) { - DelayTable *table = new DelayTable(); - arc_delays_[i] = table; - } + for (DcalcAPIndex i = 0; i < ap_count; i++) + arc_delays_[i] = new DelayTable(); } } @@ -1041,7 +1039,7 @@ Graph::setPeriodCheckAnnotation(const Pin *pin, float period) { if (period_check_annotations_ == nullptr) - period_check_annotations_ = new PeriodCheckAnnotations; + period_check_annotations_ = new PeriodCheckAnnotations(network_); float *periods = period_check_annotations_->findKey(pin); if (periods == nullptr) { periods = new float[ap_count_]; @@ -1057,10 +1055,8 @@ void Graph::removePeriodCheckAnnotations() { if (period_check_annotations_) { - for (auto pin_floats : *period_check_annotations_) { - float *periods = pin_floats.second; + for (const auto [pin, periods] : *period_check_annotations_) delete [] periods; - } delete period_check_annotations_; period_check_annotations_ = nullptr; } diff --git a/graph/GraphCmp.cc b/graph/GraphCmp.cc index 6241c16d..a4ca3dd9 100644 --- a/graph/GraphCmp.cc +++ b/graph/GraphCmp.cc @@ -37,7 +37,7 @@ VertexNameLess::operator()(const Vertex *vertex1, //////////////////////////////////////////////////////////////// EdgeLess::EdgeLess(const Network *network, - Graph *graph) : + Graph *&graph) : pin_less_(network), graph_(graph) { diff --git a/include/sta/ArcDelayCalc.hh b/include/sta/ArcDelayCalc.hh index b826def6..b5179afd 100644 --- a/include/sta/ArcDelayCalc.hh +++ b/include/sta/ArcDelayCalc.hh @@ -40,6 +40,10 @@ class Corner; class Parasitic; class DcalcAnalysisPt; class MultiDrvrNet; +class ArcDcalcArg; + +typedef std::vector ArcDcalcArgPtrSeq; +typedef std::vector ArcDcalcArgSeq; // Driver load pin -> index in driver loads. typedef map LoadPinIndexMap; @@ -56,6 +60,7 @@ public: Edge *edge, const TimingArc *arc, const Slew in_slew, + float load_cap, const Parasitic *parasitic); ArcDcalcArg(const Pin *in_pin, const Pin *drvr_pin, @@ -65,6 +70,7 @@ public: const Pin *inPin() const { return in_pin_; } const RiseFall *inEdge() const; const Pin *drvrPin() const { return drvr_pin_; } + Vertex *drvrVertex(const Graph *graph) const; LibertyCell *drvrCell() const; const LibertyLibrary *drvrLibrary() const; const RiseFall *drvrEdge() const; @@ -74,9 +80,12 @@ public: Slew inSlew() const { return in_slew_; } float inSlewFlt() const; void setInSlew(Slew in_slew); - const Parasitic *parasitic() { return parasitic_; } + const Parasitic *parasitic() const { return parasitic_; } void setParasitic(const Parasitic *parasitic); + float loadCap() const { return load_cap_; } + void setLoadCap(float load_cap); float inputDelay() const { return input_delay_; } + void setInputDelay(float input_delay); protected: const Pin *in_pin_; @@ -84,10 +93,21 @@ protected: Edge *edge_; const TimingArc *arc_; Slew in_slew_; + float load_cap_; const Parasitic *parasitic_; float input_delay_; }; + +ArcDcalcArg +makeArcDcalcArg(const char *inst_name, + const char *in_port_name, + const char *in_rf_name, + const char *drvr_port_name, + const char *drvr_rf_name, + const char *input_delay_str, + const StaState *sta); + // Arc delay calc result. class ArcDcalcResult { @@ -127,6 +147,9 @@ typedef vector ArcDcalcResultSeq; // DmpCeffElmoreDelayCalc // DmpCeffTwoPoleDelayCalc // ArnoldiDelayCalc +// CcsCeffDelayCalc +// CcsSimfDelayCalc +// PrimafDelayCalc // Abstract class for the graph delay calculator traversal to interface // to a delay calculator primitive. @@ -136,6 +159,7 @@ public: explicit ArcDelayCalc(StaState *sta); virtual ~ArcDelayCalc() {} virtual ArcDelayCalc *copy() = 0; + virtual const char *name() const = 0; // Find the parasitic for drvr_pin that is acceptable to the delay // calculator by probing parasitics_. @@ -154,6 +178,11 @@ public: const Net *net, const Corner *corner, const MinMaxAll *min_max) = 0; + // Set the in_slew, load_cap, parasitic for gates. + virtual void setDcalcArgParasiticSlew(ArcDcalcArg &gate, + const DcalcAnalysisPt *dcalc_ap) = 0; + virtual void setDcalcArgParasiticSlew(ArcDcalcArgSeq &gates, + const DcalcAnalysisPt *dcalc_ap) = 0; // Find the wire delays and slews for an input port without a driving cell. // This call primarily initializes the load delay/slew iterator. virtual ArcDcalcResult inputPortDelay(const Pin *port_pin, @@ -172,6 +201,7 @@ public: const Parasitic *parasitic, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) = 0; + // deprecated 2024-02-27 virtual void gateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, @@ -185,7 +215,6 @@ public: // Find gate delays and slews for parallel gates. virtual ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args, - float load_cap, const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap) = 0; diff --git a/include/sta/EnumNameMap.hh b/include/sta/EnumNameMap.hh index e3f3172e..230cf8d0 100644 --- a/include/sta/EnumNameMap.hh +++ b/include/sta/EnumNameMap.hh @@ -49,8 +49,8 @@ template EnumNameMap::EnumNameMap(initializer_list> enum_names) : enum_map_(enum_names) { - for (auto iter = enum_map_.begin(); iter != enum_map_.end(); iter++) - name_map_[iter->second] = iter->first; + for (const auto& [key, name] : enum_map_) + name_map_[name] = key; } template diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index 8bf525bc..efa0637d 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -46,7 +46,7 @@ typedef ArrayTable RequiredsTable; typedef ArrayTable PrevPathsTable; typedef Map PinVertexMap; typedef Iterator VertexEdgeIterator; -typedef Map PeriodCheckAnnotations; +typedef Map PeriodCheckAnnotations; typedef Vector DelayTableSeq; typedef ObjectId EdgeId; typedef ObjectId ArrivalId; @@ -352,13 +352,13 @@ protected: EdgeId in_edges_; // Edges to this vertex. EdgeId out_edges_; // Edges from this vertex. - // 4 bytes + // 32 bits unsigned int tag_group_index_:tag_group_index_bits; // 24 // Each bit corresponds to a different BFS queue. unsigned int bfs_in_queue_:int(BfsIndex::bits); // 4 unsigned int slew_annotated_:slew_annotated_bits; - // 4 bytes (32 bits) + // 32 bits unsigned int level_:Graph::vertex_level_bits; // Levelization search state. // LevelColor gcc barfs if this is dcl'd. @@ -369,6 +369,8 @@ protected: // This flag distinguishes the driver and load vertices. bool is_bidirect_drvr_:1; bool is_reg_clk_:1; + + // 15 bits bool is_disabled_constraint_:1; bool is_gated_clk_enable_:1; // Constrained by timing check edge. @@ -379,7 +381,6 @@ protected: bool has_downstream_clk_pin_:1; bool crpr_path_pruning_disabled_:1; bool requireds_pruned_:1; - unsigned object_idx_:VertexTable::idx_bits; private: @@ -441,6 +442,7 @@ protected: EdgeId vertex_out_next_; // Vertex out edges doubly linked list. EdgeId vertex_out_prev_; ArcId arc_delays_; + // 16 bits bool delay_annotation_is_incremental_:1; bool is_bidirect_inst_path_:1; bool is_bidirect_net_path_:1; diff --git a/include/sta/GraphCmp.hh b/include/sta/GraphCmp.hh index 8753d69e..3ee38807 100644 --- a/include/sta/GraphCmp.hh +++ b/include/sta/GraphCmp.hh @@ -37,13 +37,13 @@ class EdgeLess { public: EdgeLess(const Network *network, - Graph *graph); + Graph *&graph); bool operator()(const Edge *edge1, const Edge *edge2) const; private: const PinPathNameLess pin_less_; - Graph *graph_; + Graph *&graph_; }; void diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh index e91fa00a..1ed9bea3 100644 --- a/include/sta/GraphDelayCalc.hh +++ b/include/sta/GraphDelayCalc.hh @@ -120,6 +120,10 @@ public: const RiseFall *from_rf, const Edge *edge, const DcalcAnalysisPt *dcalc_ap); + Slew edgeFromSlew(const Vertex *from_vertex, + const RiseFall *from_rf, + const TimingRole *role, + const DcalcAnalysisPt *dcalc_ap); protected: void seedInvalidDelays(); diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index 704cf8e5..f507c49e 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -73,7 +73,7 @@ typedef Map ScaledCellMap; typedef Map ScaledPortMap; typedef Map ModeDefMap; typedef Map ModeValueMap; -typedef Map LatchEnableMap; +typedef Map LatchEnableMap; typedef Vector LatchEnableSeq; typedef Map OcvDerateMap; typedef Vector InternalPowerAttrsSeq; @@ -473,10 +473,10 @@ public: bool hasInferedRegTimingArcs() const { return has_infered_reg_timing_arcs_; } TestCell *testCell() const { return test_cell_; } bool isLatchData(LibertyPort *port); - void latchEnable(TimingArcSet *arc_set, + void latchEnable(const TimingArcSet *arc_set, // Return values. - LibertyPort *&enable_port, - FuncExpr *&enable_func, + const LibertyPort *&enable_port, + const FuncExpr *&enable_func, const RiseFall *&enable_rf) const; const RiseFall *latchCheckEnableEdge(TimingArcSet *check_set); bool isDisabledConstraint() const { return is_disabled_constraint_; } @@ -532,7 +532,7 @@ public: // Check all liberty cells to make sure they exist // for all the defined corners. static void checkLibertyCorners(); - void ensureVoltageWaveforms(); + void ensureVoltageWaveforms(const DcalcAnalysisPt *dcalc_ap); protected: void addPort(ConcretePort *port); @@ -802,20 +802,20 @@ public: DriverWaveform *driverWaveform(const RiseFall *rf) const; void setDriverWaveform(DriverWaveform *driver_waveform, const RiseFall *rf); - void setClkTreeDelay(const TableModel *model, - const RiseFall *from_rf, - const RiseFall *to_rf, - const MinMax *min_max); - // Should be deprecated. - float clkTreeDelay(float in_slew, - const RiseFall *from_rf, - const MinMax *min_max) const; float clkTreeDelay(float in_slew, const RiseFall *from_rf, const RiseFall *to_rf, const MinMax *min_max) const; - // Assumes input slew of 0.0. - RiseFallMinMax clkTreeDelays() const; + float clkTreeDelay(float in_slew, + const RiseFall *from_rf, + const MinMax *min_max) const; + void setClkTreeDelay(const TableModel *model, + const RiseFall *from_rf, + const RiseFall *to_rf, + const MinMax *min_max); + // deprecated 2024-06-22 + RiseFallMinMax clkTreeDelays() const __attribute__ ((deprecated)); + // deprecated 2024-02-27 RiseFallMinMax clockTreePathDelays() const __attribute__ ((deprecated)); static bool equiv(const LibertyPort *port1, diff --git a/include/sta/Map.hh b/include/sta/Map.hh index 450a812e..5622579c 100644 --- a/include/sta/Map.hh +++ b/include/sta/Map.hh @@ -101,9 +101,7 @@ public: void deleteKeysContents() { - for (auto key_value : this) { - KEY key = key_value.first; - VALUE value = key_value.second; + for (const auto [key, value] : this) { delete key; delete value; } diff --git a/include/sta/MinMax.hh b/include/sta/MinMax.hh index f3d8eab9..e2c67c44 100644 --- a/include/sta/MinMax.hh +++ b/include/sta/MinMax.hh @@ -108,9 +108,9 @@ public: bool matches(const MinMax *min_max) const; bool matches(const MinMaxAll *min_max) const; static MinMaxAll *find(const char *min_max); - // for (auto min_max : min_max->range()) {} + // for (const auto min_max : min_max->range()) {} const std::vector &range() const { return range_; } - // for (auto mm_index : min_max->rangeIndex()) {} + // for (const auto mm_index : min_max->rangeIndex()) {} const std::vector &rangeIndex() const { return range_index_; } private: diff --git a/include/sta/Network.hh b/include/sta/Network.hh index 5f0f1e21..891919ec 100644 --- a/include/sta/Network.hh +++ b/include/sta/Network.hh @@ -513,6 +513,7 @@ public: LibertyPort *port, Net *net) = 0; // makePin/connectPin replaced by connect. + // deprecated 2018-09-28 virtual void connectPin(Pin *pin, Net *net) __attribute__ ((deprecated)); // Disconnect pin from net. diff --git a/include/sta/Parasitics.hh b/include/sta/Parasitics.hh index 52c6caa3..7cf45d33 100644 --- a/include/sta/Parasitics.hh +++ b/include/sta/Parasitics.hh @@ -175,6 +175,7 @@ public: // Find the parasitic node connected to pin. virtual ParasiticNode *findParasiticNode(const Parasitic *parasitic, const Pin *pin) const = 0; + // deprecated 2024-02-27 virtual ParasiticNode *findNode(const Parasitic *parasitic, const Pin *pin) const __attribute__ ((deprecated)); // Make a subnode of the parasitic network net connected to pin. @@ -188,6 +189,7 @@ public: virtual const Pin *pin(const ParasiticNode *node) const = 0; virtual const Net *net(const ParasiticNode *node, const Network *network) const = 0; + virtual unsigned netId(const ParasiticNode *node) const = 0; virtual bool isExternal(const ParasiticNode *node) const = 0; // Node capacitance to ground. virtual float nodeGndCap(const ParasiticNode *node) const = 0; @@ -308,4 +310,17 @@ private: float coupling_cap_factor_; }; +class ParasiticNodeLess +{ +public: + ParasiticNodeLess(const Parasitics *parasitics, + const Network *network); + ParasiticNodeLess(const ParasiticNodeLess &less); + bool operator()(const ParasiticNode *node1, + const ParasiticNode *node2) const; +private: + const Parasitics *parasitics_; + const Network *network_; +}; + } // namespace diff --git a/include/sta/PathEnd.hh b/include/sta/PathEnd.hh index 46a526a2..8c27be9a 100644 --- a/include/sta/PathEnd.hh +++ b/include/sta/PathEnd.hh @@ -136,7 +136,8 @@ public: virtual PathDelay *pathDelay() const; // This returns the crpr signed with respect to the check type. // Positive for setup, negative for hold. - virtual Crpr commonClkPessimism(const StaState *sta) const; + virtual Crpr checkCrpr(const StaState *sta) const; + virtual Crpr crpr(const StaState *sta) const; virtual MultiCyclePath *multiCyclePath() const; virtual TimingArc *checkArc() const { return nullptr; } // PathEndDataCheck data clock path. @@ -244,7 +245,7 @@ public: virtual float targetNonInterClkUncertainty(const StaState *sta) const; virtual float interClkUncertainty(const StaState *sta) const; virtual float targetClkUncertainty(const StaState *sta) const; - virtual Crpr commonClkPessimism(const StaState *sta) const; + virtual Crpr crpr(const StaState *sta) const; virtual Required requiredTime(const StaState *sta) const; virtual Slack slack(const StaState *sta) const; virtual Slack slackNoCrpr(const StaState *sta) const; @@ -426,7 +427,7 @@ public: virtual Arrival targetClkArrivalNoCrpr(const StaState *sta) const; virtual Delay targetClkDelay(const StaState *sta) const; virtual Delay targetClkInsertionDelay(const StaState *sta) const; - virtual Crpr commonClkPessimism(const StaState *sta) const; + virtual Crpr crpr(const StaState *sta) const; virtual int exceptPathCmp(const PathEnd *path_end, const StaState *sta) const; diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index 7d83ad18..945093ee 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -955,6 +955,13 @@ public: float &wire_cap, float &fanout, bool &has_net_load) const; + void pinCaps(const Pin *pin, + const RiseFall *rf, + const Corner *corner, + const MinMax *min_max, + float &pin_cap, + float &wire_cap, + float &fanout) const; void portExtFanout(const Port *port, const Corner *corner, const MinMax *min_max, @@ -1235,13 +1242,6 @@ protected: void annotateHierClkLatency(); void annotateHierClkLatency(const Pin *hpin, ClockLatency *latency); - void pinCaps(const Pin *pin, - const RiseFall *rf, - const Corner *corner, - const MinMax *min_max, - float &pin_cap, - float &wire_cap, - float &fanout) const; void netCaps(const Pin *drvr_pin, const RiseFall *rf, const Corner *corner, @@ -1256,7 +1256,8 @@ protected: const RiseFall *rf, const Corner *corner, const MinMax *min_max); - float portCapacitance(Instance *inst, LibertyPort *port, + float portCapacitance(Instance *inst, + LibertyPort *port, const RiseFall *rf, const Corner *corner, const MinMax *min_max) const; diff --git a/include/sta/SdcClass.hh b/include/sta/SdcClass.hh index 7ef169a7..8b30dca4 100644 --- a/include/sta/SdcClass.hh +++ b/include/sta/SdcClass.hh @@ -85,7 +85,7 @@ typedef MinMaxAll SetupHoldAll; typedef Vector ExceptionThruSeq; typedef Set LibertyPortPairSet; typedef Map DisabledInstancePortsMap; -typedef Map DisabledCellPortsMap; +typedef Map DisabledCellPortsMap; typedef MinMaxValues ClockUncertainties; typedef Set ExceptionPathSet; typedef PinPair EdgePins; diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 30debd8f..be39820b 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -28,6 +28,8 @@ #include "VertexVisitor.hh" #include "SearchClass.hh" #include "PowerClass.hh" +#include "ArcDelayCalc.hh" +#include "CircuitSim.hh" struct Tcl_Interp; @@ -773,7 +775,7 @@ public: const RiseFallBoth *rf, float slew); void writeSdf(const char *filename, - Corner *corner, + const Corner *corner, char divider, bool include_typ, int digits, @@ -938,7 +940,7 @@ public: // bug that should be reported. void updateTiming(bool full); // Invalidate all delay calculations. Arrivals also invalidated. - void delaysInvalid(); + void delaysInvalid() const; // Invalidate all arrival and required times. void arrivalsInvalid(); PinSet startpointPins(); @@ -1285,6 +1287,24 @@ public: const Corner *corner); PwrActivity findClkedActivity(const Pin *pin); + void writeGateSpice(ArcDcalcArgSeq gates, + const char *spice_filename, + const char *subckt_filename, + const char *lib_subckt_filename, + const char *model_filename, + const char *power_name, + const char *gnd_name, + CircuitSim ckt_sim, + const Corner *corner, + const MinMax *min_max); + void writeGateGnuplot(ArcDcalcArgSeq gates, + PinSet plot_pins, + const char *spice_waveform_filename, + const char *csv_filename, + const char *gnuplot_filename, + const Corner *corner, + const MinMax *min_max); + void writeTimingModel(const char *lib_name, const char *cell_name, const char *filename, diff --git a/include/sta/StaMain.hh b/include/sta/StaMain.hh index f576aa0a..66ae11a6 100644 --- a/include/sta/StaMain.hh +++ b/include/sta/StaMain.hh @@ -64,7 +64,5 @@ sourceTclFile(const char *filename, bool echo, bool verbose, Tcl_Interp *interp); -bool -is_regular_file(const char *filename); } // namespace diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index 7c29d7b8..31d4d165 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -39,6 +39,7 @@ class Table1; typedef Vector FloatSeq; typedef Vector FloatTable; typedef Vector Table1Seq; +typedef Table1 Waveform; TableAxisVariable stringTableAxisVariable(const char *variable); @@ -66,6 +67,7 @@ public: // 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, @@ -455,9 +457,10 @@ public: // Return values. size_t &index, bool &exists) const; + size_t findAxisClosestIndex(float value) const; FloatSeq *values() const { return values_; } - float min() const { return (*values_)[0]; } - float max() const { return (*values_)[values_->size() - 1]; } + float min() const; + float max() const; private: TableAxisVariable variable_; @@ -492,26 +495,43 @@ public: const RiseFall *rf() const { return rf_; } const TableAxis *slewAxis() const { return slew_axis_.get(); } const TableAxis *capAxis() const { return cap_axis_.get(); } - Table1 voltageWaveform(float in_slew, - float load_cap); - float voltageTime(float in_slew, - float load_cap, - float voltage); - const Table1 *currentWaveform(float slew, - float cap); + // Make voltage wavefroms from liberty time/current values. + // Required before voltageTime, timeVoltage, voltageCurrent. + void makeVoltageWaveforms(float vdd); float timeCurrent(float slew, float cap, float time); float timeVoltage(float slew, float cap, float time); + float voltageTime(float in_slew, + float load_cap, + float voltage); float voltageCurrent(float slew, float cap, float volt); float referenceTime(float slew); - void makeVoltageWaveforms(float vdd); + float beginTime(float slew, + float cap); + float endTime(float slew, + float cap); static bool checkAxes(const TableTemplate *tbl_template); + Table1 currentWaveform(float slew, + float cap); + // Waveform closest to slew/cap; no interpolation. + const Table1 *currentWaveformRaw(float slew, + float cap); + Table1 voltageWaveform(float in_slew, + float load_cap); + // Waveform closest to slew/cap; no interpolation. + const Table1 *voltageWaveformRaw(float slew, + float cap); + Table1 voltageCurrentWaveform(float slew, + float cap); + // V/I for last segment of min slew/max cap. + float finalResistance(); + private: void findVoltages(size_t wave_index, float cap); @@ -519,27 +539,30 @@ private: float cap, float axis_value, Table1Seq &waveforms); - float voltageTime1(float voltage, + float beginEndTime(float slew, + float cap, + bool begin); + double voltageTime1(double volt, + double dx1, + double dx2, + size_t wave_index00, + size_t wave_index01, + size_t wave_index10, + size_t wave_index11); + float voltageTime2(float volt, size_t wave_index); - void waveformMinMaxTime(float slew, - float cap, - Table1Seq &waveforms, - // Return values. - float &min_time, - float &max_time); // Row. TableAxisPtr slew_axis_; // Column. TableAxisPtr cap_axis_; const RiseFall *rf_; - Table1Seq current_waveforms_; + Table1Seq current_waveforms_; // from liberty Table1Seq voltage_waveforms_; Table1Seq voltage_currents_; - FloatTable voltage_times_; Table1 *ref_times_; float vdd_; - static constexpr size_t voltage_waveform_step_count_ = 20; + static constexpr size_t voltage_waveform_step_count_ = 100; }; class DriverWaveform diff --git a/include/sta/TimingArc.hh b/include/sta/TimingArc.hh index 87142e7a..bc593fa0 100644 --- a/include/sta/TimingArc.hh +++ b/include/sta/TimingArc.hh @@ -27,6 +27,8 @@ namespace sta { class TimingArcAttrs; class WireTimingArc; +class GateTableModel; +class DcalcAnalysisPt; typedef int TimingArcIndex; typedef Vector TimingArcSeq; @@ -147,7 +149,7 @@ public: TimingRole *role() const { return role_; }; TimingSense sense() const; // Rise/fall if the arc set is rising_edge or falling_edge. - RiseFall *isRisingFallingEdge() const; + const RiseFall *isRisingFallingEdge() const; size_t arcCount() const { return arcs_.size(); } TimingArcSeq &arcs() { return arcs_; } // Return 1 or 2 arcs matching from transition. @@ -235,8 +237,11 @@ public: TimingSense sense() const; // Index in TimingArcSet. unsigned index() const { return index_; } - TimingModel *model(const OperatingConditions *op_cond) const; TimingModel *model() const { return model_; } + GateTimingModel *gateModel(const DcalcAnalysisPt *dcalc_ap) const; + CheckTimingModel *checkModel(const DcalcAnalysisPt *dcalc_ap) const; + GateTableModel *gateTableModel() const; + GateTableModel *gateTableModel(const DcalcAnalysisPt *dcalc_ap) const; const TimingArc *cornerArc(int ap_index) const; void setCornerArc(TimingArc *corner_arc, int ap_index); @@ -247,6 +252,7 @@ public: const TimingArc *arc2); protected: + TimingModel *model(const DcalcAnalysisPt *dcalc_ap) const; void setIndex(unsigned index); void addScaledModel(const OperatingConditions *op_cond, TimingModel *scaled_model); diff --git a/include/sta/Transition.hh b/include/sta/Transition.hh index e4f3d44a..42baede9 100644 --- a/include/sta/Transition.hh +++ b/include/sta/Transition.hh @@ -97,9 +97,9 @@ public: RiseFall *asRiseFall() const { return as_rise_fall_; } // Find transition corresponding to string. static RiseFallBoth *find(const char *tr_str); - // for (auto tr : min_max->range()) {} + // for (const auto rf : rf->range()) {} const std::vector &range() const { return range_; } - // for (auto tr_index : min_max->rangeIndex()) {} + // for (const auto rf_index : rf->rangeIndex()) {} const std::vector &rangeIndex() const { return range_index_; } static const int index_count = 3; diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 1e39e7ee..5acdc63b 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -121,10 +121,8 @@ LibertyLibrary::~LibertyLibrary() delete units_; ocv_derate_map_.deleteContents(); - for (auto name_volt : supply_voltage_map_) { - const char *supply_name = name_volt.first; + for (auto [supply_name, volt] : supply_voltage_map_) stringDelete(supply_name); - } delete buffers_; delete inverters_; driver_waveform_map_.deleteContents(); @@ -204,8 +202,8 @@ BusDclSeq LibertyLibrary::busDcls() const { BusDclSeq dcls; - for (auto name_dcl : bus_dcls_) - dcls.push_back(name_dcl.second); + for (auto [name, dcl] : bus_dcls_) + dcls.push_back(dcl); return dcls; } @@ -228,10 +226,8 @@ LibertyLibrary::tableTemplates() const { TableTemplateSeq tbl_templates; for (int type = 0; type < table_template_type_count; type++) { - for (auto name_template : template_maps_[type]) { - TableTemplate *tbl_template = name_template.second; + for (auto [name, tbl_template] : template_maps_[type]) tbl_templates.push_back(tbl_template); - } } return tbl_templates; } @@ -1312,8 +1308,7 @@ LibertyCell::finish(bool infer_latches, void LibertyCell::findDefaultCondArcs() { - for (auto port_pair_set : port_timing_arc_set_map_) { - TimingArcSetSeq *sets = port_pair_set.second; + for (auto [port_pair, sets] : port_timing_arc_set_map_) { bool has_cond_arcs = false; for (auto set : *sets) { if (set->cond()) { @@ -1908,10 +1903,10 @@ LibertyCell::isLatchData(LibertyPort *port) } void -LibertyCell::latchEnable(TimingArcSet *d_to_q_set, +LibertyCell::latchEnable(const TimingArcSet *d_to_q_set, // Return values. - LibertyPort *&enable_port, - FuncExpr *&enable_func, + const LibertyPort *&enable_port, + const FuncExpr *&enable_func, const RiseFall *&enable_edge) const { LatchEnable *latch_enable = latch_d_to_q_map_.findKey(d_to_q_set); @@ -1938,7 +1933,7 @@ LibertyCell::latchCheckEnableEdge(TimingArcSet *check_set) } void -LibertyCell::ensureVoltageWaveforms() +LibertyCell::ensureVoltageWaveforms(const DcalcAnalysisPt *dcalc_ap) { if (!have_voltage_waveforms_) { float vdd = 0.0; // shutup gcc @@ -1948,7 +1943,7 @@ LibertyCell::ensureVoltageWaveforms() criticalError(1120, "library missing vdd"); for (TimingArcSet *arc_set : timingArcSets()) { for (TimingArc *arc : arc_set->arcs()) { - GateTableModel*model = dynamic_cast(arc->model()); + GateTableModel *model = arc->gateTableModel(dcalc_ap); if (model) { OutputWaveforms *output_waveforms = model->outputWaveforms(); if (output_waveforms) diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index ff63db88..a2123a68 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -695,22 +695,22 @@ LibertyReader::endLibraryAttrs(LibertyGroup *group) } bool missing_threshold = false; - for (auto tr : RiseFall::range()) { - int tr_index = tr->index(); - if (!have_input_threshold_[tr_index]) { - libWarn(1145, group, "input_threshold_pct_%s not found.", tr->name()); + for (auto rf : RiseFall::range()) { + int rf_index = rf->index(); + if (!have_input_threshold_[rf_index]) { + libWarn(1145, group, "input_threshold_pct_%s not found.", rf->name()); missing_threshold = true; } - if (!have_output_threshold_[tr_index]) { - libWarn(1146, group, "output_threshold_pct_%s not found.", tr->name()); + if (!have_output_threshold_[rf_index]) { + libWarn(1146, group, "output_threshold_pct_%s not found.", rf->name()); missing_threshold = true; } - if (!have_slew_lower_threshold_[tr_index]) { - libWarn(1147, group, "slew_lower_threshold_pct_%s not found.", tr->name()); + if (!have_slew_lower_threshold_[rf_index]) { + libWarn(1147, group, "slew_lower_threshold_pct_%s not found.", rf->name()); missing_threshold = true; } - if (!have_slew_upper_threshold_[tr_index]) { - libWarn(1148, group, "slew_upper_threshold_pct_%s not found.", tr->name()); + if (!have_slew_upper_threshold_[rf_index]) { + libWarn(1148, group, "slew_upper_threshold_pct_%s not found.", rf->name()); missing_threshold = true; } } @@ -5110,13 +5110,13 @@ LibertyReader::endOcvDerateFactors(LibertyGroup *) { if (ocv_derate_) { for (auto early_late : derate_type_->range()) { - for (auto tr : rf_type_->range()) { + for (auto rf : rf_type_->range()) { if (path_type_ == PathType::clk_and_data) { - ocv_derate_->setDerateTable(tr, early_late, PathType::clk, table_); - ocv_derate_->setDerateTable(tr, early_late, PathType::data, table_); + ocv_derate_->setDerateTable(rf, early_late, PathType::clk, table_); + ocv_derate_->setDerateTable(rf, early_late, PathType::data, table_); } else - ocv_derate_->setDerateTable(tr, early_late, path_type_, table_); + ocv_derate_->setDerateTable(rf, early_late, path_type_, table_); } } } diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index ab68dd72..21786e63 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -31,6 +31,9 @@ using std::max; using std::abs; using std::make_shared; +size_t +findValueIndex(float value, + const FloatSeq *values); static void deleteSigmaModels(TableModel *models[EarlyLate::index_count]); static string @@ -1425,6 +1428,25 @@ TableAxis::~TableAxis() delete values_; } +float +TableAxis::min() const +{ + if (!values_->empty()) + return (*values_)[0]; + else + return 0.0; +} + +float +TableAxis::max() const +{ + size_t size = values_->size(); + if (size > 0) + return (*values_)[values_->size() - 1]; + else + return 0.0; +} + bool TableAxis::inBounds(float value) const { @@ -1434,14 +1456,22 @@ TableAxis::inBounds(float value) const && value <= (*values_)[size - 1]; } -// Bisection search. size_t TableAxis::findAxisIndex(float value) const { - size_t size = values_->size(); - if (size <= 1 || value <= (*values_)[0]) + return findValueIndex(value, values_); +} + +// Bisection search. +// Assumes values are monotonically increasing. +size_t +findValueIndex(float value, + const FloatSeq *values) +{ + size_t size = values->size(); + if (size <= 1 || value <= (*values)[0]) return 0; - else if (value >= (*values_)[size - 1]) + else if (value >= (*values)[size - 1]) // Return max_index-1 for value too large so interpolation pts are index,index+1. return size - 2; else { @@ -1449,7 +1479,7 @@ TableAxis::findAxisIndex(float value) const int upper = size; while (upper - lower > 1) { int mid = (upper + lower) >> 1; - if (value >= (*values_)[mid]) + if (value >= (*values)[mid]) lower = mid; else upper = mid; @@ -1486,6 +1516,31 @@ TableAxis::findAxisIndex(float value, exists = false; } +size_t +TableAxis::findAxisClosestIndex(float value) const +{ + size_t size = values_->size(); + if (size <= 1 || value <= (*values_)[0]) + return 0; + else if (value >= (*values_)[size - 1]) + return size - 1; + else { + int lower = -1; + int upper = size; + while (upper - lower > 1) { + int mid = (upper + lower) >> 1; + if (value >= (*values_)[mid]) + lower = mid; + else + upper = mid; + } + if ((value - (*values_)[lower]) < ((*values_)[upper] - value)) + return lower; + else + return upper; + } +} + const char * TableAxis::variableString() const { @@ -1588,7 +1643,6 @@ OutputWaveforms::~OutputWaveforms() current_waveforms_.deleteContents(); voltage_waveforms_.deleteContents(); voltage_currents_.deleteContents(); - voltage_times_.deleteContents(); delete ref_times_; } @@ -1616,10 +1670,9 @@ OutputWaveforms::makeVoltageWaveforms(float vdd) size_t size = current_waveforms_.size(); voltage_waveforms_.resize(size); voltage_currents_.resize(size); - voltage_times_.resize(size); size_t cap_count = cap_axis_->size(); for (size_t slew_index = 0; slew_index < slew_axis_->size(); slew_index++) { - for (size_t cap_index = 0; cap_index < cap_axis_->size(); cap_index++) { + for (size_t cap_index = 0; cap_index < cap_count; cap_index++) { size_t wave_index = slew_index * cap_count + cap_index; findVoltages(wave_index, cap_axis_->axisValue(cap_index)); } @@ -1650,6 +1703,7 @@ OutputWaveforms::findVoltages(size_t wave_index, prev_time = time; prev_current = current; } + (*volts)[volts->size() - 1] = vdd_; Table1 *volt_table = new Table1(volts, currents->axis1ptr()); voltage_waveforms_[wave_index] = volt_table; @@ -1660,39 +1714,33 @@ OutputWaveforms::findVoltages(size_t wave_index, FloatSeq *currents1 = new FloatSeq(*currents->values()); Table1 *volt_currents = new Table1(currents1, volt_axis); voltage_currents_[wave_index] = volt_currents; - - // Sample the voltage waveform at uniform intervals to speed up - // voltage time lookup. - FloatSeq *voltage_times = new FloatSeq; - float volt_step = vdd_ / voltage_waveform_step_count_; - size_t i = 0; - float time0 = time_axis->axisValue(i); - float volt0 = (*volts)[i]; - i = 1; - float time1 = time_axis->axisValue(i); - float volt1 = (*volts)[i]; - for (size_t v = 0; v <= voltage_waveform_step_count_; v++) { - float volt3 = v * volt_step; - while (volt3 > volt1 && i < volts->size() - 1) { - time0 = time1; - volt0 = volt1; - i++; - time1 = time_axis->axisValue(i); - volt1 = (*volts)[i]; - } - float time3 = time0 + (time1 - time0) * (volt3 - volt0) / (volt1 - volt0); - voltage_times->push_back(time3); - } - voltage_times_[wave_index] = voltage_times; } -const Table1 * +Table1 OutputWaveforms::currentWaveform(float slew, float cap) { - size_t slew_index = slew_axis_->findAxisIndex(slew); - size_t cap_index = cap_axis_->findAxisIndex(cap); - size_t wave_index = slew_index * cap_axis_->size() + cap_index; + FloatSeq *times = new FloatSeq; + FloatSeq *currents = new FloatSeq; + for (size_t i = 0; i <= voltage_waveform_step_count_; i++) { + float volt = i * vdd_ / voltage_waveform_step_count_; + float time = voltageTime(slew, cap, volt); + float current = voltageCurrent(slew, cap, volt); + times->push_back(time); + currents->push_back(current); + } + TableAxisPtr time_axis = make_shared(TableAxisVariable::time, times); + return Table1(currents, time_axis); +} + +const Table1 * +OutputWaveforms::currentWaveformRaw(float slew, + float cap) +{ + size_t slew_index = slew_axis_->findAxisClosestIndex(slew); + size_t cap_index = cap_axis_->findAxisClosestIndex(cap); + size_t cap_count = cap_axis_->size(); + size_t wave_index = slew_index * cap_count + cap_index; return current_waveforms_[wave_index]; } @@ -1701,7 +1749,9 @@ OutputWaveforms::timeCurrent(float slew, float cap, float time) { - return waveformValue(slew, cap, time, current_waveforms_); + // Current waveform is not monotonic, so use volt/current correspondence. + float volt = timeVoltage(slew, cap, time); + return voltageCurrent(slew, cap, volt); } float @@ -1709,7 +1759,81 @@ OutputWaveforms::timeVoltage(float slew, float cap, float time) { - return waveformValue(slew, cap, time, voltage_waveforms_); + size_t slew_index = slew_axis_->findAxisIndex(slew); + size_t cap_index = cap_axis_->findAxisIndex(cap); + size_t cap_count = cap_axis_->size(); + size_t wave_index00 = slew_index * cap_count + cap_index; + size_t wave_index01 = slew_index * cap_count + (cap_index + 1); + size_t wave_index10 = (slew_index + 1) * cap_count + cap_index; + size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1); + + size_t index1 = slew_index; + size_t index2 = cap_index; + double x1 = slew; + double x2 = cap; + double x1l = slew_axis_->axisValue(index1); + double x1u = slew_axis_->axisValue(index1 + 1); + double dx1 = (x1 - x1l) / (x1u - x1l); + double x2l = cap_axis_->axisValue(index2); + double x2u = cap_axis_->axisValue(index2 + 1); + double dx2 = (x2 - x2l) / (x2u - x2l); + + double v_lo = 0.0; + double v_hi = vdd_; + double v_mid = (v_hi + v_lo) * 0.5; + double time_mid; + while (v_hi - v_lo > .001) { + time_mid = voltageTime1(v_mid, dx1, dx2, wave_index00, wave_index01, + wave_index10, wave_index11); + if (time > time_mid) { + v_lo = v_mid; + v_mid = (v_hi + v_lo) * 0.5; + } + else { + v_hi = v_mid; + v_mid = (v_hi + v_lo) * 0.5; + } + } + return v_mid; +} + +double +OutputWaveforms::voltageTime1(double volt, + double dx1, + double dx2, + size_t wave_index00, + size_t wave_index01, + size_t wave_index10, + size_t wave_index11) +{ + double y00 = voltageTime2(volt, wave_index00); + 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; + return time; +} + +float +OutputWaveforms::voltageTime2(float volt, + size_t wave_index) +{ + const Table1 *voltage_waveform = voltage_waveforms_[wave_index]; + const FloatSeq *voltages = voltage_waveform->values(); + size_t index1 = findValueIndex(volt, voltages); + float volt_lo = (*voltages)[index1]; + float volt_hi = (*voltages)[index1 + 1]; + float dv = volt_hi - volt_lo; + + const TableAxis *time_axis = voltage_waveform->axis1(); + float time_lo = time_axis->axisValue(index1); + float time_hi = time_axis->axisValue(index1 + 1); + float dt = time_hi - time_lo; + return time_lo + dt * (volt - volt_lo) / dv; } float @@ -1773,14 +1897,11 @@ Table1 OutputWaveforms::voltageWaveform(float slew, float cap) { - float min_time, max_time; - waveformMinMaxTime(slew, cap, voltage_waveforms_, min_time, max_time); - float time_step = (max_time - min_time) / voltage_waveform_step_count_; FloatSeq *times = new FloatSeq; FloatSeq *volts = new FloatSeq; - for (size_t i = 0; i < voltage_waveform_step_count_; i++) { - float time = min_time + i * time_step; - float volt = timeVoltage(slew, cap, time); + for (size_t i = 0; i <= voltage_waveform_step_count_; i++) { + float volt = i * vdd_ / voltage_waveform_step_count_; + float time = voltageTime(slew, cap, volt); times->push_back(time); volts->push_back(volt); } @@ -1788,42 +1909,21 @@ OutputWaveforms::voltageWaveform(float slew, return Table1(volts, time_axis); } -void -OutputWaveforms::waveformMinMaxTime(float slew, - float cap, - Table1Seq &waveforms, - // Return values. - float &min_time, - float &max_time) +const Table1 * +OutputWaveforms::voltageWaveformRaw(float slew, + float cap) { - size_t slew_index = slew_axis_->findAxisIndex(slew); - size_t cap_index = cap_axis_->findAxisIndex(cap); + size_t slew_index = slew_axis_->findAxisClosestIndex(slew); + size_t cap_index = cap_axis_->findAxisClosestIndex(cap); size_t cap_count = cap_axis_->size(); - size_t wave_index00 = slew_index * cap_count + cap_index; - size_t wave_index01 = slew_index * cap_count + (cap_index + 1); - size_t wave_index10 = (slew_index + 1) * cap_count + cap_index; - size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1); - - const Table1 *waveform00 = waveforms[wave_index00]; - const Table1 *waveform01 = waveforms[wave_index01]; - const Table1 *waveform10 = waveforms[wave_index10]; - const Table1 *waveform11 = waveforms[wave_index11]; - - min_time = waveform00->axis1()->min(); - min_time = min(min_time, waveform01->axis1()->min()); - min_time = min(min_time, waveform10->axis1()->min()); - min_time = min(min_time, waveform11->axis1()->min()); - - max_time = waveform00->axis1()->max(); - max_time = max(max_time, waveform01->axis1()->max()); - max_time = max(max_time, waveform10->axis1()->max()); - max_time = max(max_time, waveform11->axis1()->max()); + size_t wave_index = slew_index * cap_count + cap_index; + return voltage_waveforms_[wave_index]; } 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); @@ -1845,33 +1945,109 @@ OutputWaveforms::voltageTime(float slew, double x2u = cap_axis_->axisValue(index2 + 1); double dx2 = (x2 - x2l) / (x2u - x2l); - double y00 = voltageTime1(volt, wave_index00); - double y01 = voltageTime1(volt, wave_index01); - double y10 = voltageTime1(volt, wave_index10); - double y11 = voltageTime1(volt, wave_index11); - double time - = (1 - dx1) * (1 - dx2) * y00 - + dx1 * (1 - dx2) * y10 - + dx1 * dx2 * y11 - + (1 - dx1) * dx2 * y01; + double time = voltageTime1(volt, dx1, dx2, wave_index00, wave_index01, + wave_index10, wave_index11); return time; } float -OutputWaveforms::voltageTime1(float voltage, - size_t wave_index) +OutputWaveforms::beginTime(float slew, + float cap) { - FloatSeq *voltage_times = voltage_times_[wave_index]; - float volt_step = vdd_ / voltage_waveform_step_count_; - size_t volt_idx = voltage / volt_step; - if (volt_idx >= voltage_times->size() - 1) - return (*voltage_times)[voltage_times->size() - 1]; - else { - double time0 = (*voltage_times)[volt_idx]; - double time1 = (*voltage_times)[volt_idx + 1]; - double time = time0 + (time1 - time0) * (voltage - volt_step * volt_idx); - return time; + return beginEndTime(slew, cap, true); +} + +float +OutputWaveforms::endTime(float slew, + float cap) +{ + return beginEndTime(slew, cap, false); +} + +float +OutputWaveforms::beginEndTime(float slew, + float cap, + bool begin) +{ + size_t slew_index = slew_axis_->findAxisIndex(slew); + size_t cap_index = cap_axis_->findAxisIndex(cap); + size_t cap_count = cap_axis_->size(); + size_t wave_index00 = slew_index * cap_count + cap_index; + size_t wave_index01 = slew_index * cap_count + (cap_index + 1); + size_t wave_index10 = (slew_index + 1) * cap_count + cap_index; + size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1); + + const Table1 *waveform00 = current_waveforms_[wave_index00]; + const Table1 *waveform01 = current_waveforms_[wave_index01]; + const Table1 *waveform10 = current_waveforms_[wave_index10]; + const Table1 *waveform11 = current_waveforms_[wave_index11]; + + // Interpolate waveform samples at voltage steps. + size_t index1 = slew_index; + size_t index2 = cap_index; + float x1 = slew; + float x2 = cap; + float x1l = slew_axis_->axisValue(index1); + float x1u = slew_axis_->axisValue(index1 + 1); + float dx1 = (x1 - x1l) / (x1u - x1l); + float x2l = cap_axis_->axisValue(index2); + float x2u = cap_axis_->axisValue(index2 + 1); + float dx2 = (x2 - x2l) / (x2u - x2l); + + float y00, y01, y10, y11; + if (begin) { + y00 = waveform00->axis1()->min(); + y01 = waveform01->axis1()->min(); + y10 = waveform10->axis1()->min(); + y11 = waveform11->axis1()->min(); } + else { + y00 = waveform00->axis1()->max(); + y01 = waveform01->axis1()->max(); + y10 = waveform10->axis1()->max(); + y11 = waveform11->axis1()->max(); + } + + float wave_value + = (1 - dx1) * (1 - dx2) * y00 + + dx1 * (1 - dx2) * y10 + + dx1 * dx2 * y11 + + (1 - dx1) * dx2 * y01; + return wave_value; +} + +Table1 +OutputWaveforms::voltageCurrentWaveform(float slew, + float cap) +{ + FloatSeq *volts = new FloatSeq; + FloatSeq *currents = new FloatSeq; + for (size_t i = 0; i < voltage_waveform_step_count_; i++) { + float volt = i * vdd_ / voltage_waveform_step_count_; + float current = voltageCurrent(slew, cap, volt); + volts->push_back(volt); + currents->push_back(current); + } + TableAxisPtr volt_axis = + make_shared(TableAxisVariable::input_voltage, volts); + return Table1(currents, volt_axis); +} + +// Incremental resistance at final value of waveform. +// This corresponds to the pulldown/pullup that holds the output to the rail +// after the waveform has transitioned to the final value. +float +OutputWaveforms::finalResistance() +{ + size_t slew_index = 0; + size_t cap_count = cap_axis_->size(); + size_t cap_index = cap_count - 1; + size_t wave_index = slew_index * cap_count + cap_index; + const Table1 *voltage_currents = voltage_currents_[wave_index]; + FloatSeq *voltages = voltage_currents->axis1()->values(); + FloatSeq *currents = voltage_currents->values(); + size_t idx_last1 = voltages->size() - 2; + return (vdd_ - (*voltages)[idx_last1]) / abs((*currents)[idx_last1]); } //////////////////////////////////////////////////////////////// diff --git a/liberty/TimingArc.cc b/liberty/TimingArc.cc index 29be2abf..89219382 100644 --- a/liberty/TimingArc.cc +++ b/liberty/TimingArc.cc @@ -21,6 +21,8 @@ #include "TimingRole.hh" #include "Liberty.hh" #include "TimingArc.hh" +#include "DcalcAnalysisPt.hh" +#include "TableModel.hh" namespace sta { @@ -316,13 +318,13 @@ TimingArcSet::sense() const return attrs_->timingSense(); } -RiseFall * +const RiseFall * TimingArcSet::isRisingFallingEdge() const { int arc_count = arcs_.size(); if (arc_count == 2) { - RiseFall *from_rf1 = arcs_[0]->fromEdge()->asRiseFall(); - RiseFall *from_rf2 = arcs_[1]->fromEdge()->asRiseFall(); + const RiseFall *from_rf1 = arcs_[0]->fromEdge()->asRiseFall(); + const RiseFall *from_rf2 = arcs_[1]->fromEdge()->asRiseFall(); if (from_rf1 == from_rf2) return from_rf1; } @@ -545,18 +547,42 @@ TimingArc::~TimingArc() delete scaled_models_; } -TimingModel * -TimingArc::model(const OperatingConditions *op_cond) const +GateTimingModel * +TimingArc::gateModel(const DcalcAnalysisPt *dcalc_ap) const { - if (scaled_models_) { - TimingModel *model = scaled_models_->findKey(op_cond); - if (model) - return model; - else - return model_; + return dynamic_cast(model(dcalc_ap)); +} + +GateTableModel * +TimingArc::gateTableModel() const +{ + return dynamic_cast(model_); +} + +GateTableModel * +TimingArc::gateTableModel(const DcalcAnalysisPt *dcalc_ap) const +{ + return dynamic_cast(model(dcalc_ap)); +} + +CheckTimingModel * +TimingArc::checkModel(const DcalcAnalysisPt *dcalc_ap) const +{ + return dynamic_cast(model(dcalc_ap)); +} + +TimingModel * +TimingArc::model(const DcalcAnalysisPt *dcalc_ap) const +{ + const TimingArc *corner_arc = cornerArc(dcalc_ap->libertyIndex()); + ScaledTimingModelMap *scaled_models = corner_arc->scaled_models_; + if (scaled_models) { + const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); + TimingModel *scaled_model = scaled_models->findKey(op_cond); + if (scaled_model) + return scaled_model; } - else - return model_; + return corner_arc->model(); } void diff --git a/network/ConcreteLibrary.cc b/network/ConcreteLibrary.cc index e6cceeef..820f9206 100644 --- a/network/ConcreteLibrary.cc +++ b/network/ConcreteLibrary.cc @@ -320,8 +320,9 @@ public: int from() const { return from_; } int to() const { return to_; } ConcretePortSeq &members() { return members_; } + const ConcretePortSeq &members() const { return members_; } void setDirection(PortDirection *direction); - PortDirection *direction() { return direction_; } + PortDirection *direction() const { return direction_; } private: int from_; @@ -385,9 +386,7 @@ ConcreteCell::groupBusPorts(const char bus_brkt_left, } // Make the bus ports. - for (auto name_bus : bus_map) { - string bus_name = name_bus.first; - BusPort &bus_port = name_bus.second; + for (const auto& [bus_name, bus_port] : bus_map) { int from = bus_port.from(); int to = bus_port.to(); size_t size = to - from + 1; diff --git a/parasitics/ConcreteParasitics.cc b/parasitics/ConcreteParasitics.cc index f29af721..ec76fdcb 100644 --- a/parasitics/ConcreteParasitics.cc +++ b/parasitics/ConcreteParasitics.cc @@ -246,10 +246,8 @@ ConcretePiElmore::unannotatedLoads(const Pin *drvr_pin, const Parasitics *parasitics) const { PinSet loads = parasitics->loads(drvr_pin); - for (auto pin_elmore : loads_) { - const Pin *load = pin_elmore.first; + for (const auto [load, elmore] : loads_) loads.erase(load); - } return loads; } @@ -371,10 +369,8 @@ ConcretePiPoleResidue::unannotatedLoads(const Pin *drvr_pin, const Parasitics *parasitics) const { PinSet loads = parasitics->loads(drvr_pin); - for (auto pin_pole_residue : load_pole_residue_) { - const Pin *load = pin_pole_residue.first; + for (const auto& [load, pole_residue] : load_pole_residue_) loads.erase(load); - } return loads; } @@ -395,6 +391,7 @@ ConcreteParasiticNode::ConcreteParasiticNode(const Pin *pin, bool is_external) : is_net_(false), is_external_(is_external), + id_(0), cap_(0.0) { net_pin_.pin_ = pin; @@ -506,14 +503,10 @@ ConcreteParasiticNetwork::~ConcreteParasiticNetwork() void ConcreteParasiticNetwork::deleteNodes() { - for (auto id_node : sub_nodes_) { - ConcreteParasiticNode *node = id_node.second; + for (const auto& [id, node] : sub_nodes_) delete node; - } - for (auto pin_node : pin_nodes_) { - ConcreteParasiticNode *node = pin_node.second; + for (const auto& [pin, node] : pin_nodes_) delete node; - } } void @@ -547,14 +540,10 @@ ParasiticNodeSeq ConcreteParasiticNetwork::nodes() const { ParasiticNodeSeq nodes; - for (auto pin_node : pin_nodes_) { - ParasiticNode *node = pin_node.second; + for (const auto [pin, node] : pin_nodes_) nodes.push_back(node); - } - for (auto id_node : sub_nodes_) { - ParasiticNode *node = id_node.second; + for (const auto& [id, node] : sub_nodes_) nodes.push_back(node); - } return nodes; } @@ -562,14 +551,12 @@ float ConcreteParasiticNetwork::capacitance() const { float cap = 0.0; - for (auto id_node : sub_nodes_) { - ConcreteParasiticNode *node = id_node.second; + for (const auto& [id, node] : sub_nodes_) { if (!node->isExternal()) cap += node->capacitance(); } - for (auto pin_node : pin_nodes_) { - ConcreteParasiticNode *node = pin_node.second; + for (const auto [pin, node] : pin_nodes_) { if (!node->isExternal()) cap += node->capacitance(); } @@ -617,7 +604,8 @@ ConcreteParasiticNetwork::ensureParasiticNode(const Net *net, if (id_node == sub_nodes_.end()) { node = new ConcreteParasiticNode(net, id, net != net_); sub_nodes_[net_id] = node; - max_node_id_ = max((int) max_node_id_, id); + if (net == net_) + max_node_id_ = max((int) max_node_id_, id); } else node = id_node->second; @@ -790,8 +778,7 @@ ConcreteParasitics::deleteParasitics() { int ap_count = corners_->parasiticAnalysisPtCount(); int ap_rf_count = ap_count * RiseFall::index_count; - for (auto drvr_parasitics : drvr_parasitic_map_) { - ConcreteParasitic **parasitics = drvr_parasitics.second; + for (const auto [drvr, parasitics] : drvr_parasitic_map_) { if (parasitics) { for (int i = 0; i < ap_rf_count; i++) delete parasitics[i]; @@ -800,8 +787,7 @@ ConcreteParasitics::deleteParasitics() } drvr_parasitic_map_.clear(); - for (auto net_parasitics : parasitic_network_map_) { - ConcreteParasiticNetwork **parasitics = net_parasitics.second; + for (const auto [net, parasitics] : parasitic_network_map_) { if (parasitics) { for (int i = 0; i < ap_count; i++) delete parasitics[i]; @@ -817,8 +803,8 @@ ConcreteParasitics::deleteParasitics(const Pin *drvr_pin, { ConcreteParasitic **parasitics = drvr_parasitic_map_[drvr_pin]; if (parasitics) { - for (auto tr : RiseFall::range()) { - int ap_rf_index = parasiticAnalysisPtIndex(ap, tr); + for (auto rf : RiseFall::range()) { + int ap_rf_index = parasiticAnalysisPtIndex(ap, rf); delete parasitics[ap_rf_index]; parasitics[ap_rf_index] = nullptr; } @@ -1247,8 +1233,10 @@ ConcreteParasitics::makeParasiticNetwork(const Net *net, ConcreteParasiticNetwork *parasitic = parasitics[ap_index]; if (parasitic) { delete parasitic; - for (const Pin *drvr_pin : *network_->drivers(net)) - deleteParasitics(drvr_pin, ap); + if (net) { + for (const Pin *drvr_pin : *network_->drivers(net)) + deleteParasitics(drvr_pin, ap); + } } parasitic = new ConcreteParasiticNetwork(net, includes_pin_caps, network_); parasitics[ap_index] = parasitic; @@ -1446,6 +1434,14 @@ ConcreteParasitics::net(const ParasiticNode *node, return cnode->net(network); } +unsigned +ConcreteParasitics::netId(const ParasiticNode *node) const +{ + const ConcreteParasiticNode *cnode = + static_cast(node); + return cnode->id(); +} + bool ConcreteParasitics::isExternal(const ParasiticNode *node) const { diff --git a/parasitics/ConcreteParasitics.hh b/parasitics/ConcreteParasitics.hh index 04014fda..fbb1b3d4 100644 --- a/parasitics/ConcreteParasitics.hh +++ b/parasitics/ConcreteParasitics.hh @@ -133,6 +133,7 @@ public: const Pin *pin(const ParasiticNode *node) const override; const Net *net(const ParasiticNode *node, const Network *network) const override; + unsigned netId(const ParasiticNode *node) const override; bool isExternal(const ParasiticNode *node) const override; float nodeGndCap(const ParasiticNode *node) const override; diff --git a/parasitics/ConcreteParasiticsPvt.hh b/parasitics/ConcreteParasiticsPvt.hh index 4979d63f..b4503b70 100644 --- a/parasitics/ConcreteParasiticsPvt.hh +++ b/parasitics/ConcreteParasiticsPvt.hh @@ -43,7 +43,7 @@ typedef std::map ConcreteElmoreLoadMap; typedef std::map ConcretePoleResidueMap; typedef std::map ConcreteParasiticSubNodeMap; -typedef std::map ConcreteParasiticPinNodeMap; +typedef std::map ConcreteParasiticPinNodeMap; typedef std::set ParasiticNodeSet; typedef std::set ParasiticResistorSet; typedef std::vector ParasiticResistorSeq; @@ -262,6 +262,7 @@ public: float capacitance() const { return cap_; } const char *name(const Network *network) const; const Net *net(const Network *network) const; + unsigned id() const { return id_; } bool isExternal() const { return is_external_; } const Pin *pin() const; void incrCapacitance(float cap); diff --git a/parasitics/EstimateParasitics.cc b/parasitics/EstimateParasitics.cc index fa6d0cbc..eeff7430 100644 --- a/parasitics/EstimateParasitics.cc +++ b/parasitics/EstimateParasitics.cc @@ -18,6 +18,7 @@ #include "Wireload.hh" #include "Liberty.hh" +#include "PortDirection.hh" #include "Network.hh" #include "Sdc.hh" #include "Parasitics.hh" @@ -147,7 +148,7 @@ EstimateParasitics::estimatePiElmoreBalanced(const Pin *drvr_pin, bool &elmore_use_load_cap) { if (wireload_res == 0.0 - || fanout == 0) { + || fanout == 0.0) { // No resistance, so load is capacitance only. c2 = wireload_cap + net_pin_cap; rpi = 0.0; @@ -168,22 +169,19 @@ EstimateParasitics::estimatePiElmoreBalanced(const Pin *drvr_pin, network_->connectedPinIterator(drvr_pin); while (load_iter->hasNext()) { const Pin *load_pin = load_iter->next(); + Port *port = network_->port(load_pin); + double cap = 0.0; // Bidirects don't count themselves as loads. - if (load_pin != drvr_pin && network_->isLoad(load_pin)) { - Port *port = network_->port(load_pin); - double load_cap = 0.0; - if (network_->isLeaf(load_pin)) - load_cap = sdc_->pinCapacitance(load_pin, rf, corner, min_max); - else if (network_->isTopLevelPort(load_pin)) - load_cap = sdc_->portExtCap(port, rf, corner, min_max); - else - report_->critical(1050, "load pin not leaf or top level"); - double cap = load_cap + cap_fanout; - double y2_ = res_fanout * cap * cap; - y1 += cap; - y2 += -y2_; - y3 += y2_ * res_fanout * cap; - } + if (load_pin == drvr_pin) + cap = sdc_->portExtCap(port, rf, corner, min_max); + else if (network_->isLeaf(load_pin)) + cap = sdc_->pinCapacitance(load_pin, rf, corner, min_max) + cap_fanout; + else if (network_->isTopLevelPort(load_pin)) + cap = sdc_->portExtCap(port, rf, corner, min_max) + cap_fanout; + double y2_ = res_fanout * cap * cap; + y1 += cap; + y2 += -y2_; + y3 += y2_ * res_fanout * cap; } delete load_iter; @@ -196,6 +194,8 @@ EstimateParasitics::estimatePiElmoreBalanced(const Pin *drvr_pin, else { c1 = static_cast(y2 * y2 / y3); c2 = static_cast(y1 - y2 * y2 / y3); + if (c2 < 0.0) + c2 = 0.0; rpi = static_cast(-y3 * y3 / (y2 * y2 * y2)); } elmore_res = static_cast(res_fanout); diff --git a/parasitics/Parasitics.cc b/parasitics/Parasitics.cc index 0ab184bb..65b62a1d 100644 --- a/parasitics/Parasitics.cc +++ b/parasitics/Parasitics.cc @@ -203,29 +203,32 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin, const MinMax *min_max, const ParasiticAnalysisPt *ap) { + Parasitic *parasitic = nullptr; const Net *net = findParasiticNet(drvr_pin); - Parasitic *parasitic = makeParasiticNetwork(net, false, ap); - const OperatingConditions *op_cond = sdc_->operatingConditions(min_max); - float wireload_cap, wireload_res; - wireload->findWireload(fanout, op_cond, wireload_cap, wireload_res); + if (net) { + parasitic = makeParasiticNetwork(net, false, ap); + const OperatingConditions *op_cond = sdc_->operatingConditions(min_max); + float wireload_cap, wireload_res; + wireload->findWireload(fanout, op_cond, wireload_cap, wireload_res); - WireloadTree tree = WireloadTree::balanced; - 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; + WireloadTree tree = WireloadTree::balanced; + 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; + } } return parasitic; } @@ -324,4 +327,38 @@ ParasiticAnalysisPt::setCouplingCapFactor(float factor) coupling_cap_factor_ = factor; } +//////////////////////////////////////////////////////////////// + +ParasiticNodeLess::ParasiticNodeLess(const Parasitics *parasitics, + const Network *network) : + parasitics_(parasitics), + network_(network) +{ +} + +ParasiticNodeLess::ParasiticNodeLess(const ParasiticNodeLess &less) : + parasitics_(less.parasitics_), + network_(less.network_) +{ +} + +bool +ParasiticNodeLess::operator()(const ParasiticNode *node1, + const ParasiticNode *node2) const +{ + const Pin *pin1 = parasitics_->pin(node1); + const Pin *pin2 = parasitics_->pin(node2); + const Net *net1 = parasitics_->net(node1, network_); + const Net *net2 = parasitics_->net(node2, network_); + 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))); +} + } // namespace diff --git a/parasitics/Parasitics.tcl b/parasitics/Parasitics.tcl index 4932c5a9..0aca7d82 100644 --- a/parasitics/Parasitics.tcl +++ b/parasitics/Parasitics.tcl @@ -37,16 +37,20 @@ proc_redirect read_spef { set reduce [info exists flags(-reduce)] if { [info exists flags(-quiet)] } { + # deprecated 2024-02-08 sta_warn 272 "read_spef -quiet is deprecated." } if { [info exists keys(-reduce_to)] } { + # deprecated 2024-02-08 sta_warn 273 "read_spef -reduce_to is deprecated. Use -reduce instead." set reduce 1 } if { [info exists flags(-delete_after_reduce)] } { + # deprecated 2024-02-08 sta_warn 274 "read_spef -delete_after_reduce is deprecated." } if { [info exists flags(-save)] } { + # deprecated 2024-02-08 sta_warn 275 "read_spef -save is deprecated." } diff --git a/parasitics/ReduceParasitics.cc b/parasitics/ReduceParasitics.cc index 4d8f3f75..07c5b733 100644 --- a/parasitics/ReduceParasitics.cc +++ b/parasitics/ReduceParasitics.cc @@ -183,7 +183,7 @@ ReduceToPi::reducePiDfs(const Pin *drvr_pin, && resistor != from_res) { if (isVisited(onode)) { // Resistor loop. - debugPrint(debug_, "parasitic_reduce", 2, " loop detected thru resistor %lu", + debugPrint(debug_, "parasitic_reduce", 2, " loop detected thru resistor %zu", parasitics_->id(resistor)); markLoopResistor(resistor); } diff --git a/parasitics/ReportParasiticAnnotation.cc b/parasitics/ReportParasiticAnnotation.cc index bc6c9b6e..41eb3081 100644 --- a/parasitics/ReportParasiticAnnotation.cc +++ b/parasitics/ReportParasiticAnnotation.cc @@ -80,14 +80,14 @@ ReportParasiticAnnotation::report() void ReportParasiticAnnotation::reportAnnotationCounts() { - report_->reportLine("Found %lu unannotated drivers.", unannotated_.size()); + report_->reportLine("Found %zu 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_->reportLine("Found %lu partially unannotated drivers.", + report_->reportLine("Found %zu partially unannotated drivers.", partially_annotated_.size()); if (report_unannotated_) { sort(partially_annotated_, PinPathNameLess(network_)); diff --git a/parasitics/SpefReader.cc b/parasitics/SpefReader.cc index 8767986a..761b5f48 100644 --- a/parasitics/SpefReader.cc +++ b/parasitics/SpefReader.cc @@ -120,10 +120,8 @@ SpefReader::~SpefReader() design_flow_ = nullptr; } - for (auto index_name : name_map_) { - char *name = index_name.second; + for (const auto [index, name] : name_map_) stringDelete(name); - } } void @@ -496,7 +494,9 @@ SpefReader::findParasiticNode(char *name, int id = atoi(id_str); if (local_only && !network_->isConnected(net, net_)) - warn(1653, "%s not connected to net %s.", name, network_->pathName(net_)); + warn(1653, "%s not connected to net %s.", + name, + network_->pathName(net_)); return parasitics_->ensureParasiticNode(parasitic_, net, id, network_); } else diff --git a/power/Power.cc b/power/Power.cc index 112af13d..33e649b8 100644 --- a/power/Power.cc +++ b/power/Power.cc @@ -586,12 +586,10 @@ Power::evalBddActivity(DdNode *bdd, const Instance *inst) { float activity = 0.0; - for (auto port_var : bdd_.portVarMap()) { - const LibertyPort *port = port_var.first; + for (const auto [port, var_node] : bdd_.portVarMap()) { const Pin *pin = findLinkPin(inst, port); if (pin) { PwrActivity var_activity = findActivity(pin); - DdNode *var_node = port_var.second; unsigned int var_index = Cudd_NodeReadIndex(var_node); DdNode *diff = Cudd_bddBooleanDiff(bdd_.cuddMgr(), bdd, var_index); Cudd_Ref(diff); diff --git a/power/ReadVcdActivities.cc b/power/ReadVcdActivities.cc index 396dab63..fec6b2d3 100644 --- a/power/ReadVcdActivities.cc +++ b/power/ReadVcdActivities.cc @@ -105,7 +105,7 @@ ReadVcdActivities::readActivities() setActivities(); else report_->warn(1450, "VCD max time is zero."); - report_->reportLine("Annotated %lu pin activities.", annotated_pins_.size()); + report_->reportLine("Annotated %zu pin activities.", annotated_pins_.size()); } void diff --git a/sdc/DeratingFactors.cc b/sdc/DeratingFactors.cc index 843f5655..a7499f75 100644 --- a/sdc/DeratingFactors.cc +++ b/sdc/DeratingFactors.cc @@ -41,8 +41,8 @@ DeratingFactors::setFactor(PathClkOrData clk_data, const EarlyLate *early_late, float factor) { - for (auto tr1 : rf->range()) - factors_[int(clk_data)].setValue(tr1, early_late, factor); + for (auto rf1 : rf->range()) + factors_[int(clk_data)].setValue(rf1, early_late, factor); } void diff --git a/sdc/InputDrive.cc b/sdc/InputDrive.cc index f17f8c00..606df5f5 100644 --- a/sdc/InputDrive.cc +++ b/sdc/InputDrive.cc @@ -20,17 +20,17 @@ namespace sta { InputDrive::InputDrive() { - for (auto tr_index : RiseFall::rangeIndex()) { + for (auto rf_index : RiseFall::rangeIndex()) { for (auto mm_index : MinMax::rangeIndex()) - drive_cells_[tr_index][mm_index] = nullptr; + drive_cells_[rf_index][mm_index] = nullptr; } } InputDrive::~InputDrive() { - for (auto tr_index : RiseFall::rangeIndex()) { + for (auto rf_index : RiseFall::rangeIndex()) { for (auto mm_index : MinMax::rangeIndex()) { - InputDriveCell *drive_cell = drive_cells_[tr_index][mm_index]; + InputDriveCell *drive_cell = drive_cells_[rf_index][mm_index]; delete drive_cell; } } @@ -210,8 +210,8 @@ InputDriveCell::setToPort(const LibertyPort *to_port) void InputDriveCell::setFromSlews(float *from_slews) { - for (auto tr_index : RiseFall::rangeIndex()) - from_slews_[tr_index] = from_slews[tr_index]; + for (auto rf_index : RiseFall::rangeIndex()) + from_slews_[rf_index] = from_slews[rf_index]; } bool diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 78948974..fefbec01 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -271,15 +271,12 @@ Sdc::deleteConstraints() inst_min_pulse_width_map_.deleteContentsClear(); clk_min_pulse_width_map_.deleteContentsClear(); - for (auto pin_data_check : data_checks_from_map_) { - DataCheckSet *checks = pin_data_check.second; + for (auto [pin, checks] : data_checks_from_map_) { checks->deleteContents(); delete checks; } - for (auto pin_data_check : data_checks_to_map_) { - DataCheckSet *checks = pin_data_check.second; + for (auto [pin, checks] : data_checks_to_map_) delete checks; - } input_delays_.deleteContents(); input_delay_pin_map_.deleteContents(); @@ -323,9 +320,7 @@ Sdc::removeNetLoadCaps() void Sdc::removeLibertyAnnotations() { - for (auto cell_port : disabled_cell_ports_) { - DisabledCellPorts *disable = cell_port.second; - LibertyCell *cell = disable->cell(); + for (auto [cell, disable] : disabled_cell_ports_) { if (disable->all()) cell->setIsDisabledConstraint(false); @@ -1957,8 +1952,8 @@ void Sdc::ensureClkGroupExclusions() { if (clk_group_exclusions_.empty()) { - for (auto name_clk_groups : clk_groups_name_map_) - makeClkGroupExclusions(name_clk_groups.second); + for (const auto [name, clk_groups] : clk_groups_name_map_) + makeClkGroupExclusions(clk_groups); } } @@ -2071,8 +2066,7 @@ Sdc::removeClockGroupsLogicallyExclusive(const char *name) removeClockGroups(groups); } else { - for (auto name_group : clk_groups_name_map_) { - ClockGroups *groups = name_group.second; + for (const auto [name, groups] : clk_groups_name_map_) { if (groups->logicallyExclusive()) removeClockGroups(groups); } @@ -2088,8 +2082,7 @@ Sdc::removeClockGroupsPhysicallyExclusive(const char *name) removeClockGroups(groups); } else { - for (auto name_group : clk_groups_name_map_) { - ClockGroups *groups = name_group.second; + for (const auto [name, groups] : clk_groups_name_map_) { if (groups->physicallyExclusive()) removeClockGroups(groups); } @@ -2105,8 +2098,7 @@ Sdc::removeClockGroupsAsynchronous(const char *name) removeClockGroups(groups); } else { - for (auto name_group : clk_groups_name_map_) { - ClockGroups *groups = name_group.second; + for (const auto [name, groups] : clk_groups_name_map_) { if (groups->asynchronous()) removeClockGroups(groups); } @@ -2126,10 +2118,8 @@ Sdc::removeClockGroups(ClockGroups *groups) void Sdc::clockGroupsDeleteClkRefs(Clock *clk) { - for (auto name_group : clk_groups_name_map_) { - ClockGroups *groups = name_group.second; + for (const auto [name, groups] : clk_groups_name_map_) groups->removeClock(clk); - } clearClkGroupExclusions(); } @@ -4034,9 +4024,7 @@ Sdc::clearGroupPathMap() { // GroupPath exceptions are deleted with other exceptions. // Delete group_path name strings. - for (auto name_groups : group_path_map_) { - const char *name = name_groups.first; - GroupPathSet *groups = name_groups.second; + for (auto [name, groups] : group_path_map_) { stringDelete(name); groups->deleteContents(); delete groups; diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index 5fd36b28..5808f5c3 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -382,7 +382,7 @@ WriteSdc::writeClocks() const { // Write clocks in the order they were defined because generated // clocks depend on master clocks having been previously defined. - for (auto clk : sdc_->clocks_) { + for (const auto clk : sdc_->clocks_) { if (clk->isGenerated()) writeGeneratedClock(clk); else @@ -852,8 +852,8 @@ void WriteSdc::writeClockSenses() const { Vector pin_clks; - for (auto iter : sdc_->clk_sense_map_) - pin_clks.push_back(iter.first); + for (const auto& [pin_clk, sense] : sdc_->clk_sense_map_) + pin_clks.push_back(pin_clk); // Sort by pin/clk pair so regressions results are stable. sort(pin_clks, PinClockPairNameLess(sdc_network_)); @@ -937,10 +937,8 @@ ClockGroupLess::operator()(const ClockGroup *clk_group1, void WriteSdc::writeClockGroups() const { - for (auto &name_groups : sdc_->clk_groups_name_map_) { - ClockGroups *clk_groups = name_groups.second; + for (const auto [name, clk_groups] : sdc_->clk_groups_name_map_) writeClockGroups(clk_groups); - } } void @@ -1408,8 +1406,7 @@ void WriteSdc::writeDataChecks() const { Vector checks; - for (auto pin_checks : sdc_->data_checks_to_map_) { - DataCheckSet *checks1 = pin_checks.second; + for (const auto [pin, checks1] : sdc_->data_checks_to_map_) { for (DataCheck *check : *checks1) checks.push_back(check); } @@ -1512,9 +1509,7 @@ void WriteSdc::writeNetLoads() const { int corner_index = 0; // missing corner arg - for (auto net_cap : sdc_->net_wire_cap_maps_[corner_index]) { - const Net *net = net_cap.first; - MinMaxFloatValues &caps = net_cap.second; + for (const auto [net, caps] : sdc_->net_wire_cap_maps_[corner_index]) { float min_cap, max_cap; bool min_exists, max_exists; caps.value(MinMax::min(), min_cap, min_exists); @@ -1725,10 +1720,8 @@ void WriteSdc::writeNetResistances() const { NetSeq nets; - for (auto net_res : sdc_->netResistances()) { - const Net *net = net_res.first; + for (const auto [net, res] : sdc_->netResistances()) nets.push_back(net); - } sort(nets, NetPathNameLess(sdc_network_)); for (const Net *net : nets) { float min_res, max_res; @@ -1843,10 +1836,8 @@ void WriteSdc::sortedLogicValuePins(LogicValueMap &value_map, PinSeq &pins) const { - for (auto pin_value : value_map) { - const Pin *pin = pin_value.first; + for (const auto [pin, value] : value_map) pins.push_back(pin); - } // Sort pins. sort(pins, PinPathNameLess(sdc_network_)); } @@ -1860,9 +1851,7 @@ WriteSdc::writeDeratings() const if (factors) writeDerating(factors); - for (auto net_derating : sdc_->net_derating_factors_) { - const Net *net = net_derating.first; - DeratingFactorsNet *factors = net_derating.second; + for (const auto [net, factors] : sdc_->net_derating_factors_) { WriteGetNet write_net(net, this); for (auto early_late : EarlyLate::range()) { writeDerating(factors, TimingDerateType::net_delay, early_late, @@ -1870,16 +1859,12 @@ WriteSdc::writeDeratings() const } } - for (auto inst_derating : sdc_->inst_derating_factors_) { - const Instance *inst = inst_derating.first; - DeratingFactorsCell *factors = inst_derating.second; + for (const auto [inst, factors] : sdc_->inst_derating_factors_) { WriteGetInstance write_inst(inst, this); writeDerating(factors, &write_inst); } - for (auto cell_derating : sdc_->cell_derating_factors_) { - const LibertyCell *cell = cell_derating.first; - DeratingFactorsCell *factors = cell_derating.second; + for (const auto [cell, factors] : sdc_->cell_derating_factors_) { WriteGetLibCell write_cell(cell, this); writeDerating(factors, &write_cell); } @@ -2029,12 +2014,10 @@ WriteSdc::writeVoltages() const gzprintf(stream_, "set_voltage %.3f\n", voltage_max); } - for (auto net_volt : sdc_->net_voltage_map_) { - const Net *net = net_volt.first; - MinMaxFloatValues &values = net_volt.second; - values.value(MinMax::max(), voltage_max, exists_max); + for (const auto& [net, volts] : sdc_->net_voltage_map_) { + volts.value(MinMax::max(), voltage_max, exists_max); if (exists_max) { - values.value(MinMax::min(), voltage_min, exists_min); + 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), @@ -2065,23 +2048,17 @@ WriteSdc::writeDesignRules() const void WriteSdc::writeMinPulseWidths() const { - for (auto pin_widths : sdc_->pin_min_pulse_width_map_) { - const Pin *pin = pin_widths.first; - RiseFallValues *min_widths = pin_widths.second; + for (const auto [pin, min_widths] : sdc_->pin_min_pulse_width_map_) { WriteGetPin write_obj(pin, false, this); writeMinPulseWidths(min_widths, write_obj); } - for (auto inst_widths : sdc_->inst_min_pulse_width_map_) { - const Instance *inst = inst_widths.first; - RiseFallValues *min_widths = inst_widths.second; + for (const auto [inst, min_widths] : sdc_->inst_min_pulse_width_map_) { WriteGetInstance write_obj(inst, this); writeMinPulseWidths(min_widths, write_obj); } - for (auto clk_widths : sdc_->clk_min_pulse_width_map_) { - const Clock *clk = clk_widths.first; - RiseFallValues *min_widths = clk_widths.second; + for (const auto [clk, min_widths] : sdc_->clk_min_pulse_width_map_) { WriteGetClock write_obj(clk, this); writeMinPulseWidths(min_widths, write_obj); } @@ -2123,9 +2100,7 @@ WriteSdc::writeMinPulseWidth(const char *hi_low, void WriteSdc::writeLatchBorowLimits() const { - for (auto pin_borrow : sdc_->pin_latch_borrow_limit_map_) { - const Pin *pin = pin_borrow.first; - float limit = pin_borrow.second; + for (const auto [pin, limit] : sdc_->pin_latch_borrow_limit_map_) { gzprintf(stream_, "set_max_time_borrow "); writeTime(limit); gzprintf(stream_, " "); @@ -2133,9 +2108,7 @@ WriteSdc::writeLatchBorowLimits() const gzprintf(stream_, "\n"); } - for (auto inst_borrow : sdc_->inst_latch_borrow_limit_map_) { - const Instance *inst = inst_borrow.first; - float limit = inst_borrow.second; + for (const auto [inst, limit] : sdc_->inst_latch_borrow_limit_map_) { gzprintf(stream_, "set_max_time_borrow "); writeTime(limit); gzprintf(stream_, " "); @@ -2143,9 +2116,7 @@ WriteSdc::writeLatchBorowLimits() const gzprintf(stream_, "\n"); } - for (auto clk_borrow : sdc_->clk_latch_borrow_limit_map_) { - const Clock *clk = clk_borrow.first; - float limit = clk_borrow.second; + for (const auto [clk, limit] : sdc_->clk_latch_borrow_limit_map_) { gzprintf(stream_, "set_max_time_borrow "); writeTime(limit); gzprintf(stream_, " "); @@ -2266,12 +2237,10 @@ WriteSdc::writeCapLimits(const MinMax *min_max, gzprintf(stream_, " [current_design]\n"); } - for (auto port_limit : sdc_->port_cap_limit_map_) { - const Port *port = port_limit.first; - MinMaxFloatValues values = port_limit.second; + for (const auto [port, limits] : sdc_->port_cap_limit_map_) { float cap; bool exists; - values.value(min_max, cap, exists); + limits.value(min_max, cap, exists); if (exists) { gzprintf(stream_, "%s ", cmd); writeCapacitance(cap); @@ -2281,12 +2250,10 @@ WriteSdc::writeCapLimits(const MinMax *min_max, } } - for (auto pin_limit : sdc_->pin_cap_limit_map_) { - const Pin *pin = pin_limit.first; - MinMaxFloatValues values = pin_limit.second; + for (const auto [pin, limits] : sdc_->pin_cap_limit_map_) { float cap; bool exists; - values.value(min_max, cap, exists); + limits.value(min_max, cap, exists); if (exists) { gzprintf(stream_, "%s ", cmd); writeCapacitance(cap); diff --git a/sdf/SdfWriter.cc b/sdf/SdfWriter.cc index 22d2e24e..5e0fbe0b 100644 --- a/sdf/SdfWriter.cc +++ b/sdf/SdfWriter.cc @@ -45,7 +45,7 @@ public: SdfWriter(StaState *sta); ~SdfWriter(); void write(const char *filename, - Corner *corner, + const Corner *corner, char sdf_divider, bool include_typ, int digits, @@ -122,7 +122,7 @@ private: void writeSdf(const char *filename, - Corner *corner, + const Corner *corner, char sdf_divider, bool include_typ, int digits, @@ -151,7 +151,7 @@ SdfWriter::~SdfWriter() void SdfWriter::write(const char *filename, - Corner *corner, + const Corner *corner, char sdf_divider, bool include_typ, int digits, diff --git a/sdf/SdfWriter.hh b/sdf/SdfWriter.hh index f3d23c08..acd2fff3 100644 --- a/sdf/SdfWriter.hh +++ b/sdf/SdfWriter.hh @@ -23,7 +23,7 @@ class Corner; void writeSdf(const char *filename, - Corner *corner, + const Corner *corner, char divider, bool include_typ, int digits, diff --git a/search/Bdd.cc b/search/Bdd.cc index 88eda5a6..5da2195f 100644 --- a/search/Bdd.cc +++ b/search/Bdd.cc @@ -168,10 +168,8 @@ Bdd::varIndexPort(int var_index) void Bdd::clearVarMap() { - for (auto port_node : bdd_port_var_map_) { - DdNode *var_node = port_node.second; + for (const auto [port, var_node] : bdd_port_var_map_) Cudd_RecursiveDeref(cudd_mgr_, var_node); - } bdd_port_var_map_.clear(); bdd_var_idx_port_map_.clear(); } diff --git a/search/Bfs.cc b/search/Bfs.cc index 95f0c0e7..f5d8a429 100644 --- a/search/Bfs.cc +++ b/search/Bfs.cc @@ -70,7 +70,7 @@ BfsIterator::clear() Level level = first_level_; while (levelLessOrEqual(level, last_level_)) { VertexSeq &level_vertices = queue_[level]; - for (auto vertex : level_vertices) { + for (Vertex *vertex : level_vertices) { if (vertex) vertex->setBfsInQueue(bfs_index_, false); } @@ -88,7 +88,7 @@ BfsIterator::reportEntries(const Network *network) VertexSeq &level_vertices = queue_[level]; if (!level_vertices.empty()) { report_->reportLine("Level %d", level); - for (auto vertex : level_vertices) { + for (Vertex *vertex : level_vertices) { if (vertex) report_->reportLine(" %s", vertex->name(network)); } @@ -101,7 +101,7 @@ void BfsIterator::deleteEntries(Level level) { VertexSeq &level_vertices = queue_[level]; - for (auto vertex : level_vertices) { + for (Vertex *vertex : level_vertices) { if (vertex) vertex->setBfsInQueue(bfs_index_, false); } @@ -281,7 +281,7 @@ BfsIterator::checkInQueue(Vertex *vertex) { Level level = vertex->level(); if (static_cast(queue_.size()) > level) { - for (auto v : queue_[level]) { + for (Vertex *v : queue_[level]) { if (v == vertex) { if (vertex->bfsInQueue(bfs_index_)) return; @@ -308,7 +308,7 @@ BfsIterator::remove(Vertex *vertex) Level level = vertex->level(); if (vertex->bfsInQueue(bfs_index_) && static_cast(queue_.size()) > level) { - for (auto &v : queue_[level]) { + for (Vertex *v : queue_[level]) { if (v == vertex) { v = nullptr; vertex->setBfsInQueue(bfs_index_, false); diff --git a/search/CheckMinPulseWidths.cc b/search/CheckMinPulseWidths.cc index 6c1e35a4..f1835b39 100644 --- a/search/CheckMinPulseWidths.cc +++ b/search/CheckMinPulseWidths.cc @@ -411,7 +411,7 @@ MinPulseWidthCheck::width(const StaState *sta) const { return closeArrival(sta) + closeOffset(sta) - open_path_.arrival(sta) - + commonClkPessimism(sta); + + checkCrpr(sta); } float @@ -458,7 +458,7 @@ minPulseWidth(const Path *path, } Crpr -MinPulseWidthCheck::commonClkPessimism(const StaState *sta) const +MinPulseWidthCheck::checkCrpr(const StaState *sta) const { CheckCrpr *check_crpr = sta->search()->checkCrpr(); PathVertex close; diff --git a/search/CheckMinPulseWidths.hh b/search/CheckMinPulseWidths.hh index c2433b5b..d493929f 100644 --- a/search/CheckMinPulseWidths.hh +++ b/search/CheckMinPulseWidths.hh @@ -80,7 +80,7 @@ public: float closeOffset(const StaState *sta) const; const ClockEdge *openClkEdge(const StaState *sta) const; const ClockEdge *closeClkEdge(const StaState *sta) const; - Crpr commonClkPessimism(const StaState *sta) const; + Crpr checkCrpr(const StaState *sta) const; protected: // Open path of the pulse. diff --git a/search/ClkSkew.cc b/search/ClkSkew.cc index 099bca62..bc6c45f2 100644 --- a/search/ClkSkew.cc +++ b/search/ClkSkew.cc @@ -281,8 +281,7 @@ ClkSkews::findWorstClkSkew(const Corner *corner, clks.push_back(clk); ClkSkewMap skews = findClkSkew(clks, corner, setup_hold, include_internal_latency); float worst_skew = 0.0; - for (auto clk_skew_itr : skews) { - ClkSkew &clk_skew = clk_skew_itr.second; + for (const auto& [clk, clk_skew] : skews) { float skew = clk_skew.skew(); if (abs(skew) > abs(worst_skew)) worst_skew = skew; @@ -318,9 +317,7 @@ ClkSkews::findClkSkew(ConstClockSeq &clks, // Reduce skews from each register source. for (size_t i = 0; i < partial_skews.size(); i++) { - for (auto clk_skew_itr : partial_skews[i]) { - const Clock *clk = clk_skew_itr.first; - auto partial_skew = clk_skew_itr.second; + for (auto& [clk, partial_skew] : partial_skews[i]) { auto ins = skews.insert(std::make_pair(clk, partial_skew)); if (!ins.second) { ClkSkew &final_skew = ins.first->second; diff --git a/search/Genclks.cc b/search/Genclks.cc index f93a5b1d..1066df86 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -676,10 +676,10 @@ Genclks::seedSrcPins(Clock *gclk, for (auto path_ap : corners_->pathAnalysisPts()) { const MinMax *min_max = path_ap->pathMinMax(); const EarlyLate *early_late = min_max; - for (auto tr : RiseFall::range()) { - Tag *tag = makeTag(gclk, master_clk, master_pin, tr, src_filter, + for (auto rf : RiseFall::range()) { + Tag *tag = makeTag(gclk, master_clk, master_pin, rf, src_filter, path_ap); - Arrival insert = search_->clockInsertion(master_clk, master_pin, tr, + Arrival insert = search_->clockInsertion(master_clk, master_pin, rf, min_max, early_late, path_ap); tag_bldr.setArrival(tag, insert, nullptr); } diff --git a/search/Latches.cc b/search/Latches.cc index c625b855..3ec2dfe8 100644 --- a/search/Latches.cc +++ b/search/Latches.cc @@ -473,9 +473,9 @@ Latches::latchDtoQEnable(Edge *d_q_edge, state = LatchEnableState::open; LibertyCell *cell = network_->libertyCell(inst); if (cell) { - TimingArcSet *d_q_set = d_q_edge->timingArcSet(); - LibertyPort *enable_port; - FuncExpr *enable_func; + const TimingArcSet *d_q_set = d_q_edge->timingArcSet(); + const LibertyPort *enable_port; + const FuncExpr *enable_func; cell->latchEnable(d_q_set, enable_port, enable_func, enable_rf); if (enable_port) { Pin *enable_pin = network_->findPin(inst, enable_port); diff --git a/search/MakeTimingModel.cc b/search/MakeTimingModel.cc index d8252e3c..235b8920 100644 --- a/search/MakeTimingModel.cc +++ b/search/MakeTimingModel.cc @@ -395,9 +395,7 @@ void MakeTimingModel::makeSetupHoldTimingArcs(const Pin *input_pin, const ClockEdgeDelays &clk_margins) { - for (auto clk_edge_margins : clk_margins) { - const ClockEdge *clk_edge = clk_edge_margins.first; - RiseFallMinMax &margins = clk_edge_margins.second; + for (const auto& [clk_edge, margins] : clk_margins) { for (MinMax *min_max : MinMax::range()) { bool setup = (min_max == MinMax::max()); TimingArcAttrsPtr attrs = nullptr; @@ -442,9 +440,7 @@ void MakeTimingModel::makeInputOutputTimingArcs(const Pin *input_pin, OutputPinDelays &output_pin_delays) { - for (auto out_pin_delay : output_pin_delays) { - const Pin *output_pin = out_pin_delay.first; - OutputDelays &output_delays = out_pin_delay.second; + for (const auto& [output_pin, output_delays] : output_pin_delays) { TimingArcAttrsPtr attrs = nullptr; for (RiseFall *output_rf : RiseFall::range()) { MinMax *min_max = MinMax::max(); @@ -499,9 +495,7 @@ MakeTimingModel::findClkedOutputPaths() delayAsFloat(delay, min_max, sta_)); } } - for (auto clk_edge_delay : clk_delays) { - const ClockEdge *clk_edge = clk_edge_delay.first; - RiseFallMinMax &delays = clk_edge_delay.second; + 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) { @@ -659,9 +653,6 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin, { const DcalcAnalysisPt *dcalc_ap = corner_->findDcalcAnalysisPt(min_max_); const Pvt *pvt = dcalc_ap->operatingConditions(); - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); - int lib_index = dcalc_ap->libertyIndex(); - PinSet *drvrs = network_->drivers(network_->net(network_->term(output_pin))); const Pin *drvr_pin = *drvrs->begin(); const LibertyPort *drvr_port = network_->libertyPort(drvr_pin); @@ -680,8 +671,7 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin, drvr_arc->fromEdge()->asRiseFall(), dcalc_ap->index()); float in_slew1 = delayAsFloat(in_slew); - TimingModel *drvr_model = drvr_arc->cornerArc(lib_index)->model(op_cond); - GateTableModel *drvr_gate_model = dynamic_cast(drvr_model); + GateTableModel *drvr_gate_model = drvr_arc->gateTableModel(dcalc_ap); if (drvr_gate_model) { float output_load_cap = graph_delay_calc_->loadCap(output_pin, dcalc_ap); ArcDelay drvr_self_delay; diff --git a/search/PathEnd.cc b/search/PathEnd.cc index 6c67ad40..9f8503d2 100644 --- a/search/PathEnd.cc +++ b/search/PathEnd.cc @@ -259,7 +259,16 @@ PathEnd::borrow(const StaState *) const } Crpr -PathEnd::commonClkPessimism(const StaState *) const +PathEnd::checkCrpr(const StaState *sta) const +{ + if (checkRole(sta)->genericRole() == TimingRole::hold()) + return -crpr(sta); + else + return crpr(sta);; +} + +Crpr +PathEnd::crpr(const StaState *) const { return 0.0; } @@ -618,7 +627,7 @@ Arrival PathEndClkConstrained::targetClkArrival(const StaState *sta) const { return targetClkArrivalNoCrpr(sta) - + commonClkPessimism(sta); + + checkCrpr(sta); } Arrival @@ -689,24 +698,21 @@ PathEndClkConstrained::targetClkUncertainty(const StaState *sta) const } Crpr -PathEndClkConstrained::commonClkPessimism(const StaState *sta) const +PathEndClkConstrained::crpr(const StaState *sta) const { if (!crpr_valid_) { CheckCrpr *check_crpr = sta->search()->checkCrpr(); crpr_ = check_crpr->checkCrpr(path_.path(), targetClkPath()); crpr_valid_ = true; } - if (checkRole(sta)->genericRole() == TimingRole::hold()) - return -crpr_; - else - return crpr_; + return crpr_; } Required PathEndClkConstrained::requiredTime(const StaState *sta) const { return requiredTimeNoCrpr(sta) - + commonClkPessimism(sta); + + checkCrpr(sta); } Required @@ -1014,8 +1020,7 @@ PathEndCheck::exceptPathCmp(const PathEnd *path_end, Delay PathEndCheck::clkSkew(const StaState *sta) { - commonClkPessimism(sta); - return sourceClkDelay(sta) - targetClkDelay(sta) - crpr_ + return sourceClkDelay(sta) - targetClkDelay(sta) - crpr(sta) // Uncertainty decreases slack, but increases skew. - checkTgtClkUncertainty(&clk_path_, clk_path_.clkEdge(sta), checkRole(sta), sta); } @@ -1373,13 +1378,12 @@ PathEndOutputDelay::targetClkArrivalNoCrpr(const StaState *sta) const } Crpr -PathEndOutputDelay::commonClkPessimism(const StaState *sta) const +PathEndOutputDelay::crpr(const StaState *sta) const { if (!crpr_valid_) { CheckCrpr *check_crpr = sta->search()->checkCrpr(); crpr_ = check_crpr->outputDelayCrpr(path_.path(), targetClkEdge(sta)); - if (checkRole(sta)->genericRole() == TimingRole::hold()) - crpr_ = -crpr_; + crpr_valid_ = true; } return crpr_; } diff --git a/search/PathGroup.cc b/search/PathGroup.cc index 40d793fe..0b61358e 100644 --- a/search/PathGroup.cc +++ b/search/PathGroup.cc @@ -255,8 +255,7 @@ PathGroups::makeGroups(int group_count, { int mm_index = min_max->index(); if (setup_hold) { - for (auto name_group : sdc_->groupPaths()) { - const char *name = name_group.first; + for (const auto [name, group] : sdc_->groupPaths()) { if (reportGroup(name, group_names)) { PathGroup *group = PathGroup::makePathGroupSlack(name, group_count, endpoint_count, unique_pins, @@ -840,7 +839,7 @@ public: virtual void visit(Vertex *vertex); private: - VisitPathEnds *visit_path_ends_; + VisitPathEnds visit_path_ends_; PathEndVisitor *path_end_visitor_; const Corner *corner_; const MinMaxAll *min_max_; @@ -851,7 +850,7 @@ MakeEndpointPathEnds::MakeEndpointPathEnds(PathEndVisitor *path_end_visitor, const Corner *corner, const MinMaxAll *min_max, const StaState *sta) : - visit_path_ends_(new VisitPathEnds(sta)), + visit_path_ends_(sta), path_end_visitor_(path_end_visitor->copy()), corner_(corner), min_max_(min_max), @@ -860,7 +859,7 @@ MakeEndpointPathEnds::MakeEndpointPathEnds(PathEndVisitor *path_end_visitor, } MakeEndpointPathEnds::MakeEndpointPathEnds(const MakeEndpointPathEnds &make_path_ends) : - visit_path_ends_(new VisitPathEnds(make_path_ends.sta_)), + visit_path_ends_(make_path_ends.sta_), path_end_visitor_(make_path_ends.path_end_visitor_->copy()), corner_(make_path_ends.corner_), min_max_(make_path_ends.min_max_), @@ -870,7 +869,6 @@ MakeEndpointPathEnds::MakeEndpointPathEnds(const MakeEndpointPathEnds &make_path MakeEndpointPathEnds::~MakeEndpointPathEnds() { - delete visit_path_ends_; delete path_end_visitor_; } @@ -883,8 +881,7 @@ MakeEndpointPathEnds::copy() const void MakeEndpointPathEnds::visit(Vertex *vertex) { - visit_path_ends_->visitPathEnds(vertex, corner_, min_max_, true, - path_end_visitor_); + visit_path_ends_.visitPathEnds(vertex, corner_, min_max_, true, path_end_visitor_); } //////////////////////////////////////////////////////////////// @@ -904,7 +901,7 @@ PathGroups::makeGroupPathEnds(VertexSet *endpoints, Vector visitors(thread_count_, MakeEndpointPathEnds(visitor, corner, min_max, this)); - for (auto endpoint : *endpoints) { + for (const auto endpoint : *endpoints) { dispatch_queue_->dispatch( [endpoint, &visitors](int i) { visitors[i].visit(endpoint); } ); } diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 9f521745..662a1dba 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -1192,7 +1192,7 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check) reportLine(pin_name, delay_zero, close_arrival, close_el); if (sdc_->crprEnabled()) { - Crpr pessimism = check->commonClkPessimism(this); + Crpr pessimism = check->checkCrpr(this); close_arrival += pessimism; reportLine("clock reconvergence pessimism", pessimism, close_arrival, close_el); } @@ -1803,7 +1803,7 @@ ReportPath::clkRegLatchDesc(const PathEnd *end) TimingRole *role = arc_set->role(); if (role == TimingRole::regClkToQ() || role == TimingRole::latchEnToQ()) { - RiseFall *arc_rf = arc_set->isRisingFallingEdge(); + const RiseFall *arc_rf = arc_set->isRisingFallingEdge(); clk_set = arc_set; if (arc_rf == check_clk_rf) clk_rf_set = arc_set; @@ -2320,7 +2320,7 @@ ReportPath::reportCommonClkPessimism(const PathEnd *end, Arrival &clk_arrival) { if (sdc_->crprEnabled()) { - Crpr pessimism = end->commonClkPessimism(this); + Crpr pessimism = end->checkCrpr(this); clk_arrival += pessimism; reportLine("clock reconvergence pessimism", pessimism, clk_arrival, end->clkEarlyLate(this)); @@ -3250,8 +3250,8 @@ ReportPath::edgeRegLatchDesc(Edge *first_edge, Instance *inst = network_->instance(first_edge->to(graph_)->pin()); LibertyCell *cell = network_->libertyCell(inst); if (cell) { - LibertyPort *enable_port; - FuncExpr *enable_func; + const LibertyPort *enable_port; + const FuncExpr *enable_func; const RiseFall *enable_rf; cell->latchEnable(first_edge->timingArcSet(), enable_port, enable_func, enable_rf); diff --git a/search/Search.cc b/search/Search.cc index 521d3589..350084f2 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -905,8 +905,7 @@ Search::visitStartpoints(VertexVisitor *visitor) } delete pin_iter; - for (auto iter : sdc_->inputDelayPinMap()) { - const Pin *pin = iter.first; + for (const auto [pin, input_delays] : sdc_->inputDelayPinMap()) { // Already hit these. if (!network_->isTopLevelPort(pin)) { Vertex *vertex = graph_->pinDrvrVertex(pin); @@ -1674,8 +1673,7 @@ Search::seedInputArrivals(ClockSet *clks) { // Input arrivals can be on internal pins, so iterate over the pins // that have input arrivals rather than the top level input pins. - for (auto iter : sdc_->inputDelayPinMap()) { - const Pin *pin = iter.first; + for (const auto [pin, input_delays] : sdc_->inputDelayPinMap()) { if (!sdc_->isLeafPinClock(pin)) { Vertex *vertex = graph_->pinDrvrVertex(pin); seedInputArrival(pin, vertex, clks); @@ -2928,7 +2926,7 @@ Search::reportClkInfos() const sort(clk_infos, ClkInfoLess(this)); for (ClkInfo *clk_info : clk_infos) report_->reportLine("ClkInfo %s", clk_info->asString(this)); - report_->reportLine("%lu clk infos", clk_info_set_->size()); + report_->reportLine("%zu clk infos", clk_info_set_->size()); } ClkInfo * diff --git a/search/Sim.cc b/search/Sim.cc index 6d67611a..cd33de74 100644 --- a/search/Sim.cc +++ b/search/Sim.cc @@ -682,9 +682,7 @@ Sim::propagateConstants(bool thru_sequentials) void Sim::setConstraintConstPins(LogicValueMap &value_map) { - for (auto pin_value : value_map) { - const Pin *pin = pin_value.first; - LogicValue value = pin_value.second; + for (const auto [pin, value] : value_map) { debugPrint(debug_, "sim", 2, "case pin %s = %c", network_->pathName(pin), logicValueString(value)); @@ -1219,10 +1217,9 @@ isModeDisabled(Edge *edge, if (cond_value == LogicValue::zero) { // For a mode value to be disabled by having a value of // logic zero one mode value must logic one. - for (auto name_mode : *mode_def->values()) { - ModeValueDef *value_def1 = name_mode.second; - if (value_def1) { - FuncExpr *cond1 = value_def1->cond(); + for (const auto [name, value_def] : *mode_def->values()) { + if (value_def) { + FuncExpr *cond1 = value_def->cond(); if (cond1) { LogicValue cond_value1 = sim->evalExpr(cond1, inst); if (cond_value1 == LogicValue::one) { diff --git a/search/Sta.cc b/search/Sta.cc index fc1a6777..79325f65 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -349,8 +349,7 @@ Sta::updateComponentsState() corners_->copyState(this); levelize_->copyState(this); parasitics_->copyState(this); - if (arc_delay_calc_) - arc_delay_calc_->copyState(this); + arc_delay_calc_->copyState(this); sim_->copyState(this); search_->copyState(this); latches_->copyState(this); @@ -531,8 +530,7 @@ Sta::~Sta() delete search_; delete latches_; delete parasitics_; - if (arc_delay_calc_) - delete arc_delay_calc_; + delete arc_delay_calc_; delete graph_delay_calc_; delete sim_; delete levelize_; @@ -776,8 +774,7 @@ Sta::setAnalysisType(AnalysisType analysis_type) { if (analysis_type != sdc_->analysisType()) { sdc_->setAnalysisType(analysis_type); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); search_->deletePathGroups(); corners_->analysisTypeChanged(); if (graph_) @@ -797,8 +794,7 @@ Sta::setOperatingConditions(OperatingConditions *op_cond, { sdc_->setOperatingConditions(op_cond, min_max); corners_->operatingConditionsChanged(); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); } const Pvt * @@ -1000,8 +996,7 @@ void Sta::setWireloadMode(WireloadMode mode) { sdc_->setWireloadMode(mode); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); } void @@ -1009,8 +1004,7 @@ Sta::setWireload(Wireload *wireload, const MinMaxAll *min_max) { sdc_->setWireload(wireload, min_max); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); } void @@ -1018,8 +1012,7 @@ Sta::setWireloadSelection(WireloadSelection *selection, const MinMaxAll *min_max) { sdc_->setWireloadSelection(selection, min_max); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); } void @@ -1148,8 +1141,7 @@ void Sta::setPropagatedClock(Clock *clk) { sdc_->setPropagatedClock(clk); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); clkPinsInvalid(); } @@ -1157,8 +1149,7 @@ void Sta::removePropagatedClock(Clock *clk) { sdc_->removePropagatedClock(clk); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); clkPinsInvalid(); } @@ -1166,8 +1157,7 @@ void Sta::setPropagatedClock(Pin *pin) { sdc_->setPropagatedClock(pin); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); clkPinsInvalid(); } @@ -1175,8 +1165,7 @@ void Sta::removePropagatedClock(Pin *pin) { sdc_->removePropagatedClock(pin); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); clkPinsInvalid(); } @@ -1609,8 +1598,7 @@ Sta::disableAfter() { // Levelization respects disabled edges. levelize_->invalid(); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); } //////////////////////////////////////////////////////////////// @@ -1837,8 +1825,7 @@ Sta::setLogicValue(Pin *pin, // fails. This could be more incremental if the graph delay // calculator searched thru disabled edges but ignored their // results. - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); } void @@ -1854,8 +1841,7 @@ Sta::setCaseAnalysis(Pin *pin, // simply invaldating the delays downstream from the constant pin // fails. This could be handled incrementally by invalidating delays // on the output of gates one level downstream. - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); } void @@ -1870,8 +1856,7 @@ Sta::removeCaseAnalysis(Pin *pin) // simply invaldating the delays downstream from the constant pin // fails. This could be handled incrementally by invalidating delays // on the output of gates one level downstream. - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); } void @@ -2131,8 +2116,7 @@ void Sta::constraintsChanged() { levelize_->invalid(); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); sim_->constantsInvalid(); } @@ -2215,10 +2199,8 @@ Sta::pocvEnabled() const void Sta::setPocvEnabled(bool enabled) { - if (enabled != pocv_enabled_) { - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); - } + if (enabled != pocv_enabled_) + delaysInvalid(); pocv_enabled_ = enabled; updateComponentsState(); } @@ -2258,8 +2240,7 @@ Sta::setPresetClrArcsEnabled(bool enable) { if (sdc_->presetClrArcsEnabled() != enable) { levelize_->invalid(); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); } sdc_->setPresetClrArcsEnabled(enable); } @@ -2274,8 +2255,7 @@ void Sta::setCondDefaultArcsEnabled(bool enabled) { if (sdc_->condDefaultArcsEnabled() != enabled) { - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); sdc_->setCondDefaultArcsEnabled(enabled); } } @@ -2291,8 +2271,7 @@ Sta::setBidirectInstPathsEnabled(bool enabled) { if (sdc_->bidirectInstPathsEnabled() != enabled) { levelize_->invalid(); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); sdc_->setBidirectInstPathsEnabled(enabled); } } @@ -2307,8 +2286,7 @@ void Sta::setBidirectNetPathsEnabled(bool enabled) { if (sdc_->bidirectNetPathsEnabled() != enabled) { - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); sdc_->setBidirectNetPathsEnabled(enabled); } } @@ -2656,7 +2634,7 @@ Sta::findClkDelays(const Clock *clk, //////////////////////////////////////////////////////////////// void -Sta::delaysInvalid() +Sta::delaysInvalid() const { graph_delay_calc_->delaysInvalid(); search_->arrivalsInvalid(); @@ -3106,8 +3084,8 @@ Sta::vertexSlacks(Vertex *vertex, Slack (&slacks)[RiseFall::index_count][MinMax::index_count]) { findRequired(vertex); - for(int rf_index : RiseFall::rangeIndex()) { - for(MinMax *min_max : MinMax::range()) { + for (int rf_index : RiseFall::rangeIndex()) { + for (const MinMax *min_max : MinMax::range()) { slacks[rf_index][min_max->index()] = MinMax::min()->initValue(); } } @@ -3327,8 +3305,7 @@ Sta::setArcDelayCalc(const char *delay_calc_name) arc_delay_calc_ = makeDelayCalc(delay_calc_name, sta_); // Update pointers to arc_delay_calc. updateComponentsState(); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); } void @@ -3639,7 +3616,7 @@ Sta::setAnnotatedSlew(Vertex *vertex, void Sta::writeSdf(const char *filename, - Corner *corner, + const Corner *corner, char divider, bool include_typ, int digits, @@ -3656,7 +3633,7 @@ void Sta::removeDelaySlewAnnotations() { graph_->removeDelaySlewAnnotations(); - graph_delay_calc_->delaysInvalid(); + delaysInvalid(); } LogicValue @@ -3768,7 +3745,7 @@ void Sta::removeNetLoadCaps() const { sdc_->removeNetLoadCaps(); - graph_delay_calc_->delaysInvalid(); + delaysInvalid(); } void @@ -3920,8 +3897,7 @@ Sta::readSpef(const char *filename, pin_cap_included, keep_coupling_caps, coupling_cap_factor, reduce, corner, min_max, this); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); return success; } @@ -4023,8 +3999,7 @@ void Sta::deleteParasitics() { parasitics_->deleteParasitics(); - graph_delay_calc_->delaysInvalid(); - search_->arrivalsInvalid(); + delaysInvalid(); } Parasitic * diff --git a/search/TagGroup.cc b/search/TagGroup.cc index e922d05c..bb0b2a6f 100644 --- a/search/TagGroup.cc +++ b/search/TagGroup.cc @@ -90,7 +90,7 @@ void TagGroup::report(const StaState *sta) const { Report *report = sta->report(); - report->reportLine("Group %u hash = %lu", index_, hash_); + report->reportLine("Group %u hash = %zu", index_, hash_); arrivalMapReport(arrival_map_, sta); } diff --git a/search/WritePathSpice.cc b/spice/WritePathSpice.cc similarity index 94% rename from search/WritePathSpice.cc rename to spice/WritePathSpice.cc index 93b0970e..ab6509fe 100644 --- a/search/WritePathSpice.cc +++ b/spice/WritePathSpice.cc @@ -40,7 +40,7 @@ #include "PathRef.hh" #include "PathExpanded.hh" #include "StaState.hh" -#include "Sim.hh" +#include "search/Sim.hh" #include "WriteSpice.hh" namespace sta { @@ -137,6 +137,8 @@ private: // Input clock waveform cycles. int clk_cycle_count_; + InstanceSet written_insts_; + using WriteSpice::writeHeader; using WriteSpice::writePrintStmt; using WriteSpice::writeSubckts; @@ -177,12 +179,14 @@ WritePathSpice::WritePathSpice(Path *path, CircuitSim ckt_sim, const StaState *sta) : WriteSpice(spice_filename, subckt_filename, lib_subckt_filename, - model_filename, power_name, gnd_name, ckt_sim, sta), + model_filename, power_name, gnd_name, ckt_sim, + path->dcalcAnalysisPt(sta), sta), path_(path), path_expanded_(sta), - clk_cycle_count_(3) + clk_cycle_count_(3), + written_insts_(network_) { - initPowerGnd( path_->dcalcAnalysisPt(this)); + initPowerGnd(); } void @@ -253,18 +257,17 @@ float WritePathSpice::pathMaxTime() { float max_time = 0.0; - DcalcAPIndex dcalc_ap_index = path_->dcalcAnalysisPt(this)->index(); for (size_t i = 0; i < path_expanded_.size(); i++) { PathRef *path = path_expanded_.path(i); const RiseFall *rf = path->transition(this); Vertex *vertex = path->vertex(this); - float path_max_slew = railToRailSlew(findSlew(vertex,rf,nullptr,dcalc_ap_index),rf); + float path_max_slew = railToRailSlew(findSlew(vertex,rf,nullptr), rf); if (vertex->isDriver(network_)) { VertexOutEdgeIterator edge_iter(vertex, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); Vertex *load = edge->to(graph_); - float load_slew = railToRailSlew(findSlew(load, rf, nullptr, dcalc_ap_index),rf); + float load_slew = railToRailSlew(findSlew(load, rf, nullptr), rf); if (load_slew > path_max_slew) path_max_slew = load_slew; } @@ -387,9 +390,8 @@ float WritePathSpice::findSlew(Path *path) { Vertex *vertex = path->vertex(this); - DcalcAPIndex dcalc_ap_index = path->dcalcAnalysisPt(this)->index(); const RiseFall *rf = path->transition(this); - return findSlew(vertex, rf, nullptr, dcalc_ap_index); + return findSlew(vertex, rf, nullptr); } float @@ -398,8 +400,7 @@ WritePathSpice::findSlew(Path *path, TimingArc *next_arc) { Vertex *vertex = path->vertex(this); - DcalcAPIndex dcalc_ap_index = path->dcalcAnalysisPt(this)->index(); - return findSlew(vertex, rf, next_arc, dcalc_ap_index); + return findSlew(vertex, rf, next_arc); } //////////////////////////////////////////////////////////////// @@ -496,7 +497,7 @@ WritePathSpice::writeGateStage(Stage stage) const char *load_pin_name = stageLoadPinName(stage); string subckt_name = "stage" + std::to_string(stage); - Instance *inst = stageInstance(stage); + const Instance *inst = stageInstance(stage); LibertyPort *input_port = stageGateInputPort(stage); LibertyPort *drvr_port = stageDrvrPort(stage); @@ -511,10 +512,9 @@ WritePathSpice::writeGateStage(Stage stage) network_->pathName(inst), input_port->name(), drvr_port->name()); - writeSubcktInst(input_pin); + writeSubcktInst(inst); PathRef *drvr_path = stageDrvrPath(stage); - DcalcAPIndex dcalc_ap_index = drvr_path->dcalcAnalysisPt(this)->index(); const RiseFall *drvr_rf = drvr_path->transition(this); Edge *gate_edge = stageGateEdge(stage); @@ -523,11 +523,20 @@ WritePathSpice::writeGateStage(Stage stage) gatePortValues(input_pin, drvr_pin, drvr_rf, gate_edge, port_values, is_clked); - const Clock *clk = (is_clked) ? stageDrvrPath(stage)->clock(this) : nullptr; - writeSubcktInstVoltSrcs(input_pin, port_values, clk, dcalc_ap_index); + PinSet inputs(network_); + inputs.insert(input_pin); + writeSubcktInstVoltSrcs(inst, port_values, inputs); streamPrint(spice_stream_, "\n"); - writeSubcktInstLoads(drvr_pin, load_pin); + PinSet drvr_loads(network_); + PinConnectedPinIterator *pin_iter = network_->connectedPinIterator(drvr_pin); + while (pin_iter->hasNext()) { + const Pin *load_pin = pin_iter->next(); + drvr_loads.insert(load_pin); + } + delete pin_iter; + + writeSubcktInstLoads(drvr_pin, load_pin, drvr_loads, written_insts_); writeStageParasitics(stage); streamPrint(spice_stream_, ".ends\n\n"); } @@ -538,9 +547,14 @@ WritePathSpice::writeStageParasitics(Stage stage) PathRef *drvr_path = stageDrvrPath(stage); DcalcAnalysisPt *dcalc_ap = drvr_path->dcalcAnalysisPt(this); ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); + const Pin *drvr_pin = stageDrvrPin(stage); + const Parasitic *parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); + if (parasitic == nullptr) { + const RiseFall *drvr_rf = drvr_path->transition(this); + parasitic = parasitics_->findPiElmore(drvr_pin, drvr_rf, parasitic_ap); + } NetSet coupling_nets; - writeDrvrParasitics(stageDrvrPin(stage), drvr_path->transition(this), - coupling_nets, parasitic_ap); + writeDrvrParasitics(drvr_pin, parasitic, coupling_nets); } //////////////////////////////////////////////////////////////// diff --git a/include/sta/WritePathSpice.hh b/spice/WritePathSpice.hh similarity index 100% rename from include/sta/WritePathSpice.hh rename to spice/WritePathSpice.hh diff --git a/search/WriteSpice.cc b/spice/WriteSpice.cc similarity index 91% rename from search/WriteSpice.cc rename to spice/WriteSpice.cc index 94dc99f9..84d7b656 100644 --- a/search/WriteSpice.cc +++ b/spice/WriteSpice.cc @@ -14,7 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "WriteSpice.hh" +#include "spice/WriteSpice.hh" + +#include // swap #include "Debug.hh" #include "Units.hh" @@ -27,7 +29,7 @@ #include "Liberty.hh" #include "Network.hh" #include "Graph.hh" -#include "Sim.hh" +#include "search/Sim.hh" #include "Clock.hh" #include "PathVertex.hh" #include "DcalcAnalysisPt.hh" @@ -36,6 +38,8 @@ namespace sta { using std::ifstream; +using std::swap; +using std::set; Net * pinNet(const Pin *pin, @@ -77,6 +81,7 @@ WriteSpice::WriteSpice(const char *spice_filename, const char *power_name, const char *gnd_name, CircuitSim ckt_sim, + const DcalcAnalysisPt *dcalc_ap, const StaState *sta) : StaState(sta), spice_filename_(spice_filename), @@ -86,23 +91,23 @@ WriteSpice::WriteSpice(const char *spice_filename, power_name_(power_name), gnd_name_(gnd_name), ckt_sim_(ckt_sim), + dcalc_ap_(dcalc_ap), default_library_(network_->defaultLibertyLibrary()), short_ckt_resistance_(.0001), cap_index_(1), res_index_(1), volt_index_(1), - next_node_index_(1), bdd_(sta) { } void -WriteSpice::initPowerGnd(const DcalcAnalysisPt *dcalc_ap) +WriteSpice::initPowerGnd() { bool exists = false; default_library_->supplyVoltage(power_name_, power_voltage_, exists); if (!exists) { - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); + const OperatingConditions *op_cond = dcalc_ap_->operatingConditions(); if (op_cond == nullptr) op_cond = network_->defaultLibertyLibrary()->defaultOperatingConditions(); power_voltage_ = op_cond->voltage(); @@ -182,7 +187,7 @@ WriteSpice::writeGnuplotFile(StdStringSeq &node_nanes) csv_filename.c_str()); for (size_t i = 3; i <= node_nanes.size() + 1; i++) { streamPrint(gnuplot_stream, ",\\\n"); - streamPrint(gnuplot_stream, "'' using 1:%lu with lines", i); + streamPrint(gnuplot_stream, "'' using 1:%zu with lines", i); } streamPrint(gnuplot_stream, "\n"); streamPrint(gnuplot_stream, "pause mouse close\n"); @@ -312,9 +317,8 @@ WriteSpice::findCellSubckts(StdStringSet &cell_names) //////////////////////////////////////////////////////////////// void -WriteSpice::writeSubcktInst(const Pin *input_pin) +WriteSpice::writeSubcktInst(const Instance *inst) { - const Instance *inst = network_->instance(input_pin); const char *inst_name = network_->pathName(inst); LibertyCell *cell = network_->libertyCell(inst); const char *cell_name = cell->name(); @@ -340,23 +344,20 @@ WriteSpice::writeSubcktInst(const Pin *input_pin) // Power/ground and input voltage sources. void -WriteSpice::writeSubcktInstVoltSrcs(const Pin *input_pin, +WriteSpice::writeSubcktInstVoltSrcs(const Instance *inst, LibertyPortLogicValues &port_values, - const Clock *clk, - DcalcAPIndex dcalc_ap_index) + const PinSet &excluded_input_pins) { - const Instance *inst = network_->instance(input_pin); LibertyCell *cell = network_->libertyCell(inst); const char *cell_name = cell->name(); StringVector &spice_port_names = cell_spice_port_names_[cell_name]; - - const LibertyPort *input_port = network_->libertyPort(input_pin); const char *inst_name = network_->pathName(inst); debugPrint(debug_, "write_spice", 2, "subckt %s", cell->name()); for (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; LibertyPgPort *pg_port = cell->findPgPort(subckt_port_name); debugPrint(debug_, "write_spice", 2, " port %s%s", subckt_port_name, @@ -369,10 +370,9 @@ WriteSpice::writeSubcktInstVoltSrcs(const Pin *input_pin, else if (stringEq(subckt_port_name, gnd_name_)) writeVoltageSource(inst_name, subckt_port_name, gnd_voltage_); else if (port - && port != input_port + && excluded_input_pins.find(pin) == excluded_input_pins.end() && port->direction()->isAnyInput()) { // Input voltage to sensitize path from gate input to output. - const Pin *pin = network_->findPin(inst, port); // Look for tie high/low or propagated constant values. LogicValue port_value = sim_->logicValue(pin); if (port_value == LogicValue::unknown) { @@ -395,11 +395,7 @@ WriteSpice::writeSubcktInstVoltSrcs(const Pin *input_pin, power_voltage_); break; case LogicValue::rise: - writeClkedStepSource(pin, RiseFall::rise(), clk, dcalc_ap_index); - - break; case LogicValue::fall: - writeClkedStepSource(pin, RiseFall::fall(), clk, dcalc_ap_index); break; } } @@ -465,34 +461,14 @@ WriteSpice::pgPortVoltage(LibertyPgPort *pg_port) return voltage; } -// PWL voltage source that rises half way into the first clock cycle. -void -WriteSpice::writeClkedStepSource(const Pin *pin, - const RiseFall *rf, - const Clock *clk, - DcalcAPIndex dcalc_ap_index) -{ - Vertex *vertex = graph_->pinLoadVertex(pin); - float slew = findSlew(vertex, rf, nullptr, dcalc_ap_index); - float time = clkWaveformTimeOffset(clk) + clk->period() / 2.0; - writeRampVoltSource(pin, rf, time, slew); -} - -float -WriteSpice::clkWaveformTimeOffset(const Clock *clk) -{ - return clk->period() / 10; -} - //////////////////////////////////////////////////////////////// float WriteSpice::findSlew(Vertex *vertex, const RiseFall *rf, - TimingArc *next_arc, - DcalcAPIndex dcalc_ap_index) + TimingArc *next_arc) { - float slew = delayAsFloat(graph_->slew(vertex, rf, dcalc_ap_index)); + float slew = delayAsFloat(graph_->slew(vertex, rf, dcalc_ap_->index())); if (slew == 0.0 && next_arc) slew = slewAxisMinValue(next_arc); if (slew == 0.0) @@ -504,7 +480,7 @@ WriteSpice::findSlew(Vertex *vertex, float WriteSpice::slewAxisMinValue(TimingArc *arc) { - GateTableModel *gate_model = dynamic_cast(arc->model()); + GateTableModel *gate_model = arc->gateTableModel(dcalc_ap_); if (gate_model) { const TableModel *model = gate_model->delayModel(); const TableAxis *axis1 = model->axis1(); @@ -532,27 +508,20 @@ WriteSpice::slewAxisMinValue(TimingArc *arc) void WriteSpice::writeDrvrParasitics(const Pin *drvr_pin, - const RiseFall *drvr_rf, - const NetSet &aggressor_nets, - const ParasiticAnalysisPt *parasitic_ap) + const Parasitic *parasitic, + 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); - Parasitic *parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); - node_map_.clear(); - next_node_index_ = 1; - if (parasitic) - writeParasiticNetwork(drvr_pin, parasitic, aggressor_nets); + if (parasitics_->isParasiticNetwork(parasitic)) + writeParasiticNetwork(drvr_pin, parasitic, coupling_nets); + else if (parasitics_->isPiElmore(parasitic)) + writePiElmore(drvr_pin, parasitic); else { - parasitic = parasitics_->findPiElmore(drvr_pin, drvr_rf, parasitic_ap); - if (parasitic) - writePiElmore(drvr_pin, parasitic); - else { - streamPrint(spice_stream_, "* Net has no parasitics.\n"); - writeNullParasitic(drvr_pin); - } + streamPrint(spice_stream_, "* Net has no parasitics.\n"); + writeNullParasitic(drvr_pin); } } @@ -561,7 +530,7 @@ WriteSpice::writeParasiticNetwork(const Pin *drvr_pin, const Parasitic *parasitic, const NetSet &coupling_nets) { - Set reachable_pins; + set reachable_pins; // Sort resistors for consistent regression results. ParasiticResistorSeq resistors = parasitics_->resistors(parasitic); sort(resistors.begin(), resistors.end(), @@ -575,8 +544,8 @@ WriteSpice::writeParasiticNetwork(const Pin *drvr_pin, ParasiticNode *node2 = parasitics_->node2(resistor); streamPrint(spice_stream_, "R%d %s %s %.3e\n", res_index_++, - nodeName(node1), - nodeName(node2), + parasitics_->name(node1), + parasitics_->name(node2), resistance); // Necessary but not sufficient. Need a DFS. @@ -595,7 +564,7 @@ WriteSpice::writeParasiticNetwork(const Pin *drvr_pin, if (pin != drvr_pin && network_->isLoad(pin) && !network_->isHierarchical(pin) - && !reachable_pins.hasKey(pin)) { + && reachable_pins.find(pin) == reachable_pins.end()) { streamPrint(spice_stream_, "R%d %s %s %.3e\n", res_index_++, network_->pathName(drvr_pin), @@ -605,6 +574,7 @@ WriteSpice::writeParasiticNetwork(const Pin *drvr_pin, } delete pin_iter; + // Grounded node capacitors. // Sort nodes for consistent regression results. ParasiticNodeSeq nodes = parasitics_->nodes(parasitic); sort(nodes.begin(), nodes.end(), @@ -621,12 +591,12 @@ WriteSpice::writeParasiticNetwork(const Pin *drvr_pin, if (cap > 0.0) { streamPrint(spice_stream_, "C%d %s 0 %.3e\n", cap_index_++, - nodeName(node), + parasitics_->name(node), cap); } } - // Sort coupling capacitors consistent regression results. + // Sort coupling capacitors for consistent regression results. ParasiticCapacitorSeq capacitors = parasitics_->capacitors(parasitic); sort(capacitors.begin(), capacitors.end(), [=] (const ParasiticCapacitor *c1, @@ -640,21 +610,21 @@ WriteSpice::writeParasiticNetwork(const Pin *drvr_pin, float cap = parasitics_->value(capacitor); const Net *net1 = node1 ? parasitics_->net(node1, network_) : nullptr; const Net *net2 = node2 ? parasitics_->net(node2, network_) : nullptr; - const ParasiticNode *net_node = nullptr; - const char *coupling_name; - if (net1 == net) { - net_node = node1; - coupling_name = net2 && coupling_nets.hasKey(net2) ? nodeName(node2) : "0"; + if (net2 == net) { + swap(net1, net2); + swap(node1, node2); } - else if (net2 == net) { - net_node = node2; - coupling_name = net1 && coupling_nets.hasKey(net1) ? nodeName(node1) : "0"; - } - if (net_node) + if (net2 && coupling_nets.hasKey(net2)) + // Write half the capacitance because the coupled net will do the same. streamPrint(spice_stream_, "C%d %s %s %.3e\n", cap_index_++, - nodeName(net_node), - coupling_name, + parasitics_->name(node1), + parasitics_->name(node2), + cap * .5); + else + streamPrint(spice_stream_, "C%d %s 0 %.3e\n", + cap_index_++, + parasitics_->name(node1), cap); } } @@ -674,27 +644,6 @@ pinNet(const Pin *pin, return net; } -const char * -WriteSpice::nodeName(const ParasiticNode *node) -{ - const Pin *pin = parasitics_->pin(node); - if (pin) - return parasitics_->name(node); - else { - int node_index; - auto index_itr = node_map_.find(node); - if (index_itr == node_map_.end()) { - node_index = next_node_index_++; - node_map_[node] = node_index; - } - else - node_index = index_itr->second; - const Net *net = parasitics_->net(node, network_); - const char *net_name = network_->pathName(net); - return stringPrintTmp("%s:%d", net_name, node_index); - } -} - void WriteSpice::writePiElmore(const Pin *drvr_pin, const Parasitic *parasitic) @@ -1081,21 +1030,23 @@ WriteSpice::seqPortValues(Sequential *seq, LibertyPortLogicValues &port_values) { FuncExpr *data = seq->data(); + // SHOULD choose values for all ports of data to make output rise/fall + // matching rf. LibertyPort *port = onePort(data); if (port) { TimingSense sense = data->portTimingSense(port); switch (sense) { case TimingSense::positive_unate: if (rf == RiseFall::rise()) - port_values[port] = LogicValue::rise; + port_values[port] = LogicValue::one; else - port_values[port] = LogicValue::fall; + port_values[port] = LogicValue::zero; break; case TimingSense::negative_unate: if (rf == RiseFall::rise()) - port_values[port] = LogicValue::fall; + port_values[port] = LogicValue::zero; else - port_values[port] = LogicValue::rise; + port_values[port] = LogicValue::one; break; case TimingSense::non_unate: case TimingSense::none: @@ -1153,20 +1104,25 @@ WriteSpice::drvrLoads(const Pin *drvr_pin) void WriteSpice::writeSubcktInstLoads(const Pin *drvr_pin, - const Pin *exclude) + const Pin *path_load, + const PinSet &excluded_input_pins, + InstanceSet &written_insts) { streamPrint(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) { - if (load_pin != exclude + 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)) { - writeSubcktInst(load_pin); - writeSubcktInstVoltSrcs(load_pin, port_values, nullptr, 0); + && !network_->isTopLevelPort(load_pin) + && !written_insts.hasKey(load_inst)) { + writeSubcktInst(load_inst); + writeSubcktInstVoltSrcs(load_inst, port_values, excluded_input_pins); streamPrint(spice_stream_, "\n"); + written_insts.insert(load_inst); } } } @@ -1264,4 +1220,25 @@ streamPrint(ofstream &stream, va_end(args); } +//////////////////////////////////////////////////////////////// + +// Unused +// PWL voltage source that rises half way into the first clock cycle. +void +WriteSpice::writeClkedStepSource(const Pin *pin, + const RiseFall *rf, + const Clock *clk) +{ + Vertex *vertex = graph_->pinLoadVertex(pin); + float slew = findSlew(vertex, rf, nullptr); + float time = clkWaveformTimeOffset(clk) + clk->period() / 2.0; + writeRampVoltSource(pin, rf, time, slew); } + +float +WriteSpice::clkWaveformTimeOffset(const Clock *clk) +{ + return clk->period() / 10; +} + +} // namespace diff --git a/search/WriteSpice.hh b/spice/WriteSpice.hh similarity index 90% rename from search/WriteSpice.hh rename to spice/WriteSpice.hh index 9d45d55f..5a5f8137 100644 --- a/search/WriteSpice.hh +++ b/spice/WriteSpice.hh @@ -50,10 +50,11 @@ public: const char *power_name, const char *gnd_name, CircuitSim ckt_sim, + const DcalcAnalysisPt *dcalc_ap, const StaState *sta); protected: - void initPowerGnd(const DcalcAnalysisPt *dcalc_ap); + void initPowerGnd(); void writeHeader(string &title, float max_time, float time_step); @@ -63,11 +64,10 @@ protected: void findCellSubckts(StdStringSet &cell_names); void recordSpicePortNames(const char *cell_name, StringVector &tokens); - void writeSubcktInst(const Pin *input_pin); - void writeSubcktInstVoltSrcs(const Pin *input_pin, + void writeSubcktInst(const Instance *inst); + void writeSubcktInstVoltSrcs(const Instance *inst, LibertyPortLogicValues &port_values, - const Clock *clk, - DcalcAPIndex dcalc_ap_index); + const PinSet &excluded_input_pins); float pgPortVoltage(LibertyPgPort *pg_port); void writeVoltageSource(const char *inst_name, const char *port_name, @@ -79,20 +79,21 @@ protected: float voltage); void writeClkedStepSource(const Pin *pin, const RiseFall *rf, - const Clock *clk, - DcalcAPIndex dcalc_ap_index); + const Clock *clk); void writeDrvrParasitics(const Pin *drvr_pin, const RiseFall *drvr_rf, // Nets with parasitics to include coupling caps to. const NetSet &coupling_nets, const ParasiticAnalysisPt *parasitic_ap); + void writeDrvrParasitics(const Pin *drvr_pin, + const Parasitic *parasitic, + const NetSet &coupling_nets); void writeParasiticNetwork(const Pin *drvr_pin, const Parasitic *parasitic, const NetSet &aggressor_nets); void writePiElmore(const Pin *drvr_pin, const Parasitic *parasitic); void writeNullParasitic(const Pin *drvr_pin); - const char *nodeName(const ParasiticNode *node); void writeVoltageSource(const char *node_name, float voltage); @@ -126,8 +127,7 @@ protected: const char *spiceTrans(const RiseFall *rf); float findSlew(Vertex *vertex, const RiseFall *rf, - TimingArc *next_arc, - DcalcAPIndex dcalc_ap_index); + TimingArc *next_arc); float slewAxisMinValue(TimingArc *arc); float clkWaveformTimeOffset(const Clock *clk); @@ -151,7 +151,9 @@ protected: // Return values. LibertyPortLogicValues &port_values); void writeSubcktInstLoads(const Pin *drvr_pin, - const Pin *exclude); + const Pin *path_load, + const PinSet &excluded_input_pins, + InstanceSet &written_insts); PinSeq drvrLoads(const Pin *drvr_pin); void writeSubcktInstVoltSrcs(); string replaceFileExt(string filename, @@ -164,6 +166,7 @@ protected: const char *power_name_; const char *gnd_name_; CircuitSim ckt_sim_; + const DcalcAnalysisPt *dcalc_ap_; ofstream spice_stream_; LibertyLibrary *default_library_; @@ -177,8 +180,6 @@ protected: int cap_index_; int res_index_; int volt_index_; - ParasiticNodeMap node_map_; - int next_node_index_; CellSpicePortNames cell_spice_port_names_; Bdd bdd_; }; diff --git a/spice/WriteSpice.i b/spice/WriteSpice.i new file mode 100644 index 00000000..9115a9bf --- /dev/null +++ b/spice/WriteSpice.i @@ -0,0 +1,43 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2024, 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 . + +%module write_gate_spice + +%{ + +#include "spice/WritePathSpice.hh" + +%} + +%inline %{ + +void +write_path_spice_cmd(PathRef *path, + const char *spice_filename, + const char *subckt_filename, + const char *lib_subckt_filename, + const char *model_filename, + const char *power_name, + const char *gnd_name, + CircuitSim ckt_sim) +{ + Sta *sta = Sta::sta(); + writePathSpice(path, spice_filename, subckt_filename, + lib_subckt_filename, model_filename, + power_name, gnd_name, ckt_sim, sta); +} + +%} // inline diff --git a/spice/WriteSpice.tcl b/spice/WriteSpice.tcl new file mode 100644 index 00000000..200df1e8 --- /dev/null +++ b/spice/WriteSpice.tcl @@ -0,0 +1,279 @@ +# OpenSTA, Static Timing Analyzer +# Copyright (c) 2024, 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 . + +namespace eval sta { + +define_cmd_args "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]} + +proc write_path_spice { args } { + parse_key_args "write_path_spice" args \ + keys {-spice_directory -lib_subckt_file -model_file \ + -power -ground -path_args -simulator} \ + flags {} + + if { [info exists keys(-spice_directory)] } { + set spice_dir [file nativename $keys(-spice_directory)] + if { ![file exists $spice_dir] } { + sta_error 1920 "Directory $spice_dir not found." + } + if { ![file isdirectory $spice_dir] } { + sta_error 1921 "$spice_dir is not a directory." + } + if { ![file writable $spice_dir] } { + sta_error 1922 "Cannot write in $spice_dir." + } + } else { + sta_error 1923 "No -spice_directory specified." + } + + if { [info exists keys(-lib_subckt_file)] } { + set lib_subckt_file [file nativename $keys(-lib_subckt_file)] + if { ![file readable $lib_subckt_file] } { + sta_error 1924 "-lib_subckt_file $lib_subckt_file is not readable." + } + } else { + sta_error 1925 "No -lib_subckt_file specified." + } + + if { [info exists keys(-model_file)] } { + set model_file [file nativename $keys(-model_file)] + if { ![file readable $model_file] } { + sta_error 1926 "-model_file $model_file is not readable." + } + } else { + sta_error 1927 "No -model_file specified." + } + + if { [info exists keys(-power)] } { + set power $keys(-power) + } else { + sta_error 1928 "No -power specified." + } + + if { [info exists keys(-ground)] } { + set ground $keys(-ground) + } else { + sta_error 1929 "No -ground specified." + } + + set ckt_sim [parse_ckt_sim_key keys] + + if { ![info exists keys(-path_args)] } { + sta_error 1930 "No -path_args specified." + } + set path_args $keys(-path_args) + set path_ends [eval [concat find_timing_paths $path_args]] + if { $path_ends == {} } { + sta_error 1931 "No paths found for -path_args $path_args." + } else { + set path_index 1 + foreach path_end $path_ends { + set path [$path_end path] + set path_name "path_$path_index" + set spice_file [file join $spice_dir "$path_name.sp"] + set subckt_file [file join $spice_dir "$path_name.subckt"] + write_path_spice_cmd $path $spice_file $subckt_file \ + $lib_subckt_file $model_file $power $ground $ckt_sim + incr path_index + } + } +} + +set ::ckt_sims {hspice ngspice xyce} + +proc parse_ckt_sim_key { keys_var } { + upvar 1 $keys_var keys + global ckt_sims + + set ckt_sim "ngspice" + if { [info exists keys(-simulator)] } { + set ckt_sim [file nativename $keys(-simulator)] + if { [lsearch $ckt_sims $ckt_sim] == -1 } { + sta_error 1910 "Unknown circuit simulator" + } + } + return $ckt_sim +} + +################################################################ + +define_cmd_args "write_gate_spice" \ + { -gates {{instance input_port driver_port edge [delay]}...}\ + -spice_filename spice_filename\ + -lib_subckt_file lib_subckts_file\ + -model_file model_file\ + -power power\ + -ground ground\ + [-simulator hspice|ngspice|xyce]\ + [-corner corner]\ + [-min] [-max]} + +proc write_gate_spice { args } { + parse_key_args "write_gate_spice" args \ + keys {-gates -spice_filename -lib_subckt_file -model_file \ + -power -ground -simulator -corner}\ + flags {-measure_stmts -min -max} + + if { [info exists keys(-gates)] } { + set gates $keys(-gates) + } else { + sta_error 1932 "Missing -gates argument." + } + if { [info exists keys(-spice_filename)] } { + set spice_file [file nativename $keys(-spice_filename)] + set spice_dir [file dirname $spice_file] + if { ![file writable $spice_dir] } { + sta_error 1903 "Cannot write $spice_dir." + } + } else { + sta_error 1904 "No -spice_filename specified." + } + + if { [info exists keys(-lib_subckt_file)] } { + set lib_subckt_file [file nativename $keys(-lib_subckt_file)] + if { ![file readable $lib_subckt_file] } { + sta_error 1905 "-lib_subckt_file $lib_subckt_file is not readable." + } + } else { + sta_error 1906 "No -lib_subckt_file specified." + } + + if { [info exists keys(-model_file)] } { + set model_file [file nativename $keys(-model_file)] + if { ![file readable $model_file] } { + sta_error 1907 "-model_file $model_file is not readable." + } + } else { + sta_error 1908 "No -model_file specified." + } + + if { [info exists keys(-power)] } { + set power $keys(-power) + } else { + sta_error 1909 "No -power specified." + } + + if { [info exists keys(-ground)] } { + set ground $keys(-ground) + } else { + sta_error 1915 "No -ground specified." + } + + set ckt_sim [parse_ckt_sim_key keys] + + set corner [parse_corner keys] + set min_max [parse_min_max_flags flags] + check_argc_eq0 "write_gate_spice" $args + + set spice_dir [file dirname $spice_file] + set spice_root [file rootname [file tail $spice_file]] + set subckt_file [file join $spice_dir "$spice_root.subckt"] + write_gate_spice_cmd $gates $spice_file $subckt_file \ + $lib_subckt_file $model_file $power $ground $ckt_sim \ + $corner $min_max +} + +################################################################ + +# plot_pins defaults to input_pin, driver_pina and load pins for each driver. +define_cmd_args "write_gate_gnuplot" \ + { -gates {{instance input_port driver_port edge [delay]}...}\ + -plot_pins plot_pins\ + -plot_basename plot_basename\ + [-corner corner] [-min] [-max]} + +proc write_gate_gnuplot { args } { + parse_key_args "write_gate_gnuplot" args \ + keys {-gates -plot_pins -plot_basename -spice_waveforms -corner} \ + flags {-min -max} + + if { [info exists keys(-gates)] } { + set gates $keys(-gates) + } else { + sta_error 1933 "Missing -gates argument." + } + if { [info exists keys(-plot_pins)] } { + set plot_pins [get_port_pins_error "-plot_pins" $keys(-plot_pins)] + } else { + set plot_pins {} + set plot_all_loads 0 + set gate_idx 0 + foreach gate $gates { + set in_pin [parse_gate_in_pin $gate] + set drvr_pin [parse_gate_drvr_pin $gate] + lappend plot_pins $in_pin + lappend plot_pins $drvr_pin + # Only plot driver loads. + if { $plot_all_loads || $gate_idx == 0 } { + set pin_iter [$drvr_pin connected_pin_iterator] + while { [$pin_iter has_next] } { + set pin [$pin_iter next] + if { [$pin is_load] } { + lappend plot_pins $pin + } + } + $pin_iter finish + } + incr gate_idx + } + } + + if { [info exists keys(-plot_basename)] } { + set plot_base [file nativename $keys(-plot_basename)] + set plot_dir [file dirname $plot_base] + if { ![file writable $plot_dir] } { + sta_error 1913 "Cannot write $plot_dir." + } + } else { + sta_error 1914 "No -plot_basename specified." + } + set gnuplot_filename "${plot_base}.gnuplot" + set csv_filename "${plot_base}.csv" + + set sim_wave_filename "" + if { [info exists keys(-spice_waveforms)] } { + set sim_wave_filename $keys(-spice_waveforms) + } + + set corner [parse_corner keys] + set min_max [parse_min_max_flags flags] + + write_gate_gnuplot_cmd $gates $plot_pins $sim_wave_filename \ + $gnuplot_filename $csv_filename $corner $min_max +} + +proc parse_gate_drvr_pin { gate_arg } { + lassign $gate_arg inst_name in_port_name in_rf drvr_port_name drvr_rf + set inst [get_instance_error "instance" $inst_name] + set drvr_pin [$inst find_pin $drvr_port_name] + return $drvr_pin +} + +proc parse_gate_in_pin { gate_arg } { + lassign $gate_arg inst_name in_port_name in_rf drvr_port_name drvr_rf + set inst [get_instance_error "instance" $inst_name] + set in_pin [$inst find_pin $in_port_name] + return $in_pin +} + +# sta namespace end. +} diff --git a/spice/Xyce.cc b/spice/Xyce.cc new file mode 100644 index 00000000..7635fe6a --- /dev/null +++ b/spice/Xyce.cc @@ -0,0 +1,77 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2024, 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 . + + +#include "Xyce.hh" + +#include +#include +#include + +#include "Error.hh" + +namespace sta { + +using std::string; +using std::ifstream; +using std::getline; +using std::stringstream; +using std::vector; +using std::make_shared; + +void +readXyceCsv(const char *csv_filename, + // Return values. + StdStringSeq &titles, + WaveformSeq &waveforms) +{ + ifstream file(csv_filename); + if (file.is_open()) { + string line; + + // Read the header line. + getline(file, line); + stringstream ss(line); + string field; + size_t col = 0; + while (getline(ss, field, ',')) { + // Skip TIME title. + if (col > 0) + titles.push_back(field); + col++; + } + + vector values(titles.size() + 1); + while (getline(file, line)) { + stringstream ss(line); + size_t col = 0; + while (getline(ss, field, ',')) { + float value = std::stof(field); + values[col].push_back(value); + col++; + } + } + file.close(); + TableAxisPtr time_axis = make_shared(TableAxisVariable::time, + new FloatSeq(values[0])); + for (size_t var = 1; var < values.size(); var++) + waveforms.emplace_back(new FloatSeq(values[var]), time_axis); + } + else + throw FileNotReadable(csv_filename); +} + +} // namespace diff --git a/spice/Xyce.hh b/spice/Xyce.hh new file mode 100644 index 00000000..94b84693 --- /dev/null +++ b/spice/Xyce.hh @@ -0,0 +1,35 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2024, 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 . + +#pragma once + +#include +#include + +#include "TableModel.hh" + +namespace sta { + +typedef std::vector StdStringSeq; +typedef std::vector WaveformSeq; + +void +readXyceCsv(const char *csv_filename, + // Return values. + StdStringSeq &titles, + WaveformSeq &waveforms); + +} // namespace diff --git a/tcl/CmdArgs.tcl b/tcl/CmdArgs.tcl index 8fed92ee..24f4da20 100644 --- a/tcl/CmdArgs.tcl +++ b/tcl/CmdArgs.tcl @@ -400,12 +400,21 @@ proc parse_corner { keys_var } { upvar 1 $keys_var keys if { [info exists keys(-corner)] } { - set corner_name $keys(-corner) - set corner [find_corner $corner_name] - if { $corner == "NULL" } { - sta_error 102 "$corner_name is not the name of process corner." + set corner_arg $keys(-corner) + if { [is_object $corner_arg] } { + set object_type [object_type $corner_arg] + if { $object_type == "Corner" } { + return $corner_arg + } else { + sta_error 144 "corner object type '$object_type' is not a corner." + } } else { - return $corner + set corner [find_corner $corner_arg] + if { $corner == "NULL" } { + sta_error 102 "$corner_arg is not the name of process corner." + } else { + return $corner + } } } elseif { [multi_corner] } { sta_error 103 "-corner keyword required with multi-corner analysis." @@ -510,7 +519,7 @@ proc parse_min_max_all_flags { flags_var } { } elseif { [info exists flags(-max)] && ![info exists flags(-min)] } { return "max" } else { - return "all" + return "min_max" } } @@ -518,13 +527,13 @@ proc parse_min_max_all_flags { flags_var } { proc parse_min_max_all_check_flags { flags_var } { upvar 1 $flags_var flags if { [info exists flags(-min)] && [info exists flags(-max)] } { - return "all" + return "min_max" } elseif { [info exists flags(-min)] && ![info exists flags(-max)] } { return "min" } elseif { [info exists flags(-max)] && ![info exists flags(-min)] } { return "max" } else { - return "all" + return "min_max" } } @@ -550,7 +559,7 @@ proc parse_early_late_all_flags { flags_var } { } elseif { [info exists flags(-late)] && ![info exists flags(-early)] } { return "max" } else { - return "all" + return "min_max" } } diff --git a/tcl/CmdUtil.tcl b/tcl/CmdUtil.tcl index 50e1b26e..34f50db1 100644 --- a/tcl/CmdUtil.tcl +++ b/tcl/CmdUtil.tcl @@ -167,10 +167,10 @@ proc set_unit_values { unit key suffix key_var } { set scale [unit_prefix_scale $unit $prefix ] set_cmd_unit_scale $unit $scale } else { - sta_error 343 "unknown unit $unit prefix '${arg_prefix}'." + sta_error 166 "unknown unit $unit prefix '${arg_prefix}'." } } else { - sta_error 501 "incorrect unit suffix '$arg_suffix'." + sta_error 167 "incorrect unit suffix '$arg_suffix'." } if [info exists keys(-digits)] { set_cmd_unit_digits $unit $keys(-digits) diff --git a/tcl/Network.tcl b/tcl/Network.tcl index b6f31337..7fc7c1c3 100644 --- a/tcl/Network.tcl +++ b/tcl/Network.tcl @@ -26,9 +26,11 @@ proc_redirect report_instance { check_argc_eq1 "report_instance" $args if { [info exists flags(-connections)] } { + # deprecated 2024-01-17 sta_warn 233 "report_instance -connections is deprecated." } if { [info exists flags(-verbose)] } { + # deprecated 2024-01-17 sta_warn 234 "report_instance -verbose is deprecated." } set instance_path [lindex $args 0] @@ -183,12 +185,15 @@ proc_redirect report_net { check_argc_eq1 "report_net" $args if { [info exists flags(-connections)] } { + # deprecated 2024-01-17 sta_warn 235 "report_net -connections is deprecated." } if { [info exists flags(-verbose)] } { + # deprecated 2024-01-17 sta_warn 236 "report_net -verbose is deprecated." } if { [info exists flags(-hier_pins)] } { + # deprecated 2024-01-17 sta_warn 237 "report_net -hier_pins is deprecated." } diff --git a/tcl/NetworkEdit.tcl b/tcl/NetworkEdit.tcl index 4256aaf9..38a11555 100644 --- a/tcl/NetworkEdit.tcl +++ b/tcl/NetworkEdit.tcl @@ -133,38 +133,6 @@ proc parse_connect_pin { arg } { return [list $inst $port] } -proc connect_pins { net pins } { - sta_warn 251 "connect_pins is deprecated. Use connect_pin." - # Visit the pins to make sure command will succeed. - set insts_ports [parse_connect_pins $pins] - if { $insts_ports == 0 } { - return 0 - } - set net [get_net_arg "net" $net] - if { $net == "NULL" } { - return 0 - } - foreach {inst port} $insts_ports { - connect_pin_cmd $inst $port $net - } - return 1 -} - -proc parse_connect_pins { arg } { - set path_regexp [path_regexp] - set inst_ports {} - # Copy backslashes that will be removed by foreach. - set arg [string map {\\ \\\\} $arg] - foreach obj $arg { - set inst_port [parse_connect_pin $obj] - if { $inst_port == 0 } { - return 0 - } - set inst_ports [concat $inst_ports $inst_port] - } - return $inst_ports -} - ################################################################ define_cmd_args "disconnect_pin" {net -all|pin} diff --git a/tcl/Sdc.tcl b/tcl/Sdc.tcl index 8b344d12..e840545d 100644 --- a/tcl/Sdc.tcl +++ b/tcl/Sdc.tcl @@ -1300,7 +1300,7 @@ proc set_clock_gating_check { args } { flags {-rise -fall -high -low} check_argc_eq0or1 "set_clock_gating_check" $args - set tr [parse_rise_fall_flags flags] + set rf [parse_rise_fall_flags flags] set active_value "" if {[info exists flags(-high)] && [info exists flags(-low)]} { @@ -1315,20 +1315,20 @@ proc set_clock_gating_check { args } { sta_error 397 "missing -setup or -hold argument." } if [info exists keys(-hold)] { - set_clock_gating_check1 $args $tr "min" $keys(-hold) $active_value + set_clock_gating_check1 $args $rf "min" $keys(-hold) $active_value } if [info exists keys(-setup)] { - set_clock_gating_check1 $args $tr "max" $keys(-setup) $active_value + set_clock_gating_check1 $args $rf "max" $keys(-setup) $active_value } } -proc set_clock_gating_check1 { args tr setup_hold margin active_value } { +proc set_clock_gating_check1 { args rf setup_hold margin active_value } { set margin [time_ui_sta $margin] if { [llength $args] == 0 } { if { $active_value != "" } { sta_error 398 "-high and -low only permitted for pins and instances." } - set_clock_gating_check_cmd $tr $setup_hold $margin + set_clock_gating_check_cmd $rf $setup_hold $margin } elseif { [llength $args] == 1 } { parse_clk_inst_port_pin_arg [lindex $args 0] clks insts pins @@ -1336,18 +1336,18 @@ proc set_clock_gating_check1 { args tr setup_hold margin active_value } { sta_error 399 "-high and -low only permitted for pins and instances." } foreach clk $clks { - set_clock_gating_check_clk_cmd $clk $tr $setup_hold $margin + set_clock_gating_check_clk_cmd $clk $rf $setup_hold $margin } if { $active_value == "" } { set active_value "X" } foreach pin $pins { - set_clock_gating_check_pin_cmd $pin $tr $setup_hold \ + set_clock_gating_check_pin_cmd $pin $rf $setup_hold \ $margin $active_value } foreach inst $insts { - set_clock_gating_check_instance_cmd $inst $tr $setup_hold \ + set_clock_gating_check_instance_cmd $inst $rf $setup_hold \ $margin $active_value } } @@ -1486,7 +1486,7 @@ proc set_clock_latency { args } { parse_clk_port_pin_arg $objects clks pins - set tr [parse_rise_fall_flags flags] + set rf [parse_rise_fall_flags flags] set min_max [parse_min_max_all_flags flags] set pin_clk "NULL" @@ -1502,14 +1502,14 @@ proc set_clock_latency { args } { set early_late [parse_early_late_all_flags flags] foreach clk $clks { - set_clock_insertion_cmd $clk "NULL" $tr $min_max $early_late $delay + set_clock_insertion_cmd $clk "NULL" $rf $min_max $early_late $delay } foreach pin $pins { # Source only allowed on clocks and clock pins. if { ![is_clock_src $pin] } { sta_error 409 "-source '[get_full_name $pin]' is not a clock pin." } - set_clock_insertion_cmd $pin_clk $pin $tr $min_max $early_late $delay + set_clock_insertion_cmd $pin_clk $pin $rf $min_max $early_late $delay } } else { # Latency. @@ -1518,10 +1518,10 @@ proc set_clock_latency { args } { } foreach clk $clks { - set_clock_latency_cmd $clk "NULL" $tr $min_max $delay + set_clock_latency_cmd $clk "NULL" $rf $min_max $delay } foreach pin $pins { - set_clock_latency_cmd $pin_clk $pin $tr $min_max $delay + set_clock_latency_cmd $pin_clk $pin $rf $min_max $delay } } } @@ -1647,7 +1647,7 @@ proc set_clock_transition { args } { parse_key_args "set_clock_transition" args keys {} \ flags {-rise -fall -max -min} - set tr [parse_rise_fall_flags flags] + set rf [parse_rise_fall_flags flags] set min_max [parse_min_max_all_flags flags] check_argc_eq2 "set_clock_transition" $args @@ -1658,7 +1658,7 @@ proc set_clock_transition { args } { if { [$clk is_virtual] } { sta_warn 419 "transition time can not be specified for virtual clocks." } else { - set_clock_slew_cmd $clk $tr $min_max [time_ui_sta $slew] + set_clock_slew_cmd $clk $rf $min_max [time_ui_sta $slew] } } } @@ -2353,7 +2353,7 @@ proc set_port_delay { cmd sta_cmd cmd_args port_dirs } { set clk_rf "rise" } - set tr [parse_rise_fall_flags flags] + set rf [parse_rise_fall_flags flags] set min_max [parse_min_max_all_flags flags] set add [info exists flags(-add_delay)] set source_latency_included [info exists flags(-source_latency_included)] @@ -2366,7 +2366,7 @@ proc set_port_delay { cmd sta_cmd cmd_args port_dirs } { } elseif { $clk != "NULL" && [lsearch [$clk sources] $pin] != -1 } { sta_warn 441 "$cmd relative to a clock defined on the same port/pin not allowed." } else { - $sta_cmd $pin $tr $clk $clk_rf $ref_pin\ + $sta_cmd $pin $rf $clk $clk_rf $ref_pin\ $source_latency_included $network_latency_included \ $min_max $add $delay } @@ -2667,11 +2667,11 @@ proc unset_port_delay { cmd swig_cmd cmd_args } { set clk_rf "rise" } - set tr [parse_rise_fall_flags flags] + set rf [parse_rise_fall_flags flags] set min_max [parse_min_max_all_flags flags] foreach pin $pins { - $swig_cmd $pin $tr $clk $clk_rf $min_max + $swig_cmd $pin $rf $clk $clk_rf $min_max } } @@ -2751,7 +2751,7 @@ define_cmd_args "set_drive" {[-rise] [-fall] [-min] [-max] \ proc set_drive { args } { parse_key_args "set_drive" args keys {} flags {-rise -fall -min -max} - set tr [parse_rise_fall_flags flags] + set rf [parse_rise_fall_flags flags] set min_max [parse_min_max_all_check_flags flags] check_argc_eq2 "set_drive" $args @@ -2761,7 +2761,7 @@ proc set_drive { args } { set res [resistance_ui_sta $res] set ports [get_ports_error "ports" [lindex $args 1]] foreach port $ports { - set_drive_resistance_cmd $port $tr $min_max $res + set_drive_resistance_cmd $port $rf $min_max $res } } @@ -2780,7 +2780,7 @@ proc set_driving_cell { args } { -input_transition_rise -input_transition_fall} \ flags {-rise -fall -min -max -dont_scale -no_design_rule} - set tr [parse_rise_fall_flags flags] + set rf [parse_rise_fall_flags flags] set min_max [parse_min_max_all_flags flags] # -cell is an undocumented non-sdc alias for -lib_cell. @@ -2871,7 +2871,7 @@ proc set_driving_cell { args } { set ports [get_ports_error "ports" [lindex $args 0]] foreach port $ports { set_drive_cell_cmd $library $cell $port $from_port \ - $from_slew_rise $from_slew_fall $to_port $tr $min_max + $from_slew_rise $from_slew_fall $to_port $rf $min_max } } @@ -2898,7 +2898,7 @@ proc set_input_transition { args } { parse_key_args "set_input_transition" args keys {-clock} \ flags {-rise -fall -max -min -clock_fall} - set tr [parse_rise_fall_flags flags] + set rf [parse_rise_fall_flags flags] set min_max [parse_min_max_all_flags flags] @@ -2917,7 +2917,7 @@ proc set_input_transition { args } { } foreach port $ports { - set_input_slew_cmd $port $tr $min_max $slew + set_input_slew_cmd $port $rf $min_max $slew } } @@ -3082,7 +3082,7 @@ proc set_max_transition { args } { set objects [lindex $args 1] parse_clk_cell_port_args $objects clks cells ports - set tr [parse_rise_fall_flags flags] + set rf [parse_rise_fall_flags flags] set path_types {} if { ![info exists flags(-clock_path)] \ @@ -3108,7 +3108,7 @@ proc set_max_transition { args } { # -clock_path/-data_path and transition only apply to clock objects. foreach path_type $path_types { foreach clk $clks { - set_slew_limit_clk $clk $tr $path_type "max" $slew + set_slew_limit_clk $clk $rf $path_type "max" $slew } } foreach cell $cells { @@ -3176,7 +3176,7 @@ proc set_timing_derate { args } { sta_warn 469 "derating factor greater than 2.0." } - set tr [parse_rise_fall_flags flags] + set rf [parse_rise_fall_flags flags] set early_late [parse_early_late_flags flags] set path_types {} @@ -3214,7 +3214,7 @@ proc set_timing_derate { args } { } foreach net $nets { foreach path_type $path_types { - set_timing_derate_net_cmd $net $path_type $tr $early_late $derate + set_timing_derate_net_cmd $net $path_type $rf $early_late $derate } } } @@ -3227,11 +3227,11 @@ proc set_timing_derate { args } { foreach path_type $path_types { foreach inst $insts { set_timing_derate_inst_cmd $inst $derate_type $path_type \ - $tr $early_late $derate + $rf $early_late $derate } foreach libcell $libcells { set_timing_derate_cell_cmd $libcell $derate_type $path_type \ - $tr $early_late $derate + $rf $early_late $derate } } } @@ -3244,7 +3244,7 @@ proc set_timing_derate { args } { } foreach derate_type $derate_types { foreach path_type $path_types { - set_timing_derate_cmd $derate_type $path_type $tr $early_late $derate + set_timing_derate_cmd $derate_type $path_type $rf $early_late $derate } } } @@ -3266,13 +3266,13 @@ proc parse_from_arg { keys_var arg_error_var } { if [info exists keys(-from)] { set key "-from" - set tr "rise_fall" + set rf "rise_fall" } elseif [info exists keys(-rise_from)] { set key "-rise_from" - set tr "rise" + set rf "rise" } elseif [info exists keys(-fall_from)] { set key "-fall_from" - set tr "fall" + set rf "fall" } else { return "NULL" } @@ -3283,7 +3283,7 @@ proc parse_from_arg { keys_var arg_error_var } { sta_warn 471 "no valid objects specified for $key." return "NULL" } - return [make_exception_from $from_pins $from_clks $from_insts $tr] + return [make_exception_from $from_pins $from_clks $from_insts $rf] } # "arg_error" is set to notify the caller to cleanup and post error. @@ -3294,18 +3294,18 @@ proc parse_thrus_arg { args_var arg_error_var } { set args_rtn {} while { $args != {} } { set arg [lindex $args 0] - set tr "" + set rf "" if { $arg == "-through" } { - set tr "rise_fall" + set rf "rise_fall" set key "-through" } elseif { $arg == "-rise_through" } { - set tr "rise" + set rf "rise" set key "-rise_through" } elseif { $arg == "-fall_through" } { - set tr "fall" + set rf "fall" set key "-fall_through" } - if { $tr != "" } { + if { $rf != "" } { if { [llength $args] > 1 } { set args [lrange $args 1 end] set arg [lindex $args 0] @@ -3315,7 +3315,7 @@ proc parse_thrus_arg { args_var arg_error_var } { set arg_error 1 sta_warn 472 "no valid objects specified for $key" } else { - lappend thrus [make_exception_thru $pins $nets $insts $tr] + lappend thrus [make_exception_thru $pins $nets $insts $rf] } } } else { @@ -3673,7 +3673,7 @@ proc set_pvt { args } { check_argc_eq1 "set_pvt" $args set insts [get_instances_error "instances" [lindex $args 0]] - if { $min_max == "all" } { + if { $min_max == "min_max" } { set_pvt_min_max $insts "min" keys set_pvt_min_max $insts "max" keys } else { diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index a46d5385..fba83d0f 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -69,7 +69,6 @@ #include "PathGroup.hh" #include "PathAnalysisPt.hh" #include "Property.hh" -#include "WritePathSpice.hh" #include "Search.hh" #include "Sta.hh" #include "search/Tag.hh" @@ -826,12 +825,13 @@ equiv_cell_timing_arcs(LibertyCell *cell1, void set_cmd_namespace_cmd(const char *namespc) { + Sta *sta = Sta::sta(); if (stringEq(namespc, "sdc")) - Sta::sta()->setCmdNamespace(CmdNamespace::sdc); + sta->setCmdNamespace(CmdNamespace::sdc); else if (stringEq(namespc, "sta")) - Sta::sta()->setCmdNamespace(CmdNamespace::sta); + sta->setCmdNamespace(CmdNamespace::sta); else - criticalError(269, "unknown namespace"); + sta->report()->warn(2120, "unknown namespace"); } bool @@ -1369,7 +1369,7 @@ set_analysis_type_cmd(const char *analysis_type) else if (stringEq(analysis_type, "on_chip_variation")) type = AnalysisType::ocv; else { - criticalError(270, "unknown analysis type"); + Sta::sta()->report()->warn(2121, "unknown analysis type"); type = AnalysisType::single; } Sta::sta()->setAnalysisType(type); @@ -1520,7 +1520,7 @@ set_wire_load_mode_cmd(const char *mode_name) { WireloadMode mode = stringWireloadMode(mode_name); if (mode == WireloadMode::unknown) - criticalError(271, "unknown wire load mode"); + Sta::sta()->report()->warn(2122, "unknown wire load mode"); else Sta::sta()->setWireloadMode(mode); } @@ -3560,22 +3560,6 @@ write_sdc_cmd(const char *filename, Sta::sta()->writeSdc(filename, leaf, compatible, digits, gzip, no_timestamp); } -void -write_path_spice_cmd(PathRef *path, - const char *spice_filename, - const char *subckt_filename, - const char *lib_subckt_filename, - const char *model_filename, - const char *power_name, - const char *gnd_name, - CircuitSim ckt_sim) -{ - Sta *sta = Sta::sta(); - writePathSpice(path, spice_filename, subckt_filename, - lib_subckt_filename, model_filename, - power_name, gnd_name, ckt_sim, sta); -} - void write_timing_model_cmd(const char *lib_name, const char *cell_name, @@ -4260,6 +4244,14 @@ timing_arc_sets() return self->timingArcSets(); } +void +ensure_voltage_waveforms() +{ + Corner *corner = Sta::sta()->cmdCorner(); + DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max()); + self->ensureVoltageWaveforms(dcalc_ap); +} + } // LibertyCell methods %extend CellPortIterator { @@ -4377,11 +4369,67 @@ Transition *to_edge() { return self->toEdge(); } const char *to_edge_name() { return self->toEdge()->asRiseFall()->name(); } TimingRole *role() { return self->role(); } +float +time_voltage(float in_slew, + float load_cap, + float time) +{ + GateTableModel *gate_model = self->gateTableModel(); + if (gate_model) { + OutputWaveforms *waveforms = gate_model->outputWaveforms(); + if (waveforms) + return waveforms->timeVoltage(in_slew, load_cap, time); + } + return 0.0; +} + +float +time_current(float in_slew, + float load_cap, + float time) +{ + GateTableModel *gate_model = self->gateTableModel(); + if (gate_model) { + OutputWaveforms *waveforms = gate_model->outputWaveforms(); + if (waveforms) + return waveforms->timeCurrent(in_slew, load_cap, time); + } + return 0.0; +} + +float +voltage_current(float in_slew, + float load_cap, + float voltage) +{ + GateTableModel *gate_model = self->gateTableModel(); + if (gate_model) { + OutputWaveforms *waveforms = gate_model->outputWaveforms(); + if (waveforms) + return waveforms->voltageCurrent(in_slew, load_cap, voltage); + } + return 0.0; +} + +float +voltage_time(float in_slew, + float load_cap, + float voltage) +{ + GateTableModel *gate_model = self->gateTableModel(); + if (gate_model) { + OutputWaveforms *waveforms = gate_model->outputWaveforms(); + if (waveforms) + return waveforms->voltageTime(in_slew, load_cap, voltage); + } + return 0.0; +} + Table1 voltage_waveform(float in_slew, float load_cap) { - GateTableModel *gate_model = dynamic_cast(self->model()); + GateTableModel *gate_model = self->gateTableModel(); if (gate_model) { OutputWaveforms *waveforms = gate_model->outputWaveforms(); if (waveforms) { @@ -4393,31 +4441,73 @@ voltage_waveform(float in_slew, } const Table1 * -current_waveform(float in_slew, - float load_cap) +voltage_waveform_raw(float in_slew, + float load_cap) { - GateTableModel *gate_model = dynamic_cast(self->model()); + GateTableModel *gate_model = self->gateTableModel(); if (gate_model) { OutputWaveforms *waveforms = gate_model->outputWaveforms(); if (waveforms) { - const Table1 *waveform = waveforms->currentWaveform(in_slew, load_cap); + const Table1 *waveform = waveforms->voltageWaveformRaw(in_slew, load_cap); return waveform; } } return nullptr; } -float -voltage_current(float in_slew, - float load_cap, - float voltage) +Table1 +current_waveform(float in_slew, + float load_cap) { - GateTableModel *gate_model = dynamic_cast(self->model()); + GateTableModel *gate_model = self->gateTableModel(); if (gate_model) { OutputWaveforms *waveforms = gate_model->outputWaveforms(); if (waveforms) { - float current = waveforms->voltageCurrent(in_slew, load_cap, voltage); - return current; + Table1 waveform = waveforms->currentWaveform(in_slew, load_cap); + return waveform; + } + } + return Table1(); +} + +const Table1 * +current_waveform_raw(float in_slew, + float load_cap) +{ + GateTableModel *gate_model = self->gateTableModel(); + if (gate_model) { + OutputWaveforms *waveforms = gate_model->outputWaveforms(); + if (waveforms) { + const Table1 *waveform = waveforms->currentWaveformRaw(in_slew, load_cap); + return waveform; + } + } + return nullptr; +} + +Table1 +voltage_current_waveform(float in_slew, + float load_cap) +{ + GateTableModel *gate_model = self->gateTableModel(); + if (gate_model) { + OutputWaveforms *waveforms = gate_model->outputWaveforms(); + if (waveforms) { + Table1 waveform = waveforms->voltageCurrentWaveform(in_slew, load_cap); + return waveform; + } + } + return Table1(); +} + +float +final_resistance() +{ + GateTableModel *gate_model = self->gateTableModel(); + if (gate_model) { + OutputWaveforms *waveforms = gate_model->outputWaveforms(); + if (waveforms) { + return waveforms->finalResistance(); } } return 0.0; @@ -4897,8 +4987,8 @@ latch_d_to_q_en() Instance *inst = network->instance(from_pin); LibertyCell *lib_cell = network->libertyCell(inst); TimingArcSet *d_q_set = self->timingArcSet(); - LibertyPort *enable_port; - FuncExpr *enable_func; + const LibertyPort *enable_port; + const FuncExpr *enable_func; const RiseFall *enable_rf; lib_cell->latchEnable(d_q_set, enable_port, enable_func, enable_rf); if (enable_port) @@ -4966,7 +5056,7 @@ float inter_clk_uncertainty() Arrival target_clk_arrival() { return self->targetClkArrival(Sta::sta()); } bool path_delay_margin_is_external() { return self->pathDelayMarginIsExternal();} -Crpr common_clk_pessimism() { return self->commonClkPessimism(Sta::sta()); } +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()); } diff --git a/tcl/StaTclTypes.i b/tcl/StaTclTypes.i index 6127dea9..645226a6 100644 --- a/tcl/StaTclTypes.i +++ b/tcl/StaTclTypes.i @@ -154,6 +154,28 @@ tclListNetworkSet(Tcl_Obj *const source, return nullptr; } +template +SET_TYPE +tclListNetworkSet1(Tcl_Obj *const source, + swig_type_info *swig_type, + Tcl_Interp *interp, + const Network *network) +{ + int argc; + Tcl_Obj **argv; + SET_TYPE set(network); + if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK + && argc > 0) { + for (int i = 0; i < argc; i++) { + void *obj; + // Ignore returned TCL_ERROR because can't get swig_type_info. + SWIG_ConvertPtr(argv[i], &obj, swig_type, false); + set.insert(reinterpret_cast(obj)); + } + } + return set; +} + StringSet * tclListSetConstChar(Tcl_Obj *const source, Tcl_Interp *interp) @@ -328,6 +350,72 @@ objectListNext(const char *list, } } +Tcl_Obj * +tclArcDcalcArg(ArcDcalcArg &gate, + Tcl_Interp *interp) +{ + Sta *sta = Sta::sta(); + const Network *network = sta->network(); + const Instance *drvr = network->instance(gate.drvrPin()); + const TimingArc *arc = gate.arc(); + + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + Tcl_Obj *obj; + + const char *inst_name = network->pathName(drvr); + obj = Tcl_NewStringObj(inst_name, strlen(inst_name)); + Tcl_ListObjAppendElement(interp, list, obj); + + const char *from_name = arc->from()->name(); + obj = Tcl_NewStringObj(from_name, strlen(from_name)); + Tcl_ListObjAppendElement(interp, list, obj); + + const char *from_edge = arc->fromEdge()->asString(); + obj = Tcl_NewStringObj(from_edge, strlen(from_edge)); + Tcl_ListObjAppendElement(interp, list, obj); + + const char *to_name = arc->to()->name(); + obj = Tcl_NewStringObj(to_name, strlen(to_name)); + Tcl_ListObjAppendElement(interp, list, obj); + + const char *to_edge = arc->toEdge()->asString(); + 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)); + Tcl_ListObjAppendElement(interp, list, obj); + + return list; +} + +ArcDcalcArg +arcDcalcArgTcl(Tcl_Obj *obj, + Tcl_Interp *interp) +{ + Sta *sta = Sta::sta(); + sta->ensureGraph(); + int list_argc; + Tcl_Obj **list_argv; + if (Tcl_ListObjGetElements(interp, obj, &list_argc, &list_argv) == TCL_OK) { + const char *input_delay = "0.0"; + int length; + if (list_argc == 6) + input_delay = Tcl_GetStringFromObj(list_argv[5], &length); + if (list_argc == 5 || list_argc == 6) { + return makeArcDcalcArg(Tcl_GetStringFromObj(list_argv[0], &length), + Tcl_GetStringFromObj(list_argv[1], &length), + Tcl_GetStringFromObj(list_argv[2], &length), + Tcl_GetStringFromObj(list_argv[3], &length), + Tcl_GetStringFromObj(list_argv[4], &length), + input_delay, sta); + } + else + sta->report()->warn(2140, "Delay calc arg requires 5 or 6 args."); + } + return ArcDcalcArg(); +} + } // namespace using namespace sta; @@ -718,6 +806,11 @@ using namespace sta; $1 = tclListSeqPtr($input, SWIGTYPE_p_Pin, interp); } +%typemap(in) PinSet { + Network *network = cmdNetwork(); + $1 = tclListNetworkSet1($input, SWIGTYPE_p_Pin, interp, network); +} + %typemap(in) PinSet* { Network *network = cmdNetwork(); $1 = tclListNetworkSet($input, SWIGTYPE_p_Pin, interp, network); @@ -1431,6 +1524,39 @@ using namespace sta; } } -%typemap(in) ArcDcalcArgPtrSeq { - $1 = tclListSeq($input, SWIGTYPE_p_ArcDcalcArg, interp); +%typemap(in) ArcDcalcArg { + Tcl_Obj *const source = $input; + $1 = arcDcalcArgTcl(source, interp); +} + +%typemap(out) ArcDcalcArg { + Tcl_Obj *tcl_obj = tclArcDcalcArg($1, interp); + Tcl_SetObjResult(interp, tcl_obj); +} + +%typemap(in) ArcDcalcArgSeq { + Tcl_Obj *const source = $input; + int argc; + Tcl_Obj **argv; + + Sta *sta = Sta::sta(); + ArcDcalcArgSeq seq; + if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK + && argc > 0) { + for (int i = 0; i < argc; i++) { + ArcDcalcArg gate = arcDcalcArgTcl(argv[i], interp); + if (gate.drvrPin()) + seq.push_back(gate); + } + } + $1 = seq; +} + +%typemap(out) ArcDcalcArgSeq { + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + for (ArcDcalcArg &gate : $1) { + Tcl_Obj *tcl_obj = tclArcDcalcArg(gate, interp); + Tcl_ListObjAppendElement(interp, list, tcl_obj); + } + Tcl_SetObjResult(interp, list); } diff --git a/tcl/WritePathSpice.tcl b/tcl/WritePathSpice.tcl index 19541b72..e69de29b 100644 --- a/tcl/WritePathSpice.tcl +++ b/tcl/WritePathSpice.tcl @@ -1,118 +0,0 @@ -# OpenSTA, Static Timing Analyzer -# Copyright (c) 2024, 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 . - -namespace eval sta { - -define_cmd_args "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]} - -proc write_path_spice { args } { - parse_key_args "write_path_spice" args \ - keys {-spice_directory -lib_subckt_file -model_file \ - -power -ground -path_args -simulator} \ - flags {} - - if { [info exists keys(-spice_directory)] } { - set spice_dir [file nativename $keys(-spice_directory)] - if { ![file exists $spice_dir] } { - sta_error 600 "Directory $spice_dir not found." - } - if { ![file isdirectory $spice_dir] } { - sta_error 601 "$spice_dir is not a directory." - } - if { ![file writable $spice_dir] } { - sta_error 602 "Cannot write in $spice_dir." - } - } else { - sta_error 603 "No -spice_directory specified." - } - - if { [info exists keys(-lib_subckt_file)] } { - set lib_subckt_file [file nativename $keys(-lib_subckt_file)] - if { ![file readable $lib_subckt_file] } { - sta_error 604 "-lib_subckt_file $lib_subckt_file is not readable." - } - } else { - sta_error 605 "No -lib_subckt_file specified." - } - - if { [info exists keys(-model_file)] } { - set model_file [file nativename $keys(-model_file)] - if { ![file readable $model_file] } { - sta_error 606 "-model_file $model_file is not readable." - } - } else { - sta_error 607 "No -model_file specified." - } - - if { [info exists keys(-power)] } { - set power $keys(-power) - } else { - sta_error 608 "No -power specified." - } - - if { [info exists keys(-ground)] } { - set ground $keys(-ground) - } else { - sta_error 609 "No -ground specified." - } - - set ckt_sim [parse_ckt_sim_key keys] - - if { ![info exists keys(-path_args)] } { - sta_error 610 "No -path_args specified." - } - set path_args $keys(-path_args) - set path_ends [eval [concat find_timing_paths $path_args]] - if { $path_ends == {} } { - sta_error 611 "No paths found for -path_args $path_args." - } else { - set path_index 1 - foreach path_end $path_ends { - set path [$path_end path] - set path_name "path_$path_index" - set spice_file [file join $spice_dir "$path_name.sp"] - set subckt_file [file join $spice_dir "$path_name.subckt"] - write_path_spice_cmd $path $spice_file $subckt_file \ - $lib_subckt_file $model_file $power $ground $ckt_sim - incr path_index - } - } -} - -set ::ckt_sims {hspice ngspice xyce} - -proc parse_ckt_sim_key { keys_var } { - upvar 1 $keys_var keys - global ckt_sims - - set ckt_sim "ngspice" - if { [info exists keys(-simulator)] } { - set ckt_sim [file nativename $keys(-simulator)] - if { [lsearch $ckt_sims $ckt_sim] == -1 } { - sta_error 1710 "Unknown circuit simulator" - } - } - return $ckt_sim -} - -# sta namespace end. -} diff --git a/util/RiseFallValues.cc b/util/RiseFallValues.cc index 8f15462c..a9ce0af2 100644 --- a/util/RiseFallValues.cc +++ b/util/RiseFallValues.cc @@ -26,15 +26,15 @@ RiseFallValues::RiseFallValues() void RiseFallValues::clear() { - for (auto tr_index : RiseFall::rangeIndex()) - exists_[tr_index] = false; + for (auto rf_index : RiseFall::rangeIndex()) + exists_[rf_index] = false; } RiseFallValues::RiseFallValues(float init_value) { - for (auto tr_index : RiseFall::rangeIndex()) { - values_[tr_index] = init_value; - exists_[tr_index] = true; + for (auto rf_index : RiseFall::rangeIndex()) { + values_[rf_index] = init_value; + exists_[rf_index] = true; } } diff --git a/verilog/VerilogReader.cc b/verilog/VerilogReader.cc index 8980c7a0..f5ff7615 100644 --- a/verilog/VerilogReader.cc +++ b/verilog/VerilogReader.cc @@ -157,8 +157,7 @@ void VerilogReader::deleteModules() { StringSet filenames; - for (auto module_iter : module_map_) { - VerilogModule *module = module_iter.second; + for (const auto [name, module] : module_map_) { filenames.insert(module->filename()); delete module; } diff --git a/verilog/VerilogWriter.cc b/verilog/VerilogWriter.cc index 1e105076..e8d193cd 100644 --- a/verilog/VerilogWriter.cc +++ b/verilog/VerilogWriter.cc @@ -258,9 +258,8 @@ VerilogWriter::writeWireDcls(Instance *inst) } delete net_iter; - for (auto name_range : bus_ranges) { - const char *bus_name = name_range.first.c_str(); - const BusIndexRange &range = name_range.second; + for (const auto& [bus_name1, range] : bus_ranges) { + const char *bus_name = bus_name1.c_str(); string net_vname = netVerilogName(bus_name, network_->pathEscape()); fprintf(stream_, " wire [%d:%d] %s;\n", range.first,