diff --git a/CMakeLists.txt b/CMakeLists.txt index 25573174..eaa3c353 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -24,14 +24,14 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14) cmake_policy(SET CMP0086 NEW) endif() -project(STA VERSION 2.4.0 +project(STA VERSION 2.5.0 LANGUAGES CXX ) option(USE_CUDD "Use CUDD BDD package") option(CUDD_DIR "CUDD BDD package directory") -set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_VERBOSE_MAKEFILE OFF) set(STA_HOME ${PROJECT_SOURCE_DIR}) message(STATUS "STA version: ${PROJECT_VERSION}") @@ -62,6 +62,7 @@ set(STA_SOURCE app/StaMain.cc dcalc/ArcDelayCalc.cc + dcalc/ArcDcalcWaveforms.cc dcalc/ArnoldiDelayCalc.cc dcalc/ArnoldiReduce.cc dcalc/DcalcAnalysisPt.cc @@ -69,11 +70,11 @@ set(STA_SOURCE dcalc/DelayCalcBase.cc dcalc/DmpCeff.cc dcalc/DmpDelayCalc.cc + dcalc/FindRoot.cc dcalc/GraphDelayCalc.cc dcalc/LumpedCapDelayCalc.cc dcalc/NetCaps.cc dcalc/ParallelDelayCalc.cc - dcalc/SlewDegradeDelayCalc.cc dcalc/UnitDelayCalc.cc graph/DelayFloat.cc @@ -114,7 +115,6 @@ set(STA_SOURCE parasitics/ConcreteParasitics.cc parasitics/EstimateParasitics.cc - parasitics/NullParasitics.cc parasitics/Parasitics.cc parasitics/ReduceParasitics.cc parasitics/ReportParasiticAnnotation.cc @@ -325,16 +325,20 @@ set_property(SOURCE ${STA_SWIG_FILE} -I${STA_HOME}/verilog ) -set_property(SOURCE ${STA_SWIG_FILE} - PROPERTY DEPENDS +set(SWIG_FILES ${STA_HOME}/dcalc/DelayCalc.i ${STA_HOME}/parasitics/Parasitics.i ${STA_HOME}/power/Power.i ${STA_HOME}/sdf/Sdf.i ${STA_HOME}/tcl/Exception.i ${STA_HOME}/tcl/StaTcl.i + ${STA_HOME}/tcl/StaTclTypes.i ${STA_HOME}/tcl/NetworkEdit.i ${STA_HOME}/verilog/Verilog.i + ) + +set_property(SOURCE ${STA_SWIG_FILE} + PROPERTY DEPENDS ${SWIG_FILES} ) swig_add_library(sta_swig @@ -343,16 +347,14 @@ swig_add_library(sta_swig SOURCES ${STA_SWIG_FILE} ) -get_target_property(SWIG_FILES sta_swig SOURCES) +get_target_property(STA_SWIG_CXX_FILE sta_swig SOURCES) -foreach(SWIG_FILE ${SWIG_FILES}) - set_source_files_properties(${SWIG_FILE} - PROPERTIES - # No simple way to modify the swig template that emits code full of warnings - # so suppress them. - COMPILE_OPTIONS "-Wno-cast-qual;-Wno-missing-braces;-Wno-deprecated-declarations" +set_source_files_properties(${STA_SWIG_CXX_FILE} + PROPERTIES + # No simple way to modify the swig template that emits code full of warnings + # so suppress them. + COMPILE_OPTIONS "-Wno-cast-qual;-Wno-missing-braces;-Wno-deprecated-declarations" ) -endforeach() target_link_libraries(sta_swig PUBLIC @@ -578,6 +580,7 @@ add_custom_target(sta_tags etags -o TAGS ${STA_SOURCE} */*.hh include/sta/*.hh + ${SWIG_FILES} ${STA_TCL_FILES} ${SWIG_TCL_FILES} WORKING_DIRECTORY ${STA_HOME} diff --git a/app/Main.cc b/app/Main.cc index c9a01274..9b45ae21 100644 --- a/app/Main.cc +++ b/app/Main.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/app/StaApp.i b/app/StaApp.i index 35f95468..fde2e64d 100644 --- a/app/StaApp.i +++ b/app/StaApp.i @@ -1,7 +1,7 @@ %module sta // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -17,6 +17,7 @@ // along with this program. If not, see . %include "Exception.i" +%include "StaTclTypes.i" %include "StaTcl.i" %include "Verilog.i" %include "NetworkEdit.i" diff --git a/app/StaMain.cc b/app/StaMain.cc index fb350b64..f78dfa3e 100644 --- a/app/StaMain.cc +++ b/app/StaMain.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/cmake/FindTCL.cmake b/cmake/FindTCL.cmake index 52fd8495..33104447 100644 --- a/cmake/FindTCL.cmake +++ b/cmake/FindTCL.cmake @@ -63,7 +63,7 @@ get_filename_component(TCL_LIB_PARENT2 "${TCL_LIB_PARENT1}" PATH) if (NOT TCL_HEADER) find_file(TCL_HEADER tcl.h PATHS ${TCL_LIB_PARENT1} ${TCL_LIB_PARENT2} - PATH_SUFFIXES include include/tcl + PATH_SUFFIXES include include/tcl include/tcl-tk NO_DEFAULT_PATH ) endif() diff --git a/dcalc/ArcDcalcWaveforms.cc b/dcalc/ArcDcalcWaveforms.cc new file mode 100644 index 00000000..90f83b9c --- /dev/null +++ b/dcalc/ArcDcalcWaveforms.cc @@ -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 . + +#include "ArcDcalcWaveforms.hh" + + +namespace sta { + +Table1 +ArcDcalcWaveforms::inputWaveform(const Pin *, + const RiseFall *, + const Corner *, + const MinMax *) +{ + return Table1(); +} + +Table1 +ArcDcalcWaveforms::drvrRampWaveform(const Pin *, + const RiseFall *, + const Pin *, + const RiseFall *, + const Pin *, + const Corner *, + const MinMax *) +{ + return Table1(); +} + +} // namespace diff --git a/dcalc/ArcDcalcWaveforms.hh b/dcalc/ArcDcalcWaveforms.hh new file mode 100644 index 00000000..7015a27a --- /dev/null +++ b/dcalc/ArcDcalcWaveforms.hh @@ -0,0 +1,59 @@ +// 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 "MinMax.hh" +#include "TableModel.hh" +#include "NetworkClass.hh" + +namespace sta { + +class Corner; +class DcalcAnalysisPt; + +// Abstract class for the graph delay calculator traversal to interface +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); +}; + +} // namespace + diff --git a/dcalc/ArcDelayCalc.cc b/dcalc/ArcDelayCalc.cc index 56825b3b..4b5a3cb7 100644 --- a/dcalc/ArcDelayCalc.cc +++ b/dcalc/ArcDelayCalc.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -16,10 +16,6 @@ #include "ArcDelayCalc.hh" -#include "TimingModel.hh" -#include "TimingArc.hh" -#include "GraphDelayCalc.hh" - namespace sta { ArcDelayCalc::ArcDelayCalc(StaState *sta): @@ -27,27 +23,114 @@ ArcDelayCalc::ArcDelayCalc(StaState *sta): { } -TimingModel * -ArcDelayCalc::model(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const +void +ArcDelayCalc::gateDelay(const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + float, + const Pvt *, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + ArcDelay &gate_delay, + Slew &drvr_slew) { - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); - const TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex()); - return corner_arc->model(op_cond); + LoadPinIndexMap load_pin_index_map(network_); + ArcDcalcResult dcalc_result = gateDelay(nullptr, arc, in_slew, load_cap, parasitic, + load_pin_index_map, dcalc_ap); + gate_delay = dcalc_result.gateDelay(); + drvr_slew = dcalc_result.drvrSlew(); } -GateTimingModel * -ArcDelayCalc::gateModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const +//////////////////////////////////////////////////////////////// + +ArcDcalcArg::ArcDcalcArg() : + drvr_pin_(nullptr), + edge_(nullptr), + arc_(nullptr), + in_slew_(0.0), + parasitic_(nullptr) { - return dynamic_cast(model(arc, dcalc_ap)); } -CheckTimingModel * -ArcDelayCalc::checkModel(const TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) const +ArcDcalcArg::ArcDcalcArg(const Pin *drvr_pin, + Edge *edge, + const TimingArc *arc, + const Slew in_slew, + const Parasitic *parasitic) : + drvr_pin_(drvr_pin), + edge_(edge), + arc_(arc), + in_slew_(in_slew), + parasitic_(parasitic) { - return dynamic_cast(model(arc, dcalc_ap)); +} + +void +ArcDcalcArg::setParasitic(const Parasitic *parasitic) +{ + parasitic_ = parasitic; +} + +//////////////////////////////////////////////////////////////// + +ArcDcalcResult::ArcDcalcResult() : + gate_delay_(0.0), + drvr_slew_(0.0) +{ +} + +ArcDcalcResult::ArcDcalcResult(size_t load_count) : + gate_delay_(0.0), + drvr_slew_(0.0) +{ + wire_delays_.resize(load_count); + load_slews_.resize(load_count); +} + +void +ArcDcalcResult::setGateDelay(ArcDelay gate_delay) +{ + gate_delay_ = gate_delay; +} + +void +ArcDcalcResult::setDrvrSlew(Slew drvr_slew) +{ + drvr_slew_ = drvr_slew; +} + +ArcDelay +ArcDcalcResult::wireDelay(size_t load_idx) const +{ + return wire_delays_[load_idx]; +} + +void +ArcDcalcResult::setWireDelay(size_t load_idx, + ArcDelay wire_delay) +{ + wire_delays_[load_idx] = wire_delay; +} + +void +ArcDcalcResult::setLoadCount(size_t load_count) +{ + wire_delays_.resize(load_count); + load_slews_.resize(load_count); +} + +Slew +ArcDcalcResult::loadSlew(size_t load_idx) const +{ + return load_slews_[load_idx]; +} + +void +ArcDcalcResult::setLoadSlew(size_t load_idx, + Slew load_slew) +{ + load_slews_[load_idx] = load_slew; } } // namespace diff --git a/dcalc/Arnoldi.hh b/dcalc/Arnoldi.hh index 0437e914..3dc238b1 100644 --- a/dcalc/Arnoldi.hh +++ b/dcalc/Arnoldi.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -64,6 +64,8 @@ public: rcmodel(); virtual ~rcmodel(); virtual float capacitance() const; + virtual PinSet unannotatedLoads(const Pin *drvr_pin, + const Parasitics *parasitics) const; const Pin **pinV; // [n] }; @@ -74,7 +76,6 @@ struct timing_table const LibertyCell *cell; const Pvt *pvt; float in_slew; - float relcap; }; } // namespace diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc index 15610b41..5cb2cf86 100644 --- a/dcalc/ArnoldiDelayCalc.cc +++ b/dcalc/ArnoldiDelayCalc.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -30,6 +30,7 @@ #include "TimingModel.hh" #include "TimingArc.hh" #include "TableModel.hh" +#include "PortDirection.hh" #include "Network.hh" #include "Graph.hh" #include "Parasitics.hh" @@ -117,34 +118,33 @@ public: Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; - ReducedParasiticType reducedParasiticType() const override; - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) override; - void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) override; - void loadDelay(const Pin *load_pin, - // Return values. - ArcDelay &wire_delay, - Slew &load_slew) override; - string reportGateDelay(const TimingArc *arc, + Parasitic *reduceParasitic(const Parasitic *parasitic_network, + const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + // Pass in load_cap or parasitic. + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + string reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, const Slew &in_slew, float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, int digits) override; + void finishDrvrPin() override; void delay_work_set_thresholds(delay_work *D, double lo, double hi, @@ -152,14 +152,12 @@ public: double derate); private: - void gateDelaySlew(const LibertyCell *drvr_cell, - const GateTableModel *table_model, - const Slew &in_slew, - float related_out_cap, - const Pvt *pvt, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew); + ArcDcalcResult gateDelaySlew(const LibertyCell *drvr_cell, + const TimingArc *arc, + const GateTableModel *table_model, + const Slew &in_slew, + const LoadPinIndexMap &load_pin_index_map, + const Pvt *pvt); void ar1_ceff_delay(delay_work *D, timing_table *tab, arnoldi1 *mod, @@ -224,9 +222,9 @@ private: double *_delayV; double *_slewV; int pin_n_; - bool input_port_; ArnoldiReduce *reduce_; delay_work *delay_work_; + vector unsaved_parasitics_; }; ArcDelayCalc * @@ -266,65 +264,70 @@ ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin, { Parasitic *parasitic = nullptr; const Corner *corner = dcalc_ap->corner(); - // set_load net has precidence over parasitics. - if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) { - const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); - Parasitic *parasitic_network = - parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); - bool delete_parasitic_network = false; - - const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); - if (parasitic_network == nullptr) { - Wireload *wireload = sdc_->wireload(cnst_min_max); - if (wireload) { - float pin_cap, wire_cap, fanout; - bool has_wire_cap; - graph_delay_calc_->netCaps(drvr_pin, drvr_rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_wire_cap); - parasitic_network = parasitics_->makeWireloadNetwork(drvr_pin, wireload, - fanout, op_cond, - parasitic_ap); - delete_parasitic_network = true; - } + // set_load net has precedence over parasitics. + if (sdc_->drvrPinHasWireCap(drvr_pin, corner) + || network_->direction(drvr_pin)->isInternal()) + return nullptr; + const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); + Parasitic *parasitic_network = + parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); + const MinMax *min_max = dcalc_ap->constraintMinMax(); + if (parasitic_network == nullptr) { + Wireload *wireload = sdc_->wireload(min_max); + if (wireload) { + float pin_cap, wire_cap, fanout; + bool has_wire_cap; + graph_delay_calc_->netCaps(drvr_pin, drvr_rf, dcalc_ap, + pin_cap, wire_cap, fanout, has_wire_cap); + parasitic_network = parasitics_->makeWireloadNetwork(drvr_pin, wireload, + fanout, min_max, + parasitic_ap); } + } - if (parasitic_network) { - parasitic = reduce_->reduceToArnoldi(parasitic_network, - drvr_pin, - parasitic_ap->couplingCapFactor(), - drvr_rf, op_cond, corner, - cnst_min_max, parasitic_ap); - if (delete_parasitic_network) { - Net *net = network_->net(drvr_pin); - parasitics_->deleteParasiticNetwork(net, parasitic_ap); - } - // Arnoldi parasitics are their own class that are not saved in the parasitic db. - unsaved_parasitics_.push_back(parasitic); - } + if (parasitic_network) { + rcmodel *rcmodel = reduce_->reduceToArnoldi(parasitic_network, drvr_pin, + parasitic_ap->couplingCapFactor(), + drvr_rf, corner, min_max, parasitic_ap); + // Arnoldi parasitics are their own class that are not saved in the parasitic db. + unsaved_parasitics_.push_back(rcmodel); + parasitic = rcmodel; } return parasitic; } -ReducedParasiticType -ArnoldiDelayCalc::reducedParasiticType() const +Parasitic * +ArnoldiDelayCalc::reduceParasitic(const Parasitic *, + const Pin *, + const RiseFall *, + const DcalcAnalysisPt *) { - return ReducedParasiticType::arnoldi; + // Decline because reduced arnoldi parasitics are not stored in the parasitics db. + return nullptr; } void -ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) +ArnoldiDelayCalc::finishDrvrPin() +{ + for (auto parasitic : unsaved_parasitics_) + delete parasitic; + unsaved_parasitics_.clear(); +} + +ArcDcalcResult +ArnoldiDelayCalc::inputPortDelay(const Pin *, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { - LumpedCapDelayCalc::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap); rcmodel_ = nullptr; _delayV[0] = 0.0; _slewV[0] = in_slew; - int j; + LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); + ArcDcalcResult dcalc_result(load_pin_index_map.size()); if (parasitic) { rcmodel_ = reinterpret_cast(const_cast(parasitic)); pin_n_ = rcmodel_->n; @@ -335,69 +338,67 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin, _delayV = (double*)realloc(_delayV,_pinNmax * sizeof(double)); _slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double)); } - pin_n_ = 1; pin_n_ = rcmodel_->n; - double slew_derate = drvr_library_->slewDerateFromLibrary(); - double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_); - double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_); - bool rising = (drvr_rf_ == RiseFall::rise()); - delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising, - slew_derate); + double slew_derate = drvr_library->slewDerateFromLibrary(); + double lo_thresh = drvr_library->slewLowerThreshold(rf); + double hi_thresh = drvr_library->slewUpperThreshold(rf); + bool rising = (rf == RiseFall::rise()); + delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising, slew_derate); delay_c *c = delay_work_->c; double c_log = c->vlg; - for (j=1;jelmore(j); - _delayV[j] = 0.6931472*elmore; - _slewV[j] = in_slew + c_log*elmore/slew_derate; + double wire_delay = 0.6931472*elmore; + double load_slew = in_slew + c_log*elmore/slew_derate; + _delayV[j] = wire_delay; + _slewV[j] = load_slew; + + const Pin *load_pin = rcmodel_->pinV[j]; + auto load_idx_itr = load_pin_index_map.find(load_pin); + if (load_idx_itr != load_pin_index_map.end()) { + size_t load_idx = load_idx_itr->second; + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, load_slew); + } } } -} - -void -ArnoldiDelayCalc::gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) -{ - input_port_ = false; - drvr_rf_ = arc->toEdge()->asRiseFall(); - const LibertyCell *drvr_cell = arc->from()->libertyCell(); - drvr_library_ = drvr_cell->libertyLibrary(); - drvr_parasitic_ = drvr_parasitic; - ConcreteParasitic *drvr_cparasitic = - reinterpret_cast(const_cast(drvr_parasitic)); - rcmodel_ = dynamic_cast(drvr_cparasitic); - GateTimingModel *model = gateModel(arc, dcalc_ap); - GateTableModel *table_model = dynamic_cast(model); - if (table_model && rcmodel_) - gateDelaySlew(drvr_cell, table_model, in_slew, - related_out_cap, pvt, - gate_delay, drvr_slew); else - LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); - drvr_slew_ = drvr_slew; - multi_drvr_slew_factor_ = 1.0F; + dcalc_result = makeResult(drvr_library, rf, 0.0, in_slew, load_pin_index_map); + return dcalc_result; } -void +ArcDcalcResult +ArnoldiDelayCalc::gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) +{ + const LibertyCell *drvr_cell = arc->from()->libertyCell(); + ConcreteParasitic *cparasitic = + reinterpret_cast(const_cast(parasitic)); + rcmodel_ = dynamic_cast(cparasitic); + GateTableModel *table_model = gateTableModel(arc, 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); + } + else + return LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, + parasitic, load_pin_index_map, dcalc_ap); +} + +ArcDcalcResult ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell, + const TimingArc *arc, const GateTableModel *table_model, const Slew &in_slew, - float related_out_cap, - const Pvt *pvt, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) + const LoadPinIndexMap &load_pin_index_map, + const Pvt *pvt) { pin_n_ = rcmodel_->n; if (pin_n_ >= _pinNmax) { @@ -407,12 +408,15 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell, _slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double)); } + ArcDcalcResult dcalc_result(load_pin_index_map.size()); pin_n_ = rcmodel_->n; - if (table_model) { - double slew_derate = drvr_library_->slewDerateFromLibrary(); - double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_); - double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_); - bool rising = (drvr_rf_ == RiseFall::rise()); + const RiseFall *rf = arc->toEdge()->asRiseFall(); + if (table_model && rf) { + const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); + double slew_derate = drvr_library->slewDerateFromLibrary(); + double lo_thresh = drvr_library->slewLowerThreshold(rf); + double hi_thresh = drvr_library->slewUpperThreshold(rf); + bool rising = (rf == RiseFall::rise()); delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising, slew_derate); if (rcmodel_->order > 0) { @@ -421,48 +425,43 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell, tab.cell = drvr_cell; tab.pvt = pvt; tab.in_slew = delayAsFloat(in_slew); - tab.relcap = related_out_cap; ar1_ceff_delay(delay_work_, &tab, rcmodel_, _delayV, _slewV); } - gate_delay = _delayV[0]; - drvr_slew = _slewV[0]; - } -} + dcalc_result.setGateDelay(_delayV[0]); + dcalc_result.setDrvrSlew(_slewV[0]); -void -ArnoldiDelayCalc::loadDelay(const Pin *load_pin, - // Return values. - ArcDelay &wire_delay, - Slew &load_slew) -{ - // This does not appear to handle input port parasitics correctly. - wire_delay = 0.0; - load_slew = drvr_slew_ * multi_drvr_slew_factor_; - if (rcmodel_) { - // HACK - for (int i = 0; i < rcmodel_->n; i++) { - if (rcmodel_->pinV[i] == load_pin) { - wire_delay = _delayV[i] - _delayV[0]; - load_slew = _slewV[i] * multi_drvr_slew_factor_; - break; + if (rcmodel_) { + for (int i = 0; i < rcmodel_->n; i++) { + const Pin *load_pin = rcmodel_->pinV[i]; + auto load_idx_itr = load_pin_index_map.find(load_pin); + if (load_idx_itr != load_pin_index_map.end()) { + size_t load_idx = load_idx_itr->second; + ArcDelay wire_delay = _delayV[i] - _delayV[0]; + Slew load_slew = _slewV[i]; + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, load_slew); + } } } } - thresholdAdjust(load_pin, wire_delay, load_slew); + return dcalc_result; } string -ArnoldiDelayCalc::reportGateDelay(const TimingArc *, - const Slew &, - float, - const Parasitic *, - float, - const Pvt *, - const DcalcAnalysisPt *, - int) +ArnoldiDelayCalc::reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap, + int digits) { - return ""; + return LumpedCapDelayCalc::reportGateDelay(drvr_pin, arc, in_slew, load_cap, + parasitic, load_pin_index_map, + dcalc_ap, digits); } //////////////////////////////////////////////////////////////// @@ -1310,12 +1309,11 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D, c1 = ctot; ArcDelay d1; Slew s1; - tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1); + tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1); tlohi = slew_derate*delayAsFloat(s1); r = tlohi/(c_log*c1); if (rdelay>0.0 && r > rdelay) r = rdelay; - // else printf("from rdelay %g to r %g\n",rdelay,r); return r; } @@ -1332,7 +1330,7 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D, double tlohi,smin,s; ArcDelay d1; Slew s1; - tab->table->gateDelay(tab->pvt, tab->in_slew, c, tab->relcap, pocv_enabled_, d1, s1); + tab->table->gateDelay(tab->pvt, tab->in_slew, c, pocv_enabled_, d1, s1); tlohi = slew_derate*delayAsFloat(s1); smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi); if (c_log*r*c >= tlohi) { @@ -1365,8 +1363,8 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab, return 0.0; ArcDelay d1, d2; Slew s1, s2; - tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1); - tab->table->gateDelay(tab->pvt, tab->in_slew, c2, tab->relcap, pocv_enabled_, d2, s2); + tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1); + tab->table->gateDelay(tab->pvt, tab->in_slew, c2, pocv_enabled_, d2, s2); double dt50 = delayAsFloat(d1)-delayAsFloat(d2); if (dt50 <= 0.0) return 0.0; @@ -1418,8 +1416,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, units_->timeUnit()->asString(s)); thix = ra_solve_for_t(p,s,vhi); tlox = ra_solve_for_t(p,s,vlo); - tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, tab->relcap, pocv_enabled_, - df, sf); + tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, pocv_enabled_, df, sf); debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s", units_->timeUnit()->asString(tab->in_slew), units_->capacitanceUnit()->asString(ctot), @@ -1430,7 +1427,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, units_->timeUnit()->asString(tlox-thix)); } ceff = ctot; - tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_, + tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_, df, sf); t50_sy = delayAsFloat(df); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); @@ -1472,7 +1469,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, units_->timeUnit()->asString(ceff_time), units_->capacitanceUnit()->asString(ceff)); - tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_, df, sf); + tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_, df, sf); t50_sy = delayAsFloat(df); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); for (j=0;jn;j++) { diff --git a/dcalc/ArnoldiDelayCalc.hh b/dcalc/ArnoldiDelayCalc.hh index 2616ab0d..20b0e626 100644 --- a/dcalc/ArnoldiDelayCalc.hh +++ b/dcalc/ArnoldiDelayCalc.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/dcalc/ArnoldiReduce.cc b/dcalc/ArnoldiReduce.cc index 8e019426..5c80c382 100644 --- a/dcalc/ArnoldiReduce.cc +++ b/dcalc/ArnoldiReduce.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -46,6 +46,14 @@ rcmodel::capacitance() const return ctot; } +PinSet +rcmodel::unannotatedLoads(const Pin *, + const Parasitics *) const +{ + // This should never be called because the rcmodel is not saved in the Parasitics. + return PinSet(); +} + struct ts_point { ParasiticNode *node_; @@ -62,7 +70,7 @@ struct ts_point struct ts_edge { - ConcreteParasiticResistor *resistor_; + ParasiticResistor *resistor_; ts_point *from; ts_point *to; }; @@ -131,23 +139,21 @@ ArnoldiReduce::~ArnoldiReduce() free(ts_pointV); } -Parasitic * +rcmodel * ArnoldiReduce::reduceToArnoldi(Parasitic *parasitic, const Pin *drvr_pin, float coupling_cap_factor, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, - const MinMax *cnst_min_max, + const MinMax *min_max, const ParasiticAnalysisPt *ap) { parasitic_network_ = reinterpret_cast(parasitic); drvr_pin_ = drvr_pin; coupling_cap_factor_ = coupling_cap_factor; rf_ = rf; - op_cond_ = op_cond; corner_ = corner; - cnst_min_max_ = cnst_min_max; + min_max_ = min_max; ap_ = ap; loadWork(); return makeRcmodelDrv(); @@ -158,18 +164,21 @@ ArnoldiReduce::loadWork() { pt_map_.clear(); - int resistor_count = 0; - ConcreteParasiticDeviceSet devices; - parasitic_network_->devices(&devices); - ConcreteParasiticDeviceSet::Iterator device_iter(devices); - while (device_iter.hasNext()) { - ParasiticDevice *device = device_iter.next(); - if (parasitics_->isResistor(device)) - resistor_count++; - } + const ParasiticResistorSeq &resistors = parasitics_->resistors(parasitic_network_); + int resistor_count = resistors.size(); - termN = parasitic_network_->pinNodes()->size(); - int subnode_count = parasitic_network_->subNodes()->size(); + termN = 0; + int subnode_count = 0; + ParasiticNodeSeq nodes = parasitics_->nodes(parasitic_network_); + for (ParasiticNode *node : nodes) { + if (!parasitics_->isExternal(node)) { + const Pin *pin = parasitics_->pin(node); + if (pin) + termN++; + else + subnode_count++; + } + } ts_pointN = subnode_count + 1 + termN; ts_edgeN = resistor_count; allocPoints(); @@ -191,50 +200,42 @@ ArnoldiReduce::loadWork() pend = pterm0; e = e0; int index = 0; - ConcreteParasiticSubNodeMap::Iterator - sub_node_iter(parasitic_network_->subNodes()); - while (sub_node_iter.hasNext()) { - ConcreteParasiticSubNode *node = sub_node_iter.next(); - pt_map_[node] = index; - p = p0 + index; - p->node_ = node; - p->eN = 0; - p->is_term = false; - index++; + + for (ParasiticNode *node : nodes) { + if (!parasitics_->isExternal(node)) { + const Pin *pin = parasitics_->pin(node); + if (pin) { + p = pend++; + pt_map_[node] = p - p0; + p->node_ = node; + p->eN = 0; + p->is_term = true; + tindex = p - pterm0; + p->tindex = tindex; + pinV[tindex] = pin; + } + else { + pt_map_[node] = index; + p = p0 + index; + p->node_ = node; + p->eN = 0; + p->is_term = false; + index++; + } + } } - ConcreteParasiticPinNodeMap::Iterator - pin_node_iter(parasitic_network_->pinNodes()); - while (pin_node_iter.hasNext()) { - ConcreteParasiticPinNode *node = pin_node_iter.next(); - p = pend++; - pt_map_[node] = p - p0; - p->node_ = node; - p->eN = 0; - p->is_term = true; - tindex = p - pterm0; - p->tindex = tindex; - const Pin *pin = parasitics_->connectionPin(node); - pinV[tindex] = pin; - } - ts_edge **eV = ts_eV; - ConcreteParasiticDeviceSet::Iterator device_iter2(devices); - while (device_iter2.hasNext()) { - ParasiticDevice *device = device_iter2.next(); - if (parasitics_->isResistor(device)) { - ConcreteParasiticResistor *resistor = - reinterpret_cast(device); - ts_point *pt1 = findPt(resistor->node1()); - ts_point *pt2 = findPt(resistor->node2()); - e->from = pt1; - e->to = pt2; - e->resistor_ = resistor; - pt1->eN++; - if (e->from != e->to) - pt2->eN++; - e++; - } + for (ParasiticResistor *resistor : resistors) { + ts_point *pt1 = findPt(parasitics_->node1(resistor)); + ts_point *pt2 = findPt(parasitics_->node2(resistor)); + e->from = pt1; + e->to = pt2; + e->resistor_ = resistor; + pt1->eN++; + if (e->from != e->to) + pt2->eN++; + e++; } for (p=p0;p!=pend;p++) { @@ -313,8 +314,7 @@ ArnoldiReduce::findPt(ParasiticNode *node) rcmodel * ArnoldiReduce::makeRcmodelDrv() { - ParasiticNode *drv_node = parasitics_->findNode(parasitic_network_, - drvr_pin_); + ParasiticNode *drv_node = parasitics_->findNode(parasitic_network_, drvr_pin_); ts_point *pdrv = findPt(drv_node); makeRcmodelDfs(pdrv); getRC(); @@ -322,8 +322,7 @@ ArnoldiReduce::makeRcmodelDrv() return nullptr; setTerms(pdrv); makeRcmodelFromTs(); - rcmodel *mod = makeRcmodelFromW(); - return mod; + return makeRcmodelFromW(); } #define ts_orient( pp, ee) \ @@ -415,7 +414,7 @@ ArnoldiReduce::getRC() p->r = 0.0; if (p->node_) { ParasiticNode *node = p->node_; - double cap = parasitics_->nodeGndCap(node, ap_) + double cap = parasitics_->nodeGndCap(node) + pinCapacitance(node); if (cap > 0.0) { p->c = cap; @@ -424,7 +423,7 @@ ArnoldiReduce::getRC() else p->c = 0.0; if (p->in_edge && p->in_edge->resistor_) - p->r = parasitics_->value(p->in_edge->resistor_, ap_); + p->r = parasitics_->value(p->in_edge->resistor_); if (!(p->r>=0.0 && p->r<100e+3)) { // 0 < r < 100kohm debugPrint(debug_, "arnoldi", 1, "R value %g out of range, drvr pin %s", @@ -433,20 +432,33 @@ ArnoldiReduce::getRC() } } } + for (ParasiticCapacitor *capacitor : parasitics_->capacitors(parasitic_network_)) { + float cap = parasitics_->value(capacitor) * ap_->couplingCapFactor(); + ParasiticNode *node1 = parasitics_->node1(capacitor); + if (!parasitics_->isExternal(node1)) { + ts_point *pt = findPt(node1); + pt->c += cap; + } + ParasiticNode *node2 = parasitics_->node2(capacitor); + if (!parasitics_->isExternal(node2)) { + ts_point *pt = findPt(node2); + pt->c += cap; + } + } } float ArnoldiReduce::pinCapacitance(ParasiticNode *node) { - const Pin *pin = parasitics_->connectionPin(node); + const Pin *pin = parasitics_->pin(node); float pin_cap = 0.0; if (pin) { Port *port = network_->port(pin); LibertyPort *lib_port = network_->libertyPort(port); if (lib_port) - pin_cap = sdc_->pinCapacitance(pin,rf_, op_cond_, corner_, cnst_min_max_); + pin_cap = sdc_->pinCapacitance(pin,rf_, corner_, min_max_); else if (network_->isTopLevelPort(pin)) - pin_cap = sdc_->portExtCap(port, rf_, corner_, cnst_min_max_); + pin_cap = sdc_->portExtCap(port, rf_, corner_, min_max_); } return pin_cap; } diff --git a/dcalc/ArnoldiReduce.hh b/dcalc/ArnoldiReduce.hh index e299f929..ad49da34 100644 --- a/dcalc/ArnoldiReduce.hh +++ b/dcalc/ArnoldiReduce.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -37,21 +37,20 @@ class rcmodel; struct ts_edge; struct ts_point; -typedef Map ArnolidPtMap; +typedef Map ArnolidPtMap; class ArnoldiReduce : public StaState { public: ArnoldiReduce(StaState *sta); ~ArnoldiReduce(); - Parasitic *reduceToArnoldi(Parasitic *parasitic, - const Pin *drvr_pin, - float coupling_cap_factor, - const RiseFall *rf, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); + rcmodel *reduceToArnoldi(Parasitic *parasitic, + const Pin *drvr_pin, + float coupling_cap_factor, + const RiseFall *rf, + const Corner *corner, + const MinMax *cnst_min_max, + const ParasiticAnalysisPt *ap); protected: void loadWork(); @@ -70,9 +69,8 @@ protected: const Pin *drvr_pin_; float coupling_cap_factor_; const RiseFall *rf_; - const OperatingConditions *op_cond_; const Corner *corner_; - const MinMax *cnst_min_max_; + const MinMax *min_max_; const ParasiticAnalysisPt *ap_; // ParasiticNode -> ts_point index. ArnolidPtMap pt_map_; diff --git a/dcalc/DcalcAnalysisPt.cc b/dcalc/DcalcAnalysisPt.cc index 1995f245..3b2b71bd 100644 --- a/dcalc/DcalcAnalysisPt.cc +++ b/dcalc/DcalcAnalysisPt.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/dcalc/DelayCalc.cc b/dcalc/DelayCalc.cc index 2c5c1ba0..ab032824 100644 --- a/dcalc/DelayCalc.cc +++ b/dcalc/DelayCalc.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -20,7 +20,6 @@ #include "StringUtil.hh" #include "UnitDelayCalc.hh" #include "LumpedCapDelayCalc.hh" -#include "SlewDegradeDelayCalc.hh" #include "DmpDelayCalc.hh" #include "ArnoldiDelayCalc.hh" @@ -35,7 +34,6 @@ registerDelayCalcs() { registerDelayCalc("unit", makeUnitDelayCalc); registerDelayCalc("lumped_cap", makeLumpedCapDelayCalc); - registerDelayCalc("slew_degrade", makeSlewDegradeDelayCalc); registerDelayCalc("dmp_ceff_elmore", makeDmpCeffElmoreDelayCalc); registerDelayCalc("dmp_ceff_two_pole", makeDmpCeffTwoPoleDelayCalc); registerDelayCalc("arnoldi", makeArnoldiDelayCalc); diff --git a/dcalc/DelayCalc.i b/dcalc/DelayCalc.i index 52711847..d94565d4 100644 --- a/dcalc/DelayCalc.i +++ b/dcalc/DelayCalc.i @@ -3,7 +3,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -19,6 +19,8 @@ // along with this program. If not, see . #include "Sta.hh" +#include "ArcDelayCalc.hh" +#include "dcalc/ArcDcalcWaveforms.hh" %} @@ -59,4 +61,76 @@ 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(); +} + %} // inline diff --git a/dcalc/DelayCalc.tcl b/dcalc/DelayCalc.tcl index e2cde430..7af909e5 100644 --- a/dcalc/DelayCalc.tcl +++ b/dcalc/DelayCalc.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -116,7 +116,7 @@ proc set_delay_calculator { alg } { if { [is_delay_calc_name $alg] } { set_delay_calculator_cmd $alg } else { - sta_error 435 "delay calculator $alg not found." + sta_error 180 "delay calculator $alg not found." } } @@ -145,38 +145,38 @@ proc set_assigned_delay_cmd { cmd cmd_args } { if [info exists keys(-from)] { set from_pins [get_port_pins_error "from_pins" $keys(-from)] } else { - sta_error 442 "$cmd missing -from argument." + sta_error 181 "$cmd missing -from argument." } if [info exists keys(-to)] { set to_pins [get_port_pins_error "to_pins" $keys(-to)] } else { - sta_error 443 "$cmd missing -to argument." + sta_error 182 "$cmd missing -to argument." } set delay [lindex $cmd_args 0] if {![string is double $delay]} { - sta_error 444 "$cmd delay is not a float." + sta_error 183 "$cmd delay is not a float." } set delay [time_ui_sta $delay] if {[info exists flags(-cell)] && [info exists flags(-net)]} { - sta_error 445 "set_annotated_delay -cell and -net options are mutually excluive." + sta_error 184 "set_annotated_delay -cell and -net options are mutually excluive." } elseif {[info exists flags(-cell)]} { if { $from_pins != {} } { set inst [[lindex $from_pins 0] instance] foreach pin $from_pins { if {[$pin instance] != $inst} { - sta_error 446 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]." + sta_error 185 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]." } } foreach pin $to_pins { if {[$pin instance] != $inst} { - sta_error 447 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]" + sta_error 186 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]" } } } } elseif {![info exists flags(-net)]} { - sta_error 448 "$cmd -cell or -net required." + sta_error 187 "$cmd -cell or -net required." } foreach from_pin $from_pins { set from_vertices [$from_pin vertices] @@ -240,7 +240,7 @@ proc set_assigned_check_cmd { cmd cmd_args } { if { [info exists keys(-from)] } { set from_pins [get_port_pins_error "from_pins" $keys(-from)] } else { - sta_error 449 "$cmd missing -from argument." + sta_error 188 "$cmd missing -from argument." } set from_rf "rise_fall" if { [info exists keys(-clock)] } { @@ -249,14 +249,14 @@ proc set_assigned_check_cmd { cmd cmd_args } { || $clk_arg eq "fall" } { set from_rf $clk_arg } else { - sta_error 450 "$cmd -clock must be rise or fall." + sta_error 189 "$cmd -clock must be rise or fall." } } if { [info exists keys(-to)] } { set to_pins [get_port_pins_error "to_pins" $keys(-to)] } else { - sta_error 451 "$cmd missing -to argument." + sta_error 190 "$cmd missing -to argument." } set to_rf [parse_rise_fall_flags flags] set corner [parse_corner keys] @@ -271,7 +271,7 @@ proc set_assigned_check_cmd { cmd cmd_args } { } elseif { [info exists flags(-removal)] } { set role "removal" } else { - sta_error 452 "$cmd missing -setup|-hold|-recovery|-removal check type.." + sta_error 191 "$cmd missing -setup|-hold|-recovery|-removal check type.." } set cond "" if { [info exists key(-cond)] } { @@ -279,7 +279,7 @@ proc set_assigned_check_cmd { cmd cmd_args } { } set check_value [lindex $cmd_args 0] if { ![string is double $check_value] } { - sta_error 453 "$cmd check_value is not a float." + sta_error 192 "$cmd check_value is not a float." } set check_value [time_ui_sta $check_value] @@ -347,7 +347,7 @@ proc set_assigned_transition { args } { set slew [lindex $args 0] if {![string is double $slew]} { - sta_error 428 "set_assigned_transition transition is not a float." + sta_error 210 "set_assigned_transition transition is not a float." } set slew [time_ui_sta $slew] set pins [get_port_pins_error "pins" [lindex $args 1]] diff --git a/dcalc/DelayCalcBase.cc b/dcalc/DelayCalcBase.cc index c2639664..7db5663f 100644 --- a/dcalc/DelayCalcBase.cc +++ b/dcalc/DelayCalcBase.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -18,53 +18,85 @@ #include "Liberty.hh" #include "TimingArc.hh" +#include "TimingModel.hh" +#include "TableModel.hh" #include "Network.hh" #include "Parasitics.hh" +#include "Sdc.hh" +#include "Corner.hh" +#include "DcalcAnalysisPt.hh" namespace sta { +using std::log; + DelayCalcBase::DelayCalcBase(StaState *sta) : ArcDelayCalc(sta) { } +void +DelayCalcBase::reduceParasitic(const Parasitic *parasitic_network, + const Net *net, + const Corner *corner, + const MinMaxAll *min_max) +{ + NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net); + while (pin_iter->hasNext()) { + const Pin *pin = pin_iter->next(); + if (network_->isDriver(pin)) { + for (RiseFall *rf : RiseFall::range()) { + for (const MinMax *min_max : min_max->range()) { + if (corner == nullptr) { + for (const Corner *corner1 : *corners_) { + DcalcAnalysisPt *dcalc_ap = corner1->findDcalcAnalysisPt(min_max); + reduceParasitic(parasitic_network, pin, rf, dcalc_ap); + } + } + else { + DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); + reduceParasitic(parasitic_network, pin, rf, dcalc_ap); + } + } + } + } + } + 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() { - for (auto parasitic : unsaved_parasitics_) - parasitics_->deleteUnsavedParasitic(parasitic); - unsaved_parasitics_.clear(); - for (auto drvr_pin : reduced_parasitic_drvrs_) - parasitics_->deleteDrvrReducedParasitics(drvr_pin); - reduced_parasitic_drvrs_.clear(); -} - -void -DelayCalcBase::inputPortDelay(const Pin *, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *) -{ - drvr_cell_ = nullptr; - drvr_library_ = network_->defaultLibertyLibrary(); - drvr_slew_ = in_slew; - drvr_rf_ = rf; - drvr_parasitic_ = parasitic; - input_port_ = true; -} - -void -DelayCalcBase::gateDelayInit(const TimingArc *arc, - const Slew &in_slew, - const Parasitic *drvr_parasitic) -{ - drvr_cell_ = arc->from()->libertyCell(); - drvr_library_ = drvr_cell_->libertyLibrary(); - drvr_rf_ = arc->toEdge()->asRiseFall(); - drvr_slew_ = in_slew; - drvr_parasitic_ = drvr_parasitic; - input_port_ = false; } // For DSPF on an input port the elmore delay is used as the time @@ -73,40 +105,47 @@ DelayCalcBase::gateDelayInit(const TimingArc *arc, // Note that this uses the driver thresholds and relies on // thresholdAdjust to convert the delay and slew to the load's thresholds. void -DelayCalcBase::dspfWireDelaySlew(const Pin *, +DelayCalcBase::dspfWireDelaySlew(const Pin *load_pin, + const RiseFall *rf, + Slew drvr_slew, float elmore, ArcDelay &wire_delay, Slew &load_slew) { - float vth = drvr_library_->inputThreshold(drvr_rf_); - float vl = drvr_library_->slewLowerThreshold(drvr_rf_); - float vh = drvr_library_->slewUpperThreshold(drvr_rf_); - float slew_derate = drvr_library_->slewDerateFromLibrary(); + + LibertyLibrary *load_library = thresholdLibrary(load_pin); + float vth = load_library->inputThreshold(rf); + float vl = load_library->slewLowerThreshold(rf); + float vh = load_library->slewUpperThreshold(rf); + float slew_derate = load_library->slewDerateFromLibrary(); wire_delay = -elmore * log(1.0 - vth); - load_slew = drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate; + load_slew = drvr_slew + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate; + load_slew = drvr_slew + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate; } void DelayCalcBase::thresholdAdjust(const Pin *load_pin, + const LibertyLibrary *drvr_library, + const RiseFall *rf, ArcDelay &load_delay, Slew &load_slew) { LibertyLibrary *load_library = thresholdLibrary(load_pin); if (load_library - && drvr_library_ - && load_library != drvr_library_) { - float drvr_vth = drvr_library_->outputThreshold(drvr_rf_); - float load_vth = load_library->inputThreshold(drvr_rf_); - float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_rf_) - - drvr_library_->slewLowerThreshold(drvr_rf_); + && drvr_library + && load_library != drvr_library) { + float drvr_vth = drvr_library->outputThreshold(rf); + float load_vth = load_library->inputThreshold(rf); + float drvr_slew_delta = drvr_library->slewUpperThreshold(rf) + - drvr_library->slewLowerThreshold(rf); float load_delay_delta = delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta); - load_delay += (drvr_rf_ == RiseFall::rise()) + load_delay += (rf == RiseFall::rise()) ? load_delay_delta : -load_delay_delta; - float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_) - - load_library->slewLowerThreshold(drvr_rf_); - float drvr_slew_derate = drvr_library_->slewDerateFromLibrary(); + float load_slew_delta = load_library->slewUpperThreshold(rf) + - load_library->slewLowerThreshold(rf); + float drvr_slew_derate = drvr_library->slewDerateFromLibrary(); float load_slew_derate = load_library->slewDerateFromLibrary(); load_slew = load_slew * ((load_slew_delta / load_slew_derate) / (drvr_slew_delta / drvr_slew_derate)); @@ -129,4 +168,55 @@ DelayCalcBase::thresholdLibrary(const Pin *load_pin) } } +ArcDelay +DelayCalcBase::checkDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &from_slew, + const Slew &to_slew, + float related_out_cap, + const DcalcAnalysisPt *dcalc_ap) +{ + CheckTimingModel *model = checkModel(arc, dcalc_ap); + if (model) { + float from_slew1 = delayAsFloat(from_slew); + float to_slew1 = delayAsFloat(to_slew); + return model->checkDelay(pinPvt(check_pin, dcalc_ap), from_slew1, to_slew1, + related_out_cap, pocv_enabled_); + } + else + return delay_zero; +} + +string +DelayCalcBase::reportCheckDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &from_slew, + const char *from_slew_annotation, + const Slew &to_slew, + float related_out_cap, + const DcalcAnalysisPt *dcalc_ap, + int digits) +{ + CheckTimingModel *model = checkModel(arc, dcalc_ap); + if (model) { + float from_slew1 = delayAsFloat(from_slew); + float to_slew1 = delayAsFloat(to_slew); + return model->reportCheckDelay(pinPvt(check_pin, dcalc_ap), from_slew1, + from_slew_annotation, to_slew1, + related_out_cap, false, digits); + } + return ""; +} + +const Pvt * +DelayCalcBase::pinPvt(const Pin *pin, + const DcalcAnalysisPt *dcalc_ap) +{ + const Instance *drvr_inst = network_->instance(pin); + const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax()); + if (pvt == nullptr) + pvt = dcalc_ap->operatingConditions(); + return pvt; +} + } // namespace diff --git a/dcalc/DelayCalcBase.hh b/dcalc/DelayCalcBase.hh index 248e8e5a..76137d0b 100644 --- a/dcalc/DelayCalcBase.hh +++ b/dcalc/DelayCalcBase.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -20,44 +20,64 @@ namespace sta { +class GateTableModel; + class DelayCalcBase : public ArcDelayCalc { public: explicit DelayCalcBase(StaState *sta); - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, + void finishDrvrPin() override; + + void reduceParasitic(const Parasitic *parasitic_network, + const Net *net, + const Corner *corner, + const MinMaxAll *min_max) override; + + ArcDelay checkDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &from_slew, + const Slew &to_slew, + float related_out_cap, const DcalcAnalysisPt *dcalc_ap) override; - void finishDrvrPin() override; + + string reportCheckDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &from_slew, + const char *from_slew_annotation, + const Slew &to_slew, + float related_out_cap, + const DcalcAnalysisPt *dcalc_ap, + int digits) override; protected: - void gateDelayInit(const TimingArc *arc, - const Slew &in_slew, - const Parasitic *drvr_parasitic); + 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. void thresholdAdjust(const Pin *load_pin, + const LibertyLibrary *drvr_library, + const RiseFall *rf, ArcDelay &load_delay, Slew &load_slew); // Helper function for input ports driving dspf parasitic. void dspfWireDelaySlew(const Pin *load_pin, - float elmore, + const RiseFall *rf, + Slew drvr_slew, + float elmore, + // Return values. ArcDelay &wire_delay, Slew &load_slew); + const Pvt *pinPvt(const Pin *pin, + const DcalcAnalysisPt *dcalc_ap); - Slew drvr_slew_; - const LibertyCell *drvr_cell_; - const LibertyLibrary *drvr_library_; - const Parasitic *drvr_parasitic_; - bool input_port_; - const RiseFall *drvr_rf_; - // Parasitics returned by findParasitic that are reduced or estimated - // that can be deleted after delay calculation for the driver pin - // is finished. - Vector unsaved_parasitics_; - Vector reduced_parasitic_drvrs_; + using ArcDelayCalc::reduceParasitic; }; } // namespace diff --git a/dcalc/DmpCeff.cc b/dcalc/DmpCeff.cc index 0d298a78..70cf302f 100644 --- a/dcalc/DmpCeff.cc +++ b/dcalc/DmpCeff.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -38,6 +38,7 @@ #include "Parasitics.hh" #include "DcalcAnalysisPt.hh" #include "ArcDelayCalc.hh" +#include "FindRoot.hh" namespace sta { @@ -47,6 +48,7 @@ using std::max; using std::sqrt; using std::log; using std::isnan; +using std::function; // Tolerance (as a scale of value) for driver parameters (Ceff, delta t, t0). static const double driver_param_tol = .01; @@ -88,38 +90,15 @@ gateModelRd(const LibertyCell *cell, double in_slew, double c2, double c1, - float related_out_cap, const Pvt *pvt, bool pocv_enabled); static void -evalDmpEqnsState(void *state); -static void -evalVoEqns(void *state, - double x, - double &y, - double &dy); -static void -evalVlEqns(void *state, - double x, - double &y, - double &dy); - -static double -findRoot(void (*func)(void *state, double x, double &y, double &dy), - void *state, - double x1, - double x2, - double x_tol, - int max_iter); -static void newtonRaphson(const int max_iter, double x[], const int n, const double x_tol, // eval(state) is called to fill fvec and fjac. - // Returns false if fails. - void (*eval)(void *state), - void *state, + function eval, // Temporaries supplied by caller. double *fvec, double **fjac, @@ -155,14 +134,15 @@ public: const RiseFall *rf, double rd, double in_slew, - float related_out_cap, double c2, double rpi, double c1); - virtual void gateDelaySlew(double &delay, + virtual void gateDelaySlew(// Return values. + double &delay, double &slew) = 0; virtual void loadDelaySlew(const Pin *load_pin, double elmore, + // Return values. ArcDelay &delay, Slew &slew); double ceff() { return ceff_; } @@ -171,29 +151,34 @@ public: // equations evaluated at x_ and fjac_ with the jabobian evaluated at x_. virtual void evalDmpEqns() = 0; // Output response to vs(t) ramp driving pi model load. - double vo(double t); - double dVoDt(double t); + void Vo(double t, + // Return values. + double &vo, + double &dol_dt); // Load responce to driver waveform. - double vl(double t); - double dVlDt(double t); - double vCross() { return v_cross_; } + void Vl(double t, + // Return values. + double &vl, + double &dvl_dt); protected: // Find driver parameters t0, delta_t, Ceff. void findDriverParams(double ceff); void gateCapDelaySlew(double cl, + // Return values. double &delay, double &slew); void gateDelays(double ceff, + // Return values. double &t_vth, double &t_vl, double &slew); - virtual double dv0dt(double t) = 0; // Partial derivatives of y(t) (jacobian). void dy(double t, double t0, double dt, double cl, + // Return values. double &dydt0, double &dyddt, double &dydcl); @@ -204,11 +189,16 @@ protected: void showX(); void showFvec(); void showJacobian(); - void findDriverDelaySlew(double &delay, + void findDriverDelaySlew(// Return values. + double &delay, double &slew); - double findVoCrossing(double vth); + double findVoCrossing(double vth, + double lower_bound, + double upper_bound); void showVo(); - double findVlCrossing(double vth); + double findVlCrossing(double vth, + double lower_bound, + double upper_bound); void showVl(); void fail(const char *reason); @@ -221,11 +211,17 @@ protected: double y0(double t, double cl); // Output response to unit ramp driving pi model load. - virtual double v0(double t) = 0; + virtual void V0(double t, + // Return values. + double &vo, + double &dvo_dt) = 0; // Upper bound on time that vo crosses vh. virtual double voCrossingUpperBound() = 0; // Load responce to driver unit ramp. - virtual double vl0(double t) = 0; + virtual void Vl0(double t, + // Return values. + double &vl, + double &dvl_dt) = 0; // Upper bound on time that vl crosses vh. double vlCrossingUpperBound(); @@ -235,7 +231,6 @@ protected: const Pvt *pvt_; const GateTableModel *gate_model_; double in_slew_; - float related_out_cap_; double c2_; double rpi_; double c1_; @@ -273,12 +268,6 @@ protected: // Load rspf elmore delay. double elmore_; double p3_; - -private: - virtual double dvl0dt(double t) = 0; - - // Implicit argument passed to evalVoEqns, evalVlEqns. - double v_cross_; }; DmpAlg::DmpAlg(int nr_order, @@ -319,7 +308,6 @@ DmpAlg::init(const LibertyLibrary *drvr_library, const RiseFall *rf, double rd, double in_slew, - float related_out_cap, // Pi model. double c2, double rpi, @@ -331,7 +319,6 @@ DmpAlg::init(const LibertyLibrary *drvr_library, gate_model_ = gate_model; rd_ = rd; in_slew_ = in_slew; - related_out_cap_ = related_out_cap; c2_ = c2; rpi_ = rpi; c1_ = c1; @@ -355,8 +342,9 @@ DmpAlg::findDriverParams(double ceff) double t0 = t_vth + log(1.0 - vth_) * rd_ * ceff - vth_ * dt; x_[DmpParam::dt] = dt; x_[DmpParam::t0] = t0; - newtonRaphson(100, x_, nr_order_, driver_param_tol, evalDmpEqnsState, - this, fvec_, fjac_, index_, p_, scale_); + newtonRaphson(100, x_, nr_order_, driver_param_tol, + [=] () { evalDmpEqns(); }, + fvec_, fjac_, index_, p_, scale_); t0_ = x_[DmpParam::t0]; dt_ = x_[DmpParam::dt]; debugPrint(debug_, "dmp_ceff", 3, " t0 = %s dt = %s ceff = %s", @@ -367,29 +355,24 @@ DmpAlg::findDriverParams(double ceff) showVo(); } -static void -evalDmpEqnsState(void *state) -{ - DmpAlg *alg = reinterpret_cast(state); - alg->evalDmpEqns(); -} - void DmpAlg::gateCapDelaySlew(double ceff, - double &delay, + // Return values. + double &delay, double &slew) { ArcDelay model_delay; Slew model_slew; - gate_model_->gateDelay(pvt_, in_slew_, ceff, related_out_cap_, - pocv_enabled_, model_delay, model_slew); + gate_model_->gateDelay(pvt_, in_slew_, ceff, pocv_enabled_, + model_delay, model_slew); delay = delayAsFloat(model_delay); slew = delayAsFloat(model_slew); } void DmpAlg::gateDelays(double ceff, - double &t_vth, + // Return values. + double &t_vth, double &t_vl, double &slew) { @@ -493,58 +476,68 @@ DmpAlg::showJacobian() } void -DmpAlg::findDriverDelaySlew(double &delay, +DmpAlg::findDriverDelaySlew(// Return values. + double &delay, double &slew) { - delay = findVoCrossing(vth_); - double tl = findVoCrossing(vl_); - double th = findVoCrossing(vh_); + double t_upper = voCrossingUpperBound(); + delay = findVoCrossing(vth_, t0_, t_upper); + double tl = findVoCrossing(vl_, t0_, delay); + double th = findVoCrossing(vh_, delay, t_upper); // Convert measured slew to table slew. slew = (th - tl) / slew_derate_; } // Find t such that vo(t)=v. double -DmpAlg::findVoCrossing(double vth) +DmpAlg::findVoCrossing(double vth, + double t_lower, + double t_upper) { - v_cross_ = vth; - double ub = voCrossingUpperBound(); - return findRoot(evalVoEqns, this, t0_, ub, vth_time_tol, find_root_max_iter); + FindRootFunc vo_func = [=] (double t, + double &y, + double &dy) { + double vo, vo_dt; + Vo(t, vo, vo_dt); + y = vo - vth; + dy = vo_dt; + }; + bool fail; + double t_vth = findRoot(vo_func, t_lower, t_upper, vth_time_tol, + find_root_max_iter, fail); + if (fail) + throw DmpError("find Vo crossing failed"); + return t_vth; } -static void -evalVoEqns(void *state, - double x, - double &y, - double &dy) -{ - DmpAlg *pi_ceff = reinterpret_cast(state); - y = pi_ceff->vo(x) - pi_ceff->vCross(); - dy = pi_ceff->dVoDt(x); -} - -double -DmpAlg::vo(double t) +void +DmpAlg::Vo(double t, + // Return values. + double &vo, + double &dvo_dt) { double t1 = t - t0_; - if (t1 <= 0.0) - return 0.0; - else if (t1 <= dt_) - return v0(t1) / dt_; - else - return (v0(t1) - v0(t1 - dt_)) / dt_; -} + if (t1 <= 0.0) { + vo = 0.0; + dvo_dt = 0.0; + } + else if (t1 <= dt_) { + double v0, dv0_dt; + V0(t1, v0, dv0_dt); -double -DmpAlg::dVoDt(double t) -{ - double t1 = t - t0_; - if (t1 <= 0) - return 0.0; - else if (t1 <= dt_) - return dv0dt(t1) / dt_; - else - return (dv0dt(t1) - dv0dt(t1 - dt_)) / dt_; + vo = v0 / dt_; + dvo_dt = dv0_dt / dt_; + } + else { + double v0, dv0_dt; + V0(t1, v0, dv0_dt); + + double v0_dt, dv0_dt_dt; + V0(t1 - dt_, v0_dt, dv0_dt_dt); + + vo = (v0 - v0_dt) / dt_; + dvo_dt = (dv0_dt - dv0_dt_dt) / dt_; + } } void @@ -552,8 +545,11 @@ DmpAlg::showVo() { report_->reportLine(" t vo(t)"); double ub = voCrossingUpperBound(); - for (double t = t0_; t < t0_ + ub; t += dt_ / 10.0) - report_->reportLine(" %g %g", t, vo(t)); + for (double t = t0_; t < t0_ + ub; t += dt_ / 10.0) { + double vo, dvo_dt; + Vo(t, vo, dvo_dt); + report_->reportLine(" %g %g", t, vo); + } } void @@ -577,9 +573,11 @@ DmpAlg::loadDelaySlew(const Pin *, showVl(); elmore_ = elmore; p3_ = 1.0 / elmore; - double load_delay = findVlCrossing(vth_); - double tl = findVlCrossing(vl_); - double th = findVlCrossing(vh_); + double t_lower = t0_; + double t_upper = vlCrossingUpperBound(); + double load_delay = findVlCrossing(vth_, t_lower, t_upper); + double tl = findVlCrossing(vl_, t_lower, load_delay); + double th = findVlCrossing(vh_, load_delay, t_upper); // Measure delay from Vo, the load dependent source excitation. double delay1 = load_delay - vo_delay_; // Convert measured slew to reported/table slew. @@ -609,13 +607,25 @@ DmpAlg::loadDelaySlew(const Pin *, } // Find t such that vl(t)=v. -// Return true if successful. double -DmpAlg::findVlCrossing(double vth) +DmpAlg::findVlCrossing(double vth, + double t_lower, + double t_upper) { - v_cross_ = vth; - double ub = vlCrossingUpperBound(); - return findRoot(evalVlEqns, this, t0_, ub, vth_time_tol, find_root_max_iter); + FindRootFunc vl_func = [=] (double t, + double &y, + double &dy) { + double vl, vl_dt; + Vl(t, vl, vl_dt); + y = vl - vth; + dy = vl_dt; + }; + bool fail; + double t_vth = findRoot(vl_func, t_lower, t_upper, vth_time_tol, + find_root_max_iter, fail); + if (fail) + throw DmpError("find Vl crossing failed"); + return t_vth; } double @@ -624,39 +634,33 @@ DmpAlg::vlCrossingUpperBound() return voCrossingUpperBound() + elmore_ * 2.0; } -static void -evalVlEqns(void *state, - double x, - double &y, - double &dy) -{ - DmpAlg *pi_ceff = reinterpret_cast(state); - y = pi_ceff->vl(x) - pi_ceff->vCross(); - dy = pi_ceff->dVlDt(x); -} - -double -DmpAlg::vl(double t) +void +DmpAlg::Vl(double t, + // Return values. + double &vl, + double &dvl_dt) { double t1 = t - t0_; - if (t1 <= 0) - return 0.0; - else if (t1 <= dt_) - return vl0(t1) / dt_; - else - return (vl0(t1) - vl0(t1 - dt_)) / dt_; -} + if (t1 <= 0.0) { + vl = 0.0; + dvl_dt = 0.0; + } + else if (t1 <= dt_) { + double vl0, dvl0_dt; + Vl0(t1, vl0, dvl0_dt); + vl = vl0 / dt_; + dvl_dt = dvl0_dt / dt_; + } + else { + double vl0, dvl0_dt; + Vl0(t1, vl0, dvl0_dt); -double -DmpAlg::dVlDt(double t) -{ - double t1 = t - t0_; - if (t1 <= 0) - return 0.0; - else if (t1 <= dt_) - return dvl0dt(t1) / dt_; - else - return (dvl0dt(t1) - dvl0dt(t1 - dt_)) / dt_; + double vl0_dt, dvl0_dt_dt; + Vl0(t1 - dt_, vl0_dt, dvl0_dt_dt); + + vl = (vl0 - vl0_dt) / dt_; + dvl_dt = (dvl0_dt - dvl0_dt_dt) / dt_; + } } void @@ -664,8 +668,11 @@ DmpAlg::showVl() { report_->reportLine(" t vl(t)"); double ub = vlCrossingUpperBound(); - for (double t = t0_; t < t0_ + ub * 2.0; t += ub / 10.0) - report_->reportLine(" %g %g", t, vl(t)); + for (double t = t0_; t < t0_ + ub * 2.0; t += ub / 10.0) { + double vl, dvl_dt; + Vl(t, vl, dvl_dt); + report_->reportLine(" %g %g", t, vl); + } } void @@ -688,32 +695,37 @@ class DmpCap : public DmpAlg { public: DmpCap(StaState *sta); - virtual const char *name() { return "cap"; } - virtual void init(const LibertyLibrary *library, - const LibertyCell *drvr_cell, - const Pvt *pvt, - const GateTableModel *gate_model, - const RiseFall *rf, - double rd, - double in_slew, - float related_out_cap, - double c2, - double rpi, - double c1); - virtual void gateDelaySlew(double &delay, - double &slew); - virtual void loadDelaySlew(const Pin *, - double elmore, - ArcDelay &delay, - Slew &slew); - virtual void evalDmpEqns(); - virtual double voCrossingUpperBound(); + const char *name() override { return "cap"; } + void init(const LibertyLibrary *library, + const LibertyCell *drvr_cell, + const Pvt *pvt, + const GateTableModel *gate_model, + const RiseFall *rf, + double rd, + double in_slew, + double c2, + double rpi, + double c1) override; + void gateDelaySlew(// Return values. + double &delay, + double &slew) override; + void loadDelaySlew(const Pin *, + double elmore, + // Return values. + ArcDelay &delay, + Slew &slew) override; + void evalDmpEqns() override; + double voCrossingUpperBound() override; private: - virtual double v0(double t); - virtual double dv0dt(double t); - virtual double vl0(double t); - virtual double dvl0dt(double t); + void V0(double t, + // Return values. + double &vo, + double &dvo_dt) override; + void Vl0(double t, + // Return values. + double &vl, + double &dvl_dt) override; }; DmpCap::DmpCap(StaState *sta): @@ -729,19 +741,19 @@ DmpCap::init(const LibertyLibrary *drvr_library, const RiseFall *rf, double rd, double in_slew, - float related_out_cap, double c2, double rpi, double c1) { debugPrint(debug_, "dmp_ceff", 3, "Using DMP cap"); DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, - rd, in_slew, related_out_cap, c2, rpi, c1); + rd, in_slew, c2, rpi, c1); ceff_ = c1 + c2; } void -DmpCap::gateDelaySlew(double &delay, +DmpCap::gateDelaySlew(// Return values. + double &delay, double &slew) { debugPrint(debug_, "dmp_ceff", 3, " ceff = %s", @@ -765,16 +777,14 @@ DmpCap::evalDmpEqns() { } -double -DmpCap::v0(double) +void +DmpCap::V0(double, + // Return values. + double &vo, + double &dvo_dt) { - return 0.0; -} - -double -DmpCap::dv0dt(double) -{ - return 0.0; + vo = 0.0; + dvo_dt = 0.0; } double @@ -783,16 +793,14 @@ DmpCap::voCrossingUpperBound() return 0.0; } -double -DmpCap::vl0(double) +void +DmpCap::Vl0(double , + // Return values. + double &vl, + double &dvl_dt) { - return 0.0; -} - -double -DmpCap::dvl0dt(double) -{ - return 0.0; + vl = 0.0; + dvl_dt = 0.0; } //////////////////////////////////////////////////////////////// @@ -802,33 +810,37 @@ class DmpPi : public DmpAlg { public: DmpPi(StaState *sta); - virtual const char *name() { return "Pi"; } - virtual void init(const LibertyLibrary *library, - const LibertyCell *drvr_cell, - const Pvt *pvt, - const GateTableModel *gate_model, - const RiseFall *rf, - double rd, - double in_slew, - float related_out_cap, - double c2, - double rpi, - double c1); - virtual void gateDelaySlew(double &delay, - double &slew); - virtual void evalDmpEqns(); - virtual double voCrossingUpperBound(); + const char *name() override { return "Pi"; } + void init(const LibertyLibrary *library, + const LibertyCell *drvr_cell, + const Pvt *pvt, + const GateTableModel *gate_model, + const RiseFall *rf, + double rd, + double in_slew, + double c2, + double rpi, + double c1) override; + void gateDelaySlew(// Return values. + double &delay, + double &slew) override; + void evalDmpEqns() override; + double voCrossingUpperBound() override; private: void findDriverParamsPi(); - virtual double v0(double t); - virtual double dv0dt(double t); double ipiIceff(double t0, double dt, double ceff_time, double ceff); - virtual double vl0(double t); - virtual double dvl0dt(double t); + void V0(double t, + // Return values. + double &vo, + double &dvo_dt) override; + void Vl0(double t, + // Return values. + double &vl, + double &dvl_dt) override; // Poles/zero. double p1_; @@ -870,14 +882,13 @@ DmpPi::init(const LibertyLibrary *drvr_library, const RiseFall *rf, double rd, double in_slew, - float related_out_cap, double c2, double rpi, double c1) { debugPrint(debug_, "dmp_ceff", 3, "Using DMP Pi"); DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, - in_slew, related_out_cap, c2, rpi, c1); + in_slew, c2, rpi, c1); // Find poles/zeros. z1_ = 1.0 / (rpi_ * c1_); @@ -901,7 +912,8 @@ DmpPi::init(const LibertyLibrary *drvr_library, } void -DmpPi::gateDelaySlew(double &delay, +DmpPi::gateDelaySlew(// Return values. + double &delay, double &slew) { driver_valid_ = false; @@ -1030,27 +1042,35 @@ DmpPi::ipiIceff(double, double dt, return ipi - iceff; } -double -DmpPi::v0(double t) +void +DmpPi::V0(double t, + // Return values. + double &vo, + double &dvo_dt) { - return k0_ * (k1_ + k2_ * t + k3_ * exp2(-p1_ * t) + k4_ * exp2(-p2_ * t)); + double exp_p1 = exp2(-p1_ * t); + double exp_p2 = exp2(-p2_ * t); + vo = k0_ * (k1_ + k2_ * t + k3_ * exp_p1 + k4_ * exp_p2); + dvo_dt = k0_ * (k2_ - k3_ * p1_ * exp_p1 - k4_ * p2_ * exp_p2); } -double -DmpPi::dv0dt(double t) -{ - return k0_ * (k2_ - k3_ * p1_ * exp2(-p1_ * t) - k4_ * p2_ * exp2(-p2_ * t)); -} - -double -DmpPi::vl0(double t) +void +DmpPi::Vl0(double t, + // Return values. + double &vl, + double &dvl_dt) { double D1 = k0_ * (k1_ - k2_ / p3_); double D3 = -p3_ * k0_ * k3_ / (p1_ - p3_); double D4 = -p3_ * k0_ * k4_ / (p2_ - p3_); double D5 = k0_ * (k2_ / p3_ - k1_ + p3_ * k3_ / (p1_ - p3_) + p3_ * k4_ / (p2_ - p3_)); - return D1 + t + D3 * exp2(-p1_ * t) + D4 * exp2(-p2_ * t) + D5 * exp2(-p3_ * t); + double exp_p1 = exp2(-p1_ * t); + double exp_p2 = exp2(-p2_ * t); + double exp_p3 = exp2(-p3_ * t); + vl = D1 + t + D3 * exp_p1 + D4 * exp_p2 + D5 * exp_p3; + dvl_dt = 1.0 - D3 * p1_ * exp_p1 - D4 * p2_ * exp_p2 + - D5 * p3_ * exp_p3; } double @@ -1059,17 +1079,6 @@ DmpPi::voCrossingUpperBound() return t0_ + dt_ + (c1_ + c2_) * (rd_ + rpi_) * 2.0; } -double -DmpPi::dvl0dt(double t) -{ - double D3 = -p3_ * k0_ * k3_ / (p1_ - p3_); - double D4 = -p3_ * k0_ * k4_ / (p2_ - p3_); - double D5 = k0_ * (k2_ / p3_ - k1_ + p3_ * k3_ / (p1_ - p3_) - + p3_ * k4_ / (p2_ - p3_)); - return 1.0 - D3 * p1_ * exp2(-p1_ * t) - D4 * p2_ * exp2(-p2_ * t) - - D5 * p3_ * exp2(-p3_ * t); -} - //////////////////////////////////////////////////////////////// // Capacitive load, so Ceff is known. @@ -1078,8 +1087,8 @@ class DmpOnePole : public DmpAlg { public: DmpOnePole(StaState *sta); - virtual void evalDmpEqns(); - virtual double voCrossingUpperBound(); + void evalDmpEqns() override; + double voCrossingUpperBound() override; }; DmpOnePole::DmpOnePole(StaState *sta) : @@ -1136,27 +1145,31 @@ class DmpZeroC2 : public DmpOnePole { public: DmpZeroC2(StaState *sta); - virtual const char *name() { return "c2=0"; } - virtual void init(const LibertyLibrary *drvr_library, - const LibertyCell *drvr_cell, - const Pvt *pvt, - const GateTableModel *gate_model, - const RiseFall *rf, - double rd, - double in_slew, - float related_out_cap, - double c2, - double rpi, - double c1); - virtual void gateDelaySlew(double &delay, - double &slew); + const char *name() override { return "c2=0"; } + void init(const LibertyLibrary *drvr_library, + const LibertyCell *drvr_cell, + const Pvt *pvt, + const GateTableModel *gate_model, + const RiseFall *rf, + double rd, + double in_slew, + double c2, + double rpi, + double c1) override; + void gateDelaySlew(// Return values. + double &delay, + double &slew) override; private: - virtual double v0(double t); - virtual double dv0dt(double t); - virtual double vl0(double t); - virtual double dvl0dt(double t); - virtual double voCrossingUpperBound(); + void V0(double t, + // Return values. + double &vo, + double &dvo_dt) override; + void Vl0(double t, + // Return values. + double &vl, + double &dvl_dt) override; + double voCrossingUpperBound() override; // Pole/zero. double p1_; @@ -1187,14 +1200,13 @@ DmpZeroC2::init(const LibertyLibrary *drvr_library, const RiseFall *rf, double rd, double in_slew, - float related_out_cap, double c2, double rpi, double c1) { debugPrint(debug_, "dmp_ceff", 3, "Using DMP C2=0"); DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, - in_slew, related_out_cap, c2, rpi, c1); + in_slew, c2, rpi, c1); ceff_ = c1; z1_ = 1.0 / (rpi_ * c1_); @@ -1207,7 +1219,8 @@ DmpZeroC2::init(const LibertyLibrary *drvr_library, } void -DmpZeroC2::gateDelaySlew(double &delay, +DmpZeroC2::gateDelaySlew(// Return values. + double &delay, double &slew) { try { @@ -1227,33 +1240,30 @@ DmpZeroC2::gateDelaySlew(double &delay, drvr_slew_ = slew; } -double -DmpZeroC2::v0(double t) +void +DmpZeroC2::V0(double t, + // Return values. + double &vo, + double &dvo_dt) { - return k0_ * (k1_ + k2_ * t + k3_ * exp2(-p1_ * t)); + double exp_p1 = exp2(-p1_ * t); + vo = k0_ * (k1_ + k2_ * t + k3_ * exp_p1); + dvo_dt = k0_ * (k2_ - k3_ * p1_ * exp_p1); } -double -DmpZeroC2::dv0dt(double t) -{ - return k0_ * (k2_ - k3_ * p1_ * exp2(-p1_ * t)); -} - -double -DmpZeroC2::vl0(double t) +void +DmpZeroC2::Vl0(double t, + // Return values. + double &vl, + double &dvl_dt) { double D1 = k0_ * (k1_ - k2_ / p3_); double D3 = -p3_ * k0_ * k3_ / (p1_ - p3_); double D5 = k0_ * (k2_ / p3_ - k1_ + p3_ * k3_ / (p1_ - p3_)); - return D1 + t + D3 * exp2(-p1_ * t) + D5 * exp2(-p3_ * t); -} - -double -DmpZeroC2::dvl0dt(double t) -{ - double D3 = -p3_ * k0_ * k3_ / (p1_ - p3_); - double D5 = k0_ * (k2_ / p3_ - k1_ + p3_ * k3_ / (p1_ - p3_)); - return 1.0 - D3 * p1_ * exp2(-p1_ * t) - D5 * p3_ * exp2(-p3_ * t); + double exp_p1 = exp2(-p1_ * t); + double exp_p3 = exp2(-p3_ * t); + vl = D1 + t + D3 * exp_p1 + D5 * exp_p3; + dvl_dt = 1.0 - D3 * p1_ * exp_p1 - D5 * p3_ * exp_p3; } double @@ -1264,70 +1274,6 @@ DmpZeroC2::voCrossingUpperBound() //////////////////////////////////////////////////////////////// -// Find the root of a function between x1 and x2 using a combination -// of Newton-Raphson and bisection search. -// x_tol is a percentage that change in x must be less than (1.0 = 100%). -// error is non-null if a problem occurs. -static double -findRoot(void (*func)(void *state, double x, double &y, double &dy), - void *state, - double x1, - double x2, - double x_tol, - int max_iter) -{ - double y1, y2, dy; - func(state, x1, y1, dy); - func(state, x2, y2, dy); - - if ((y1 > 0.0 && y2 > 0.0) || (y1 < 0.0 && y2 < 0.0)) - throw DmpError("findRoot: initial bounds do not surround a root"); - - if (y1 == 0.0) - return x1; - - if (y2 == 0.0) - return x2; - - if (y1 > 0.0) { - // Swap x1/x2 so func(x1) < 0. - double tmp = x1; - x1 = x2; - x2 = tmp; - } - double root = (x1 + x2) * 0.5; - double dx_prev = abs(x2 - x1); - double dx = dx_prev; - double y; - func(state, root, y, dy); - for (int iter = 0; iter < max_iter; iter++) { - // Newton/raphson out of range. - if ((((root - x2) * dy - y) * ((root - x1) * dy - y) > 0.0) - // Not decreasing fast enough. - || (abs(2.0 * y) > abs(dx_prev * dy))) { - // Bisect x1/x2 interval. - dx_prev = dx; - dx = (x2 - x1) * 0.5; - root = x1 + dx; - } - else { - dx_prev = dx; - dx = y / dy; - root -= dx; - } - if (abs(dx) <= x_tol * abs(root)) - // Converged. - return root; - - func(state, root, y, dy); - if (y < 0.0) - x1 = root; - else - x2 = root; - } - throw DmpError("findRoot: max iterations exceeded"); -} - // Newton-Raphson iteration to find zeros of a function. // x_tol is percentage that all changes in x must be less than (1.0 = 100%). // Eval(state) is called to fill fvec and fjac (returns false if fails). @@ -1337,8 +1283,7 @@ newtonRaphson(const int max_iter, double x[], const int size, const double x_tol, - void (*eval)(void *state), - void *state, + function eval, // Temporaries supplied by caller. double *fvec, double **fjac, @@ -1347,7 +1292,7 @@ newtonRaphson(const int max_iter, double *scale) { for (int k = 0; k < max_iter; k++) { - eval(state); + eval(); for (int i = 0; i < size; i++) // Right-hand side of linear equations. p[i] = -fvec[i]; @@ -1408,7 +1353,7 @@ luDecomp(double **a, a[i][j] = sum; } // Run down jth subdiag to form the residuals after the elimination - // of the first j-1 subdiags. These residuals divided by the + // of the first j-1 subdiags. These residuals diviyded by the // appropriate diagonal term will become the multipliers in the // elimination of the jth. subdiag. Find index of largest scaled // term in imax. @@ -1543,64 +1488,58 @@ DmpCeffDelayCalc::~DmpCeffDelayCalc() delete dmp_zero_c2_; } -void -DmpCeffDelayCalc::inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) +ArcDcalcResult +DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) { - dmp_alg_ = nullptr; - LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap); -} - -void -DmpCeffDelayCalc::gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) -{ - input_port_ = false; - drvr_rf_ = arc->toEdge()->asRiseFall(); + const RiseFall *rf = arc->toEdge()->asRiseFall(); const LibertyCell *drvr_cell = arc->from()->libertyCell(); - drvr_library_ = drvr_cell->libertyLibrary(); - drvr_parasitic_ = drvr_parasitic; + const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); - GateTimingModel *model = gateModel(arc, dcalc_ap); - GateTableModel *table_model = dynamic_cast(model); - if (table_model && drvr_parasitic) { + GateTableModel *table_model = gateTableModel(arc, dcalc_ap); + if (table_model && parasitic) { float in_slew1 = delayAsFloat(in_slew); float c2, rpi, c1; - parasitics_->piModel(drvr_parasitic, c2, rpi, c1); + parasitics_->piModel(parasitic, c2, rpi, c1); if (isnan(c2) || isnan(c1) || isnan(rpi)) - report_->error(618, "parasitic Pi model has NaNs."); - setCeffAlgorithm(drvr_library_, drvr_cell, pvt, table_model, - drvr_rf_, in_slew1, related_out_cap, - c2, rpi, c1); - double dmp_gate_delay, dmp_drvr_slew; - gateDelaySlew(dmp_gate_delay, dmp_drvr_slew); - gate_delay = dmp_gate_delay; - drvr_slew = dmp_drvr_slew; + report_->error(1040, "parasitic Pi model has NaNs."); + setCeffAlgorithm(drvr_library, drvr_cell, pinPvt(drvr_pin, dcalc_ap), + table_model, rf, in_slew1, c2, rpi, c1); + double gate_delay, drvr_slew; + gateDelaySlew(gate_delay, drvr_slew); + ArcDcalcResult dcalc_result(load_pin_index_map.size()); + 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; + ArcDelay wire_delay; + Slew load_slew; + loadDelaySlew(load_pin, drvr_slew, rf, drvr_library, parasitic, + wire_delay, load_slew); + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, load_slew); + } + return dcalc_result; } else { - LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); - if (drvr_parasitic + ArcDcalcResult dcalc_result = + LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, + load_pin_index_map, dcalc_ap); + if (parasitic && !unsuppored_model_warned_) { unsuppored_model_warned_ = true; - report_->warn(1, "cell %s delay model not supported on SPF parasitics by DMP delay calculator", + report_->warn(1041, "cell %s delay model not supported on SPF parasitics by DMP delay calculator", drvr_cell->name()); } + return dcalc_result; } - drvr_slew_ = drvr_slew; - multi_drvr_slew_factor_ = 1.0F; } void @@ -1610,7 +1549,6 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, const GateTableModel *gate_model, const RiseFall *rf, double in_slew, - float related_out_cap, double c2, double rpi, double c1) @@ -1618,7 +1556,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, double rd = 0.0; if (gate_model) { rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1, - related_out_cap, pvt, pocv_enabled_); + pvt, pocv_enabled_); // Zero Rd means the table is constant and thus independent of load cap. if (rd < 1e-2 // Rpi is small compared to Rd, which makes the load capacitive. @@ -1635,7 +1573,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, else dmp_alg_ = dmp_cap_; dmp_alg_->init(drvr_library, drvr_cell, pvt, gate_model, - drvr_rf_, rd, in_slew, related_out_cap, c2, rpi, c1); + rf, rd, in_slew, c2, rpi, c1); debugPrint(debug_, "dmp_ceff", 3, " DMP in_slew = %s c2 = %s rpi = %s c1 = %s Rd = %s (%s alg)", units_->timeUnit()->asString(in_slew), @@ -1646,51 +1584,29 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, dmp_alg_->name()); } -float -DmpCeffDelayCalc::ceff(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap) -{ - ArcDelay gate_delay; - Slew drvr_slew; - gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); - if (dmp_alg_) - return dmp_alg_->ceff(); - else - return load_cap; -} - string -DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc, +DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, const Slew &in_slew, float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, int digits) { - ArcDelay gate_delay; - Slew drvr_slew; - gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); + gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, load_pin_index_map, dcalc_ap); GateTimingModel *model = gateModel(arc, dcalc_ap); float c_eff = 0.0; string result; - if (drvr_parasitic_ && dmp_alg_) { + if (parasitic && dmp_alg_) { c_eff = dmp_alg_->ceff(); - const LibertyCell *drvr_cell = arc->from()->libertyCell(); + const LibertyCell *drvr_cell = arc->to()->libertyCell(); const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); const Units *units = drvr_library->units(); const Unit *cap_unit = units->capacitanceUnit(); const Unit *res_unit = units->resistanceUnit(); float c2, rpi, c1; - parasitics_->piModel(drvr_parasitic_, c2, rpi, c1); + parasitics_->piModel(parasitic, c2, rpi, c1); result += "Pi model C2="; result += cap_unit->asString(c2, digits); result += " Rpi="; @@ -1705,7 +1621,7 @@ DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc, c_eff = load_cap; if (model) { float in_slew1 = delayAsFloat(in_slew); - result += model->reportGateDelay(pvt, in_slew1, c_eff, related_out_cap, + result += model->reportGateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, c_eff, pocv_enabled_, digits); } return result; @@ -1718,7 +1634,6 @@ gateModelRd(const LibertyCell *cell, double in_slew, double c2, double c1, - float related_out_cap, const Pvt *pvt, bool pocv_enabled) { @@ -1726,25 +1641,26 @@ gateModelRd(const LibertyCell *cell, float cap2 = cap1 + 1e-15; ArcDelay d1, d2; Slew s1, s2; - gate_model->gateDelay(pvt, in_slew, cap1, related_out_cap, pocv_enabled, d1, s1); - gate_model->gateDelay(pvt, in_slew, cap2, related_out_cap, pocv_enabled, d2, s2); + gate_model->gateDelay(pvt, in_slew, cap1, pocv_enabled, d1, s1); + gate_model->gateDelay(pvt, in_slew, cap2, pocv_enabled, d2, s2); double vth = cell->libertyLibrary()->outputThreshold(rf); float rd = -log(vth) * abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1); return rd; } void -DmpCeffDelayCalc::gateDelaySlew(double &delay, +DmpCeffDelayCalc::gateDelaySlew(// Return values. + double &delay, double &slew) { dmp_alg_->gateDelaySlew(delay, slew); } void -DmpCeffDelayCalc::loadDelaySlew(const Pin *load_pin, - double elmore, - ArcDelay &delay, - Slew &slew) +DmpCeffDelayCalc::loadDelaySlewElmore(const Pin *load_pin, + double elmore, + ArcDelay &delay, + Slew &slew) { if (dmp_alg_) dmp_alg_->loadDelaySlew(load_pin, elmore, delay, slew); diff --git a/dcalc/DmpCeff.hh b/dcalc/DmpCeff.hh index b79dbdc6..fadc0140 100644 --- a/dcalc/DmpCeff.hh +++ b/dcalc/DmpCeff.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -34,45 +34,39 @@ class DmpCeffDelayCalc : public LumpedCapDelayCalc public: DmpCeffDelayCalc(StaState *sta); virtual ~DmpCeffDelayCalc(); - virtual void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap); - virtual void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // return values - ArcDelay &gate_delay, - Slew &drvr_slew); - virtual float ceff(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap); - virtual string reportGateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - int digits); - virtual void copyState(const StaState *sta); + ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + string reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap, + int digits) override; + void copyState(const StaState *sta) override; protected: - void gateDelaySlew(double &delay, + virtual void loadDelaySlew(const Pin *load_pin, + double drvr_slew, + const RiseFall *rf, + const LibertyLibrary *drvr_library, + const Parasitic *parasitic, + // Return values. + ArcDelay &wire_delay, + Slew &load_slew) = 0; + void gateDelaySlew(// Return values. + double &delay, double &slew); - void loadDelaySlew(const Pin *load_pin, - double elmore, - ArcDelay &delay, - Slew &slew); + void loadDelaySlewElmore(const Pin *load_pin, + double elmore, + ArcDelay &delay, + Slew &slew); // Select the appropriate special case Dartu/Menezes/Pileggi algorithm. void setCeffAlgorithm(const LibertyLibrary *library, const LibertyCell *cell, @@ -80,7 +74,6 @@ protected: const GateTableModel *gate_model, const RiseFall *rf, double in_slew, - float related_out_cap, double c2, double rpi, double c1); diff --git a/dcalc/DmpDelayCalc.cc b/dcalc/DmpDelayCalc.cc index ed97468a..8006a0f8 100644 --- a/dcalc/DmpDelayCalc.cc +++ b/dcalc/DmpDelayCalc.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -19,12 +19,13 @@ #include "TableModel.hh" #include "TimingArc.hh" #include "Liberty.hh" +#include "PortDirection.hh" +#include "Network.hh" #include "Sdc.hh" #include "Parasitics.hh" #include "DcalcAnalysisPt.hh" #include "GraphDelayCalc.hh" #include "DmpCeff.hh" -#include "Network.hh" namespace sta { @@ -35,9 +36,22 @@ class DmpCeffElmoreDelayCalc : public DmpCeffDelayCalc public: DmpCeffElmoreDelayCalc(StaState *sta); ArcDelayCalc *copy() override; - void loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) override; + ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + +protected: + void loadDelaySlew(const Pin *load_pin, + double drvr_slew, + const RiseFall *rf, + const LibertyLibrary *drvr_library, + const Parasitic *parasitic, + // Return values. + ArcDelay &wire_delay, + Slew &load_slew) override; }; ArcDelayCalc * @@ -57,26 +71,54 @@ DmpCeffElmoreDelayCalc::copy() return new DmpCeffElmoreDelayCalc(this); } -void -DmpCeffElmoreDelayCalc::loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) +ArcDcalcResult +DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { - ArcDelay wire_delay1 = 0.0; - Slew load_slew1 = drvr_slew_; + 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; + ArcDelay wire_delay = 0.0; + Slew load_slew = in_slew; + bool elmore_exists = false; + float elmore = 0.0; + if (parasitic) + parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists); + if (elmore_exists) + // Input port with no external driver. + dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew); + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, load_slew); + } + return dcalc_result; +} + +void +DmpCeffElmoreDelayCalc::loadDelaySlew(const Pin *load_pin, + double drvr_slew, + const RiseFall *rf, + const LibertyLibrary *drvr_library, + const Parasitic *parasitic, + // Return values. + ArcDelay &wire_delay, + Slew &load_slew) +{ + wire_delay = 0.0; + load_slew = drvr_slew; bool elmore_exists = false; float elmore = 0.0; - if (drvr_parasitic_) - parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists); - if (elmore_exists) { - if (input_port_) - dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); - else - loadDelaySlew(load_pin, elmore, wire_delay1, load_slew1); - } - thresholdAdjust(load_pin, wire_delay1, load_slew1); - wire_delay = wire_delay1; - load_slew = load_slew1 * multi_drvr_slew_factor_; + if (parasitic) + parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists); + if (elmore_exists) + loadDelaySlewElmore(load_pin, elmore, wire_delay, load_slew); + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); } //////////////////////////////////////////////////////////////// @@ -91,28 +133,31 @@ public: Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; - ReducedParasiticType reducedParasiticType() const override; - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) override; - void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) override; - void loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) override; + ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; private: - void loadDelay(Parasitic *pole_residue, + void loadDelaySlew(const Pin *load_pin, + double drvr_slew, + const RiseFall *rf, + const LibertyLibrary *drvr_library, + const Parasitic *parasitic, + // Return values. + ArcDelay &wire_delay, + Slew &load_slew) override; + void loadDelay(double drvr_slew, + Parasitic *pole_residue, double p1, double k1, ArcDelay &wire_delay, @@ -164,104 +209,117 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin, { Parasitic *parasitic = nullptr; const Corner *corner = dcalc_ap->corner(); - // set_load net has precidence over parasitics. - if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) { - const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); - if (parasitics_->haveParasitics()) { - // Prefer PiPoleResidue. - parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap); - if (parasitic == nullptr) { - parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap); - if (parasitic == nullptr) { - Parasitic *parasitic_network = - parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); - if (parasitic_network) { - parasitics_->reduceToPiPoleResidue2(parasitic_network, drvr_pin, - dcalc_ap->operatingConditions(), - corner, - dcalc_ap->constraintMinMax(), - parasitic_ap); - parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap); - reduced_parasitic_drvrs_.push_back(drvr_pin); - } - } - } - } - else { - const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); - Wireload *wireload = sdc_->wireload(cnst_min_max); - if (wireload) { - float pin_cap, wire_cap, fanout; - bool has_wire_cap; - graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_wire_cap); - parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, - fanout, pin_cap, - dcalc_ap->operatingConditions(), - corner, - cnst_min_max, - parasitic_ap); - // Estimated parasitics are not recorded in the "database", so - // save it for deletion after the drvr pin delay calc is finished. - if (parasitic) - unsaved_parasitics_.push_back(parasitic); - } - } + // set_load net has precedence over parasitics. + if (sdc_->drvrPinHasWireCap(drvr_pin, corner) + || network_->direction(drvr_pin)->isInternal()) + return nullptr; + const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); + // Prefer PiPoleResidue. + parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap); + if (parasitic) + return parasitic; + parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap); + if (parasitic) + return parasitic; + Parasitic *parasitic_network = + parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); + if (parasitic_network) { + parasitic = parasitics_->reduceToPiPoleResidue2(parasitic_network, drvr_pin, rf, + corner, + dcalc_ap->constraintMinMax(), + parasitic_ap); + if (parasitic) + return parasitic; + } + const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); + Wireload *wireload = sdc_->wireload(cnst_min_max); + if (wireload) { + float pin_cap, wire_cap, fanout; + bool has_wire_cap; + graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, pin_cap, wire_cap, + fanout, has_wire_cap); + parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, + fanout, pin_cap, corner, + cnst_min_max); } return parasitic; } -ReducedParasiticType -DmpCeffTwoPoleDelayCalc::reducedParasiticType() const +ArcDcalcResult +DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { - return ReducedParasiticType::pi_pole_residue2; + ArcDcalcResult dcalc_result(load_pin_index_map.size()); + 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; + if (parasitics_->isPiPoleResidue(parasitic)) { + const Parasitic *pole_residue = parasitics_->findPoleResidue(parasitic, load_pin); + if (pole_residue) { + size_t pole_count = parasitics_->poleResidueCount(pole_residue); + if (pole_count >= 1) { + ComplexFloat pole1, residue1; + // Find the 1st (elmore) pole. + parasitics_->poleResidue(pole_residue, 0, pole1, residue1); + if (pole1.imag() == 0.0 + && residue1.imag() == 0.0) { + float p1 = pole1.real(); + float elmore = 1.0F / p1; + dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew); + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); + } + } + } + } + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, load_slew); + } + return dcalc_result; +} + +ArcDcalcResult +DmpCeffTwoPoleDelayCalc::gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) +{ + const LibertyLibrary *drvr_library = arc->to()->libertyLibrary(); + const RiseFall *rf = arc->toEdge()->asRiseFall(); + vth_ = drvr_library->outputThreshold(rf); + vl_ = drvr_library->slewLowerThreshold(rf); + vh_ = drvr_library->slewUpperThreshold(rf); + slew_derate_ = drvr_library->slewDerateFromLibrary(); + return DmpCeffDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, + load_pin_index_map, dcalc_ap) ; } void -DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) +DmpCeffTwoPoleDelayCalc::loadDelaySlew(const Pin *load_pin, + double drvr_slew, + const RiseFall *rf, + const LibertyLibrary *drvr_library, + const Parasitic *parasitic, + // Return values. + ArcDelay &wire_delay, + Slew &load_slew) { parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic); - DmpCeffDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap); -} - -void -DmpCeffTwoPoleDelayCalc::gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) -{ - gateDelayInit(arc, in_slew, drvr_parasitic); - parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(drvr_parasitic); - vth_ = drvr_library_->outputThreshold(drvr_rf_); - vl_ = drvr_library_->slewLowerThreshold(drvr_rf_); - vh_ = drvr_library_->slewUpperThreshold(drvr_rf_); - slew_derate_ = drvr_library_->slewDerateFromLibrary(); - DmpCeffDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); -} - -void -DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) -{ // Should handle PiElmore parasitic. - ArcDelay wire_delay1 = 0.0; - Slew load_slew1 = drvr_slew_; + wire_delay = 0.0; + load_slew = drvr_slew; Parasitic *pole_residue = 0; if (parasitic_is_pole_residue_) - pole_residue = parasitics_->findPoleResidue(drvr_parasitic_, load_pin); + pole_residue = parasitics_->findPoleResidue(parasitic, load_pin); if (pole_residue) { size_t pole_count = parasitics_->poleResidueCount(pole_residue); if (pole_count >= 1) { @@ -272,37 +330,31 @@ DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin, && residue1.imag() == 0.0) { float p1 = pole1.real(); float k1 = residue1.real(); - if (input_port_) { - float elmore = 1.0F / p1; - // Input port with no external driver. - dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); - } - else { - if (pole_count >= 2) - loadDelay(pole_residue, p1, k1, wire_delay1, load_slew1); - else { - float elmore = 1.0F / p1; - wire_delay1 = elmore; - load_slew1 = drvr_slew_; - } - } + if (pole_count >= 2) + loadDelay(drvr_slew, pole_residue, p1, k1, wire_delay, load_slew); + else { + float elmore = 1.0F / p1; + wire_delay = elmore; + load_slew = drvr_slew; + } } } } - thresholdAdjust(load_pin, wire_delay1, load_slew1); - wire_delay = wire_delay1; - load_slew = load_slew1 * multi_drvr_slew_factor_; + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); } void -DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue, - double p1, double k1, - ArcDelay &wire_delay, +DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew, + Parasitic *pole_residue, + double p1, + double k1, + // Return values. + ArcDelay &wire_delay, Slew &load_slew) { ComplexFloat pole2, residue2; parasitics_->poleResidue(pole_residue, 1, pole2, residue2); - if (!delayZero(drvr_slew_) + if (!delayZero(drvr_slew) && pole2.imag() == 0.0 && residue2.imag() == 0.0) { double p2 = pole2.real(); @@ -311,7 +363,7 @@ DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue, double k2_p2_2 = k2 / (p2 * p2); double B = k1_p1_2 + k2_p2_2; // Convert tt to 0:1 range. - float tt = delayAsFloat(drvr_slew_) * slew_derate_ / (vh_ - vl_); + float tt = delayAsFloat(drvr_slew) * slew_derate_ / (vh_ - vl_); double y_tt = (tt - B + k1_p1_2 * exp(-p1 * tt) + k2_p2_2 * exp(-p2 * tt)) / tt; wire_delay = loadDelay(vth_, p1, p2, k1, k2, B, k1_p1_2, k2_p2_2, tt, y_tt) diff --git a/dcalc/DmpDelayCalc.hh b/dcalc/DmpDelayCalc.hh index f604e6dc..c5c8cbd3 100644 --- a/dcalc/DmpDelayCalc.hh +++ b/dcalc/DmpDelayCalc.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/dcalc/FindRoot.cc b/dcalc/FindRoot.cc new file mode 100644 index 00000000..a6bdde60 --- /dev/null +++ b/dcalc/FindRoot.cc @@ -0,0 +1,106 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2023, 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 "FindRoot.hh" + +#include // abs + +namespace sta { + +using std::abs; + +double +findRoot(FindRootFunc func, + double x1, + double x2, + double x_tol, + int max_iter, + // Return value. + bool &fail) +{ + double y1, y2, dy1; + func(x1, y1, dy1); + func(x2, y2, dy1); + return findRoot(func, x1, y1, x2, y2, x_tol, max_iter, fail); +} + +double +findRoot(FindRootFunc func, + double x1, + double y1, + double x2, + double y2, + double x_tol, + int max_iter, + // Return value. + bool &fail) +{ + if ((y1 > 0.0 && y2 > 0.0) || (y1 < 0.0 && y2 < 0.0)) { + // Initial bounds do not surround a root. + fail = true; + return 0.0; + } + + if (y1 == 0.0) { + fail = false; + return x1; + } + + if (y2 == 0.0) { + fail = false; + return x2; + } + + if (y1 > 0.0) + // Swap x1/x2 so func(x1) < 0. + std::swap(x1, x2); + double root = (x1 + x2) * 0.5; + double dx_prev = abs(x2 - x1); + double dx = dx_prev; + double y, dy; + func(root, y, dy); + for (int iter = 0; iter < max_iter; iter++) { + // Newton/raphson out of range. + if ((((root - x2) * dy - y) * ((root - x1) * dy - y) > 0.0) + // Not decreasing fast enough. + || (abs(2.0 * y) > abs(dx_prev * dy))) { + // Bisect x1/x2 interval. + dx_prev = dx; + dx = (x2 - x1) * 0.5; + root = x1 + dx; + } + else { + dx_prev = dx; + dx = y / dy; + root -= dx; + } + if (abs(dx) <= x_tol * abs(root)) { + // Converged. + fail = false; + return root; + } + + func(root, y, dy); + if (y < 0.0) + x1 = root; + else + x2 = root; + } + fail = true; + return root; +} + +} // namespace diff --git a/dcalc/SlewDegradeDelayCalc.hh b/dcalc/FindRoot.hh similarity index 59% rename from dcalc/SlewDegradeDelayCalc.hh rename to dcalc/FindRoot.hh index 7195985d..1a62df8b 100644 --- a/dcalc/SlewDegradeDelayCalc.hh +++ b/dcalc/FindRoot.hh @@ -16,12 +16,33 @@ #pragma once +#include + namespace sta { -class ArcDelayCalc; -class StaState; +typedef const std::function FindRootFunc; -ArcDelayCalc * -makeSlewDegradeDelayCalc(StaState *sta); +double +findRoot(FindRootFunc func, + double x1, + double x2, + double x_tol, + int max_iter, + // Return value. + bool &fail); + +double +findRoot(FindRootFunc func, + double x1, + double y1, + double x2, + double y2, + double x_tol, + int max_iter, + // Return value. + bool &fail); } // namespace diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 3f18bd2f..da3b40d0 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -59,7 +59,6 @@ GraphDelayCalc::GraphDelayCalc(StaState *sta) : search_non_latch_pred_(new SearchPredNonLatch2(sta)), clk_pred_(new ClkTreeSearchPred(sta)), iter_(new BfsFwdIterator(BfsIndex::dcalc, search_non_latch_pred_, sta)), - multi_drvr_nets_found_(false), incremental_delay_tolerance_(0.0) { } @@ -103,7 +102,6 @@ GraphDelayCalc::clear() { delaysInvalid(); deleteMultiDrvrNets(); - multi_drvr_nets_found_ = false; } float @@ -183,25 +181,10 @@ GraphDelayCalc::deleteVertexBefore(Vertex *vertex) invalid_delays_->erase(vertex); MultiDrvrNet *multi_drvr = multiDrvrNet(vertex); if (multi_drvr) { - VertexSet *drvrs = multi_drvr->drvrs(); - drvrs->erase(vertex); - multi_drvr_net_map_.erase(vertex); - if (drvrs->empty()) - delete multi_drvr; - else { - Level max_drvr_level = 0; - Vertex *max_drvr = nullptr; - for (Vertex *drvr_vertex : *drvrs) { - Level drvr_level = drvr_vertex->level(); - if (max_drvr == nullptr - || drvr_level > max_drvr_level) { - max_drvr = drvr_vertex; - max_drvr_level = drvr_level; - } - } - multi_drvr->setDcalcDrvr(max_drvr); - multi_drvr->findCaps(sdc_); - } + // Don't bother incrementally updating MultiDrvrNet. + for (Vertex *drvr_vertex : multi_drvr->drvrs()) + multi_drvr_net_map_.erase(drvr_vertex); + delete multi_drvr; } } @@ -382,19 +365,23 @@ GraphDelayCalc::seedNoDrvrCellSlew(Vertex *drvr_vertex, Delay drive_delay = delay_zero; float drive_res; drive->driveResistance(rf, cnst_min_max, drive_res, exists); - Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap); + const Parasitic *parasitic; + float cap; + parasiticLoad(drvr_pin, rf, dcalc_ap, nullptr, arc_delay_calc, + cap, parasitic); if (exists) { - float cap = loadCap(drvr_pin, parasitic, rf, dcalc_ap); drive_delay = cap * drive_res; slew = cap * drive_res; } const MinMax *slew_min_max = dcalc_ap->slewMinMax(); if (!drvr_vertex->slewAnnotated(rf, slew_min_max)) graph_->setSlew(drvr_vertex, rf, ap_index, slew); - arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, - parasitic, dcalc_ap); - annotateLoadDelays(drvr_vertex, rf, drive_delay, false, dcalc_ap, - arc_delay_calc); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); + ArcDcalcResult dcalc_result = + arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, parasitic, + load_pin_index_map, dcalc_ap); + annotateLoadDelays(drvr_vertex, rf, dcalc_result, load_pin_index_map, + drive_delay, false, dcalc_ap); arc_delay_calc->finishDrvrPin(); } @@ -417,11 +404,13 @@ GraphDelayCalc::seedNoDrvrSlew(Vertex *drvr_vertex, if (!drvr_vertex->slewAnnotated(rf, slew_min_max)) graph_->setSlew(drvr_vertex, rf, ap_index, slew); Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap); - arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, - parasitic, dcalc_ap); - annotateLoadDelays(drvr_vertex, rf, delay_zero, false, dcalc_ap, - arc_delay_calc); - arc_delay_calc->finishDrvrPin(); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); + ArcDcalcResult dcalc_result = + arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, parasitic, + load_pin_index_map, dcalc_ap); + annotateLoadDelays(drvr_vertex, rf, dcalc_result, load_pin_index_map, delay_zero, + false, dcalc_ap); + arc_delay_calc_->finishDrvrPin(); } void @@ -488,7 +477,7 @@ GraphDelayCalc::findPortIndex(const LibertyCell *cell, return index; index++; } - report_->critical(207, "port not found in cell"); + report_->critical(1100, "port not found in cell."); return 0; } @@ -513,6 +502,7 @@ GraphDelayCalc::findInputDriverDelay(const LibertyCell *drvr_cell, } } } + arc_delay_calc_->finishDrvrPin(); } // Driving cell delay is the load dependent delay, which is the gate @@ -531,25 +521,28 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin, arc->to()->name(), arc->toEdge()->asString(), arc->role()->asString()); - RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); + const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); if (drvr_rf) { DcalcAPIndex ap_index = dcalc_ap->index(); - const Pvt *pvt = dcalc_ap->operatingConditions(); - Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, - dcalc_ap); - float load_cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap); + const Parasitic *parasitic; + float load_cap; + parasiticLoad(drvr_pin, drvr_rf, dcalc_ap, nullptr, arc_delay_calc_, + load_cap, parasitic); - ArcDelay intrinsic_delay; - Slew intrinsic_slew; - arc_delay_calc_->gateDelay(arc, Slew(from_slew), 0.0, 0, 0.0, pvt, dcalc_ap, - intrinsic_delay, intrinsic_slew); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); + ArcDcalcResult intrinsic_result = + arc_delay_calc_->gateDelay(drvr_pin, arc, Slew(from_slew), 0.0, nullptr, + load_pin_index_map, dcalc_ap); + ArcDelay intrinsic_delay = intrinsic_result.gateDelay(); + + ArcDcalcResult gate_result = arc_delay_calc_->gateDelay(drvr_pin, arc, + Slew(from_slew), load_cap, + parasitic, + load_pin_index_map, + dcalc_ap); + ArcDelay gate_delay = gate_result.gateDelay(); + Slew gate_slew = gate_result.drvrSlew(); - // For input drivers there is no instance to find a related_output_pin. - ArcDelay gate_delay; - Slew gate_slew; - arc_delay_calc_->gateDelay(arc, Slew(from_slew), load_cap, - drvr_parasitic, 0.0, pvt, dcalc_ap, - gate_delay, gate_slew); ArcDelay load_delay = gate_delay - intrinsic_delay; debugPrint(debug_, "delay_calc", 3, " gate delay = %s intrinsic = %s slew = %s", @@ -557,8 +550,9 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin, delayAsString(intrinsic_delay, this), delayAsString(gate_slew, this)); graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew); - annotateLoadDelays(drvr_vertex, drvr_rf, load_delay, false, dcalc_ap, - arc_delay_calc_); + annotateLoadDelays(drvr_vertex, drvr_rf, gate_result, load_pin_index_map, + load_delay, false, dcalc_ap); + arc_delay_calc_->finishDrvrPin(); } } @@ -651,47 +645,64 @@ GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex, { bool delay_changed = false; MultiDrvrNet *multi_drvr = findMultiDrvrNet(drvr_vertex); - if (multi_drvr - && multi_drvr->parallelGates(network_)) { - Vertex *dcalc_drvr = multi_drvr->dcalcDrvr(); - if (drvr_vertex == dcalc_drvr) { - initLoadSlews(drvr_vertex); - arc_delay_calc->findParallelGateDelays(multi_drvr, this); - for (Vertex *drvr_vertex : *multi_drvr->drvrs()) - delay_changed |= findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc); - } - } - else { + if (multi_drvr == nullptr + || (multi_drvr + && (!multi_drvr->parallelGates(network_) + || drvr_vertex == multi_drvr->dcalcDrvr()))) { initLoadSlews(drvr_vertex); - delay_changed = findDriverDelays1(drvr_vertex, nullptr, arc_delay_calc); + delay_changed |= findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc); } - arc_delay_calc->finishDrvrPin(); + arc_delay_calc_->finishDrvrPin(); return delay_changed; } MultiDrvrNet * GraphDelayCalc::findMultiDrvrNet(Vertex *drvr_vertex) { - MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); - if (multi_drvr) + // Avoid locking for single driver nets. + if (hasMultiDrvrs(drvr_vertex)) { + UniqueLock lock(multi_drvr_lock_); + MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); + if (multi_drvr) + return multi_drvr; + multi_drvr = makeMultiDrvrNet(drvr_vertex); return multi_drvr; - else { - const PinSet *drvrs = network_->drivers(drvr_vertex->pin()); - if (drvrs && drvrs->size() > 1) { - PinSet drvrs1(network_); - // Filter input ports and non-leaf drivers. - for (const Pin *pin : *drvrs) { - if (isLeafDriver(pin, network_)) - drvrs1.insert(pin); - } - MultiDrvrNet *multi_drvr = nullptr; - if (drvrs1.size() > 1) - multi_drvr = makeMultiDrvrNet(drvrs1); - return multi_drvr; - } - else - return nullptr; } + return nullptr; +} + +bool +GraphDelayCalc::hasMultiDrvrs(Vertex *drvr_vertex) +{ + Vertex *load_vertex = firstLoad(drvr_vertex); + if (load_vertex) { + int drvr_count = 0; + VertexInEdgeIterator edge_iter(load_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->isWire()) { + Vertex *drvr = edge->from(graph_); + if (isLeafDriver(drvr->pin(), network_)) + drvr_count++; + } + if (drvr_count > 1) + return true; + } + return false; + } + return false; +} + +Vertex * +GraphDelayCalc::firstLoad(Vertex *drvr_vertex) +{ + VertexOutEdgeIterator edge_iter(drvr_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *wire_edge = edge_iter.next(); + if (wire_edge->isWire()) + return wire_edge->to(graph_); + } + return nullptr; } static bool @@ -710,31 +721,41 @@ GraphDelayCalc::multiDrvrNet(const Vertex *drvr_vertex) const } MultiDrvrNet * -GraphDelayCalc::makeMultiDrvrNet(PinSet &drvr_pins) +GraphDelayCalc::makeMultiDrvrNet(Vertex *drvr_vertex) { - debugPrint(debug_, "delay_calc", 3, "multi-driver net"); - VertexSet *drvr_vertices = new VertexSet(graph_); - MultiDrvrNet *multi_drvr = new MultiDrvrNet(drvr_vertices); - Level max_drvr_level = 0; - Vertex *max_drvr = nullptr; - PinSet::Iterator pin_iter(drvr_pins); - while (pin_iter.hasNext()) { - const Pin *pin = pin_iter.next(); - Vertex *drvr_vertex = graph_->pinDrvrVertex(pin); - debugPrint(debug_, "delay_calc", 3, " %s", - network_->pathName(pin)); - multi_drvr_net_map_[drvr_vertex] = multi_drvr; - drvr_vertices->insert(drvr_vertex); - Level drvr_level = drvr_vertex->level(); - if (max_drvr == nullptr - || drvr_level > max_drvr_level) { - max_drvr = drvr_vertex; - max_drvr_level = drvr_level; + Vertex *load_vertex = firstLoad(drvr_vertex); + if (load_vertex) { + debugPrint(debug_, "delay_calc", 3, "multi-driver net"); + MultiDrvrNet *multi_drvr = new MultiDrvrNet; + VertexSeq &drvr_vertices = multi_drvr->drvrs(); + Level max_drvr_level = 0; + Vertex *max_drvr = nullptr; + VertexInEdgeIterator edge_iter(load_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->isWire()) { + Vertex *drvr = edge->from(graph_); + const Pin *drvr_pin = drvr->pin(); + if (isLeafDriver(drvr_pin, network_)) { + debugPrint(debug_, "delay_calc", 3, " %s", + network_->pathName(drvr_pin)); + multi_drvr_net_map_[drvr] = multi_drvr; + drvr_vertices.push_back(drvr); + Level drvr_level = drvr->level(); + if (max_drvr == nullptr + || drvr_level > max_drvr_level) { + max_drvr = drvr; + max_drvr_level = drvr_level; + } + } + } } + multi_drvr->setDcalcDrvr(max_drvr); + multi_drvr->findCaps(sdc_); + return multi_drvr; } - multi_drvr->setDcalcDrvr(max_drvr); - multi_drvr->findCaps(sdc_); - return multi_drvr; + report_->critical(1101, "mult_drvr missing load."); + return nullptr; } void @@ -763,10 +784,17 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex, MultiDrvrNet *multi_drvr, ArcDelayCalc *arc_delay_calc) { - const Pin *drvr_pin = drvr_vertex->pin(); - Instance *drvr_inst = network_->instance(drvr_pin); initSlew(drvr_vertex); - initWireDelays(drvr_vertex); + if (multi_drvr + && multi_drvr->parallelGates(network_)) { + // Only init on the trigger driver. + if (drvr_vertex == multi_drvr->dcalcDrvr()) { + for (auto vertex : multi_drvr->drvrs()) + initWireDelays(vertex); + } + } + else + initWireDelays(drvr_vertex); bool delay_changed = false; bool has_delays = false; VertexInEdgeIterator edge_iter(drvr_vertex, graph_); @@ -777,8 +805,8 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex, if (search_pred_->searchFrom(from_vertex) && search_pred_->searchThru(edge) && !edge->role()->isLatchDtoQ()) { - delay_changed |= findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex, - multi_drvr, edge, arc_delay_calc); + delay_changed |= findDriverEdgeDelays(drvr_vertex, multi_drvr, edge, + arc_delay_calc); has_delays = true; } } @@ -812,53 +840,319 @@ GraphDelayCalc::findLatchEdgeDelays(Edge *edge) Instance *drvr_inst = network_->instance(drvr_pin); debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s", sdc_network_->pathName(drvr_inst)); - bool delay_changed = findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex, - nullptr, edge, arc_delay_calc_); + bool delay_changed = findDriverEdgeDelays(drvr_vertex, nullptr, edge, + arc_delay_calc_); if (delay_changed && observer_) observer_->delayChangedTo(drvr_vertex); } bool -GraphDelayCalc::findDriverEdgeDelays(const Instance *drvr_inst, - const Pin *drvr_pin, - Vertex *drvr_vertex, +GraphDelayCalc::findDriverEdgeDelays(Vertex *drvr_vertex, const MultiDrvrNet *multi_drvr, Edge *edge, ArcDelayCalc *arc_delay_calc) { - Vertex *in_vertex = edge->from(graph_); + Vertex *from_vertex = edge->from(graph_); const TimingArcSet *arc_set = edge->timingArcSet(); - const LibertyPort *related_out_port = arc_set->relatedOut(); - const Pin *related_out_pin = 0; bool delay_changed = false; - if (related_out_port) - related_out_pin = network_->findPin(drvr_inst, related_out_port); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { - const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax()); - if (pvt == nullptr) - pvt = dcalc_ap->operatingConditions(); - for (TimingArc *arc : arc_set->arcs()) { - const RiseFall *rf = arc->toEdge()->asRiseFall(); - Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap); - float related_out_cap = 0.0; - if (related_out_pin) { - Parasitic *related_out_parasitic = - arc_delay_calc->findParasitic(related_out_pin, rf, dcalc_ap); - related_out_cap = loadCap(related_out_pin, related_out_parasitic, rf, dcalc_ap); - } - delay_changed |= findArcDelay(drvr_pin, drvr_vertex, arc, parasitic, - related_out_cap, in_vertex, edge, pvt, dcalc_ap, - multi_drvr, arc_delay_calc); - } + for (const TimingArc *arc : arc_set->arcs()) + delay_changed |= findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc, + load_pin_index_map, dcalc_ap, + arc_delay_calc); } - if (delay_changed && observer_) { - observer_->delayChangedFrom(in_vertex); + observer_->delayChangedFrom(from_vertex); observer_->delayChangedFrom(drvr_vertex); } return delay_changed; } +void +GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex, + Edge *edge, + const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) +{ + MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex); + findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc, + load_pin_index_map, dcalc_ap, + arc_delay_calc); +} + +bool +GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex, + const MultiDrvrNet *multi_drvr, + Edge *edge, + const TimingArc *arc, + LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) +{ + bool delay_changed = false; + const RiseFall *from_rf = arc->fromEdge()->asRiseFall(); + const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); + if (from_rf && drvr_rf) { + const Pin *drvr_pin = drvr_vertex->pin(); + const Parasitic *parasitic; + float load_cap; + parasiticLoad(drvr_pin, drvr_rf, dcalc_ap, multi_drvr, arc_delay_calc, + load_cap, parasitic); + + if (multi_drvr + && multi_drvr->parallelGates(network_)) { + ArcDcalcArgSeq dcalc_args = makeArcDcalcArgs(drvr_vertex, multi_drvr, + edge, arc, dcalc_ap, + arc_delay_calc); + ArcDcalcResultSeq dcalc_results = + arc_delay_calc->gateDelays(dcalc_args, load_cap, 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]; + delay_changed |= annotateDelaysSlews(dcalc_arg.edge(), dcalc_arg.arc(), + dcalc_result, load_pin_index_map, + dcalc_ap); + } + } + else { + Vertex *from_vertex = edge->from(graph_); + const Slew in_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); + ArcDcalcResult dcalc_result = arc_delay_calc->gateDelay(drvr_pin, arc, in_slew, + load_cap, parasitic, + load_pin_index_map, + dcalc_ap); + delay_changed |= annotateDelaysSlews(edge, arc, dcalc_result, + load_pin_index_map, dcalc_ap); + } + arc_delay_calc->finishDrvrPin(); + } + return delay_changed; +} + +ArcDcalcArgSeq +GraphDelayCalc::makeArcDcalcArgs(Vertex *drvr_vertex, + const MultiDrvrNet *multi_drvr, + Edge *edge, + const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) +{ + ArcDcalcArgSeq dcalc_args; + for (auto drvr_vertex1 : multi_drvr->drvrs()) { + Edge *edge1 = nullptr; + const TimingArc *arc1 = nullptr; + if (drvr_vertex1 == drvr_vertex) { + edge1 = edge; + arc1 = arc; + } + else + findParallelEdge(drvr_vertex1, edge, arc, edge1, arc1); + // Shockingly one fpga vendor connects outputs with no timing arcs together. + if (edge1) { + Vertex *from_vertex = edge1->from(graph_); + const RiseFall *from_rf = arc1->fromEdge()->asRiseFall(); + 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.push_back(ArcDcalcArg(drvr_pin1, edge1, arc1, in_slew, + parasitic)); + } + } + return dcalc_args; +} + +// Find an edge/arc for parallel driver vertex to go along with the +// primary driver drvr_edge/drvr_arc. +void +GraphDelayCalc::findParallelEdge(Vertex *vertex, + Edge *drvr_edge, + const TimingArc *drvr_arc, + // Return values. + Edge *&edge, + const TimingArc *&arc) +{ + LibertyCell *drvr_cell = drvr_arc->from()->libertyCell(); + LibertyCell *vertex_cell = network_->libertyCell(network_->instance(vertex->pin())); + if (vertex_cell == drvr_cell) { + // Homogeneous drivers. + arc = drvr_arc; + LibertyPort *from_port = network_->libertyPort(drvr_edge->from(graph_)->pin()); + VertexInEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + edge = edge_iter.next(); + if (network_->libertyPort(edge->from(graph_)->pin()) == from_port) + return; + } + } + else { + VertexInEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + edge = edge_iter.next(); + for (TimingArc *arc1 : edge->timingArcSet()->arcs()) { + if (arc1->fromEdge() == drvr_arc->fromEdge() + && arc1->toEdge() == drvr_arc->toEdge()) { + arc = arc1; + return; + } + } + } + } + edge = nullptr; + arc = nullptr; +} + +bool +GraphDelayCalc::annotateDelaysSlews(Edge *edge, + const TimingArc *arc, + ArcDcalcResult &dcalc_result, + LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) +{ + bool delay_changed = annotateDelaySlew(edge, arc, + dcalc_result.gateDelay(), + dcalc_result.drvrSlew(), dcalc_ap); + if (!edge->role()->isLatchDtoQ()) { + Vertex *drvr_vertex = edge->to(graph_); + annotateLoadDelays(drvr_vertex, arc->toEdge()->asRiseFall(), dcalc_result, + load_pin_index_map, delay_zero, true, dcalc_ap); + } + return delay_changed; +} + +// Annotate the gate delay and merge the slew at the driver pin. +// Annotate the wire delays from the gate output to +// each load pin, and the merge the slews at each load pin. +bool +GraphDelayCalc::annotateDelaySlew(Edge *edge, + const TimingArc *arc, + ArcDelay &gate_delay, + Slew &gate_slew, + const DcalcAnalysisPt *dcalc_ap) +{ + bool delay_changed = false; + DcalcAPIndex ap_index = dcalc_ap->index(); + debugPrint(debug_, "delay_calc", 3, + " %s %s -> %s %s (%s) corner:%s/%s", + arc->from()->name(), + arc->fromEdge()->asString(), + arc->to()->name(), + arc->toEdge()->asString(), + arc->role()->asString(), + dcalc_ap->corner()->name(), + dcalc_ap->delayMinMax()->asString()); + debugPrint(debug_, "delay_calc", 3, + " gate delay = %s slew = %s", + delayAsString(gate_delay, this), + delayAsString(gate_slew, this)); + Vertex *drvr_vertex = edge->to(graph_); + const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); + // Merge slews. + const Slew &drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index); + const MinMax *slew_min_max = dcalc_ap->slewMinMax(); + if (delayGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax(), this) + && !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max) + && !edge->role()->isLatchDtoQ()) + graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew); + if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) { + const ArcDelay &prev_gate_delay = graph_->arcDelay(edge,arc,ap_index); + float gate_delay1 = delayAsFloat(gate_delay); + float prev_gate_delay1 = delayAsFloat(prev_gate_delay); + if (prev_gate_delay1 == 0.0 + || (abs(gate_delay1 - prev_gate_delay1) / prev_gate_delay1 + > incremental_delay_tolerance_)) + delay_changed = true; + graph_->setArcDelay(edge, arc, ap_index, gate_delay); + } + return delay_changed; +} + +// Annotate wire arc delays and load pin slews. +// extra_delay is additional wire delay to add to delay returned +// by the delay calculator. +void +GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex, + const RiseFall *drvr_rf, + ArcDcalcResult &dcalc_result, + LoadPinIndexMap &load_pin_index_map, + const ArcDelay &extra_delay, + bool merge, + const DcalcAnalysisPt *dcalc_ap) +{ + DcalcAPIndex ap_index = dcalc_ap->index(); + const MinMax *slew_min_max = dcalc_ap->slewMinMax(); + VertexOutEdgeIterator edge_iter(drvr_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *wire_edge = edge_iter.next(); + if (wire_edge->isWire()) { + Vertex *load_vertex = wire_edge->to(graph_); + Pin *load_pin = load_vertex->pin(); + size_t load_idx = load_pin_index_map[load_pin]; + ArcDelay wire_delay = dcalc_result.wireDelay(load_idx); + Slew load_slew = dcalc_result.loadSlew(load_idx); + debugPrint(debug_, "delay_calc", 3, + " %s load delay = %s slew = %s", + load_vertex->name(sdc_network_), + delayAsString(wire_delay, this), + delayAsString(load_slew, this)); + if (!load_vertex->slewAnnotated(drvr_rf, slew_min_max)) { + if (drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)) { + // Copy the driver slew to the load if it is annotated. + const Slew &drvr_slew = graph_->slew(drvr_vertex,drvr_rf,ap_index); + graph_->setSlew(load_vertex, drvr_rf, ap_index, drvr_slew); + } + else { + const Slew &slew = graph_->slew(load_vertex, drvr_rf, ap_index); + if (!merge + || delayGreater(load_slew, slew, slew_min_max, this)) + graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew); + } + } + if (!graph_->wireDelayAnnotated(wire_edge, drvr_rf, ap_index)) { + // Multiple timing arcs with the same output transition + // annotate the same wire edges so they must be combined + // rather than set. + const ArcDelay &delay = graph_->wireArcDelay(wire_edge, drvr_rf, ap_index); + Delay wire_delay_extra = extra_delay + wire_delay; + const MinMax *delay_min_max = dcalc_ap->delayMinMax(); + if (!merge + || delayGreater(wire_delay_extra, delay, delay_min_max, this)) { + graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, wire_delay_extra); + if (observer_) + observer_->delayChangedTo(load_vertex); + } + } + // Enqueue bidirect driver from load vertex. + if (sdc_->bidirectDrvrSlewFromLoad(load_pin)) + iter_->enqueue(graph_->pinDrvrVertex(load_pin)); + } + } +} + +LoadPinIndexMap +GraphDelayCalc::makeLoadPinIndexMap(Vertex *drvr_vertex) +{ + LoadPinIndexMap load_pin_index_map(network_); + size_t load_idx = 0; + VertexOutEdgeIterator edge_iter(drvr_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *wire_edge = edge_iter.next(); + if (wire_edge->isWire()) { + Vertex *load_vertex = wire_edge->to(graph_); + const Pin *load_pin = load_vertex->pin(); + load_pin_index_map[load_pin] = load_idx; + load_idx++; + } + } + return load_pin_index_map; +} + +// External float GraphDelayCalc::loadCap(const Pin *drvr_pin, const DcalcAnalysisPt *dcalc_ap) const @@ -866,93 +1160,104 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin, const MinMax *min_max = dcalc_ap->constraintMinMax(); float load_cap = 0.0; for (auto drvr_rf : RiseFall::range()) { - Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, - dcalc_ap); - float cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, nullptr); - arc_delay_calc_->finishDrvrPin(); + float cap = loadCap(drvr_pin, drvr_rf, dcalc_ap); if (min_max->compare(cap, load_cap)) load_cap = cap; } + arc_delay_calc_->finishDrvrPin(); return load_cap; } +// External float GraphDelayCalc::loadCap(const Pin *drvr_pin, - const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap) const -{ - Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, - dcalc_ap); - float cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, nullptr); - return cap; -} - -float -GraphDelayCalc::loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) const -{ - return loadCap(drvr_pin, drvr_parasitic, rf, dcalc_ap, nullptr); -} - -float -GraphDelayCalc::loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap, - const MultiDrvrNet *multi_drvr) const { float pin_cap, wire_cap; - bool has_net_load; - float fanout; - if (multi_drvr) - multi_drvr->netCaps(rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_net_load); - else - netCaps(drvr_pin, rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_net_load); - loadCap(drvr_parasitic, has_net_load, pin_cap, wire_cap); - return wire_cap + pin_cap; + loadCap(drvr_pin, rf, dcalc_ap, pin_cap, wire_cap); + return pin_cap + wire_cap; } +// External void GraphDelayCalc::loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap, - // Return values. float &pin_cap, float &wire_cap) const { - bool has_net_load; - float fanout; - // Find pin and external pin/wire capacitance. - netCaps(drvr_pin, rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_net_load); - loadCap(drvr_parasitic, has_net_load, pin_cap, wire_cap); + MultiDrvrNet *multi_drvr = nullptr; + if (graph_) { + Vertex *drvr_vertex = graph_->pinDrvrVertex(drvr_pin); + multi_drvr = multiDrvrNet(drvr_vertex); + } + const Parasitic *parasitic; + parasiticLoad(drvr_pin, rf, dcalc_ap, multi_drvr, arc_delay_calc_, + pin_cap, wire_cap, parasitic); + arc_delay_calc_->finishDrvrPin(); +} + +float +GraphDelayCalc::loadCap(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) const +{ + const Parasitic *parasitic; + float pin_cap, wire_cap; + parasiticLoad(drvr_pin, rf, dcalc_ap, nullptr, arc_delay_calc, + pin_cap, wire_cap, parasitic); + return pin_cap + wire_cap; } void -GraphDelayCalc::loadCap(const Parasitic *drvr_parasitic, - bool has_net_load, - // Return values. - float &pin_cap, - float &wire_cap) const +GraphDelayCalc::parasiticLoad(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + const MultiDrvrNet *multi_drvr, + ArcDelayCalc *arc_delay_calc, + // Return values. + float &load_cap, + const Parasitic *¶sitic) const { - // set_load net has precidence over parasitics. - if (!has_net_load && drvr_parasitic) { - if (parasitics_->isParasiticNetwork(drvr_parasitic)) - wire_cap += parasitics_->capacitance(drvr_parasitic); + float pin_cap, wire_cap; + parasiticLoad(drvr_pin, rf, dcalc_ap, multi_drvr, arc_delay_calc, + pin_cap, wire_cap, parasitic); + load_cap = pin_cap + wire_cap; +} + +void +GraphDelayCalc::parasiticLoad(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + const MultiDrvrNet *multi_drvr, + ArcDelayCalc *arc_delay_calc, + // Return values. + float &pin_cap, + float &wire_cap, + const Parasitic *¶sitic) const +{ + bool has_net_load; + float fanout; + netCaps(drvr_pin, rf, dcalc_ap, multi_drvr, + pin_cap, wire_cap, fanout, has_net_load); + + parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap); + // set_load net has precedence over parasitics. + if (!has_net_load && parasitic) { + if (parasitics_->isParasiticNetwork(parasitic)) + wire_cap += parasitics_->capacitance(parasitic); else { // PiModel includes both pin and external caps. - float cap = parasitics_->capacitance(drvr_parasitic); - if (pin_cap > cap) { - pin_cap = 0.0; - wire_cap = cap; + float parasitic_cap = parasitics_->capacitance(parasitic); + if (parasitic_cap >= pin_cap) + wire_cap = parasitic_cap - pin_cap; + else { + wire_cap = 0.0; + // Ignore parasitic if pin cap is greater. + parasitic = nullptr; } - else - wire_cap = cap - pin_cap; } } } @@ -972,15 +1277,29 @@ GraphDelayCalc::netCaps(const Pin *drvr_pin, Vertex *drvr_vertex = graph_->pinDrvrVertex(drvr_pin); multi_drvr = multiDrvrNet(drvr_vertex); } + netCaps(drvr_pin, rf, dcalc_ap, multi_drvr, + pin_cap, wire_cap, fanout, has_net_load); +} + +void +GraphDelayCalc::netCaps(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + const MultiDrvrNet *multi_drvr, + // Return values. + float &pin_cap, + float &wire_cap, + float &fanout, + bool &has_net_load) const +{ if (multi_drvr) multi_drvr->netCaps(rf, dcalc_ap, pin_cap, wire_cap, fanout, has_net_load); else { - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); const Corner *corner = dcalc_ap->corner(); const MinMax *min_max = dcalc_ap->constraintMinMax(); // Find pin and external pin/wire capacitance. - sdc_->connectedCap(drvr_pin, rf, op_cond, corner, min_max, + sdc_->connectedCap(drvr_pin, rf, corner, min_max, pin_cap, wire_cap, fanout, has_net_load); } } @@ -1049,80 +1368,6 @@ GraphDelayCalc::initWireDelays(Vertex *drvr_vertex) } } -// Call the arc delay calculator to find the delay thru a single gate -// input to output timing arc, The wire delays from the gate output to -// each load pin, and the slew at each load pin. Annotate the graph -// with the results. -bool -GraphDelayCalc::findArcDelay(const Pin *drvr_pin, - Vertex *drvr_vertex, - const TimingArc *arc, - const Parasitic *drvr_parasitic, - float related_out_cap, - Vertex *from_vertex, - Edge *edge, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - const MultiDrvrNet *multi_drvr, - ArcDelayCalc *arc_delay_calc) -{ - bool delay_changed = false; - RiseFall *from_rf = arc->fromEdge()->asRiseFall(); - RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); - if (from_rf && drvr_rf) { - DcalcAPIndex ap_index = dcalc_ap->index(); - debugPrint(debug_, "delay_calc", 3, - " %s %s -> %s %s (%s) corner:%s/%s", - arc->from()->name(), - arc->fromEdge()->asString(), - arc->to()->name(), - arc->toEdge()->asString(), - arc->role()->asString(), - dcalc_ap->corner()->name(), - dcalc_ap->delayMinMax()->asString()); - // Delay calculation is done even when the gate delays/slews are - // annotated because the wire delays may not be annotated. - const Slew from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); - ArcDelay gate_delay; - Slew gate_slew; - float load_cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, multi_drvr); - if (multi_drvr - && multi_drvr->parallelGates(network_)) - arc_delay_calc->parallelGateDelay(drvr_pin, arc, from_slew, load_cap, - drvr_parasitic, related_out_cap, pvt, dcalc_ap, - gate_delay, gate_slew); - else - arc_delay_calc->gateDelay(arc, from_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, gate_slew); - debugPrint(debug_, "delay_calc", 3, - " gate delay = %s slew = %s", - delayAsString(gate_delay, this), - delayAsString(gate_slew, this)); - // 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) - && !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max) - && !edge->role()->isLatchDtoQ()) - graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew); - if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) { - const ArcDelay &prev_gate_delay = graph_->arcDelay(edge,arc,ap_index); - float gate_delay1 = delayAsFloat(gate_delay); - float prev_gate_delay1 = delayAsFloat(prev_gate_delay); - if (prev_gate_delay1 == 0.0 - || (abs(gate_delay1 - prev_gate_delay1) / prev_gate_delay1 - > incremental_delay_tolerance_)) - delay_changed = true; - graph_->setArcDelay(edge, arc, ap_index, gate_delay); - } - if (!edge->role()->isLatchDtoQ()) - annotateLoadDelays(drvr_vertex, drvr_rf, delay_zero, true, dcalc_ap, - arc_delay_calc); - } - return delay_changed; -} - // Use clock slew for register/latch clk->q edges. Slew GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex, @@ -1139,69 +1384,6 @@ GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex, return graph_->slew(from_vertex, from_rf, dcalc_ap->index()); } -// Annotate wire arc delays and load pin slews. -// extra_delay is additional wire delay to add to delay returned -// by the delay calculator. -void -GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex, - const RiseFall *drvr_rf, - const ArcDelay &extra_delay, - bool merge, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc) -{ - DcalcAPIndex ap_index = dcalc_ap->index(); - const MinMax *slew_min_max = dcalc_ap->slewMinMax(); - VertexOutEdgeIterator edge_iter(drvr_vertex, graph_); - while (edge_iter.hasNext()) { - Edge *wire_edge = edge_iter.next(); - if (wire_edge->isWire()) { - Vertex *load_vertex = wire_edge->to(graph_); - Pin *load_pin = load_vertex->pin(); - ArcDelay wire_delay; - Slew load_slew; - arc_delay_calc->loadDelay(load_pin, wire_delay, load_slew); - debugPrint(debug_, "delay_calc", 3, - " %s load delay = %s slew = %s", - load_vertex->name(sdc_network_), - delayAsString(wire_delay, this), - delayAsString(load_slew, this)); - if (!load_vertex->slewAnnotated(drvr_rf, slew_min_max)) { - if (drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)) { - // Copy the driver slew to the load if it is annotated. - const Slew &drvr_slew = graph_->slew(drvr_vertex,drvr_rf,ap_index); - graph_->setSlew(load_vertex, drvr_rf, ap_index, drvr_slew); - } - else { - const Slew &slew = graph_->slew(load_vertex, drvr_rf, ap_index); - if (!merge - || delayGreater(load_slew, slew, slew_min_max, this)) - graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew); - } - } - if (!graph_->wireDelayAnnotated(wire_edge, drvr_rf, ap_index)) { - // Multiple timing arcs with the same output transition - // annotate the same wire edges so they must be combined - // rather than set. - const ArcDelay &delay = graph_->wireArcDelay(wire_edge, drvr_rf, - ap_index); - Delay wire_delay_extra = extra_delay + wire_delay; - const MinMax *delay_min_max = dcalc_ap->delayMinMax(); - if (!merge - || delayGreater(wire_delay_extra, delay, delay_min_max, this)) { - graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, - wire_delay_extra); - if (observer_) - observer_->delayChangedTo(load_vertex); - } - } - // Enqueue bidirect driver from load vertex. - if (sdc_->bidirectDrvrSlewFromLoad(load_pin)) - iter_->enqueue(graph_->pinDrvrVertex(load_pin)); - } - } -} - void GraphDelayCalc::findCheckEdgeDelays(Edge *edge, ArcDelayCalc *arc_delay_calc) @@ -1227,9 +1409,6 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge, for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { DcalcAPIndex ap_index = dcalc_ap->index(); if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) { - const Pvt *pvt = sdc_->pvt(inst,dcalc_ap->constraintMinMax()); - if (pvt == nullptr) - pvt = dcalc_ap->operatingConditions(); const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, dcalc_ap); int slew_index = dcalc_ap->checkDataSlewIndex(); @@ -1246,21 +1425,17 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge, delayAsString(from_slew, this), delayAsString(to_slew, this)); float related_out_cap = 0.0; - if (related_out_pin) { - Parasitic *related_out_parasitic = - arc_delay_calc->findParasitic(related_out_pin, to_rf, dcalc_ap); - related_out_cap = loadCap(related_out_pin, - related_out_parasitic, - to_rf, dcalc_ap); - } - ArcDelay check_delay; - arc_delay_calc->checkDelay(arc, from_slew, to_slew, related_out_cap, - pvt, dcalc_ap, check_delay); + if (related_out_pin) + related_out_cap = loadCap(related_out_pin, to_rf,dcalc_ap,arc_delay_calc); + ArcDelay check_delay = arc_delay_calc->checkDelay(to_pin, arc, from_slew, + to_slew, related_out_cap, + dcalc_ap); debugPrint(debug_, "delay_calc", 3, " check_delay = %s", delayAsString(check_delay, this)); graph_->setArcDelay(edge, arc, ap_index, check_delay); delay_changed = true; + arc_delay_calc_->finishDrvrPin(); } } } @@ -1285,47 +1460,6 @@ GraphDelayCalc::checkEdgeClkSlew(const Vertex *from_vertex, //////////////////////////////////////////////////////////////// -float -GraphDelayCalc::ceff(Edge *edge, - TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap) -{ - Vertex *from_vertex = edge->from(graph_); - Vertex *to_vertex = edge->to(graph_); - Pin *to_pin = to_vertex->pin(); - Instance *inst = network_->instance(to_pin); - const TimingArcSet *arc_set = edge->timingArcSet(); - float ceff = 0.0; - const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax()); - if (pvt == nullptr) - pvt = dcalc_ap->operatingConditions(); - RiseFall *from_rf = arc->fromEdge()->asRiseFall(); - RiseFall *to_rf = arc->toEdge()->asRiseFall(); - if (from_rf && to_rf) { - const LibertyPort *related_out_port = arc_set->relatedOut(); - const Pin *related_out_pin = 0; - if (related_out_port) - related_out_pin = network_->findPin(inst, related_out_port); - float related_out_cap = 0.0; - if (related_out_pin) { - Parasitic *related_out_parasitic = - arc_delay_calc_->findParasitic(related_out_pin, to_rf, dcalc_ap); - related_out_cap = loadCap(related_out_pin, related_out_parasitic, - to_rf, dcalc_ap); - } - Parasitic *to_parasitic = arc_delay_calc_->findParasitic(to_pin, to_rf, - dcalc_ap); - const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); - float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap); - ceff = arc_delay_calc_->ceff(arc, from_slew, load_cap, to_parasitic, - related_out_cap, pvt, dcalc_ap); - arc_delay_calc_->finishDrvrPin(); - } - return ceff; -} - -//////////////////////////////////////////////////////////////// - string GraphDelayCalc::reportDelayCalc(const Edge *edge, const TimingArc *arc, @@ -1341,9 +1475,6 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge, const TimingArcSet *arc_set = edge->timingArcSet(); string result; DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); - const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax()); - if (pvt == nullptr) - pvt = dcalc_ap->operatingConditions(); RiseFall *from_rf = arc->fromEdge()->asRiseFall(); RiseFall *to_rf = arc->toEdge()->asRiseFall(); if (from_rf && to_rf) { @@ -1352,29 +1483,28 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge, if (related_out_port) related_out_pin = network_->findPin(inst, related_out_port); float related_out_cap = 0.0; - if (related_out_pin) { - Parasitic *related_out_parasitic = - arc_delay_calc_->findParasitic(related_out_pin, to_rf, dcalc_ap); - related_out_cap = loadCap(related_out_pin, related_out_parasitic, - to_rf, dcalc_ap); - } + if (related_out_pin) + related_out_cap = loadCap(related_out_pin, to_rf, dcalc_ap, arc_delay_calc_); if (role->isTimingCheck()) { const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, dcalc_ap); int slew_index = dcalc_ap->checkDataSlewIndex(); const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index); bool from_ideal_clk = clk_network_->isIdealClock(from_vertex->pin()); const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr; - result = arc_delay_calc_->reportCheckDelay(arc, from_slew, from_slew_annotation, - to_slew, related_out_cap, pvt, - dcalc_ap, digits); + result = arc_delay_calc_->reportCheckDelay(to_pin, arc, from_slew, + from_slew_annotation, to_slew, + related_out_cap, dcalc_ap, digits); } else { - Parasitic *to_parasitic = - arc_delay_calc_->findParasitic(to_pin, to_rf, dcalc_ap); const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap); - float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap); - result = arc_delay_calc_->reportGateDelay(arc, from_slew, load_cap, to_parasitic, - related_out_cap, pvt, dcalc_ap, digits); + const Parasitic *to_parasitic; + float load_cap; + parasiticLoad(to_pin, to_rf, dcalc_ap, nullptr, arc_delay_calc_, + load_cap, to_parasitic); + LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(to_vertex); + result = arc_delay_calc_->reportGateDelay(to_pin, arc, from_slew, load_cap, + to_parasitic, load_pin_index_map, + dcalc_ap, digits); } arc_delay_calc_->finishDrvrPin(); } @@ -1441,17 +1571,11 @@ GraphDelayCalc::minPeriod(const Pin *pin, //////////////////////////////////////////////////////////////// -MultiDrvrNet::MultiDrvrNet(VertexSet *drvrs) : - dcalc_drvr_(nullptr), - drvrs_(drvrs) +MultiDrvrNet::MultiDrvrNet() : + dcalc_drvr_(nullptr) { } -MultiDrvrNet::~MultiDrvrNet() -{ - delete drvrs_; -} - void MultiDrvrNet::netCaps(const RiseFall *drvr_rf, const DcalcAnalysisPt *dcalc_ap, @@ -1480,7 +1604,6 @@ MultiDrvrNet::findCaps(const Sdc *sdc) for (auto dcalc_ap : corners->dcalcAnalysisPts()) { DcalcAPIndex ap_index = dcalc_ap->index(); const Corner *corner = dcalc_ap->corner(); - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); const MinMax *min_max = dcalc_ap->constraintMinMax(); for (auto drvr_rf : RiseFall::range()) { int drvr_rf_index = drvr_rf->index(); @@ -1489,7 +1612,7 @@ MultiDrvrNet::findCaps(const Sdc *sdc) float pin_cap, wire_cap, fanout; bool has_net_load; // Find pin and external pin/wire capacitance. - sdc->connectedCap(drvr_pin, drvr_rf, op_cond, corner, min_max, + sdc->connectedCap(drvr_pin, drvr_rf, corner, min_max, pin_cap, wire_cap, fanout, has_net_load); net_caps.init(pin_cap, wire_cap, fanout, has_net_load); } diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc index 5e99dd7a..67cecec0 100644 --- a/dcalc/LumpedCapDelayCalc.cc +++ b/dcalc/LumpedCapDelayCalc.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -23,6 +23,7 @@ #include "TimingArc.hh" #include "TimingModel.hh" #include "Liberty.hh" +#include "PortDirection.hh" #include "Network.hh" #include "Sdc.hh" #include "Parasitics.hh" @@ -57,176 +58,131 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin, { Parasitic *parasitic = nullptr; const Corner *corner = dcalc_ap->corner(); - // set_load net has precidence over parasitics. - if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) { - const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); - if (parasitics_->haveParasitics()) { - // Prefer PiElmore. - parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap); - if (parasitic == nullptr) { - Parasitic *parasitic_network = - parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); - if (parasitic_network) { - parasitics_->reduceToPiElmore(parasitic_network, drvr_pin, - dcalc_ap->operatingConditions(), - corner, - dcalc_ap->constraintMinMax(), - parasitic_ap); - parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap); - reduced_parasitic_drvrs_.push_back(drvr_pin); - } - } - } - else { - const MinMax *cnst_min_max = dcalc_ap->constraintMinMax(); - Wireload *wireload = sdc_->wireload(cnst_min_max); - if (wireload) { - float pin_cap, wire_cap, fanout; - bool has_net_load; - graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, - pin_cap, wire_cap, fanout, has_net_load); - parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, - fanout, pin_cap, - dcalc_ap->operatingConditions(), - corner, - cnst_min_max, - parasitic_ap); - // Estimated parasitics are not recorded in the "database", so save - // it for deletion after the drvr pin delay calc is finished. - if (parasitic) - unsaved_parasitics_.push_back(parasitic); - } - } + // set_load net has precedence over parasitics. + if (sdc_->drvrPinHasWireCap(drvr_pin, corner) + || network_->direction(drvr_pin)->isInternal()) + return nullptr; + const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); + // Prefer PiElmore. + parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap); + if (parasitic) + return parasitic; + Parasitic *parasitic_network = parasitics_->findParasiticNetwork(drvr_pin, + parasitic_ap); + if (parasitic_network) { + parasitic = reduceParasitic(parasitic_network, drvr_pin, rf, dcalc_ap); + if (parasitic) + return parasitic; + } + const MinMax *min_max = dcalc_ap->constraintMinMax(); + Wireload *wireload = sdc_->wireload(min_max); + if (wireload) { + float pin_cap, wire_cap, fanout; + bool has_net_load; + graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, + pin_cap, wire_cap, fanout, has_net_load); + parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, fanout, + pin_cap, corner, min_max); } return parasitic; } -ReducedParasiticType -LumpedCapDelayCalc::reducedParasiticType() const +Parasitic * +LumpedCapDelayCalc::reduceParasitic(const Parasitic *parasitic_network, + const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap) + { - return ReducedParasiticType::pi_elmore; + const Corner *corner = dcalc_ap->corner(); + const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); + return parasitics_->reduceToPiElmore(parasitic_network, drvr_pin, rf, + corner, dcalc_ap->constraintMinMax(), + parasitic_ap); } -float -LumpedCapDelayCalc::ceff(const TimingArc *, - const Slew &, - float load_cap, - const Parasitic *, - float, - const Pvt *, - const DcalcAnalysisPt *) +ArcDcalcResult +LumpedCapDelayCalc::inputPortDelay(const Pin *, + float in_slew, + const RiseFall *rf, + const Parasitic *, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { - return load_cap; + const LibertyLibrary *drvr_library = network_->defaultLibertyLibrary(); + return makeResult(drvr_library,rf, 0.0, in_slew, load_pin_index_map); } -void -LumpedCapDelayCalc::gateDelay(const TimingArc *arc, +ArcDcalcResult +LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin, + const TimingArc *arc, const Slew &in_slew, float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) + const Parasitic *, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) { - gateDelayInit(arc, in_slew, drvr_parasitic); GateTimingModel *model = gateModel(arc, dcalc_ap); debugPrint(debug_, "delay_calc", 3, - " in_slew = %s load_cap = %s related_load_cap = %s lumped", + " in_slew = %s load_cap = %s lumped", delayAsString(in_slew, this), - units()->capacitanceUnit()->asString(load_cap), - units()->capacitanceUnit()->asString(related_out_cap)); + units()->capacitanceUnit()->asString(load_cap)); + const RiseFall *rf = arc->toEdge()->asRiseFall(); + const LibertyLibrary *drvr_library = arc->to()->libertyLibrary(); if (model) { - ArcDelay gate_delay1; - Slew drvr_slew1; + ArcDelay gate_delay; + Slew drvr_slew; float in_slew1 = delayAsFloat(in_slew); // NaNs cause seg faults during table lookup. - if (isnan(load_cap) || isnan(related_out_cap) || isnan(delayAsFloat(in_slew))) - report_->error(710, "gate delay input variable is NaN"); - model->gateDelay(pvt, in_slew1, load_cap, related_out_cap, - pocv_enabled_, gate_delay1, drvr_slew1); - gate_delay = gate_delay1; - drvr_slew = drvr_slew1; - drvr_slew_ = drvr_slew1; - } - else { - gate_delay = delay_zero; - drvr_slew = delay_zero; - drvr_slew_ = 0.0; + if (isnan(load_cap) || isnan(delayAsFloat(in_slew))) + report_->error(1350, "gate delay input variable is NaN"); + model->gateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, load_cap, pocv_enabled_, + gate_delay, drvr_slew); + return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map); } + else + return makeResult(drvr_library, rf, delay_zero, delay_zero, load_pin_index_map); } -void -LumpedCapDelayCalc::loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) +ArcDcalcResult +LumpedCapDelayCalc::makeResult(const LibertyLibrary *drvr_library, + const RiseFall *rf, + ArcDelay gate_delay, + Slew drvr_slew, + const LoadPinIndexMap &load_pin_index_map) { - Delay wire_delay1 = 0.0; - Slew load_slew1 = drvr_slew_ * multi_drvr_slew_factor_; - thresholdAdjust(load_pin, wire_delay1, load_slew1); - wire_delay = wire_delay1; - load_slew = load_slew1; + ArcDcalcResult dcalc_result(load_pin_index_map.size()); + 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; + ArcDelay wire_delay = 0.0; + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, drvr_slew); + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, drvr_slew); + } + return dcalc_result; } string -LumpedCapDelayCalc::reportGateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - int digits) +LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *, + const LoadPinIndexMap &, + const DcalcAnalysisPt *dcalc_ap, + int digits) { GateTimingModel *model = gateModel(arc, dcalc_ap); if (model) { float in_slew1 = delayAsFloat(in_slew); - return model->reportGateDelay(pvt, in_slew1, load_cap, related_out_cap, + return model->reportGateDelay(pinPvt(check_pin, dcalc_ap), in_slew1, load_cap, false, digits); } return ""; } -void -LumpedCapDelayCalc::checkDelay(const TimingArc *arc, - const Slew &from_slew, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &margin) -{ - CheckTimingModel *model = checkModel(arc, dcalc_ap); - if (model) { - float from_slew1 = delayAsFloat(from_slew); - float to_slew1 = delayAsFloat(to_slew); - model->checkDelay(pvt, from_slew1, to_slew1, related_out_cap, pocv_enabled_, margin); - } - else - margin = delay_zero; -} - -string -LumpedCapDelayCalc::reportCheckDelay(const TimingArc *arc, - const Slew &from_slew, - const char *from_slew_annotation, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - int digits) -{ - CheckTimingModel *model = checkModel(arc, dcalc_ap); - if (model) { - float from_slew1 = delayAsFloat(from_slew); - float to_slew1 = delayAsFloat(to_slew); - return model->reportCheckDelay(pvt, from_slew1, from_slew_annotation, - to_slew1, related_out_cap, false, digits); - } - return ""; -} - } // namespace diff --git a/dcalc/LumpedCapDelayCalc.hh b/dcalc/LumpedCapDelayCalc.hh index db7473c0..b62a2faf 100644 --- a/dcalc/LumpedCapDelayCalc.hh +++ b/dcalc/LumpedCapDelayCalc.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -30,54 +30,40 @@ public: Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; - ReducedParasiticType reducedParasiticType() const override; - void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) override; - float ceff(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap) override; - void loadDelay(const Pin *load_pin, - // Return values. - ArcDelay &wire_delay, - Slew &load_slew) override; - void checkDelay(const TimingArc *arc, - const Slew &from_slew, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &margin) override; - string reportGateDelay(const TimingArc *arc, + Parasitic *reduceParasitic(const Parasitic *parasitic_network, + const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + string reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, const Slew &in_slew, float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, int digits) override; - string reportCheckDelay(const TimingArc *arc, - const Slew &from_slew, - const char *from_slew_annotation, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - int digits) override; protected: + ArcDcalcResult makeResult(const LibertyLibrary *drvr_library, + const RiseFall *rf, + ArcDelay gate_delay, + Slew drvr_slew, + const LoadPinIndexMap &load_pin_index_map); + + using ArcDelayCalc::reduceParasitic; }; ArcDelayCalc * diff --git a/dcalc/NetCaps.cc b/dcalc/NetCaps.cc index 4521eb99..44fc5924 100644 --- a/dcalc/NetCaps.cc +++ b/dcalc/NetCaps.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/dcalc/NetCaps.hh b/dcalc/NetCaps.hh index ca1ad970..311a5104 100644 --- a/dcalc/NetCaps.hh +++ b/dcalc/NetCaps.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/dcalc/ParallelDelayCalc.cc b/dcalc/ParallelDelayCalc.cc index 62fd90a6..732a239f 100644 --- a/dcalc/ParallelDelayCalc.cc +++ b/dcalc/ParallelDelayCalc.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -31,141 +31,81 @@ ParallelDelayCalc::ParallelDelayCalc(StaState *sta): { } -void -ParallelDelayCalc::inputPortDelay(const Pin *drvr_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) +ArcDcalcResultSeq +ParallelDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, + float load_cap, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) { - DelayCalcBase::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap); - multi_drvr_slew_factor_ = 1.0; -} - -void -ParallelDelayCalc::gateDelayInit(const TimingArc *arc, - const Slew &in_slew, - const Parasitic *drvr_parasitic) -{ - DelayCalcBase::gateDelayInit(arc, in_slew, drvr_parasitic); - multi_drvr_slew_factor_ = 1.0F; -} - -void -ParallelDelayCalc::findParallelGateDelays(const MultiDrvrNet *multi_drvr, - GraphDelayCalc *dcalc) -{ - int count = RiseFall::index_count * corners_->dcalcAnalysisPtCount(); - parallel_delays_.resize(count); - parallel_slews_.resize(count); - for (auto dcalc_ap : corners_->dcalcAnalysisPts()) { - for (auto drvr_rf : RiseFall::range()) { - DcalcAPIndex ap_index = dcalc_ap->index(); - int drvr_rf_index = drvr_rf->index(); - int index = ap_index * RiseFall::index_count + drvr_rf_index; - findMultiDrvrGateDelay(multi_drvr, drvr_rf, dcalc_ap, dcalc, - parallel_delays_[index], - parallel_slews_[index]); - } + 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(), + 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); } -void -ParallelDelayCalc::findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr, - const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap, - GraphDelayCalc *dcalc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew) +ArcDcalcResultSeq +ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args, + float load_cap, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) { - ArcDelay delay_sum = 0.0; + size_t drvr_count = dcalc_args.size(); + ArcDcalcResultSeq dcalc_results(drvr_count); Slew slew_sum = 0.0; - for (Vertex *drvr_vertex : *multi_drvr->drvrs()) { - Pin *drvr_pin = drvr_vertex->pin(); - Instance *drvr_inst = network_->instance(drvr_pin); - const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax()); - if (pvt == nullptr) - pvt = dcalc_ap->operatingConditions(); - VertexInEdgeIterator edge_iter(drvr_vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - TimingArcSet *arc_set = edge->timingArcSet(); - const LibertyPort *related_out_port = arc_set->relatedOut(); - for (TimingArc *arc : arc_set->arcs()) { - RiseFall *arc_rf = arc->toEdge()->asRiseFall(); - if (arc_rf == drvr_rf) { - Vertex *from_vertex = edge->from(graph_); - RiseFall *from_rf = arc->fromEdge()->asRiseFall(); - Slew from_slew = dcalc->edgeFromSlew(from_vertex, from_rf, - edge, dcalc_ap); - ArcDelay intrinsic_delay; - Slew intrinsic_slew; - gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap, - intrinsic_delay, intrinsic_slew); - Parasitic *parasitic = findParasitic(drvr_pin, drvr_rf, dcalc_ap); - const Pin *related_out_pin = 0; - float related_out_cap = 0.0; - if (related_out_port) { - Instance *inst = network_->instance(drvr_pin); - related_out_pin = network_->findPin(inst, related_out_port); - if (related_out_pin) { - Parasitic *related_out_parasitic = findParasitic(related_out_pin, - drvr_rf, - dcalc_ap); - related_out_cap = dcalc->loadCap(related_out_pin, - related_out_parasitic, - drvr_rf, dcalc_ap); - } - } - float load_cap = dcalc->loadCap(drvr_pin, parasitic, - drvr_rf, dcalc_ap); - ArcDelay gate_delay; - Slew gate_slew; - gateDelay(arc, from_slew, load_cap, parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, gate_slew); - delay_sum += 1.0F / (gate_delay - intrinsic_delay); - slew_sum += 1.0F / gate_slew; - } - } + ArcDelay load_delay_sum = 0.0; + vector intrinsic_delays(dcalc_args.size()); + vector load_delays(dcalc_args.size()); + for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) { + ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx]; + ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx]; + const Pin *drvr_pin = dcalc_arg.drvrPin(); + const TimingArc *arc = dcalc_arg.arc(); + Slew in_slew = dcalc_arg.inSlew(); + + ArcDcalcResult intrinsic_result = gateDelay(drvr_pin, arc, in_slew, 0.0, nullptr, + load_pin_index_map, dcalc_ap); + ArcDelay intrinsic_delay = intrinsic_result.gateDelay(); + intrinsic_delays[drvr_idx] = intrinsic_result.gateDelay(); + + ArcDcalcResult gate_result = gateDelay(drvr_pin, arc, in_slew, load_cap, + dcalc_arg.parasitic(), + load_pin_index_map, dcalc_ap); + ArcDelay gate_delay = gate_result.gateDelay(); + Slew drvr_slew = gate_result.drvrSlew(); + ArcDelay load_delay = gate_delay - intrinsic_delay; + load_delays[drvr_idx] = load_delay; + + if (!delayZero(load_delay)) + load_delay_sum += 1.0 / load_delay; + if (!delayZero(drvr_slew)) + slew_sum += 1.0 / drvr_slew; + + 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; + dcalc_result.setWireDelay(load_idx, gate_result.wireDelay(load_idx)); + dcalc_result.setLoadSlew(load_idx, gate_result.loadSlew(load_idx)); } } - parallel_delay = 1.0F / delay_sum; - parallel_slew = 1.0F / slew_sum; -} -void -ParallelDelayCalc::parallelGateDelay(const Pin *, - const TimingArc *arc, - const Slew &from_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) -{ - ArcDelay intrinsic_delay; - Slew intrinsic_slew; - gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap, - intrinsic_delay, intrinsic_slew); - const RiseFall *drvr_rf = arc->toEdge()->asRiseFall(); - int index = dcalc_ap->index() * RiseFall::index_count + drvr_rf->index(); - ArcDelay parallel_delay = parallel_delays_[index]; - Slew parallel_slew = parallel_slews_[index]; - gate_delay = parallel_delay + intrinsic_delay; - gate_slew = parallel_slew; + ArcDelay gate_load_delay = delayZero(load_delay_sum) + ? delay_zero + : 1.0 / load_delay_sum; + ArcDelay drvr_slew = delayZero(slew_sum) ? delay_zero : 1.0 / slew_sum; - Delay gate_delay1; - Slew gate_slew1; - gateDelay(arc, from_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay1, gate_slew1); - float factor = delayRatio(gate_slew, gate_slew1); - multi_drvr_slew_factor_ = factor; + for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) { + ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx]; + dcalc_result.setGateDelay(intrinsic_delays[drvr_idx] + gate_load_delay); + dcalc_result.setDrvrSlew(drvr_slew); + } + return dcalc_results; } } // namespace diff --git a/dcalc/ParallelDelayCalc.hh b/dcalc/ParallelDelayCalc.hh index 68510e99..7f361218 100644 --- a/dcalc/ParallelDelayCalc.hh +++ b/dcalc/ParallelDelayCalc.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -17,52 +17,26 @@ #pragma once #include +#include #include "DelayCalcBase.hh" namespace sta { -// Delay calculation for parallel gates based on using parallel drive resistance. +// Delay calculation for parallel gates using parallel drive resistance. class ParallelDelayCalc : public DelayCalcBase { public: - explicit ParallelDelayCalc(StaState *sta); - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) override; - void gateDelayInit(const TimingArc *arc, - const Slew &in_slew, - const Parasitic *drvr_parasitic); - void findParallelGateDelays(const MultiDrvrNet *multi_drvr, - GraphDelayCalc *dcalc) override; - void parallelGateDelay(const Pin *drvr_pin, - const TimingArc *arc, - const Slew &from_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) override; - + ParallelDelayCalc(StaState *sta); + ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &dcalc_args, + float load_cap, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; protected: - void findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr, - const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap, - GraphDelayCalc *dcalc, - // Return values. - ArcDelay ¶llel_delay, - Slew ¶llel_slew); - - // [drvr_rf->index][dcalc_ap->index] - vector parallel_delays_; - // [drvr_rf->index][dcalc_ap->index] - vector parallel_slews_; - float multi_drvr_slew_factor_; + ArcDcalcResultSeq gateDelaysParallel(ArcDcalcArgSeq &dcalc_args, + float load_cap, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap); }; } // namespace diff --git a/dcalc/SlewDegradeDelayCalc.cc b/dcalc/SlewDegradeDelayCalc.cc deleted file mode 100644 index 3e00e164..00000000 --- a/dcalc/SlewDegradeDelayCalc.cc +++ /dev/null @@ -1,141 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, 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 "SlewDegradeDelayCalc.hh" - -#include "TimingArc.hh" -#include "Liberty.hh" -#include "Network.hh" -#include "Sdc.hh" -#include "Parasitics.hh" -#include "DcalcAnalysisPt.hh" -#include "LumpedCapDelayCalc.hh" - -namespace sta { - -// Liberty table model lumped capacitance arc delay calculator. -// Effective capacitance is the pi model total capacitance (C1+C2). -// Wire delays are elmore delays. -// Driver slews are degraded to loads by rise/fall transition_degradation -// tables. -class SlewDegradeDelayCalc : public LumpedCapDelayCalc -{ -public: - SlewDegradeDelayCalc(StaState *sta); - ArcDelayCalc *copy() override; - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) override; - void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) override; - void loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) override; - - using LumpedCapDelayCalc::gateDelay; - using LumpedCapDelayCalc::reportGateDelay; - -private: - const Pvt *pvt_; -}; - -ArcDelayCalc * -makeSlewDegradeDelayCalc(StaState *sta) -{ - return new SlewDegradeDelayCalc(sta); -} - -SlewDegradeDelayCalc::SlewDegradeDelayCalc(StaState *sta) : - LumpedCapDelayCalc(sta) -{ -} - -ArcDelayCalc * -SlewDegradeDelayCalc::copy() -{ - return new SlewDegradeDelayCalc(this); -} - -void -SlewDegradeDelayCalc::inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) -{ - pvt_ = dcalc_ap->operatingConditions(); - LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap); -} - -void -SlewDegradeDelayCalc::gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) -{ - input_port_ = false; - drvr_parasitic_ = drvr_parasitic; - drvr_rf_ = arc->toEdge()->asRiseFall(); - drvr_cell_ = arc->from()->libertyCell(); - drvr_library_ = drvr_cell_->libertyLibrary(); - pvt_ = pvt; - LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic, - related_out_cap, pvt, dcalc_ap, - gate_delay, drvr_slew); -} - -void -SlewDegradeDelayCalc::loadDelay(const Pin *load_pin, - ArcDelay &wire_delay, - Slew &load_slew) -{ - ArcDelay wire_delay1 = 0.0; - Slew load_slew1 = drvr_slew_; - bool elmore_exists = false; - float elmore = 0.0; - if (drvr_parasitic_) - parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists); - if (elmore_exists) { - if (drvr_library_ && drvr_library_->wireSlewDegradationTable(drvr_rf_)) { - wire_delay1 = elmore; - load_slew1 = drvr_library_->degradeWireSlew(drvr_rf_, - delayAsFloat(drvr_slew_), - delayAsFloat(wire_delay1)); - } - dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1); - } - thresholdAdjust(load_pin, wire_delay1, load_slew1); - wire_delay = wire_delay1; - load_slew = load_slew1 * multi_drvr_slew_factor_; -} - -} // namespace diff --git a/dcalc/UnitDelayCalc.cc b/dcalc/UnitDelayCalc.cc index cc629ba5..39c02fb5 100644 --- a/dcalc/UnitDelayCalc.cc +++ b/dcalc/UnitDelayCalc.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -45,86 +45,82 @@ UnitDelayCalc::findParasitic(const Pin *, return nullptr; } -ReducedParasiticType -UnitDelayCalc::reducedParasiticType() const +Parasitic * +UnitDelayCalc::reduceParasitic(const Parasitic *, + const Pin *, + const RiseFall *, + const DcalcAnalysisPt *) { - return ReducedParasiticType::none; + return nullptr; } void +UnitDelayCalc::reduceParasitic(const Parasitic *, + const Net *, + const Corner *, + const MinMaxAll *) +{ +} + +ArcDcalcResult UnitDelayCalc::inputPortDelay(const Pin *, float, const RiseFall *, const Parasitic *, - const DcalcAnalysisPt *) + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { + return unitDelayResult(load_pin_index_map); } -void -UnitDelayCalc::gateDelay(const TimingArc *, +ArcDcalcResult +UnitDelayCalc::gateDelay(const Pin *, + const TimingArc *, const Slew &, float, const Parasitic *, - float, - const Pvt *, const DcalcAnalysisPt *, - // Return values. - ArcDelay &gate_delay, Slew &drvr_slew) + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { - gate_delay = units_->timeUnit()->scale(); - drvr_slew = 0.0; + return unitDelayResult(load_pin_index_map); } -void -UnitDelayCalc::findParallelGateDelays(const MultiDrvrNet *, - GraphDelayCalc *) +ArcDcalcResultSeq +UnitDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, + float, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *) { + size_t drvr_count = dcalc_args.size(); + ArcDcalcResultSeq dcalc_results(drvr_count); + for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) { + ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx]; + dcalc_result = unitDelayResult(load_pin_index_map); + } + return dcalc_results; } -void -UnitDelayCalc::parallelGateDelay(const Pin *, - const TimingArc *, - const Slew &, - float, - const Parasitic *, - float, - const Pvt *, - const DcalcAnalysisPt *, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) +ArcDcalcResult +UnitDelayCalc::unitDelayResult(const LoadPinIndexMap &load_pin_index_map) { - gate_delay = units_->timeUnit()->scale(); - gate_slew = 0.0; -} - -void -UnitDelayCalc::loadDelay(const Pin *, - ArcDelay &wire_delay, - Slew &load_slew) -{ - wire_delay = 0.0; - load_slew = 0.0; -} - -float -UnitDelayCalc::ceff(const TimingArc *, - const Slew &, - float, - const Parasitic *, - float, - const Pvt *, - const DcalcAnalysisPt *) -{ - return 0.0; + size_t load_count = load_pin_index_map.size(); + ArcDcalcResult dcalc_result(load_count); + dcalc_result.setGateDelay(units_->timeUnit()->scale()); + dcalc_result.setDrvrSlew(0.0); + for (size_t load_idx = 0; load_idx < load_count; load_idx++) { + dcalc_result.setWireDelay(load_idx, 0.0); + dcalc_result.setLoadSlew(load_idx, 0.0); + } + return dcalc_result; } string -UnitDelayCalc::reportGateDelay(const TimingArc *, +UnitDelayCalc::reportGateDelay(const Pin *, + const TimingArc *, const Slew &, float, const Parasitic *, - float, - const Pvt *, + const LoadPinIndexMap &, const DcalcAnalysisPt *, int) { @@ -133,26 +129,24 @@ UnitDelayCalc::reportGateDelay(const TimingArc *, return result; } -void -UnitDelayCalc::checkDelay(const TimingArc *, +ArcDelay +UnitDelayCalc::checkDelay(const Pin *, + const TimingArc *, const Slew &, const Slew &, float, - const Pvt *, - const DcalcAnalysisPt *, - // Return values. - ArcDelay &margin) + const DcalcAnalysisPt *) { - margin = units_->timeUnit()->scale(); + return units_->timeUnit()->scale(); } string -UnitDelayCalc::reportCheckDelay(const TimingArc *, +UnitDelayCalc::reportCheckDelay(const Pin *, + const TimingArc *, const Slew &, const char *, const Slew &, float, - const Pvt *, const DcalcAnalysisPt *, int) { diff --git a/dcalc/UnitDelayCalc.hh b/dcalc/UnitDelayCalc.hh index 6ecae7cf..8d247f5d 100644 --- a/dcalc/UnitDelayCalc.hh +++ b/dcalc/UnitDelayCalc.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -29,72 +29,58 @@ public: Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) override; - ReducedParasiticType reducedParasiticType() const override; - void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, + Parasitic *reduceParasitic(const Parasitic *parasitic_network, + const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap) override; + void reduceParasitic(const Parasitic *parasitic_network, + const Net *net, + const Corner *corner, + const MinMaxAll *min_max) override; + ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) override; + ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + // Pass in load_cap or parasitic. + float load_cap, + const Parasitic *parasitic, + 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, + const TimingArc *arc, + const Slew &from_slew, + const Slew &to_slew, + float related_out_cap, const DcalcAnalysisPt *dcalc_ap) override; - void gateDelay(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &drvr_slew) override; - void findParallelGateDelays(const MultiDrvrNet *multi_drvr, - GraphDelayCalc *dcalc) override; - // Retrieve the delay and slew for one parallel gate. - void parallelGateDelay(const Pin *drvr_pin, + string reportGateDelay(const Pin *drvr_pin, const TimingArc *arc, - const Slew &from_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) override; - void loadDelay(const Pin *load_pin, - // Return values. - ArcDelay &wire_delay, - Slew &load_slew) override; - float ceff(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap) override; - void checkDelay(const TimingArc *arc, - const Slew &from_slew, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &margin) override; - string reportGateDelay(const TimingArc *arc, const Slew &in_slew, float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, int digits) override; - string reportCheckDelay(const TimingArc *arc, + string reportCheckDelay(const Pin *check_pin, + const TimingArc *arc, const Slew &from_slew, const char *from_slew_annotation, const Slew &to_slew, float related_out_cap, - const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, int digits) override; - void finishDrvrPin() override; + void finishDrvrPin() override; + +protected: + ArcDcalcResult unitDelayResult(const LoadPinIndexMap &load_pin_index_map); }; ArcDelayCalc * diff --git a/doc/ApiChanges.txt b/doc/ApiChanges.txt index 0b395352..7f3195ba 100644 --- a/doc/ApiChanges.txt +++ b/doc/ApiChanges.txt @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 diff --git a/doc/CLA.txt b/doc/CLA.txt new file mode 100644 index 00000000..7f479167 --- /dev/null +++ b/doc/CLA.txt @@ -0,0 +1,52 @@ +Parallax Software maintains a responsible open source policy and +promotes good practices in intellectual property management. Please +read this Agreement carefully. By submitting your Contributions (see +definition below) and clicking ["Sign in with GitHub to agree"], you +agree to all of the terms and conditions defined herein. + +Parallax Software, Inc. appreciates your willingness to grant +permission to use your software code checked directly into a source +control system that is available by GitHub Inc ("Contributions") in +conjunction with OpenSTA. By clicking ["Sign in with GitHub to +agree"], you hereby grant to Parallax Software and to recipients of +software distributed with OpenSTA a perpetual, worldwide, +non-exclusive, no-charge, royalty-free, irrevocable license to use, +make, have made, offer to sell, sell, import, reproduce, prepare +derivative works of, publicly display, publicly perform, sublicense, +and distribute your present and future Contributions and such +derivative works as part of OpenSTA. + +Nothing in this license shall constitute a copyright transfer or in +any other way infringe your rights to use your own Contributions for +any other purpose. This license is for your protection as a +Contributor as well as the protection of OpenSTA and its users. + +1. You represent and warrant that you are the sole owner of the +Contributions and/or have sufficient rights in your Contribution to +grant all rights you grant hereunder. + +2. You represent that the Contributions are your original works of +authorship, that you created the Contributions and did not copy them +from another source, and no other person claims, or has the right to +claim, any right in any invention or patent related to the +Contributions. + +3. You represent that you are legally entitled to grant the above +license. If your employer has rights to intellectual property that you +create, you represent that you have received permission to make the +Contributions on behalf of that employer, or that your employer has +waived such rights for the Contributions. + +4. Finally, it means that you have not entered into any agreements +that would prevent you from granting the rights provided in this +Agreement. + +5. You understand that the decision to include the Contribution in any +product or source repository is entirely that of Parallax Software and +this Agreement does not guarantee that the Contributions will be +included in any product, technology or services. + +If you become aware of any facts or circumstances related to the +representation above that would make these representations inaccurate +or untrue, you agree to notify Parallax Software promptly with any +details. diff --git a/doc/ChangeLog.txt b/doc/ChangeLog.txt index fea53e71..f665546c 100644 --- a/doc/ChangeLog.txt +++ b/doc/ChangeLog.txt @@ -3,6 +3,19 @@ OpenSTA Timing Analyzer Release Notes This file summarizes user visible changes for each release. +Release 2.5.0 2024/01/17 +------------------------- + +The report_net -connections, -verbose and -hier_pins flags are deprecated. +The report_instance -connections and -verbose flags are deprecated. +The options are now enabled in all cases. + +The read_spef parasitic reduction arguments have changed. The +-reduce_to and -delete_after_reduce arguments are deprecated and +replaced with the -reduce flag. With the -reduce flag, the current +delay calculator reduces the parastic network to the appropriate type +and deletes the parasitic network. + Release 2.4.0 2023/01/19 ------------------------- diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt index 95e9a184..30afc942 100644 Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ diff --git a/doc/OpenSTA.pdf b/doc/OpenSTA.pdf index 547636d4..b04d5b6e 100644 Binary files a/doc/OpenSTA.pdf and b/doc/OpenSTA.pdf differ diff --git a/doc/StaApi.txt b/doc/StaApi.txt index 5ba99a50..812db703 100644 --- a/doc/StaApi.txt +++ b/doc/StaApi.txt @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 diff --git a/doc/messages.txt b/doc/messages.txt index 9eb9087f..76d0a8be 100644 --- a/doc/messages.txt +++ b/doc/messages.txt @@ -1,511 +1,531 @@ -egrep "([eE]rror|[wW]arn)\([0-9]" */*.{cc,ll,yy} --exclude "build/*" include/sta/*.hh >doc/messages.txt -egrep "(sta_error|sta_warn) \([0-9]" */*.tcl >>doc/messages.txt -last used 593 +0100 CmdArgs.tcl:108 unsupported object type $object_type. +0101 CmdArgs.tcl:166 object '$obj' not found. +0102 CmdArgs.tcl:406 $corner_name is not the name of process corner. +0103 CmdArgs.tcl:411 -corner keyword required with multi-corner analysis. +0104 CmdArgs.tcl:425 $corner_name is not the name of process corner. +0105 CmdArgs.tcl:430 missing -corner arg. +0106 CmdArgs.tcl:441 $corner_name is not the name of process corner. +0107 CmdArgs.tcl:458 $corner_name is not the name of process corner. +0108 CmdArgs.tcl:483 both -min and -max specified. +0109 CmdArgs.tcl:497 both -min and -max specified. +0110 CmdArgs.tcl:524 only one of -early and -late can be specified. +0111 CmdArgs.tcl:530 -early or -late must be specified. +0112 CmdArgs.tcl:537 both -early and -late specified. +0113 CmdArgs.tcl:552 $arg_name must be a single library. +0114 CmdArgs.tcl:558 $arg_name type '$object_type' is not a library. +0115 CmdArgs.tcl:563 library '$arg' not found. +0116 CmdArgs.tcl:580 $arg_name must be a single lib cell. +0123 CmdArgs.tcl:667 $arg_name must be a single instance. +0124 CmdArgs.tcl:673 $arg_name type '$object_type' is not an instance. +0125 CmdArgs.tcl:678 instance '$arg' not found. +0126 CmdArgs.tcl:697 $arg_name type '$object_type' is not an instance. +0127 CmdArgs.tcl:704 instance '$arg' not found. +0131 CmdArgs.tcl:765 $arg_name type '$object_type' is not a pin or port. +0132 CmdArgs.tcl:772 pin '$arg' not found. +0133 CmdArgs.tcl:792 $arg_name type '$object_type' is not a port. +0139 CmdArgs.tcl:873 unsupported object type $object_type. +0141 CmdArgs.tcl:894 $arg_name '$object_type' is not a net. +0142 CmdArgs.tcl:918 unsupported object type $object_type. +0143 CmdArgs.tcl:899 $arg_name '$arg' not found. +0160 CmdUtil.tcl:44 no commands match '$pattern'. +0161 CmdUtil.tcl:89 Usage: $cmd $cmd_args($cmd) +0162 CmdUtil.tcl:91 Usage: $cmd argument error +0163 CmdUtil.tcl:161 unknown $unit unit '$suffix'. +0164 CmdUtil.tcl:209 unsupported object type $list_type. +0165 CmdUtil.tcl:226 unknown namespace $namespc. +0180 DelayCalc.tcl:119 delay calculator $alg not found. +0181 DelayCalc.tcl:148 $cmd missing -from argument. +0182 DelayCalc.tcl:153 $cmd missing -to argument. +0183 DelayCalc.tcl:158 $cmd delay is not a float. +0184 DelayCalc.tcl:163 set_annotated_delay -cell and -net options are mutually excluive. +0185 DelayCalc.tcl:169 $cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]. +0186 DelayCalc.tcl:174 $cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst] +0187 DelayCalc.tcl:179 $cmd -cell or -net required. +0188 DelayCalc.tcl:243 $cmd missing -from argument. +0189 DelayCalc.tcl:252 $cmd -clock must be rise or fall. +0190 DelayCalc.tcl:259 $cmd missing -to argument. +0191 DelayCalc.tcl:274 $cmd missing -setup|-hold|-recovery|-removal check type.. +0192 DelayCalc.tcl:282 $cmd check_value is not a float. +0204 ArnoldiDelayCalc.cc:606 arnoldi delay calc failed. +0210 DelayCalc.tcl:350 set_assigned_transition transition is not a float. +0220 Link.tcl:34 missing top_cell_name argument and no current_design. +0225 InternalPower.cc:192 unsupported table order +0226 InternalPower.cc:207 unsupported table axes +0230 Network.tcl:39 instance $instance_path not found. +0231 Network.tcl:212 net $net_path not found. +0232 Network.tcl:215 net $net_path not found. +0233 Network.tcl:29 report_instance -connections is deprecated. +0234 Network.tcl:32 report_instance -verbose is deprecated. +0235 Network.tcl:186 report_net -connections is deprecated. +0236 Network.tcl:189 report_net -verbose is deprecated. +0237 Network.tcl:192 report_net -hier_pins is deprecated. +0239 TableModel.cc:262 unsupported table order +0240 TableModel.cc:325 unsupported table axes +0241 TableModel.cc:546 unsupported table order +0242 TableModel.cc:564 unsupported table axes +0243 TimingArc.cc:240 timing arc max index exceeded -dcalc/ArnoldiDelayCalc.cc: criticalError(204, "arnoldi delay calc failed."); -dcalc/DmpCeff.cc: report_->warn(1, "cell %s delay model not supported on SPF parasitics by DMP delay calculator", -liberty/InternalPower.cc: criticalError(229, "unsupported table order"); -liberty/InternalPower.cc: criticalError(230, "unsupported table axes"); -liberty/Liberty.cc: criticalError(231, "unsupported slew degradation table axes"); -liberty/Liberty.cc: criticalError(232, "unsupported slew degradation table axes"); -liberty/Liberty.cc: criticalError(233, "unsupported slew degradation table order"); -liberty/Liberty.cc: criticalError(234, "unsupported slew degradation table axes"); -liberty/Liberty.cc: report->warn(2, "cell %s/%s port %s not found in cell %s/%s.", -liberty/Liberty.cc: report->warn(3, "cell %s/%s %s -> %s timing group %s not found in cell %s/%s.", -liberty/Liberty.cc: criticalError(235, "timing arc set max index exceeded"); -liberty/Liberty.cc: criticalError(205, "timing arc count mismatch"); -liberty/Liberty.cc: report->warn(4, "cell %s/%s %s -> %s latch enable %s_edge timing arc is inconsistent with %s -> %s setup_%s check.", -liberty/Liberty.cc: report->warn(5, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense.", -liberty/Liberty.cc: report->warn(6, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense.", -liberty/LibertyExpr.cc: report_->error(7, "%s references unknown port %s.", -liberty/LibertyExpr.cc: report_->error(206, "%s %s.", error_msg_, msg); -liberty/LibertyParser.cc: criticalError(236, "valueIterator called for LibertySimpleAttribute"); -liberty/LibertyParser.cc: criticalError(237, "LibertyStringAttrValue called for float value"); -liberty/LibertyParser.cc: criticalError(238, "LibertyStringAttrValue called for float value"); -liberty/LibertyParser.cc: liberty_report->fileWarn(24, liberty_filename, line, -liberty/LibertyParser.cc: sta::liberty_report->vfileError(25, sta::liberty_filename, sta::liberty_line, -liberty/LibertyParser.cc: sta::liberty_report->fileError(26, sta::liberty_filename, sta::liberty_line, -liberty/LibertyReader.cc: libWarn(53, group, "library %s already exists.", name); -liberty/LibertyReader.cc: libError(30, group, "library does not have a name."); -liberty/LibertyReader.cc: libWarn(31, group, "default_wire_load %s not found.", default_wireload_); -liberty/LibertyReader.cc: libWarn(32, group, "default_wire_selection %s not found.", -liberty/LibertyReader.cc: libWarn(33, group, "input_threshold_pct_%s not found.", tr->name()); -liberty/LibertyReader.cc: libWarn(34, group, "output_threshold_pct_%s not found.", tr->name()); -liberty/LibertyReader.cc: libWarn(35, group, "slew_lower_threshold_pct_%s not found.", tr->name()); -liberty/LibertyReader.cc: libWarn(36, group, "slew_upper_threshold_pct_%s not found.", tr->name()); -liberty/LibertyReader.cc: libError(37, group, "Library %s is missing one or more thresholds.", -liberty/LibertyReader.cc: libWarn(38, attr, "unknown unit multiplier %s.", mult_str); -liberty/LibertyReader.cc: libWarn(39, attr, "unknown unit scale %c.", scale_char); -liberty/LibertyReader.cc: libWarn(40, attr, "unknown unit suffix %s.", s + 1); -liberty/LibertyReader.cc: libWarn(41, attr, "capacitive_load_units are not ff or pf."); -liberty/LibertyReader.cc: libWarn(42, attr, "capacitive_load_units are not a string."); -liberty/LibertyReader.cc: libWarn(43, attr, "capacitive_load_units missing suffix."); -liberty/LibertyReader.cc: libWarn(44, attr, "capacitive_load_units scale is not a float."); -liberty/LibertyReader.cc: libWarn(45, attr, "capacitive_load_units missing scale and suffix."); -liberty/LibertyReader.cc: libWarn(46, attr, "capacitive_load_unit missing values suffix."); -liberty/LibertyReader.cc: libWarn(47, attr, "delay_model %s not supported.", type_name); -liberty/LibertyReader.cc: libWarn(48, attr, "delay_model %s not supported.", type_name); -liberty/LibertyReader.cc: libWarn(49, attr, "delay_model %s not supported.", type_name); -liberty/LibertyReader.cc: libWarn(50, attr, "delay_model %s not supported.\n.", type_name); -liberty/LibertyReader.cc: libWarn(51, attr, "unknown delay_model %s\n.", type_name); -liberty/LibertyReader.cc: libWarn(52, attr, "unknown bus_naming_style format."); -liberty/LibertyReader.cc: libWarn(54, attr, "voltage_map voltage is not a float."); -liberty/LibertyReader.cc: libWarn(55, attr, "voltage_map missing voltage."); -liberty/LibertyReader.cc: libWarn(56, attr, "voltage_map supply name is not a string."); -liberty/LibertyReader.cc: libWarn(57, attr, "voltage_map missing supply name and voltage."); -liberty/LibertyReader.cc: libWarn(58, attr, "voltage_map missing values suffix."); -liberty/LibertyReader.cc: libWarn(59, attr, "default_wire_load_mode %s not found.", -liberty/LibertyReader.cc: libWarn(60, attr, "default_operating_condition %s not found.", -liberty/LibertyReader.cc: libWarn(61, group, "table template does not have a name."); -liberty/LibertyReader.cc: libWarn(62, group, "missing variable_%d attribute.", index + 1); -liberty/LibertyReader.cc: libWarn(63, attr, "axis type %s not supported.", type); -liberty/LibertyReader.cc: libWarn(64, group, "bus type %s missing bit_from.", name); -liberty/LibertyReader.cc: libWarn(65, group, "bus type %s missing bit_to.", name); -liberty/LibertyReader.cc: libWarn(66, group, "type does not have a name."); -liberty/LibertyReader.cc: libWarn(67, group, "scaling_factors do not have a name."); -liberty/LibertyReader.cc: libWarn(68, group, "operating_conditions does not have a name."); -liberty/LibertyReader.cc: libWarn(69, group, "wire_load does not have a name."); -liberty/LibertyReader.cc: libWarn(70, attr, "fanout_length is missing length and fanout."); -liberty/LibertyReader.cc: libWarn(71, group, "wire_load_selection does not have a name."); -liberty/LibertyReader.cc: libWarn(72, attr, "wireload %s not found.", wireload_name); -liberty/LibertyReader.cc: libWarn(73, attr, -liberty/LibertyReader.cc: libWarn(74, attr, "wire_load_from_area min not a float."); -liberty/LibertyReader.cc: libWarn(75, attr, "wire_load_from_area max not a float."); -liberty/LibertyReader.cc: libWarn(76, attr, "wire_load_from_area missing parameters."); -liberty/LibertyReader.cc: libWarn(77, attr, "wire_load_from_area missing parameters."); -liberty/LibertyReader.cc: libWarn(78, group, "cell does not have a name."); -liberty/LibertyReader.cc: libWarn(79, group, "cell %s ocv_derate_group %s not found.", -liberty/LibertyReader.cc: libWarn(80, line, "port %s function size does not match port size.", -liberty/LibertyReader.cc: libWarn(81, line, "%s %s bus width mismatch.", type, clk_attr); -liberty/LibertyReader.cc: libWarn(82, line, "%s %s bus width mismatch.", type, data_attr); -liberty/LibertyReader.cc: libWarn(83, line, "%s %s bus width mismatch.", type, "clear"); -liberty/LibertyReader.cc: libWarn(84, line, "%s %s bus width mismatch.", type, "preset"); -liberty/LibertyReader.cc: libWarn(85, line, "latch enable function is non-unate for port %s.", -liberty/LibertyReader.cc: libWarn(86, line, "latch enable function is unknown for port %s.", -liberty/LibertyReader.cc: libWarn(87, group, "operating conditions %s not found.", op_cond_name); -liberty/LibertyReader.cc: libWarn(88, group, "scaled_cell does not have an operating condition."); -liberty/LibertyReader.cc: libWarn(89, group, "scaled_cell cell %s has not been defined.", name); -liberty/LibertyReader.cc: libWarn(90, group, "scaled_cell does not have a name."); -liberty/LibertyReader.cc: libWarn(91, group, "scaled_cell %s, %s port functions do not match cell port functions.", -liberty/LibertyReader.cc: libWarn(92, group, "scaled_cell ports do not match cell ports."); -liberty/LibertyReader.cc: libWarn(93, group, "scaled_cell %s, %s timing does not match cell timing.", -liberty/LibertyReader.cc: libWarn(94, line, "combinational timing to an input port."); -liberty/LibertyReader.cc: visitor->libWarn(95, line_, "missing %s_transition.", tr->name()); -liberty/LibertyReader.cc: visitor->libWarn(96, line_, "missing cell_%s.", tr->name()); -liberty/LibertyReader.cc: libWarn(97, timing->line(), -liberty/LibertyReader.cc: libWarn(98, power_group->line(), -liberty/LibertyReader.cc: libWarn(99, attr, "scaling_factors %s not found.", scale_factors_name); -liberty/LibertyReader.cc: libWarn(100, group, "pin name is not a string."); -liberty/LibertyReader.cc: libWarn(101, group, "pin name is not a string."); -liberty/LibertyReader.cc: libWarn(102, group, "pin name is not a string."); -liberty/LibertyReader.cc: libWarn(103, group, "bus %s bus_type not found.", group->firstName()); -liberty/LibertyReader.cc: libWarn(104, attr, "bus_type %s not found.", bus_type); -liberty/LibertyReader.cc: libWarn(105, attr, "bus_type is not a string."); -liberty/LibertyReader.cc: libWarn(106, group, "bundle %s member not found.", group->firstName()); -liberty/LibertyReader.cc: libWarn(107, attr, "member is not a string."); -liberty/LibertyReader.cc: libWarn(108, attr,"members attribute is missing values."); -liberty/LibertyReader.cc: libWarn(109, attr, "unknown port direction."); -liberty/LibertyReader.cc: libWarn(110,attr, "pulse_latch unknown pulse type."); -liberty/LibertyReader.cc: libWarn(111, attr, "unknown timing_type %s.", type_name); -liberty/LibertyReader.cc: libWarn(112, attr, "unknown timing_sense %s.", sense_name); -liberty/LibertyReader.cc: libWarn(113, attr, "mode value is not a string."); -liberty/LibertyReader.cc: libWarn(114, attr, "missing mode value."); -liberty/LibertyReader.cc: libWarn(115, attr, "mode name is not a string."); -liberty/LibertyReader.cc: libWarn(116, attr, "mode missing values."); -liberty/LibertyReader.cc: libWarn(117, attr, "mode missing mode name and value."); -liberty/LibertyReader.cc: libWarn(118, group, "unsupported model axis."); -liberty/LibertyReader.cc: libWarn(119, group, "unsupported model axis."); -liberty/LibertyReader.cc: libWarn(120, group, "unsupported model axis."); -liberty/LibertyReader.cc: libWarn(121, group, "unsupported model axis."); -liberty/LibertyReader.cc: libWarn(122, group, "table template %s not found.", template_name); -liberty/LibertyReader.cc: libWarn(123, attr, "%s is missing values.", attr->name()); -liberty/LibertyReader.cc: libWarn(124, attr, "%s is not a list of floats.", attr->name()); -liberty/LibertyReader.cc: libWarn(125, attr, "table row has %u columns but axis has %d.", -liberty/LibertyReader.cc: libWarn(126, attr, "table has %u rows but axis has %d.", -liberty/LibertyReader.cc: libWarn(127, group, "lut output is not a string."); -liberty/LibertyReader.cc: libWarn(128, group, "mode definition does not have a name."); -liberty/LibertyReader.cc: libWarn(129, group, "mode value does not have a name."); -liberty/LibertyReader.cc: libWarn(130, attr, "when attribute inside table model."); -liberty/LibertyReader.cc: libWarn(131, attr, "%s attribute is not a string.", attr->name()); -liberty/LibertyReader.cc: libWarn(132, attr, "%s is not a simple attribute.", attr->name()); -liberty/LibertyReader.cc: libWarn(132, attr, "%s attribute is not an integer.",attr->name()); -liberty/LibertyReader.cc: libWarn(133, attr, "%s is not a simple attribute.", attr->name()); -liberty/LibertyReader.cc: libWarn(134, attr, "%s is not a simple attribute.", attr->name()); -liberty/LibertyReader.cc: libWarn(135, attr, "%s value %s is not a float.", -liberty/LibertyReader.cc: libWarn(136, attr, "%s missing values.", attr->name()); -liberty/LibertyReader.cc: libWarn(137, attr, "%s missing values.", attr->name()); -liberty/LibertyReader.cc: libWarn(138, attr, "%s is not a complex attribute.", attr->name()); -liberty/LibertyReader.cc: libWarn(139, attr, "%s is not a float.", token); -liberty/LibertyReader.cc: libWarn(140, attr, "%s is missing values.", attr->name()); -liberty/LibertyReader.cc: libWarn(141, attr, "%s has more than one string.", attr->name()); -liberty/LibertyReader.cc: libWarn(142, attr, "%s is missing values.", attr->name()); -liberty/LibertyReader.cc: libWarn(143, attr, "%s attribute is not boolean.", attr->name()); -liberty/LibertyReader.cc: libWarn(144, attr, "%s attribute is not boolean.", attr->name()); -liberty/LibertyReader.cc: libWarn(145, attr, "%s is not a simple attribute.", attr->name()); -liberty/LibertyReader.cc: libWarn(146, attr, "attribute %s value %s not recognized.", -liberty/LibertyReader.cc: libWarn(147, attr, "unknown early/late value."); -liberty/LibertyReader.cc: libWarn(148, attr, "OCV derate group named %s not found.", derate_name); -liberty/LibertyReader.cc: libWarn(149, group, "ocv_derate does not have a name."); -liberty/LibertyReader.cc: libError(150, attr, "unknown rf_type."); -liberty/LibertyReader.cc: libWarn(151, attr, "unknown derate type."); -liberty/LibertyReader.cc: libWarn(152, group, "unsupported model axis."); -liberty/LibertyReader.cc: libWarn(153, group, "unsupported model axis."); -liberty/LibertyReader.cc: libWarn(154, group, "unsupported model axis."); -liberty/LibertyReader.cc: libError(155, attr, "unknown pg_type."); -liberty/LibertyReader.cc: visitor_->libWarn(156, line_, "port %s subscript out of range.", -liberty/LibertyReader.cc: visitor_->libWarn(157, line_, "port range %s of non-bus port %s.", -liberty/LibertyReader.cc: visitor_->libWarn(158, line_, "port %s not found.", port_name); -liberty/LibertyReader.cc: visitor_->libWarn(159, line_, "port %s not found.", bus_bit_name); -liberty/TableModel.cc: criticalError(239, "unsupported table order"); -liberty/TableModel.cc: criticalError(240, "unsupported table axes"); -liberty/TableModel.cc: criticalError(241, "unsupported table order"); -liberty/TableModel.cc: criticalError(242, "unsupported table axes"); -liberty/TimingArc.cc: criticalError(243, "timing arc max index exceeded\n"); -network/ConcreteNetwork.cc: report->error(8, "cell type %s can not be linked.", top_cell_name); -parasitics/SpefReader.cc: warn(167, "illegal bus delimiters."); -parasitics/SpefReader.cc: warn(168, "unknown units %s.", units); -parasitics/SpefReader.cc: warn(168, "unknown units %s.", units); -parasitics/SpefReader.cc: warn(170, "unknown units %s.", units); -parasitics/SpefReader.cc: warn(168, "unknown units %s.", units); -parasitics/SpefReader.cc: warn(169, "no name map entry for %d.", index); -parasitics/SpefReader.cc: warn(170, "unknown port direction %s.", spef_dir); -parasitics/SpefReader.cc: warn(171, "pin %s not found.", name); -parasitics/SpefReader.cc: warn(172, "instance %s not found.", name); -parasitics/SpefReader.cc: warn(173, "pin %s not found.", name); -parasitics/SpefReader.cc: warn(174, "net %s not found.", name); -parasitics/SpefReader.cc: warn(175, "%s not connected to net %s.", name, network_->pathName(net_)); -parasitics/SpefReader.cc: warn(176, "pin %s not found.", name); -parasitics/SpefReader.cc: warn(177, "node %s not a pin or net:number", name); -parasitics/SpefReader.cc: warn(178, "pin %s not found.", name); -parasitics/SpefReader.cc: sta::spef_reader->warn(179, "%s.", msg); -sdc/Clock.cc: criticalError(244, "generated clock edges size is not three."); -sdc/Sdc.cc: report_->warn(9, "No common period was found between clocks %s and %s.", -sdf/SdfReader.cc: sdfError(180, "TIMESCALE units not us, ns, or ps."); -sdf/SdfReader.cc: sdfError(181, "TIMESCALE multiplier not 1, 10, or 100."); -sdf/SdfReader.cc: sdfError(182, "pin %s is a hierarchical pin.", from_pin_name); -sdf/SdfReader.cc: sdfError(183, "pin %s is a hierarchical pin.", to_pin_name); -sdf/SdfReader.cc: sdfError(184, "INTERCONNECT from %s to %s not found.", -sdf/SdfReader.cc: sdfError(185, "pin %s not found.", from_pin_name); -sdf/SdfReader.cc: sdfError(186, "pin %s not found.", to_pin_name); -sdf/SdfReader.cc: sdfError(187, "pin %s not found.", to_pin_name); -sdf/SdfReader.cc: sdfError(188, "%s with no triples.", sdf_cmd); -sdf/SdfReader.cc: sdfError(189, "%s with more than 2 triples.", sdf_cmd); -sdf/SdfReader.cc: sdfError(190, "instance %s cell %s does not match enclosing cell %s.", -sdf/SdfReader.cc: sdfError(191, "cell %s IOPATH %s -> %s not found.", -sdf/SdfReader.cc: sdfError(192, "cell %s %s -> %s %s check not found.", -sdf/SdfReader.cc: sdfError(193, "%s not supported.", feature); -sdf/SdfReader.cc: sdfError(194, "instance %s port %s not found.", -sdf/SdfReader.cc: sdfError(195, "instance %s not found.", inst_name.c_str()); -sdf/SdfReader.cc: sta::sdf_reader->sdfError(196, "%s.\n", msg); -search/CheckTiming.cc: criticalError(245, "unknown print flag"); -search/Corner.cc: criticalError(246, "unknown parasitic analysis point count"); -search/Corner.cc: criticalError(247, "unknown analysis point count"); -search/Crpr.cc: criticalError(248, "missing prev paths"); -search/GatedClk.cc: criticalError(249, "illegal gated clock active value"); -search/Genclks.cc: report_->warn(10, "no master clock found for generated clock %s.", -search/Genclks.cc: report_->error(11, "generated clock %s is in the fanout of multiple clocks.", -search/Genclks.cc: report_->error(12, -search/Genclks.cc: report_->warn(13, "generated clock %s source pin %s missing paths from master clock %s.", -search/PathEnum.cc: criticalError(250, "diversion path not found"); -search/Sim.cc: report_->warn(15, "propagated logic value %c differs from constraint value of %c on pin %s.", -search/Sta.cc: report_->fileWarn(160, file, line, "'%s' is not a valid startpoint.", -search/Sta.cc: report_->warn(16, "'%s' is not a valid startoint.", -search/Sta.cc: report_->fileWarn(161, file, line, "'%s' is not a valid endpoint.", -search/Sta.cc: report_->warn(17, "'%s' is not a valid endpoint.", -search/VertexVisitor.cc: criticalError(266, "VertexPinCollector::copy not supported."); -search/WritePathSpice.cc: report_->error(24, "pg_pin %s/%s voltage %s not found,", -search/WritePathSpice.cc: report_->error(25, "Liberty pg_port %s/%s missing voltage_name attribute,", -search/WritePathSpice.cc: report_->error(26, "%s pg_port %s not found,", -search/WritePathSpice.cc: report_->error(27, "no register/latch found for path from %s to %s,", -search/WritePathSpice.cc: report_->error(28, "The following subkcts are missing from %s", -search/WritePathSpice.cc: report_->error(29, "subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground.", -search/WritePathSpice.cc: criticalError(267, "out of memory"); -verilog/VerilogReader.cc: warn(165, module->filename(), module->line(), -verilog/VerilogReader.cc: warn(166, module->filename(), module->line(), -verilog/VerilogReader.cc: linkWarn(197, module->filename(), module->line(), -verilog/VerilogReader.cc: reader->warn(18, filename_, dcl->line(), -verilog/VerilogReader.cc: reader->warn(19, filename_, inst->line(), -verilog/VerilogReader.cc: reader->warn(20, reader->filename(), reader->line(), -verilog/VerilogReader.cc: report->error(162, "%s is not a verilog module.", top_cell_name); -verilog/VerilogReader.cc: report->error(163, "%s is not a verilog module.", top_cell_name); -verilog/VerilogReader.cc: linkWarn(198, filename_, mod_inst->line(), -verilog/VerilogReader.cc: linkError(199, filename_, mod_inst->line(), -verilog/VerilogReader.cc: linkWarn(200, parent_module->filename(), mod_inst->line(), -verilog/VerilogReader.cc: linkWarn(201, parent_module->filename(), mod_inst->line(), -verilog/VerilogReader.cc: linkWarn(202, parent_module->filename(), mod_inst->line(), -verilog/VerilogReader.cc: linkWarn(203, module->filename(), assign->line(), -verilog/VerilogReader.cc: sta::verilog_reader->report()->fileError(164, -verilog/VerilogWriter.cc: criticalError(268, "unknown port direction"); -parasitics/SpefParse.yy: sta::spef_reader->warn(21, "%d is not positive.", value); -parasitics/SpefParse.yy: sta::spef_reader->warn(22, "%.4f is not positive.", value); -parasitics/SpefParse.yy: sta::spef_reader->warn(23, "%.4f is not positive.", value); -include/sta/ArrayTable.hh: criticalError(223, "max array table block count exceeded."); -include/sta/ArrayTable.hh: criticalError(222, "null ObjectId reference is undefined."); -include/sta/MinMaxValues.hh: criticalError(226, "uninitialized value reference"); -include/sta/ObjectTable.hh: criticalError(224, "max object table block count exceeded."); -include/sta/ObjectTable.hh: criticalError(225, "null ObjectId reference is undefined."); -dcalc/DelayCalc.tcl: sta_error 435 "delay calculator $alg not found." -parasitics/Parasitics.tcl: sta_error 433 "path instance '$path' not found." -parasitics/Parasitics.tcl: sta_error 434 "-reduce_to must be pi_elmore or pi_pole_residue2." -sdf/Sdf.tcl: sta_error 429 "-analysis_type must be single, bc_wc or on_chip_variation" -sdf/Sdf.tcl: sta_error 430 "-cond_use min_max cannot be used with analysis type single." -sdf/Sdf.tcl: sta_error 431 "$key must be sdf_min, sdf_typ, or sdf_max." -sdf/Sdf.tcl: sta_error 432 "SDF -divider must be / or ." -tcl/Cmds.tcl: sta_error 439 "unsupported object type $list_type." -tcl/Cmds.tcl: sta_error 440 "-from/-to arguments not supported with -of_objects." -tcl/Cmds.tcl: sta_error 441 "unsupported -filter expression." -tcl/Cmds.tcl: sta_error 442 "$cmd missing -from argument." -tcl/Cmds.tcl: sta_error 443 "$cmd missing -to argument." -tcl/Cmds.tcl: sta_error 444 "$cmd delay is not a float." -tcl/Cmds.tcl: sta_error 445 "set_annotated_delay -cell and -net options are mutually excluive." -tcl/Cmds.tcl: sta_error 446 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]." -tcl/Cmds.tcl: sta_error 447 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]" -tcl/Cmds.tcl: sta_error 448 "$cmd -cell or -net required." -tcl/Cmds.tcl: sta_error 449 "$cmd missing -from argument." -tcl/Cmds.tcl: sta_error 450 "$cmd -clock must be rise or fall." -tcl/Cmds.tcl: sta_error 451 "$cmd missing -to argument." -tcl/Cmds.tcl: sta_error 452 "$cmd missing -setup|-hold|-recovery|-removal check type.." -tcl/Cmds.tcl: sta_error 453 "$cmd check_value is not a float." -tcl/Cmds.tcl: sta_error 454 "the -all and -name options are mutually exclusive." -tcl/Cmds.tcl: sta_error 455 "either -all or -name options must be specified." -tcl/Cmds.tcl: sta_error 456 "one of -logically_exclusive, -physically_exclusive or -asynchronous is required." -tcl/Cmds.tcl: sta_error 457 "the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive." -tcl/Cmds.tcl: sta_warn 303 "-clock ignored for clock objects." -tcl/Cmds.tcl: sta_error 458 "-source '[$pin path_name]' is not a clock pin." -tcl/Cmds.tcl: sta_error 459 "-from/-to must be used together." -tcl/Cmds.tcl: sta_error 460 "-rise, -fall options not allowed for single clock uncertainty." -tcl/Cmds.tcl: sta_error 461 "missing -from, -rise_from or -fall_from argument." -tcl/Cmds.tcl: sta_error 462 "missing -to, -rise_to or -fall_to argument." -tcl/Cmds.tcl: sta_warn 304 "-from/-to keywords ignored for lib_pin, port and pin arguments." -tcl/Cmds.tcl: sta_error 463 "-from/-to hierarchical instance not supported." -tcl/Cmds.tcl: sta_error 464 "$cmd command failed." -tcl/Cmds.tcl: sta_error 465 "positional arguments not supported." -tcl/Cmds.tcl: sta_error 466 "-from, -through or -to required." -tcl/Cmds.tcl: sta_error 467 "unsupported object type $object_type." -tcl/Cmds.tcl: sta_warn 305 "object '$obj' not found." -tcl/Cmds.tcl: sta_error 468 "$corner_name is not the name of process corner." -tcl/Cmds.tcl: sta_error 469 "-corner keyword required with multi-corner analysis." -tcl/Cmds.tcl: sta_error 470 "$corner_name is not the name of process corner." -tcl/Cmds.tcl: sta_error 471 "missing -corner arg." -tcl/Cmds.tcl: sta_error 472 "$corner_name is not the name of process corner." -tcl/Cmds.tcl: sta_error 473 "$corner_name is not the name of process corner." -tcl/Cmds.tcl: sta_error 474 "both -min and -max specified." -tcl/Cmds.tcl: sta_error 475 "both -min and -max specified." -tcl/Cmds.tcl: sta_error 476 "only one of -early and -late can be specified." -tcl/Cmds.tcl: sta_error 477 "-early or -late must be specified." -tcl/Cmds.tcl: sta_error 478 "both -early and -late specified." -tcl/Cmds.tcl: sta_error 479 "$arg_name must be a single library." -tcl/Cmds.tcl: sta_error 480 "$arg_name type '$object_type' is not a library." -tcl/Cmds.tcl: sta_error 481 "library '$arg' not found." -tcl/Cmds.tcl: sta_error 482 "$arg_name must be a single lib cell." -tcl/Cmds.tcl: sta_error 483 "$arg_name must be a single instance." -tcl/Cmds.tcl: sta_error 484 "$arg_name type '$object_type' is not an instance." -tcl/Cmds.tcl: sta_error 485 "instance '$arg' not found." -tcl/Cmds.tcl: sta_error 486 "$arg_name type '$object_type' is not an instance." -tcl/Cmds.tcl: sta_error 487 "instance '$arg' not found." -tcl/Cmds.tcl: sta_error 488 "$arg_name type '$object_type' is not a pin or port." -tcl/Cmds.tcl: sta_error 489 "pin '$arg' not found." -tcl/Cmds.tcl: sta_error 490 "$arg_name type '$object_type' is not a port." -tcl/Cmds.tcl: sta_warn 313 "unsupported object type $object_type." -tcl/Cmds.tcl: sta_warn 314"$arg_name must be a single net." -tcl/Cmds.tcl: sta_warn 315 "$arg_name '$object_type' is not a net." -tcl/Cmds.tcl: sta_warn 316 "$arg_name '$arg' not found." -tcl/Cmds.tcl: sta_error 491 "$cmd object is null." -tcl/Cmds.tcl: sta_error 492 "$cmd $type_key must be specified with object name argument." -tcl/Cmds.tcl: sta_error 492 "get_property unsupported object type $object_type." -tcl/Cmds.tcl: sta_error 493 "get_property $object is not an object." -tcl/Cmds.tcl: sta_error 494 "$object_type not supported." -tcl/Cmds.tcl: sta_error 495 "$object_type '$object_name' not found." -tcl/Cmds.tcl: sta_error 496 "Directory $spice_dir not found.\n" -tcl/Cmds.tcl: sta_error 497 "$spice_dir is not a directory.\n" -tcl/Cmds.tcl: sta_error 498 "Cannot write in $spice_dir.\n" -tcl/Cmds.tcl: sta_error 499 "No -spice_directory specified.\n" -tcl/Cmds.tcl: sta_error 500 "-lib_subckt_file $lib_subckt_file is not readable.\n" -tcl/Cmds.tcl: sta_error 501 "No -lib_subckt_file specified.\n" -tcl/Cmds.tcl: sta_error 502 "-model_file $model_file is not readable.\n" -tcl/Cmds.tcl: sta_error 503 "No -model_file specified.\n" -tcl/Cmds.tcl: sta_error 504 "No -power specified.\n" -tcl/Cmds.tcl: sta_error 505 "No -ground specified.\n" -tcl/Cmds.tcl: sta_error 506 "No -path_args specified.\n" -tcl/Cmds.tcl: sta_error 507 "No paths found for -path_args $path_args.\n" -tcl/Link.tcl: sta_error 593 "missing top_cell_name argument and no current_design." -tcl/Network.tcl: sta_error 589 "unknown namespace $namespc." -tcl/Network.tcl: sta_error 590 "instance $instance_path not found." -tcl/Network.tcl: sta_error 591 "net $net_path not found." -tcl/Network.tcl: sta_error 592 "net $net_path not found." -tcl/NetworkEdit.tcl: sta_error 586 "unsupported object type $object_type." -tcl/NetworkEdit.tcl: sta_warn 372 "connect_pins is deprecated. Use connect_pin." -tcl/NetworkEdit.tcl: sta_error 587 "unsupported object type $object_type." -tcl/NetworkEdit.tcl: sta_error 588 "unsupported object type $object_type." -tcl/NetworkEdit.tcl: sta_warn 372 "disconnect_pins is deprecated. Use disconnect_pin." -tcl/Power.tcl: sta_warn 301 "activity should be 0.0 to 1.0 or 2.0" -tcl/Power.tcl: sta_warn 302 "duty should be 0.0 to 1.0" -tcl/Sdc.tcl: sta_error 511 "cannot open '$filename'." -tcl/Sdc.tcl: sta_error 512 "incomplete command at end of file." -tcl/Sdc.tcl: sta_error 513 "hierarchy separator must be one of '$sdc_dividers'." -tcl/Sdc.tcl: sta_error 514 "unknown unit $unit '$suffix'." -tcl/Sdc.tcl: sta_error 514 "unknown $unit prefix '$prefix'." -tcl/Sdc.tcl: sta_warn 319 "$unit scale [format %.0e $scale] does not match library scale [format %.0e $unit_scale]." -tcl/Sdc.tcl: sta_error 515 "unknown $unit unit '$suffix'." -tcl/Sdc.tcl: sta_warn 320 "current_design for other than top cell not supported." -tcl/Sdc.tcl: sta_warn 321 "patterns argument not supported with -of_objects." -tcl/Sdc.tcl: sta_warn 322 "instance '$pattern' not found." -tcl/Sdc.tcl: sta_error 516 "unsupported -filter expression." -tcl/Sdc.tcl: sta_warn 323 "clock '$pattern' not found." -tcl/Sdc.tcl: sta_warn 324 "positional arguments not supported with -of_objects." -tcl/Sdc.tcl: sta_warn 325 "library '$lib_name' not found." -tcl/Sdc.tcl: sta_warn 326 "cell '$cell_pattern' not found." -tcl/Sdc.tcl: sta_warn 327 "library/cell/port '$pattern' not found." -tcl/Sdc.tcl: sta_warn 328 "port '$port_pattern' not found." -tcl/Sdc.tcl: sta_warn 329 "library '$lib_name' not found." -tcl/Sdc.tcl: sta_warn 330 "-nocase ignored without -regexp." -tcl/Sdc.tcl: sta_warn 331 "library '$pattern' not found." -tcl/Sdc.tcl: sta_warn 332 "patterns argument not supported with -of_objects." -tcl/Sdc.tcl: sta_warn 333 "net '$pattern' not found." -tcl/Sdc.tcl: sta_warn 334 "patterns argument not supported with -of_objects." -tcl/Sdc.tcl: sta_warn 335 "pin '$pattern' not found." -tcl/Sdc.tcl: sta_error 517 "unsupported -filter expression." -tcl/Sdc.tcl: sta_warn 336 "patterns argument not supported with -of_objects." -tcl/Sdc.tcl: sta_warn 337 "port '$pattern' not found." -tcl/Sdc.tcl: sta_error 518 "unsupported -filter expression." -tcl/Sdc.tcl: sta_error 519 "-add requires -name." -tcl/Sdc.tcl: sta_error 520 "-name or port_pin_list must be specified." -tcl/Sdc.tcl: sta_error 521 "missing -period argument." -tcl/Sdc.tcl: sta_error 522 "-waveform edge_list must have an even number of edge times." -tcl/Sdc.tcl: sta_warn 338 "adjusting non-increasing clock -waveform edge times." -tcl/Sdc.tcl: sta_warn 339 "-waveform time greater than two periods." -tcl/Sdc.tcl: sta_error 523 "empty ports/pins/nets argument." -tcl/Sdc.tcl: sta_error 524 "-add requires -name." -tcl/Sdc.tcl: sta_error 525 "name or port_pin_list must be specified." -tcl/Sdc.tcl: sta_error 526 "missing -source argument." -tcl/Sdc.tcl: sta_error 527 "-master_clock argument empty." -tcl/Sdc.tcl: sta_error 528 "-add requireds -master_clock." -tcl/Sdc.tcl: sta_error 529 "-multiply_by and -divide_by options are exclusive." -tcl/Sdc.tcl: sta_error 530 "-divide_by is not an integer greater than one." -tcl/Sdc.tcl: sta_error 531 "-combinational implies -divide_by 1." -tcl/Sdc.tcl: sta_error 532 "-multiply_by is not an integer greater than one." -tcl/Sdc.tcl: sta_error 533 "-duty_cycle is not a float between 0 and 100." -tcl/Sdc.tcl: sta_error 534 "-edges only supported for three edges." -tcl/Sdc.tcl: sta_error 535 "edges times are not monotonically increasing." -tcl/Sdc.tcl: sta_error 536 "-edge_shift length does not match -edges length." -tcl/Sdc.tcl: sta_error 537 "missing -multiply_by, -divide_by, -combinational or -edges argument." -tcl/Sdc.tcl: sta_error 538 "cannot specify -invert without -multiply_by, -divide_by or -combinational." -tcl/Sdc.tcl: sta_error 539 "-duty_cycle requires -multiply_by value." -tcl/Sdc.tcl: sta_error 540 "missing -pll_output argument." -tcl/Sdc.tcl: sta_error 541 "missing -pll_feedback argument." -tcl/Sdc.tcl: sta_error 542 "PLL output and feedback pins must be on the same instance." -tcl/Sdc.tcl: sta_error 543 "source pin must be on the same instance as the PLL output pin." -tcl/Sdc.tcl: sta_error 544 "PLL output must be one of the clock pins." -tcl/Sdc.tcl: sta_error 545 "group_path command failed." -tcl/Sdc.tcl: sta_error 546 "positional arguments not supported." -tcl/Sdc.tcl: sta_error 547 "-from, -through or -to required." -tcl/Sdc.tcl: sta_error 548 "-name and -default are mutually exclusive." -tcl/Sdc.tcl: sta_error 549 "-name or -default option is required." -tcl/Sdc.tcl: sta_error 550 "cannot specify both -high and -low." -tcl/Sdc.tcl: sta_error 551 "missing -setup or -hold argument." -tcl/Sdc.tcl: sta_error 552 "-high and -low only permitted for pins and instances." -tcl/Sdc.tcl: sta_error 553 "-high and -low only permitted for pins and instances." -tcl/Sdc.tcl: sta_error 554 "one of -logically_exclusive, -physically_exclusive or -asynchronous is required." -tcl/Sdc.tcl: sta_error 555 "the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive." -tcl/Sdc.tcl: sta_warn 349 "unknown keyword argument $arg." -tcl/Sdc.tcl: sta_warn 341 "extra positional argument $arg." -tcl/Sdc.tcl: sta_warn 342 "-clock ignored for clock objects." -tcl/Sdc.tcl: sta_error 556 "-source '[get_full_name $pin]' is not a clock pin." -tcl/Sdc.tcl: sta_error 557 "-early/-late is only allowed with -source." -tcl/Sdc.tcl: sta_warn 343 "set_sense -type data not supported." -tcl/Sdc.tcl: sta_error 558 "set_sense -type clock|data" -tcl/Sdc.tcl: sta_warn 344 "set_clock_sense is deprecated as of SDC 2.1. Use set_sense -type clock." -tcl/Sdc.tcl: sta_warn 345 "-pulse argument not supported." -tcl/Sdc.tcl: sta_warn 346 "-positive, -negative, -stop_propagation and -pulse are mutually exclusive." -tcl/Sdc.tcl: sta_warn 347 "hierarchical pin '[get_full_name $pin]' not supported." -tcl/Sdc.tcl: sta_error 559 "transition time can not be specified for virtual clocks." -tcl/Sdc.tcl: sta_error 560 "missing uncertainty value." -tcl/Sdc.tcl: sta_error 561 "-from/-to must be used together." -tcl/Sdc.tcl: sta_error 562 "-rise, -fall options not allowed for single clock uncertainty." -tcl/Sdc.tcl: sta_error 563 "missing -from, -rise_from or -fall_from argument." -tcl/Sdc.tcl: sta_error 564 "missing -to, -rise_to or -fall_to argument." -tcl/Sdc.tcl: sta_warn 348 "-from/-to keywords ignored for lib_pin, port and pin arguments." -tcl/Sdc.tcl: sta_error 565 "-from/-to hierarchical instance not supported." -tcl/Sdc.tcl: sta_error 566 "pin '[get_full_name $inst]${hierarchy_separator}${port_name}' not found." -tcl/Sdc.tcl: sta_error 567 "pin '[get_name $cell]${hierarchy_separator}${port_name}' not found." -tcl/Sdc.tcl: sta_warn 349 "'$args' ignored." -tcl/Sdc.tcl: sta_warn 350 "-from, -through or -to required." -tcl/Sdc.tcl: sta_warn 351 "-source_latency_included ignored with -reference_pin." -tcl/Sdc.tcl: sta_warn 352 "-network_latency_included ignored with -reference_pin." -tcl/Sdc.tcl: sta_warn 353 "$cmd not allowed on [pin_direction $pin] port '[get_full_name $pin]'." -tcl/Sdc.tcl: sta_warn 354 "$cmd relative to a clock defined on the same port/pin not allowed." -tcl/Sdc.tcl: sta_error 568 "missing delay argument." -tcl/Sdc.tcl: sta_warn 355 "'$args' ignored." -tcl/Sdc.tcl: sta_error 569 "missing path multiplier argument." -tcl/Sdc.tcl: sta_warn 356 "'$args' ignored." -tcl/Sdc.tcl: sta_error 570 "cannot use -start with -end." -tcl/Sdc.tcl: sta_warn 357 "virtual clock [get_name $clk] can not be propagated." -tcl/Sdc.tcl: sta_error 571 "value must be 0, zero, 1, one, rise, rising, fall, or falling." -tcl/Sdc.tcl: sta_error 572 "cell '$lib_name:$cell_name' not found." -tcl/Sdc.tcl: sta_error 573 "'$cell_name' not found." -tcl/Sdc.tcl: sta_error 574 "missing -lib_cell argument." -tcl/Sdc.tcl: sta_error 575 "port '$to_port_name' not found." -tcl/Sdc.tcl: sta_error 576 "-pin argument required for cells with multiple outputs." -tcl/Sdc.tcl: sta_error 577 "port '$from_port_name' not found." -tcl/Sdc.tcl: sta_warn 358 "-multiply_by ignored." -tcl/Sdc.tcl: sta_warn 359 "-dont_scale ignored." -tcl/Sdc.tcl: sta_warn 360 "-no_design_rule ignored." -tcl/Sdc.tcl: sta_warn 361 "set_fanout_load not supported." -tcl/Sdc.tcl: sta_warn 361 "-clock not supported." -tcl/Sdc.tcl: sta_warn 362 "-clock_fall not supported." -tcl/Sdc.tcl: sta_warn 363 "-pin_load not allowed for net objects." -tcl/Sdc.tcl: sta_warn 364 "-wire_load not allowed for net objects." -tcl/Sdc.tcl: sta_warn 365 "-rise/-fall not allowed for net objects." -tcl/Sdc.tcl: sta_error 578 "port '[get_name $port]' is not an input." -tcl/Sdc.tcl: sta_warn 366 "-data_path, -clock_path, -rise, -fall ignored for ports and designs." -tcl/Sdc.tcl: sta_warn 367 "derating factor greater than 2.0." -tcl/Sdc.tcl: sta_warn 368 "-cell_delay and -cell_check flags ignored for net objects." -tcl/Sdc.tcl: sta_warn 369 "no valid objects specified for $key." -tcl/Sdc.tcl: sta_warn 370 "no valid objects specified for $key" -tcl/Sdc.tcl: sta_warn 370 "no valid objects specified for $key." -tcl/Sdc.tcl: sta_error 579 "operating condition '$op_cond_name' not found." -tcl/Sdc.tcl: sta_error 580 "operating condition '$op_cond_name' not found." -tcl/Sdc.tcl: sta_error 581 "-analysis_type must be single, bc_wc or on_chip_variation." -tcl/Sdc.tcl: sta_warn 371 "set_wire_load_min_block_size not supported." -tcl/Sdc.tcl: sta_error 582 "mode must be top, enclosed or segmented." -tcl/Sdc.tcl: sta_error 583 "no wire load model specified." -tcl/Sdc.tcl: sta_error 583 "wire load model '$model_name' not found." -tcl/Sdc.tcl: sta_error 584 "wire load selection group '$selection_name' not found." -tcl/Sdc.tcl: sta_error 585 "no default operating conditions found." -tcl/Search.tcl: sta_error 508 "-min and -max cannot both be specified." -tcl/Search.tcl: sta_error 509 "pin '$pin_arg' is hierarchical." -tcl/Search.tcl: sta_error 510 "-format $format not recognized." -tcl/Search.tcl: sta_warn 318 "unknown path group '$name'." -tcl/Sta.tcl: sta_error 419 "report_clock_skew -setup and -hold are mutually exclusive options." -tcl/Sta.tcl: sta_error 420 "$cmd -path_delay must be min, min_rise, min_fall, max, max_rise, max_fall or min_max." -tcl/Sta.tcl: sta_error 421 "$cmd command failed." -tcl/Sta.tcl: sta_error 422 "-endpoint_count must be a positive integer." -tcl/Sta.tcl: sta_error 423 "-group_count must be a positive integer." -tcl/Sta.tcl: sta_error 424 "'$arg' is not a known keyword or flag." -tcl/Sta.tcl: sta_error 425 "positional arguments not supported." -tcl/Sta.tcl: sta_error 426 "analysis type single is not consistent with doing both setup/max and hold/min checks." -tcl/Sta.tcl: sta_error 427 "positional arguments not supported." -tcl/Sta.tcl: sta_error 428 "set_assigned_transition transition is not a float." -tcl/Util.tcl: sta_error 400 "$cmd $key missing value." -tcl/Util.tcl: sta_error 401 "$cmd $key missing value." -tcl/Util.tcl: sta_error 402 "$cmd $arg is not a known keyword or flag." -tcl/Util.tcl: sta_error 403 "$cmd $arg is not a known keyword or flag." -tcl/Util.tcl: sta_error 404 "Usage: $cmd $cmd_args($cmd)" -tcl/Util.tcl: sta_error 405 "Usage: $cmd argument error" -tcl/Util.tcl: sta_warn 300 "no commands match '$pattern'." -tcl/Util.tcl: sta_error 406 "$cmd positional arguments not supported." -tcl/Util.tcl: sta_error 407 "$cmd requires one positional argument." -tcl/Util.tcl: sta_error 408 "$cmd requires zero or one positional arguments." -tcl/Util.tcl: sta_error 409 "$cmd requires two positional arguments." -tcl/Util.tcl: sta_error 410 "$cmd requires one or two positional arguments." -tcl/Util.tcl: sta_error 411 "$cmd requires three positional arguments." -tcl/Util.tcl: sta_error 412 "$cmd requires four positional arguments." -tcl/Util.tcl: sta_error 413 "$cmd_arg '$arg' is not a float." -tcl/Util.tcl: sta_error 414 "$cmd_arg '$arg' is not a positive float." -tcl/Util.tcl: sta_error 415 "$cmd_arg '$arg' is not an integer." -tcl/Util.tcl: sta_error 416 "$cmd_arg '$arg' is not a positive integer." -tcl/Util.tcl: sta_error 417 "$cmd_arg '$arg' is not an integer greater than or equal to one." -tcl/Util.tcl: sta_error 418 "$cmd_arg '$arg' is not between 0 and 100." -tcl/Variables.tcl: sta_error 436 "sta_report_default_digits must be a positive integer." -tcl/Variables.tcl: sta_error 437 "sta_crpr_mode must be pin or transition." -tcl/Variables.tcl: sta_error 438 "$var_name value must be 0 or 1." +0244 Clock.cc:474 generated clock edges size is not three. +0245 CheckTiming.cc:425 unknown print flag +0246 Corner.cc:377 unknown parasitic analysis point count +0247 Corner.cc:421 unknown analysis point count +0248 Crpr.cc:73 missing prev paths +0249 GatedClk.cc:247 illegal gated clock active value +0250 NetworkEdit.tcl:107 unsupported object type $object_type. +0251 NetworkEdit.tcl:137 connect_pins is deprecated. Use connect_pin. +0252 NetworkEdit.tcl:206 unsupported object type $object_type. +0253 NetworkEdit.tcl:224 unsupported object type $object_type. +0266 VertexVisitor.cc:32 VertexPinCollector::copy not supported. +0267 WritePathSpice.cc:1876 out of memory +0268 VerilogWriter.cc:223 unknown port direction +0269 StaTcl.i:834 unknown namespace +0270 StaTcl.i:1356 unknown analysis type +0271 StaTcl.i:1507 unknown wire load mode +0272 Parasitics.tcl:40 read_spef -quiet is deprecated. +0273 Parasitics.tcl:43 read_spef -reduce_to is deprecated. Use -reduce instead. +0274 Parasitics.tcl:47 read_spef -delete_after_reduce is deprecated. +0275 Parasitics.tcl:50 read_spef -save is deprecated. +0276 Parasitics.tcl:58 path instance '$path' not found. +0280 PathEnum.cc:569 diversion path not found +0301 Power.tcl:220 activity should be 0.0 to 1.0 or 2.0 +0302 Power.tcl:228 duty should be 0.0 to 1.0 +0303 Power.tcl:243 activity cannot be set on clock ports. +0320 Property.tcl:32 $cmd object is null. +0321 Property.tcl:37 $cmd $type_key must be specified with object name argument. +0322 Property.tcl:77 get_property unsupported object type $object_type. +0323 Property.tcl:80 get_property $object is not an object. +0324 Property.tcl:107 $object_type not supported. +0325 Property.tcl:110 $object_type '$object_name' not found. +0340 Sdc.tcl:73 cannot open '$filename'. +0341 Sdc.tcl:128 incomplete command at end of file. +0342 Sdc.tcl:212 hierarchy separator must be one of '$sdc_dividers'. +0343 Sdc.tcl:259 unknown unit $unit '$suffix'. +0344 Sdc.tcl:281 unknown $unit prefix '$prefix'. +0345 Sdc.tcl:288 $unit scale [format %.0e $scale] does not match library scale [format %.0e $unit_scale]. +0346 Sdc.tcl:394 only one of -cells, -data_pins, -clock_pins, -async_pins, -output_pins are suppported. +0347 Sdc.tcl:437 current_design for other than top cell not supported. +0348 Sdc.tcl:473 patterns argument not supported with -of_objects. +0349 Sdc.tcl:506 instance '$pattern' not found. +0350 Sdc.tcl:539 unsupported instance -filter expression. +0351 Sdc.tcl:566 clock '$pattern' not found. +0352 Sdc.tcl:592 positional arguments not supported with -of_objects. +0353 Sdc.tcl:619 library '$lib_name' not found. +0354 Sdc.tcl:631 cell '$cell_pattern' not found. +0355 Sdc.tcl:678 library/cell/port '$pattern' not found. +0356 Sdc.tcl:698 port '$port_pattern' not found. +0357 Sdc.tcl:703 library '$lib_name' not found. +0358 Sdc.tcl:713 -nocase ignored without -regexp. +0359 Sdc.tcl:739 library '$pattern' not found. +0360 Sdc.tcl:802 patterns argument not supported with -of_objects. +0361 Sdc.tcl:826 net '$pattern' not found. +0362 Sdc.tcl:855 patterns argument not supported with -of_objects. +0363 Sdc.tcl:892 pin '$pattern' not found. +0364 Sdc.tcl:924 unsupported pin -filter expression. +0365 Sdc.tcl:949 patterns argument not supported with -of_objects. +0366 Sdc.tcl:963 port '$pattern' not found. +0367 Sdc.tcl:1000 unsupported port -filter expression. +0368 Sdc.tcl:1033 -add requires -name. +0369 Sdc.tcl:1038 -name or port_pin_list must be specified. +0370 Sdc.tcl:1046 missing -period argument. +0371 Sdc.tcl:1052 -waveform edge_list must have an even number of edge times. +0372 Sdc.tcl:1061 non-increasing clock -waveform edge times. +0373 Sdc.tcl:1064 -waveform time greater than two periods. +0374 Sdc.tcl:1122 empty ports/pins/nets argument. +0375 Sdc.tcl:1130 -add requires -name. +0376 Sdc.tcl:1135 name or port_pin_list must be specified. +0377 Sdc.tcl:1142 missing -source argument. +0378 Sdc.tcl:1157 -master_clock argument empty. +0379 Sdc.tcl:1160 -add requireds -master_clock. +0380 Sdc.tcl:1164 -multiply_by and -divide_by options are exclusive. +0381 Sdc.tcl:1168 -divide_by is not an integer greater than one. +0382 Sdc.tcl:1171 -combinational implies -divide_by 1. +0383 Sdc.tcl:1176 -multiply_by is not an integer greater than one. +0384 Sdc.tcl:1182 -duty_cycle is not a float between 0 and 100. +0385 Sdc.tcl:1188 -edges only supported for three edges. +0386 Sdc.tcl:1194 edges times are not monotonically increasing. +0387 Sdc.tcl:1203 -edge_shift length does not match -edges length. +0388 Sdc.tcl:1209 missing -multiply_by, -divide_by, -combinational or -edges argument. +0389 Sdc.tcl:1217 cannot specify -invert without -multiply_by, -divide_by or -combinational. +0390 Sdc.tcl:1223 -duty_cycle requires -multiply_by value. +0391 Sdc.tcl:1283 group_path command failed. +0392 Sdc.tcl:1290 positional arguments not supported. +0393 Sdc.tcl:1294 -from, -through or -to required. +0394 Sdc.tcl:1300 -name and -default are mutually exclusive. +0395 Sdc.tcl:1302 -name or -default option is required. +0396 Sdc.tcl:1343 cannot specify both -high and -low. +0397 Sdc.tcl:1351 missing -setup or -hold argument. +0398 Sdc.tcl:1365 -high and -low only permitted for pins and instances. +0399 Sdc.tcl:1372 -high and -low only permitted for pins and instances. +0400 Sdc.tcl:1415 one of -logically_exclusive, -physically_exclusive or -asynchronous is required. +0401 Sdc.tcl:1418 the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive. +0402 Sdc.tcl:1437 unknown keyword argument $arg. +0403 Sdc.tcl:1439 extra positional argument $arg. +0404 Sdc.tcl:1468 the -all and -name options are mutually exclusive. +0405 Sdc.tcl:1471 either -all or -name options must be specified. +0406 Sdc.tcl:1479 one of -logically_exclusive, -physically_exclusive or -asynchronous is required. +0407 Sdc.tcl:1482 the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive. +0408 Sdc.tcl:1532 -clock ignored for clock objects. +0409 Sdc.tcl:1546 -source '[get_full_name $pin]' is not a clock pin. +0410 Sdc.tcl:1553 -early/-late is only allowed with -source. +0411 Sdc.tcl:1582 -clock ignored for clock objects. +0412 Sdc.tcl:1594 -source '[$pin path_name]' is not a clock pin. +0413 Sdc.tcl:1622 set_sense -type data not supported. +0414 Sdc.tcl:1626 set_sense -type clock|data +0415 Sdc.tcl:1637 set_clock_sense is deprecated as of SDC 2.1. Use set_sense -type clock. +0416 Sdc.tcl:1649 -pulse argument not supported. +0417 Sdc.tcl:1658 -positive, -negative, -stop_propagation and -pulse are mutually exclusive. +0418 Sdc.tcl:1671 hierarchical pin '[get_full_name $pin]' not supported. +0419 Sdc.tcl:1695 transition time can not be specified for virtual clocks. +0420 Sdc.tcl:1728 missing uncertainty value. +0421 Sdc.tcl:1776 -from/-to must be used together. +0422 Sdc.tcl:1796 -rise, -fall options not allowed for single clock uncertainty. +0423 Sdc.tcl:1862 -from/-to must be used together. +0424 Sdc.tcl:1882 -rise, -fall options not allowed for single clock uncertainty. +0425 Sdc.tcl:1923 missing -from, -rise_from or -fall_from argument. +0426 Sdc.tcl:1935 missing -to, -rise_to or -fall_to argument. +0427 Sdc.tcl:1983 missing -from, -rise_from or -fall_from argument. +0428 Sdc.tcl:1995 missing -to, -rise_to or -fall_to argument. +0429 Sdc.tcl:2037 -from/-to keywords ignored for lib_pin, port and pin arguments. +0430 Sdc.tcl:2067 -from/-to hierarchical instance not supported. +0431 Sdc.tcl:2099 pin '[get_full_name $inst]${hierarchy_separator}${port_name}' not found. +0432 Sdc.tcl:2140 pin '[get_name $cell]${hierarchy_separator}${port_name}' not found. +0434 Sdc.tcl:2174 -from/-to keywords ignored for lib_pin, port and pin arguments. +0435 Sdc.tcl:2226 -from/-to hierarchical instance not supported. +0436 Sdc.tcl:2280 '$args' ignored. +0437 Sdc.tcl:2284 -from, -through or -to required. +0438 Sdc.tcl:2363 -source_latency_included ignored with -reference_pin. +0439 Sdc.tcl:2366 -network_latency_included ignored with -reference_pin. +0440 Sdc.tcl:2385 $cmd not allowed on [pin_direction $pin] port '[get_full_name $pin]'. +0441 Sdc.tcl:2387 $cmd relative to a clock defined on the same port/pin not allowed. +0442 Sdc.tcl:2435 missing delay argument. +0443 Sdc.tcl:2441 '$args' ignored. +0444 Sdc.tcl:2566 missing path multiplier argument. +0445 Sdc.tcl:2571 '$args' ignored. +0446 Sdc.tcl:2578 cannot use -start with -end. +0447 Sdc.tcl:2628 $cmd command failed. +0448 Sdc.tcl:2635 positional arguments not supported. +0449 Sdc.tcl:2639 -from, -through or -to required. +0450 Sdc.tcl:2706 virtual clock [get_name $clk] can not be propagated. +0451 Sdc.tcl:2748 value must be 0, zero, 1, one, rise, rising, fall, or falling. +0452 Sdc.tcl:2817 cell '$lib_name:$cell_name' not found. +0453 Sdc.tcl:2823 '$cell_name' not found. +0454 Sdc.tcl:2827 missing -lib_cell argument. +0455 Sdc.tcl:2835 port '$to_port_name' not found. +0456 Sdc.tcl:2847 -pin argument required for cells with multiple outputs. +0457 Sdc.tcl:2862 port '$from_port_name' not found. +0458 Sdc.tcl:2880 -multiply_by ignored. +0459 Sdc.tcl:2883 -dont_scale ignored. +0460 Sdc.tcl:2886 -no_design_rule ignored. +0461 Sdc.tcl:2909 set_fanout_load not supported. +0462 Sdc.tcl:2933 -clock not supported. +0463 Sdc.tcl:2936 -clock_fall not supported. +0464 Sdc.tcl:2982 -pin_load not allowed for net objects. +0465 Sdc.tcl:2985 -wire_load not allowed for net objects. +0466 Sdc.tcl:2988 -rise/-fall not allowed for net objects. +0467 Sdc.tcl:3075 port '[get_name $port]' is not an input. +0468 Sdc.tcl:3121 -data_path, -clock_path, -rise, -fall ignored for ports and designs. +0469 Sdc.tcl:3192 derating factor greater than 2.0. +0470 Sdc.tcl:3229 -cell_delay and -cell_check flags ignored for net objects. +0471 Sdc.tcl:3299 no valid objects specified for $key. +0472 Sdc.tcl:3332 no valid objects specified for $key +0473 Sdc.tcl:3381 no valid objects specified for $key. +0474 Sdc.tcl:3449 operating condition '$op_cond_name' not found. +0475 Sdc.tcl:3467 operating condition '$op_cond_name' not found. +0476 Sdc.tcl:3481 -analysis_type must be single, bc_wc or on_chip_variation. +0477 Sdc.tcl:3493 set_wire_load_min_block_size not supported. +0478 Sdc.tcl:3506 mode must be top, enclosed or segmented. +0479 Sdc.tcl:3521 no wire load model specified. +0480 Sdc.tcl:3543 wire load model '$model_name' not found. +0481 Sdc.tcl:3582 wire load selection group '$selection_name' not found. +0482 Sdc.tcl:3670 define_corners must be called before read_liberty. +0500 Sdc.tcl:3740 no default operating conditions found. +0510 Search.tcl:136 $cmd -path_delay must be min, min_rise, min_fall, max, max_rise, max_fall or min_max. +0511 Search.tcl:146 $cmd command failed. +0512 Search.tcl:165 -endpoint_count must be a positive integer. +0513 Search.tcl:174 -group_count must be >= 1. +0514 Search.tcl:205 '$arg' is not a known keyword or flag. +0515 Search.tcl:207 positional arguments not supported. +0516 Search.tcl:326 report_clock_skew -setup and -hold are mutually exclusive options. +0520 Search.tcl:496 analysis type single is not consistent with doing both setup/max and hold/min checks. +0521 Search.tcl:501 positional arguments not supported. +0522 Search.tcl:764 -min and -max cannot both be specified. +0523 Search.tcl:784 pin '$pin_arg' is hierarchical. +0524 Search.tcl:850 -format $format not recognized. +0526 Search.tcl:994 specify one of -setup and -hold. +0527 Search.tcl:1043 unknown path group '$name'. +0540 Sta.tcl:158 -from/-to arguments not supported with -of_objects. +0541 Sta.tcl:286 unsupported -filter expression. +0560 Util.tcl:44 $cmd $key missing value. +0561 Util.tcl:61 $cmd $key missing value. +0562 Util.tcl:71 $cmd $arg is not a known keyword or flag. +0563 Util.tcl:93 $cmd $arg is not a known keyword or flag. +0564 Util.tcl:241 $cmd positional arguments not supported. +0565 Util.tcl:247 $cmd requires one positional argument. +0566 Util.tcl:254 $cmd requires zero or one positional arguments. +0567 Util.tcl:260 $cmd requires two positional arguments. +0568 Util.tcl:267 $cmd requires one or two positional arguments. +0569 Util.tcl:273 $cmd requires three positional arguments. +0570 Util.tcl:279 $cmd requires four positional arguments. +0571 Util.tcl:287 $cmd_arg '$arg' is not a float. +0572 Util.tcl:293 $cmd_arg '$arg' is not a positive float. +0573 Util.tcl:299 $cmd_arg '$arg' is not an integer. +0574 Util.tcl:305 $cmd_arg '$arg' is not a positive integer. +0575 Util.tcl:311 $cmd_arg '$arg' is not an integer greater than or equal to one. +0576 Util.tcl:317 $cmd_arg '$arg' is not between 0 and 100. +0590 Variables.tcl:45 sta_report_default_digits must be a positive integer. +0591 Variables.tcl:70 sta_crpr_mode must be pin or transition. +0592 Variables.tcl:187 $var_name value must be 0 or 1. +0600 WritePathSpice.tcl:36 Directory $spice_dir not found. +0601 WritePathSpice.tcl:39 $spice_dir is not a directory. +0602 WritePathSpice.tcl:42 Cannot write in $spice_dir. +0603 WritePathSpice.tcl:45 No -spice_directory specified. +0604 WritePathSpice.tcl:51 -lib_subckt_file $lib_subckt_file is not readable. +0605 WritePathSpice.tcl:54 No -lib_subckt_file specified. +0606 WritePathSpice.tcl:60 -model_file $model_file is not readable. +0607 WritePathSpice.tcl:63 No -model_file specified. +0608 WritePathSpice.tcl:69 No -power specified. +0609 WritePathSpice.tcl:75 No -ground specified. +0610 WritePathSpice.tcl:81 No -path_args specified. +0611 WritePathSpice.tcl:86 No paths found for -path_args $path_args. +0616 Levelize.cc:220 maximum logic level exceeded +0620 Sdf.tcl:41 -cond_use must be min, max or min_max. +0621 Sdf.tcl:46 -cond_use min_max cannot be used with analysis type single. +0623 Sdf.tcl:154 SDF -divider must be / or . +0800 VcdReader.cc:110 unhandled vcd command. +0801 VcdReader.cc:146 timescale syntax error. +0802 VcdReader.cc:160 Unknown timescale unit. +0804 VcdReader.cc:217 Variable syntax error. +1000 ConcreteNetwork.cc:1923 cell type %s can not be linked. +1010 CycleAccting.cc:87 No common period was found between clocks %s and %s. +1040 DmpCeff.cc:1510 parasitic Pi model has NaNs. +1041 DmpCeff.cc:1538 cell %s delay model not supported on SPF parasitics by DMP delay calculator +1060 Genclks.cc:274 no master clock found for generated clock %s. +1062 Genclks.cc:938 generated clock %s source pin %s missing paths from master clock %s. +1100 Power.cc:659 unknown cudd constant +1110 Liberty.cc:767 cell %s/%s port %s not found in cell %s/%s. +1111 Liberty.cc:793 cell %s/%s %s -> %s timing group %s not found in cell %s/%s. +1112 Liberty.cc:812 Liberty cell %s/%s for corner %s/%s not found. +1113 Liberty.cc:1776 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with %s -> %s setup_%s check. +1114 Liberty.cc:1790 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense. +1115 Liberty.cc:1798 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense. +1116 Liberty.cc:366 unsupported slew degradation table axes +1117 Liberty.cc:382 unsupported slew degradation table axes +1118 Liberty.cc:387 unsupported slew degradation table order +1119 Liberty.cc:417 unsupported slew degradation table axes +1120 Liberty.cc:906 library missing vdd +1121 Liberty.cc:1415 timing arc count mismatch +1125 LibertyParser.cc:310 valueIterator called for LibertySimpleAttribute +1126 LibertyParser.cc:390 LibertyStringAttrValue called for float value +1127 LibertyParser.cc:420 LibertyStringAttrValue called for float value +1130 LibertyExpr.cc:82 %s references unknown port %s. +1131 LibertyExpr.cc:175 %s %s. +1140 LibertyReader.cc:598 library %s already exists. +1141 LibertyReader.cc:632 library missing name. +1142 LibertyReader.cc:658 default_wire_load %s not found. +1143 LibertyReader.cc:669 default_wire_selection %s not found. +1144 LibertyReader.cc:681 default_operating_condition %s not found. +1145 LibertyReader.cc:691 input_threshold_pct_%s not found. +1146 LibertyReader.cc:695 output_threshold_pct_%s not found. +1147 LibertyReader.cc:699 slew_lower_threshold_pct_%s not found. +1148 LibertyReader.cc:703 slew_upper_threshold_pct_%s not found. +1149 LibertyReader.cc:708 Library %s is missing one or more thresholds. +1150 LibertyReader.cc:787 unknown unit multiplier %s. +1151 LibertyReader.cc:810 unknown unit scale %c. +1152 LibertyReader.cc:813 unknown unit suffix %s. +1153 LibertyReader.cc:816 unknown unit suffix %s. +1154 LibertyReader.cc:841 capacitive_load_units are not ff or pf. +1155 LibertyReader.cc:844 capacitive_load_units are not a string. +1156 LibertyReader.cc:847 capacitive_load_units missing suffix. +1157 LibertyReader.cc:850 capacitive_load_units scale is not a float. +1158 LibertyReader.cc:853 capacitive_load_units missing scale and suffix. +1159 LibertyReader.cc:856 capacitive_load_unit missing values suffix. +1160 LibertyReader.cc:874 delay_model %s not supported. +1161 LibertyReader.cc:878 delay_model %s not supported. +1162 LibertyReader.cc:882 delay_model %s not supported. +1163 LibertyReader.cc:887 delay_model %s not supported. +. +1164 LibertyReader.cc:890 unknown delay_model %s +. +1165 LibertyReader.cc:909 unknown bus_naming_style format. +1166 LibertyReader.cc:930 voltage_map voltage is not a float. +1167 LibertyReader.cc:933 voltage_map missing voltage. +1168 LibertyReader.cc:936 voltage_map supply name is not a string. +1169 LibertyReader.cc:939 voltage_map missing supply name and voltage. +1170 LibertyReader.cc:942 voltage_map missing values suffix. +1171 LibertyReader.cc:1027 default_max_transition is 0.0. +1172 LibertyReader.cc:1042 default_max_fanout is 0.0. +1173 LibertyReader.cc:1132 default_fanout_load is 0.0. +1174 LibertyReader.cc:1160 default_wire_load_mode %s not found. +1175 LibertyReader.cc:1331 table template missing name. +1176 LibertyReader.cc:1376 missing variable_%d attribute. +1177 LibertyReader.cc:1452 missing table index values. +1178 LibertyReader.cc:1458 non-increasing table index values. +1179 LibertyReader.cc:1490 bus type %s missing bit_from. +1180 LibertyReader.cc:1492 bus type %s missing bit_to. +1181 LibertyReader.cc:1496 type missing name. +1182 LibertyReader.cc:1523 scaling_factors do not have a name. +1183 LibertyReader.cc:1692 operating_conditions missing name. +1184 LibertyReader.cc:1763 wire_load missing name. +1185 LibertyReader.cc:1806 fanout_length is missing length and fanout. +1186 LibertyReader.cc:1821 wire_load_selection missing name. +1187 LibertyReader.cc:1852 wireload %s not found. +1189 LibertyReader.cc:1859 wire_load_from_area min not a float. +1190 LibertyReader.cc:1862 wire_load_from_area max not a float. +1191 LibertyReader.cc:1865 wire_load_from_area missing parameters. +1192 LibertyReader.cc:1868 wire_load_from_area missing parameters. +1193 LibertyReader.cc:1887 cell missing name. +1194 LibertyReader.cc:1910 cell %s ocv_derate_group %s not found. +1195 LibertyReader.cc:1941 port %s function size does not match port size. +1196 LibertyReader.cc:1997 %s %s bus width mismatch. +1197 LibertyReader.cc:2008 %s %s bus width mismatch. +1198 LibertyReader.cc:2018 clear +1199 LibertyReader.cc:2028 preset +1200 LibertyReader.cc:2064 latch enable function is non-unate for port %s. +1201 LibertyReader.cc:2069 latch enable function is unknown for port %s. +1202 LibertyReader.cc:2141 operating conditions %s not found. +1203 LibertyReader.cc:2144 scaled_cell missing operating condition. +1204 LibertyReader.cc:2147 scaled_cell cell %s has not been defined. +1205 LibertyReader.cc:2150 scaled_cell missing name. +1206 LibertyReader.cc:2176 scaled_cell %s, %s port functions do not match cell port functions. +1207 LibertyReader.cc:2181 scaled_cell ports do not match cell ports. +1208 LibertyReader.cc:2183 scaled_cell %s, %s timing does not match cell timing. +1209 LibertyReader.cc:2202 combinational timing to an input port. +1210 LibertyReader.cc:2297 missing %s_transition. +1211 LibertyReader.cc:2299 missing cell_%s. +1212 LibertyReader.cc:2319 timing group from output port. +1213 LibertyReader.cc:2329 timing group from output port. +1214 LibertyReader.cc:2339 timing group from output port. +1215 LibertyReader.cc:2357 timing group from output port. +1217 LibertyReader.cc:2373 timing group from output port. +1218 LibertyReader.cc:2460 receiver_capacitance group not in timing or pin group. +1219 LibertyReader.cc:2477 unsupported model axis. +1220 LibertyReader.cc:2505 output_current_%s group not in timing group. +1221 LibertyReader.cc:2546 output current waveform %.2e %.2e not found. +1222 LibertyReader.cc:2566 unsupported model axis. +1223 LibertyReader.cc:2608 vector index_1 and index_2 must have exactly one value. +1224 LibertyReader.cc:2610 vector reference_time not found. +1225 LibertyReader.cc:2643 normalized_driver_waveform variable_2 must be normalized_voltage +1226 LibertyReader.cc:2646 normalized_driver_waveform variable_1 must be input_net_transition +1228 LibertyReader.cc:2868 level_shifter_type must be HL, LH, or HL_LH +1229 LibertyReader.cc:2904 switch_cell_type must be coarse_grain or fine_grain +1230 LibertyReader.cc:2928 scaling_factors %s not found. +1231 LibertyReader.cc:2969 pin name is not a string. +1232 LibertyReader.cc:2986 pin name is not a string. +1233 LibertyReader.cc:3000 pin name is not a string. +1234 LibertyReader.cc:3078 bus %s bus_type not found. +1235 LibertyReader.cc:3130 bus_type %s not found. +1236 LibertyReader.cc:3133 bus_type is not a string. +1237 LibertyReader.cc:3151 bundle %s member not found. +1238 LibertyReader.cc:3174 member is not a string. +1239 LibertyReader.cc:3181 members attribute is missing values. +1240 LibertyReader.cc:3232 unknown port direction. +1241 LibertyReader.cc:3466 max_transition is 0.0. +1242 LibertyReader.cc:3572 pulse_latch unknown pulse type. +1243 LibertyReader.cc:3861 timing group missing related_pin/related_bus_pin. +1244 LibertyReader.cc:3942 unknown timing_type %s. +1245 LibertyReader.cc:3962 unknown timing_sense %s. +1246 LibertyReader.cc:4002 mode value is not a string. +1247 LibertyReader.cc:4005 missing mode value. +1248 LibertyReader.cc:4008 mode name is not a string. +1249 LibertyReader.cc:4011 mode missing values. +1250 LibertyReader.cc:4014 mode missing mode name and value. +1251 LibertyReader.cc:4090 unsupported model axis. +1252 LibertyReader.cc:4117 unsupported model axis. +1253 LibertyReader.cc:4146 unsupported model axis. +1254 LibertyReader.cc:4181 unsupported model axis. +1255 LibertyReader.cc:4197 %s group not in timing group. +1256 LibertyReader.cc:4236 table template %s not found. +1257 LibertyReader.cc:4320 %s is missing values. +1258 LibertyReader.cc:4343 %s is not a list of floats. +1259 LibertyReader.cc:4345 table row has %u columns but axis has %d. +1260 LibertyReader.cc:4355 table has %u rows but axis has %d. +1261 LibertyReader.cc:4406 lut output is not a string. +1262 LibertyReader.cc:4423 cell %s test_cell redefinition. +1263 LibertyReader.cc:4448 mode definition missing name. +1264 LibertyReader.cc:4465 mode value missing name. +1265 LibertyReader.cc:4479 when attribute inside table model. +1266 LibertyReader.cc:4528 %s attribute is not a string. +1267 LibertyReader.cc:4531 %s is not a simple attribute. +1268 LibertyReader.cc:4551 %s attribute is not an integer. +1269 LibertyReader.cc:4554 %s is not a simple attribute. +1270 LibertyReader.cc:4567 %s is not a simple attribute. +1271 LibertyReader.cc:4593 %s value %s is not a float. +1272 LibertyReader.cc:4622 %s missing values. +1273 LibertyReader.cc:4626 %s missing values. +1274 LibertyReader.cc:4629 %s is not a complex attribute. +1275 LibertyReader.cc:4655 %s is not a float. +1276 LibertyReader.cc:4678 %s is missing values. +1277 LibertyReader.cc:4681 %s has more than one string. +1278 LibertyReader.cc:4690 %s is missing values. +1279 LibertyReader.cc:4715 %s attribute is not boolean. +1280 LibertyReader.cc:4718 %s attribute is not boolean. +1281 LibertyReader.cc:4721 %s is not a simple attribute. +1282 LibertyReader.cc:4737 attribute %s value %s not recognized. +1283 LibertyReader.cc:4768 unknown early/late value. +1284 LibertyReader.cc:4988 OCV derate group named %s not found. +1285 LibertyReader.cc:5004 ocv_derate missing name. +1286 LibertyReader.cc:5057 unknown rise/fall. +1287 LibertyReader.cc:5077 unknown derate type. +1288 LibertyReader.cc:5109 unsupported model axis. +1289 LibertyReader.cc:5141 unsupported model axis. +1290 LibertyReader.cc:5173 unsupported model axis. +1291 LibertyReader.cc:5244 unknown pg_type. +1292 LibertyReader.cc:5639 port %s subscript out of range. +1293 LibertyReader.cc:5643 port range %s of non-bus port %s. +1294 LibertyReader.cc:5657 port %s not found. +1295 LibertyReader.cc:5727 port %s not found. +1297 LibertyReader.cc:1418 axis type %s not supported. +1330 LibertyWriter.cc:286 %s/%s bundled ports not supported. +1331 LibertyWriter.cc:417 %s/%s/%s timing model not supported. +1332 LibertyWriter.cc:437 3 axis table models not supported. +1333 LibertyWriter.cc:581 %s/%s/%s timing arc type %s not supported. +1350 LumpedCapDelayCalc.cc:138 gate delay input variable is NaN +1355 MakeTimingModel.cc:206 clock %s pin %s is inside model block. +1360 Vcd.cc:172 Unknown variable %s ID %s +1370 PathEnum.cc:474 path diversion missing edge. +1398 VerilogReader.cc:1782 %s is not a verilog module. +1399 VerilogReader.cc:1787 %s is not a verilog module. +1400 PathVertex.cc:236 missing arrivals. +1401 PathVertex.cc:250 missing arrivals. +1402 PathVertex.cc:279 missing requireds. +1422 PathVertexRep.cc:153 missing arrivals. +1450 ReadVcdActivities.cc:107 VCD max time is zero. +1451 ReadVcdActivities.cc:174 problem parsing bus %s. +1452 ReadVcdActivities.cc:251 clock %s vcd period %s differs from SDC clock period %s +1521 Sim.cc:864 propagated logic value %c differs from constraint value of %c on pin %s. +1525 SpefParse.yy:805 %d is not positive. +1526 SpefParse.yy:814 %.4f is not positive. +1527 SpefParse.yy:820 %.4f is not positive. +1550 Sta.cc:2031 '%s' is not a valid start point. +1551 Sta.cc:2104 '%s' is not a valid endpoint. +1552 Sta.cc:2107 '%s' is not a valid endpoint. +1553 Sta.cc:2430 maximum corner count exceeded +1554 Sta.cc:2028 '%s' is not a valid start point. +1570 StaTcl.i:109 no network has been linked. +1571 StaTcl.i:123 network does not support edits. +1574 StaTcl.i:2748 POCV support requires compilation with SSTA=1. +1575 StaTcl.i:2986 unknown report path field %s +1576 StaTcl.i:2998 unknown report path field %s +1600 WritePathSpice.cc:289 No liberty libraries found, +1602 WritePathSpice.cc:522 Liberty pg_port %s/%s missing voltage_name attribute, +1603 WritePathSpice.cc:1101 %s pg_port %s not found, +1604 WritePathSpice.cc:1156 no register/latch found for path from %s to %s, +1605 WritePathSpice.cc:1573 The subkct file %s is missing definitions for %s +1606 WritePathSpice.cc:1671 subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground. +1640 SpefReader.cc:150 illegal bus delimiters. +1641 SpefReader.cc:234 unknown units %s. +1642 SpefReader.cc:247 unknown units %s. +1643 SpefReader.cc:260 unknown units %s. +1644 SpefReader.cc:275 unknown units %s. +1645 SpefReader.cc:296 no name map entry for %d. +1646 SpefReader.cc:315 unknown port direction %s. +1647 SpefReader.cc:342 pin %s not found. +1648 SpefReader.cc:345 instance %s not found. +1650 SpefReader.cc:365 net %s not found. +1651 SpefReader.cc:478 %s not connected to net %s. +1652 SpefReader.cc:484 pin %s not found. +1653 SpefReader.cc:498 %s not connected to net %s. +1654 SpefReader.cc:502 node %s not a pin or net:number +1655 SpefReader.cc:513 %s not connected to net %s. +1656 SpefReader.cc:517 pin %s not found. +1657 SpefReader.cc:634 %s. diff --git a/etc/TclEncode.tcl b/etc/TclEncode.tcl index 7af0affd..98127018 100755 --- a/etc/TclEncode.tcl +++ b/etc/TclEncode.tcl @@ -3,7 +3,7 @@ exec tclsh $0 ${1+"$@"} # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 diff --git a/graph/Delay.cc b/graph/Delay.cc index f4bd3d2e..6f2c6103 100644 --- a/graph/Delay.cc +++ b/graph/Delay.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/graph/DelayFloat.cc b/graph/DelayFloat.cc index a4b0cc20..7ec03e9f 100644 --- a/graph/DelayFloat.cc +++ b/graph/DelayFloat.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/graph/DelayNormal1.cc b/graph/DelayNormal1.cc index b677b198..294766c1 100644 --- a/graph/DelayNormal1.cc +++ b/graph/DelayNormal1.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -200,7 +200,7 @@ delayAsFloat(const Delay &delay, else if (early_late == EarlyLate::late()) return delay.mean() + delay.sigma() * sta->sigmaFactor(); else - sta->report()->critical(594, "unknown early/late value."); + sta->report()->critical(1020, "unknown early/late value."); } return delay.mean(); } diff --git a/graph/DelayNormal2.cc b/graph/DelayNormal2.cc index a58787a3..4bdd482b 100644 --- a/graph/DelayNormal2.cc +++ b/graph/DelayNormal2.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -375,7 +375,7 @@ delayAsFloat(const Delay &delay, else if (early_late == EarlyLate::late()) return delay.mean() + delay.sigma(early_late) * sta->sigmaFactor(); else - sta->report()->critical(595, "unknown early/late value."); + sta->report()->critical(1030, "unknown early/late value."); } return delay.mean(); } diff --git a/graph/Graph.cc b/graph/Graph.cc index 29af550a..2007e610 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -106,7 +106,7 @@ public: int &bidirect_count, int &load_count, const Network *network); - virtual void operator()(Pin *pin); + virtual void operator()(const Pin *pin); protected: Pin *drvr_pin_; @@ -133,7 +133,7 @@ FindNetDrvrLoadCounts::FindNetDrvrLoadCounts(Pin *drvr_pin, } void -FindNetDrvrLoadCounts::operator()(Pin *pin) +FindNetDrvrLoadCounts::operator()(const Pin *pin) { if (network_->isDriver(pin)) { if (pin != drvr_pin_) @@ -790,7 +790,7 @@ Graph::arcDelayAnnotated(const Edge *edge, if (arc_delay_annotated_.size()) { size_t index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index; if (index >= arc_delay_annotated_.size()) - report_->critical(208, "arc_delay_annotated array bounds exceeded"); + report_->critical(1080, "arc_delay_annotated array bounds exceeded"); return arc_delay_annotated_[index]; } else @@ -805,7 +805,7 @@ Graph::setArcDelayAnnotated(Edge *edge, { size_t index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index; if (index >= arc_delay_annotated_.size()) - report_->critical(209, "arc_delay_annotated array bounds exceeded"); + report_->critical(1081, "arc_delay_annotated array bounds exceeded"); arc_delay_annotated_[index] = annotated; } @@ -817,7 +817,7 @@ Graph::wireDelayAnnotated(Edge *edge, size_t index = (edge->arcDelays() + TimingArcSet::wireArcIndex(rf)) * ap_count_ + ap_index; if (index >= arc_delay_annotated_.size()) - report_->critical(210, "arc_delay_annotated array bounds exceeded"); + report_->critical(1082, "arc_delay_annotated array bounds exceeded"); return arc_delay_annotated_[index]; } @@ -830,7 +830,7 @@ Graph::setWireDelayAnnotated(Edge *edge, size_t index = (edge->arcDelays() + TimingArcSet::wireArcIndex(rf)) * ap_count_ + ap_index; if (index >= arc_delay_annotated_.size()) - report_->critical(228, "arc_delay_annotated array bounds exceeded"); + report_->critical(1083, "arc_delay_annotated array bounds exceeded"); arc_delay_annotated_[index] = annotated; } diff --git a/graph/GraphCmp.cc b/graph/GraphCmp.cc index feefe4fc..6241c16d 100644 --- a/graph/GraphCmp.cc +++ b/graph/GraphCmp.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ArcDelayCalc.hh b/include/sta/ArcDelayCalc.hh index c1c6617b..2bcc11a8 100644 --- a/include/sta/ArcDelayCalc.hh +++ b/include/sta/ArcDelayCalc.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -18,10 +18,14 @@ #include #include +#include #include "MinMax.hh" #include "LibertyClass.hh" +#include "TimingArc.hh" +#include "TableModel.hh" #include "NetworkClass.hh" +#include "GraphClass.hh" #include "Delay.hh" #include "ParasiticsClass.hh" #include "StaState.hh" @@ -30,18 +34,77 @@ namespace sta { using std::string; using std::vector; +using std::map; +class Corner; class Parasitic; class DcalcAnalysisPt; class MultiDrvrNet; +// Driver load pin -> index in driver loads. +typedef map LoadPinIndexMap; + +// Arguments for gate delay calculation delay/slew at one driver pin +// through one timing arc at one delay calc analysis point. +class ArcDcalcArg +{ +public: + ArcDcalcArg(); + ArcDcalcArg(const Pin *drvr_pin, + Edge *edge, + const TimingArc *arc, + const Slew in_slew, + const Parasitic *parasitic); + const Pin *drvrPin() const { return drvr_pin_; } + Edge *edge() const { return edge_; } + const TimingArc *arc() const { return arc_; } + Slew inSlew() const { return in_slew_; } + const Parasitic *parasitic() { return parasitic_; } + void setParasitic(const Parasitic *parasitic); + +protected: + const Pin *drvr_pin_; + Edge *edge_; + const TimingArc *arc_; + Slew in_slew_; + const Parasitic *parasitic_; +}; + +// Arc delay calc result. +class ArcDcalcResult +{ +public: + ArcDcalcResult(); + ArcDcalcResult(size_t load_count); + void setLoadCount(size_t load_count); + ArcDelay &gateDelay() { return gate_delay_; } + void setGateDelay(ArcDelay gate_delay); + Slew &drvrSlew() { return drvr_slew_; } + void setDrvrSlew(Slew drvr_slew); + ArcDelay wireDelay(size_t load_idx) const; + void setWireDelay(size_t load_idx, + ArcDelay wire_delay); + Slew loadSlew(size_t load_idx) const; + void setLoadSlew(size_t load_idx, + Slew load_slew); + +protected: + ArcDelay gate_delay_; + Slew drvr_slew_; + // Load wire delay and slews indexed by load pin index. + vector wire_delays_; + vector load_slews_; +}; + +typedef vector ArcDcalcArgSeq; +typedef vector ArcDcalcResultSeq; + // Delay calculator class hierarchy. // ArcDelayCalc // UnitDelayCalc // DelayCalcBase // ParallelDelayCalc // LumpedCapDelayCalc -// SlewDegradeDelayCalc // DmpCeffDelayCalc // DmpCeffElmoreDelayCalc // DmpCeffTwoPoleDelayCalc @@ -61,95 +124,80 @@ public: virtual Parasitic *findParasitic(const Pin *drvr_pin, const RiseFall *rf, const DcalcAnalysisPt *dcalc_ap) = 0; - virtual ReducedParasiticType reducedParasiticType() const = 0; + // Reduce parasitic_network to a representation acceptable to the delay calculator. + virtual Parasitic *reduceParasitic(const Parasitic *parasitic_network, + const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap) = 0; + // Reduce parasitic_network to a representation acceptable to the delay calculator + // for one or more corners and min/max rise/fall. + // Null corner means reduce all corners. + virtual void reduceParasitic(const Parasitic *parasitic_network, + const Net *net, + const Corner *corner, + const MinMaxAll *min_max) = 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 void inputPortDelay(const Pin *port_pin, - float in_slew, - const RiseFall *rf, - const Parasitic *parasitic, - const DcalcAnalysisPt *dcalc_ap) = 0; + virtual ArcDcalcResult inputPortDelay(const Pin *port_pin, + float in_slew, + const RiseFall *rf, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) = 0; // Find the delay and slew for arc driving drvr_pin. + virtual ArcDcalcResult gateDelay(const Pin *drvr_pin, + const TimingArc *arc, + const Slew &in_slew, + // Pass in load_cap or parasitic. + float load_cap, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) = 0; virtual void gateDelay(const TimingArc *arc, const Slew &in_slew, - // Pass in load_cap or drvr_parasitic. float load_cap, - const Parasitic *drvr_parasitic, + const Parasitic *parasitic, float related_out_cap, const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, // Return values. ArcDelay &gate_delay, - Slew &drvr_slew) = 0; + Slew &drvr_slew) __attribute__ ((deprecated)); + // Find gate delays and slews for parallel gates. - virtual void findParallelGateDelays(const MultiDrvrNet *multi_drvr, - GraphDelayCalc *dcalc) = 0; - // Retrieve the delay and slew for one parallel gate. - virtual void parallelGateDelay(const Pin *drvr_pin, - const TimingArc *arc, - const Slew &from_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &gate_delay, - Slew &gate_slew) = 0; - // Find the wire delay and load slew of a load pin. - // Called after inputPortDelay or gateDelay. - virtual void loadDelay(const Pin *load_pin, - // Return values. - ArcDelay &wire_delay, - Slew &load_slew) = 0; - // Ceff for parasitics with pi models. - virtual float ceff(const TimingArc *arc, - const Slew &in_slew, - float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap) = 0; + virtual ArcDcalcResultSeq gateDelays(ArcDcalcArgSeq &args, + float load_cap, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap) = 0; // Find the delay for a timing check arc given the arc's // from/clock, to/data slews and related output pin parasitic. - virtual void checkDelay(const TimingArc *arc, - const Slew &from_slew, - const Slew &to_slew, - float related_out_cap, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - ArcDelay &margin) = 0; + virtual ArcDelay checkDelay(const Pin *check_pin, + const TimingArc *arc, + const Slew &from_slew, + const Slew &to_slew, + float related_out_cap, + const DcalcAnalysisPt *dcalc_ap) = 0; // Report delay and slew calculation. - virtual string reportGateDelay(const TimingArc *arc, + virtual string reportGateDelay(const Pin *drvr_pin, + const TimingArc *arc, const Slew &in_slew, - // Pass in load_cap or drvr_parasitic. float load_cap, - const Parasitic *drvr_parasitic, - float related_out_cap, - const Pvt *pvt, + const Parasitic *parasitic, + const LoadPinIndexMap &load_pin_index_map, const DcalcAnalysisPt *dcalc_ap, int digits) = 0; // Report timing check delay calculation. - virtual string reportCheckDelay(const TimingArc *arc, + virtual string reportCheckDelay(const Pin *check_pin, + const TimingArc *arc, const Slew &from_slew, const char *from_slew_annotation, const Slew &to_slew, float related_out_cap, - const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, int digits) = 0; virtual void finishDrvrPin() = 0; - -protected: - GateTimingModel *gateModel(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; }; } // namespace diff --git a/include/sta/ArrayTable.hh b/include/sta/ArrayTable.hh index 9f606474..16fdafce 100644 --- a/include/sta/ArrayTable.hh +++ b/include/sta/ArrayTable.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Bfs.hh b/include/sta/Bfs.hh index e83a1e82..e3a27aba 100644 --- a/include/sta/Bfs.hh +++ b/include/sta/Bfs.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ClkNetwork.hh b/include/sta/ClkNetwork.hh index 2ff7074b..0125a2e7 100644 --- a/include/sta/ClkNetwork.hh +++ b/include/sta/ClkNetwork.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Clock.hh b/include/sta/Clock.hh index eaa0c229..b5568e3d 100644 --- a/include/sta/Clock.hh +++ b/include/sta/Clock.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ClockGatingCheck.hh b/include/sta/ClockGatingCheck.hh index 53719d5a..00facd84 100644 --- a/include/sta/ClockGatingCheck.hh +++ b/include/sta/ClockGatingCheck.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ClockGroups.hh b/include/sta/ClockGroups.hh index 0dbbaf85..88ce33fd 100644 --- a/include/sta/ClockGroups.hh +++ b/include/sta/ClockGroups.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ClockInsertion.hh b/include/sta/ClockInsertion.hh index d9ecf505..c0eb9dbf 100644 --- a/include/sta/ClockInsertion.hh +++ b/include/sta/ClockInsertion.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ClockLatency.hh b/include/sta/ClockLatency.hh index aac905ac..fa4f07d7 100644 --- a/include/sta/ClockLatency.hh +++ b/include/sta/ClockLatency.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ConcreteLibrary.hh b/include/sta/ConcreteLibrary.hh index c09abac4..5909b81e 100644 --- a/include/sta/ConcreteLibrary.hh +++ b/include/sta/ConcreteLibrary.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ConcreteNetwork.hh b/include/sta/ConcreteNetwork.hh index 1375c58f..99728c9c 100644 --- a/include/sta/ConcreteNetwork.hh +++ b/include/sta/ConcreteNetwork.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Corner.hh b/include/sta/Corner.hh index cdb472b8..9ef972ab 100644 --- a/include/sta/Corner.hh +++ b/include/sta/Corner.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -55,8 +55,7 @@ public: void operatingConditionsChanged(); // Make one parasitic analysis points. - void makeParasiticAnalysisPts(bool per_corner, - bool per_min_max); + void makeParasiticAnalysisPts(bool per_corner); int parasiticAnalysisPtCount() const; ParasiticAnalysisPtSeq ¶siticAnalysisPts(); @@ -114,7 +113,7 @@ public: protected: void setParasiticAnalysisPtcount(int ap_count); void setParasiticAP(ParasiticAnalysisPt *path_ap, - int ap_index); + int mm_index); void setDcalcAnalysisPtcount(DcalcAPIndex ap_count); void addDcalcAP(DcalcAnalysisPt *dcalc_ap); void addPathAP(PathAnalysisPt *path_ap); diff --git a/include/sta/CycleAccting.hh b/include/sta/CycleAccting.hh index 8f53f5f5..c2893f14 100644 --- a/include/sta/CycleAccting.hh +++ b/include/sta/CycleAccting.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/DataCheck.hh b/include/sta/DataCheck.hh index c6f74ea7..62924e80 100644 --- a/include/sta/DataCheck.hh +++ b/include/sta/DataCheck.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/DcalcAnalysisPt.hh b/include/sta/DcalcAnalysisPt.hh index 79a24ba5..41b25878 100644 --- a/include/sta/DcalcAnalysisPt.hh +++ b/include/sta/DcalcAnalysisPt.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Debug.hh b/include/sta/Debug.hh index ed593b86..66bab1f9 100644 --- a/include/sta/Debug.hh +++ b/include/sta/Debug.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Delay.hh b/include/sta/Delay.hh index 0d96912e..130f7d2b 100644 --- a/include/sta/Delay.hh +++ b/include/sta/Delay.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/DelayCalc.hh b/include/sta/DelayCalc.hh index 9fb66084..07d77d4d 100644 --- a/include/sta/DelayCalc.hh +++ b/include/sta/DelayCalc.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/DelayFloat.hh b/include/sta/DelayFloat.hh index a53cd643..68143025 100644 --- a/include/sta/DelayFloat.hh +++ b/include/sta/DelayFloat.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/DelayNormal1.hh b/include/sta/DelayNormal1.hh index c4f33bce..a8bbacc8 100644 --- a/include/sta/DelayNormal1.hh +++ b/include/sta/DelayNormal1.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/DelayNormal2.hh b/include/sta/DelayNormal2.hh index c116134b..f7aac325 100644 --- a/include/sta/DelayNormal2.hh +++ b/include/sta/DelayNormal2.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/DeratingFactors.hh b/include/sta/DeratingFactors.hh index b9535137..c5a9fca4 100644 --- a/include/sta/DeratingFactors.hh +++ b/include/sta/DeratingFactors.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/DisabledPorts.hh b/include/sta/DisabledPorts.hh index 803850cf..23a50198 100644 --- a/include/sta/DisabledPorts.hh +++ b/include/sta/DisabledPorts.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/EnumNameMap.hh b/include/sta/EnumNameMap.hh index 47b7d2ad..e3f3172e 100644 --- a/include/sta/EnumNameMap.hh +++ b/include/sta/EnumNameMap.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/EquivCells.hh b/include/sta/EquivCells.hh index f6cbdecd..d695b79b 100644 --- a/include/sta/EquivCells.hh +++ b/include/sta/EquivCells.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Error.hh b/include/sta/Error.hh index 41e6b229..8111c58a 100644 --- a/include/sta/Error.hh +++ b/include/sta/Error.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ExceptionPath.hh b/include/sta/ExceptionPath.hh index 4ea98699..92e8c47a 100644 --- a/include/sta/ExceptionPath.hh +++ b/include/sta/ExceptionPath.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/FuncExpr.hh b/include/sta/FuncExpr.hh index ff5d24c4..586c241a 100644 --- a/include/sta/FuncExpr.hh +++ b/include/sta/FuncExpr.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Fuzzy.hh b/include/sta/Fuzzy.hh index d1e36c18..b3742ad5 100644 --- a/include/sta/Fuzzy.hh +++ b/include/sta/Fuzzy.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index d2dea625..00fec1f2 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/GraphClass.hh b/include/sta/GraphClass.hh index 388d6a45..834ee2aa 100644 --- a/include/sta/GraphClass.hh +++ b/include/sta/GraphClass.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/GraphCmp.hh b/include/sta/GraphCmp.hh index 0b588bf5..8753d69e 100644 --- a/include/sta/GraphCmp.hh +++ b/include/sta/GraphCmp.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh index da47b31e..a93dd890 100644 --- a/include/sta/GraphDelayCalc.hh +++ b/include/sta/GraphDelayCalc.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -17,6 +17,7 @@ #pragma once #include +#include #include "Map.hh" #include "NetworkClass.hh" @@ -25,10 +26,12 @@ #include "DcalcAnalysisPt.hh" #include "StaState.hh" #include "Delay.hh" +#include "ArcDelayCalc.hh" namespace sta { using std::vector; +using std::map; class DelayCalcObserver; class MultiDrvrNet; @@ -69,43 +72,32 @@ public: // delays to be recomputed during incremental delay calculation. virtual float incrementalDelayTolerance(); virtual void setIncrementalDelayTolerance(float tol); - // Load pin_cap + wire_cap. - virtual float loadCap(const Pin *drvr_pin, - const RiseFall *drvr_rf, - const DcalcAnalysisPt *dcalc_ap) const; - // Load pin_cap + wire_cap including parasitic min/max for rise/fall. - virtual float loadCap(const Pin *drvr_pin, - const DcalcAnalysisPt *dcalc_ap) const; - // pin_cap = net pin capacitances + port external pin capacitance, - // wire_cap = annotated net capacitance + port external wire capacitance. - virtual void loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - float &pin_cap, - float &wire_cap) const; - // Load pin_cap + wire_cap including parasitic. - virtual float loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap) const; + float loadCap(const Pin *drvr_pin, - const Parasitic *drvr_parasitic, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap, - const MultiDrvrNet *multi_drvr) const; - virtual void netCaps(const Pin *drvr_pin, - const RiseFall *rf, - const DcalcAnalysisPt *dcalc_ap, - // Return values. - float &pin_cap, - float &wire_cap, - float &fanout, - bool &has_set_load) const; - float ceff(Edge *edge, - TimingArc *arc, - const DcalcAnalysisPt *dcalc_ap); + const DcalcAnalysisPt *dcalc_ap) const; + float loadCap(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap) const; + void loadCap(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + float &pin_cap, + float &wire_cap) const; + void netCaps(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + float &pin_cap, + float &wire_cap, + float &fanout, + bool &has_set_load) const; + LoadPinIndexMap makeLoadPinIndexMap(Vertex *drvr_vertex); + void findDriverArcDelays(Vertex *drvr_vertex, + Edge *edge, + const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc); // Precedence: // SDF annotation // Liberty library @@ -170,18 +162,38 @@ protected: const DcalcAnalysisPt *dcalc_ap); bool findDriverDelays(Vertex *drvr_vertex, ArcDelayCalc *arc_delay_calc); + MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const; MultiDrvrNet *findMultiDrvrNet(Vertex *drvr_pin); - MultiDrvrNet *makeMultiDrvrNet(PinSet &drvr_pins); + MultiDrvrNet *makeMultiDrvrNet(Vertex *drvr_vertex); + bool hasMultiDrvrs(Vertex *drvr_vertex); + Vertex *firstLoad(Vertex *drvr_vertex); bool findDriverDelays1(Vertex *drvr_vertex, MultiDrvrNet *multi_drvr, ArcDelayCalc *arc_delay_calc); void initLoadSlews(Vertex *drvr_vertex); - bool findDriverEdgeDelays(const Instance *drvr_inst, - const Pin *drvr_pin, - Vertex *drvr_vertex, + bool findDriverEdgeDelays(Vertex *drvr_vertex, const MultiDrvrNet *multi_drvr, Edge *edge, ArcDelayCalc *arc_delay_calc); + bool findDriverArcDelays(Vertex *drvr_vertex, + const MultiDrvrNet *multi_drvr, + Edge *edge, + const TimingArc *arc, + LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc); + ArcDcalcArgSeq makeArcDcalcArgs(Vertex *drvr_vertex, + const MultiDrvrNet *multi_drvr, + Edge *edge, + const TimingArc *arc, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc); + void findParallelEdge(Vertex *vertex, + Edge *drvr_edge, + const TimingArc *drvr_arc, + // Return values. + Edge *&edge, + const TimingArc *&arc); void initWireDelays(Vertex *drvr_vertex); void initRootSlews(Vertex *vertex); void zeroSlewAndWireDelays(Vertex *drvr_vertex); @@ -189,23 +201,24 @@ protected: ArcDelayCalc *arc_delay_calc, bool propagate); void enqueueTimingChecksEdges(Vertex *vertex); - bool findArcDelay(const Pin *drvr_pin, - Vertex *drvr_vertex, - const TimingArc *arc, - const Parasitic *drvr_parasitic, - float related_out_cap, - Vertex *from_vertex, - Edge *edge, - const Pvt *pvt, - const DcalcAnalysisPt *dcalc_ap, - const MultiDrvrNet *multi_drvr, - ArcDelayCalc *arc_delay_calc); + bool annotateDelaysSlews(Edge *edge, + const TimingArc *arc, + ArcDcalcResult &dcalc_result, + LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap); + + bool annotateDelaySlew(Edge *edge, + const TimingArc *arc, + ArcDelay &gate_delay, + Slew &gate_slew, + const DcalcAnalysisPt *dcalc_ap); void annotateLoadDelays(Vertex *drvr_vertex, - const RiseFall *drvr_rf, - const ArcDelay &extra_delay, - bool merge, - const DcalcAnalysisPt *dcalc_ap, - ArcDelayCalc *arc_delay_calc); + const RiseFall *drvr_rf, + ArcDcalcResult &dcalc_result, + LoadPinIndexMap &load_pin_index_map, + const ArcDelay &extra_delay, + bool merge, + const DcalcAnalysisPt *dcalc_ap); void findLatchEdgeDelays(Edge *edge); void findCheckEdgeDelays(Edge *edge, ArcDelayCalc *arc_delay_calc); @@ -214,12 +227,36 @@ protected: const RiseFall *from_rf, const DcalcAnalysisPt *dcalc_ap); bool bidirectDrvrSlewFromLoad(const Vertex *vertex) const; - MultiDrvrNet *multiDrvrNet(const Vertex *drvr_vertex) const; - void loadCap(const Parasitic *drvr_parasitic, - bool has_set_load, - // Return values. - float &pin_cap, - float &wire_cap) const; + float loadCap(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + ArcDelayCalc *arc_delay_calc) const; + void parasiticLoad(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + const MultiDrvrNet *multi_drvr, + ArcDelayCalc *arc_delay_calc, + // Return values. + float &cap, + const Parasitic *¶sitic) const; + void parasiticLoad(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + const MultiDrvrNet *multi_drvr, + ArcDelayCalc *arc_delay_calc, + // Return values. + float &pin_cap, + float &wire_cap, + const Parasitic *¶sitic) const; + void netCaps(const Pin *drvr_pin, + const RiseFall *rf, + const DcalcAnalysisPt *dcalc_ap, + const MultiDrvrNet *multi_drvr, + // Return values. + float &pin_cap, + float &wire_cap, + float &fanout, + bool &has_net_load) const; // Observer for edge delay changes. DelayCalcObserver *observer_; @@ -239,7 +276,7 @@ protected: SearchPred *clk_pred_; BfsFwdIterator *iter_; MultiDrvrNetMap multi_drvr_net_map_; - bool multi_drvr_nets_found_; + std::mutex multi_drvr_lock_; // Percentage (0.0:1.0) change in delay that causes downstream // delays to be recomputed during incremental delay calculation. float incremental_delay_tolerance_; @@ -264,10 +301,9 @@ public: class MultiDrvrNet { public: - MultiDrvrNet(VertexSet *drvrs); - ~MultiDrvrNet(); - const VertexSet *drvrs() const { return drvrs_; } - VertexSet *drvrs() { return drvrs_; } + MultiDrvrNet(); + VertexSeq &drvrs() { return drvrs_; } + const VertexSeq &drvrs() const { return drvrs_; } bool parallelGates(const Network *network) const; Vertex *dcalcDrvr() const { return dcalc_drvr_; } void setDcalcDrvr(Vertex *drvr); @@ -283,7 +319,7 @@ public: private: // Driver that triggers delay calculation for all the drivers on the net. Vertex *dcalc_drvr_; - VertexSet *drvrs_; + VertexSeq drvrs_; // [drvr_rf->index][dcalc_ap->index] vector net_caps_; }; diff --git a/include/sta/Hash.hh b/include/sta/Hash.hh index aa6b571c..67036fc0 100644 --- a/include/sta/Hash.hh +++ b/include/sta/Hash.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/HpinDrvrLoad.hh b/include/sta/HpinDrvrLoad.hh index e496798f..74d897d0 100644 --- a/include/sta/HpinDrvrLoad.hh +++ b/include/sta/HpinDrvrLoad.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/InputDrive.hh b/include/sta/InputDrive.hh index fec1a4d0..3d6ae532 100644 --- a/include/sta/InputDrive.hh +++ b/include/sta/InputDrive.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/InternalPower.hh b/include/sta/InternalPower.hh index 58168a9a..79b4115d 100644 --- a/include/sta/InternalPower.hh +++ b/include/sta/InternalPower.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Iterator.hh b/include/sta/Iterator.hh index 6ad9985e..9ddeac6a 100644 --- a/include/sta/Iterator.hh +++ b/include/sta/Iterator.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/LeakagePower.hh b/include/sta/LeakagePower.hh index 8a34747b..b255839b 100644 --- a/include/sta/LeakagePower.hh +++ b/include/sta/LeakagePower.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index 38bcfa39..eef1af46 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -319,6 +319,7 @@ public: DriverWaveform *findDriverWaveform(const char *name); DriverWaveform *driverWaveformDefault() { return driver_waveform_default_; } void addDriverWaveform(DriverWaveform *driver_waveform); + void ensureVoltageWaveforms(); protected: float degradeWireSlew(const TableModel *model, @@ -370,6 +371,7 @@ protected: DriverWaveformMap driver_waveform_map_; // Unnamed driver waveform. DriverWaveform *driver_waveform_default_; + bool have_voltage_waveforms_; static constexpr float input_threshold_default_ = .5; static constexpr float output_threshold_default_ = .5; diff --git a/include/sta/LibertyClass.hh b/include/sta/LibertyClass.hh index 3b0f4d5b..850e12e0 100644 --- a/include/sta/LibertyClass.hh +++ b/include/sta/LibertyClass.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/LibertyWriter.hh b/include/sta/LibertyWriter.hh index 0508a282..c9fa3bfc 100644 --- a/include/sta/LibertyWriter.hh +++ b/include/sta/LibertyWriter.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/LinearModel.hh b/include/sta/LinearModel.hh index 25f1988c..de085b2c 100644 --- a/include/sta/LinearModel.hh +++ b/include/sta/LinearModel.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -29,7 +29,6 @@ public: void gateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, // Return values. ArcDelay &gate_delay, @@ -37,7 +36,6 @@ public: string reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, int digits) const override; float driveResistance(const Pvt *pvt) const override; @@ -54,13 +52,11 @@ class CheckLinearModel : public CheckTimingModel public: explicit CheckLinearModel(LibertyCell *cell, float intrinsic); - void checkDelay(const Pvt *pvt, - float from_slew, - float to_slew, - float related_out_cap, - bool pocv_enabled, - // Return values. - ArcDelay &margin) const override; + ArcDelay checkDelay(const Pvt *pvt, + float from_slew, + float to_slew, + float related_out_cap, + bool pocv_enabled) const override; string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, diff --git a/include/sta/Machine.hh b/include/sta/Machine.hh index acb91ce3..183fe33f 100644 --- a/include/sta/Machine.hh +++ b/include/sta/Machine.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/MakeConcreteNetwork.hh b/include/sta/MakeConcreteNetwork.hh index 7f5ceea3..f8ef2414 100644 --- a/include/sta/MakeConcreteNetwork.hh +++ b/include/sta/MakeConcreteNetwork.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/MakeConcreteParasitics.hh b/include/sta/MakeConcreteParasitics.hh index 3ec769a1..343bc147 100644 --- a/include/sta/MakeConcreteParasitics.hh +++ b/include/sta/MakeConcreteParasitics.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Map.hh b/include/sta/Map.hh index 82a1c54b..450a812e 100644 --- a/include/sta/Map.hh +++ b/include/sta/Map.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/MinMax.hh b/include/sta/MinMax.hh index c24520ef..b8623654 100644 --- a/include/sta/MinMax.hh +++ b/include/sta/MinMax.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/MinMaxValues.hh b/include/sta/MinMaxValues.hh index 50d0b9eb..13fec165 100644 --- a/include/sta/MinMaxValues.hh +++ b/include/sta/MinMaxValues.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Mutex.hh b/include/sta/Mutex.hh index 06b788e9..fa98d5a0 100644 --- a/include/sta/Mutex.hh +++ b/include/sta/Mutex.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Network.hh b/include/sta/Network.hh index 7a87d3e7..8a97dbc7 100644 --- a/include/sta/Network.hh +++ b/include/sta/Network.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -238,6 +238,7 @@ public: // the other primitives. LeafInstanceIterator *leafInstanceIterator() const; LeafInstanceIterator *leafInstanceIterator(const Instance *hier_inst) const; + InstanceSeq leafInstances(); // Iterate over the children of an instance. virtual InstanceChildIterator * childIterator(const Instance *instance) const = 0; diff --git a/include/sta/NetworkClass.hh b/include/sta/NetworkClass.hh index 1fd75778..97fc0a39 100644 --- a/include/sta/NetworkClass.hh +++ b/include/sta/NetworkClass.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/NetworkCmp.hh b/include/sta/NetworkCmp.hh index 1433aff3..ef234de1 100644 --- a/include/sta/NetworkCmp.hh +++ b/include/sta/NetworkCmp.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/NullParasitics.hh b/include/sta/NullParasitics.hh deleted file mode 100644 index 21331cb1..00000000 --- a/include/sta/NullParasitics.hh +++ /dev/null @@ -1,198 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, 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 "Parasitics.hh" - -namespace sta { - -// Parasitics that are not in the house. -class NullParasitics : public Parasitics -{ -public: - NullParasitics(StaState *sta); - virtual bool haveParasitics(); - virtual void clear(); - virtual void save(); - virtual void deleteParasitics(); - virtual void deleteParasitics(const Net *net, - const ParasiticAnalysisPt *ap); - virtual void deleteParasitics(const Pin *pin, - const ParasiticAnalysisPt *ap); - virtual void deleteUnsavedParasitic(Parasitic *parasitic); - virtual void deleteReducedParasitics(const Net *net, - const ParasiticAnalysisPt *ap); - virtual void deleteDrvrReducedParasitics(const Pin *drvr_pin); - - virtual float capacitance(const Parasitic *parasitic) const; - - virtual Parasitic * - findPiElmore(const Pin *drvr_pin, - const RiseFall *rf, - const ParasiticAnalysisPt *ap) const; - virtual Parasitic *makePiElmore(const Pin *drvr_pin, - const RiseFall *rf, - const ParasiticAnalysisPt *ap, - float c2, - float rpi, - float c1); - virtual bool isPiElmore(const Parasitic *parasitic) const; - virtual bool - isReducedParasiticNetwork(const Parasitic *parasitic) const; - virtual void setIsReducedParasiticNetwork(Parasitic *parasitic, - bool is_reduced); - virtual void piModel(const Parasitic *parasitic, - float &c2, - float &rpi, - float &c1) const; - virtual void setPiModel(Parasitic *parasitic, - float c2, - float rpi, - float c1); - virtual void findElmore(const Parasitic *parasitic, - const Pin *load_pin, - float &elmore, - bool &exists) const; - virtual void setElmore(Parasitic *parasitic, const Pin *load_pin, - float elmore); - - virtual bool isPiModel(const Parasitic* parasitic) const; - virtual bool isPiPoleResidue(const Parasitic* parasitic) const; - virtual Parasitic * - findPiPoleResidue(const Pin *drvr_pin, - const RiseFall *rf, - const ParasiticAnalysisPt *ap) const; - virtual Parasitic *makePiPoleResidue(const Pin *drvr_pin, - const RiseFall *rf, - const ParasiticAnalysisPt *ap, - float c2, float rpi, - float c1); - virtual Parasitic *findPoleResidue(const Parasitic *parasitic, - const Pin *load_pin) const; - virtual void setPoleResidue(Parasitic *parasitic, const Pin *load_pin, - ComplexFloatSeq *poles, - ComplexFloatSeq *residues); - virtual bool isPoleResidue(const Parasitic* parasitic) const; - virtual size_t poleResidueCount(const Parasitic *parasitic) const; - virtual void poleResidue(const Parasitic *parasitic, int pole_index, - ComplexFloat &pole, ComplexFloat &residue) const; - - virtual bool isParasiticNetwork(const Parasitic *parasitic) const; - virtual Parasitic *findParasiticNetwork(const Net *net, - const ParasiticAnalysisPt *ap) const; - virtual Parasitic * - findParasiticNetwork(const Pin *pin, - const ParasiticAnalysisPt *ap) const; - virtual Parasitic * - makeParasiticNetwork(const Net *net, - bool pin_cap_included, - const ParasiticAnalysisPt *ap); - virtual ParasiticDeviceIterator *deviceIterator(const Parasitic *) { return nullptr; } - virtual ParasiticNodeIterator *nodeIterator(const Parasitic *) { return nullptr; } - virtual bool includesPinCaps(const Parasitic *parasitic) const; - virtual void deleteParasiticNetwork(const Net *net, - const ParasiticAnalysisPt *ap); - virtual void deleteParasiticNetworks(const Net *net); - virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, - const Net *net, - int id); - virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, - const Pin *pin); - virtual void incrCap(ParasiticNode *node, float cap, - const ParasiticAnalysisPt *ap); - virtual void makeCouplingCap(const char *name, - ParasiticNode *node, - ParasiticNode *other_node, - float cap, const ParasiticAnalysisPt *ap); - virtual void makeCouplingCap(const char *name, - ParasiticNode *node, - Net *other_node_net, int other_node_id, - float cap, const ParasiticAnalysisPt *ap); - virtual void makeCouplingCap(const char *name, - ParasiticNode *node, - Pin *other_node_pin, - float cap, const ParasiticAnalysisPt *ap); - virtual void makeResistor(const char *name, ParasiticNode *node1, - ParasiticNode *node2, float res, - const ParasiticAnalysisPt *ap); - - virtual const char *name(const ParasiticNode *node); - virtual const Pin *connectionPin(const ParasiticNode *node) const; - virtual ParasiticNode *findNode(const Parasitic *parasitic, - const Pin *pin) const; - virtual float nodeGndCap(const ParasiticNode *node, - const ParasiticAnalysisPt *ap) const; - virtual ParasiticDeviceIterator * - deviceIterator(ParasiticNode *node) const; - virtual bool isResistor(const ParasiticDevice *device) const; - virtual bool isCouplingCap(const ParasiticDevice *device)const; - virtual const char *name(const ParasiticDevice *device) const; - virtual float value(const ParasiticDevice *device, - const ParasiticAnalysisPt *ap) const; - virtual ParasiticNode *node1(const ParasiticDevice *device) const; - virtual ParasiticNode *node2(const ParasiticDevice *device) const; - virtual ParasiticNode *otherNode(const ParasiticDevice *device, - ParasiticNode *node) const; - // Reduce parasitic network to reduce_to model. - virtual void reduceTo(const Parasitic *parasitic, - const Net *net, - ReducedParasiticType reduce_to, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); - virtual void reduceToPiElmore(const Parasitic *parasitic, - const Net *net, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); - // Reduce parasitic network to pi elmore model for drvr_pin. - virtual void reduceToPiElmore(const Parasitic *parasitic, - const Pin *drvr_pin, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); - virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, - const Net *net, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); - virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, - const Pin *drvr_pin, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); - virtual Parasitic * - estimatePiElmore(const Pin *drvr_pin, - const RiseFall *rf, - const Wireload *wireload, - float fanout, - float net_pin_cap, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *min_max, - const ParasiticAnalysisPt *ap); - - virtual void disconnectPinBefore(const Pin *pin); - virtual void loadPinCapacitanceChanged(const Pin *pin); -}; - -} // namespace diff --git a/include/sta/ObjectId.hh b/include/sta/ObjectId.hh index 50ae502f..3694c598 100644 --- a/include/sta/ObjectId.hh +++ b/include/sta/ObjectId.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ObjectTable.hh b/include/sta/ObjectTable.hh index 75841df2..eae030f9 100644 --- a/include/sta/ObjectTable.hh +++ b/include/sta/ObjectTable.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Parasitics.hh b/include/sta/Parasitics.hh index f7dca806..a55143c9 100644 --- a/include/sta/Parasitics.hh +++ b/include/sta/Parasitics.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -17,6 +17,8 @@ #pragma once #include +#include +#include #include "StaState.hh" #include "LibertyClass.hh" @@ -31,16 +33,17 @@ class Corner; typedef std::complex ComplexFloat; typedef Vector ComplexFloatSeq; -typedef Iterator ParasiticDeviceIterator; -typedef Iterator ParasiticNodeIterator; +typedef std::vector ParasiticNodeSeq; +typedef std::vector ParasiticResistorSeq; +typedef std::vector ParasiticCapacitorSeq; +typedef std::map ParasiticNodeResistorMap; +typedef std::map ParasiticNodeCapacitorMap; // Parasitics API. // All parasitic parameters can have multiple values, each corresponding // to an analysis point. // Parasitic annotation for a pin or net may exist for one analysis point // and not another. -// If there is only one parasitic for both rise and fall transitions -// the parasitic readers will save it under the rise transition. class Parasitics : public StaState { public: @@ -50,8 +53,6 @@ public: // Clear all state. virtual void clear() = 0; - // Save parasitics to database file. - virtual void save() = 0; // Delete all parasitics. virtual void deleteParasitics() = 0; // Delete all parasitics on net at analysis point. @@ -60,7 +61,6 @@ public: // Delete all parasitics on pin at analysis point. virtual void deleteParasitics(const Pin *pin, const ParasiticAnalysisPt *ap) = 0; - virtual void deleteUnsavedParasitic(Parasitic *parasitic) = 0; virtual void deleteReducedParasitics(const Net *net, const ParasiticAnalysisPt *ap) = 0; virtual void deleteDrvrReducedParasitics(const Pin *drvr_pin) = 0; @@ -153,8 +153,9 @@ public: virtual Parasitic *makeParasiticNetwork(const Net *net, bool includes_pin_caps, const ParasiticAnalysisPt *ap) = 0; - virtual ParasiticDeviceIterator *deviceIterator(const Parasitic *parasitic) = 0; - virtual ParasiticNodeIterator *nodeIterator(const Parasitic *parasitic) = 0; + virtual ParasiticNodeSeq nodes(const Parasitic *parasitic) const = 0; + virtual ParasiticResistorSeq resistors(const Parasitic *parasitic) const = 0; + virtual ParasiticCapacitorSeq capacitors(const Parasitic *parasitic) const = 0; // Delete parasitic network if it exists. virtual void deleteParasiticNetwork(const Net *net, const ParasiticAnalysisPt *ap) = 0; @@ -165,130 +166,98 @@ public: // Make a subnode of the parasitic network net. virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, const Net *net, - int id) = 0; + int id, + const Network *network) = 0; // Make a subnode of the parasitic network net connected to pin. virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, - const Pin *pin) = 0; + const Pin *pin, + const Network *network) = 0; // Increment the grounded capacitance on node. virtual void incrCap(ParasiticNode *node, - float cap, - const ParasiticAnalysisPt *ap) = 0; - // Coupling capacitor between parasitic nodes on a net. - // name is optional. The device takes ownership of the name string. - virtual void makeCouplingCap(const char *name, - ParasiticNode *node, - ParasiticNode *other_node, - float cap, - const ParasiticAnalysisPt *ap) = 0; - // Coupling capacitor to parasitic node on a different net. - // name is optional. The device takes ownership of the name string. - virtual void makeCouplingCap(const char *name, - ParasiticNode *node, - Net *other_node_net, - int other_node_id, - float cap, - const ParasiticAnalysisPt *ap) = 0; - // Coupling capacitor to pin on a different net. - // name is optional. The device takes ownership of the name string. - virtual void makeCouplingCap(const char *name, - ParasiticNode *node, - Pin *other_node_pin, - float cap, - const ParasiticAnalysisPt *ap) = 0; - // name is optional. The device takes ownership of the name string. - virtual void makeResistor(const char *name, - ParasiticNode *node1, - ParasiticNode *node2, - float res, - const ParasiticAnalysisPt *ap) = 0; - // Check integrity of parasitic network. - void check(Parasitic *parasitic) const; - + float cap) = 0; virtual const char *name(const ParasiticNode *node) = 0; - virtual const Pin *connectionPin(const ParasiticNode *node) const = 0; + virtual const Pin *pin(const ParasiticNode *node) const = 0; + virtual const Net *net(const ParasiticNode *node, + const Network *network) const = 0; + virtual bool isExternal(const ParasiticNode *node) const = 0; // Find the parasitic node connected to pin. virtual ParasiticNode *findNode(const Parasitic *parasitic, const Pin *pin) const = 0; // Node capacitance to ground. - virtual float nodeGndCap(const ParasiticNode *node, - const ParasiticAnalysisPt *ap) const = 0; - virtual ParasiticDeviceIterator * - deviceIterator(ParasiticNode *node) const = 0; - virtual bool isResistor(const ParasiticDevice *device) const = 0; - virtual bool isCouplingCap(const ParasiticDevice *device) const = 0; - virtual const char *name(const ParasiticDevice *device) const = 0; - // Device "value" (resistance, capacitance). - virtual float value(const ParasiticDevice *device, - const ParasiticAnalysisPt *ap) const = 0; - virtual ParasiticNode *node1(const ParasiticDevice *device) const = 0; - virtual ParasiticNode *node2(const ParasiticDevice *device) const = 0; - virtual ParasiticNode *otherNode(const ParasiticDevice *device, - ParasiticNode *node) const = 0; + virtual float nodeGndCap(const ParasiticNode *node) const = 0; - // Return true if all loads are annoatated. - virtual bool checkAnnotation(Parasitic *parasitic_network, - const Pin *drvr_pin) = 0; - virtual bool checkAnnotation(const Pin *drvr_pin, - ParasiticNode *drvr_node) = 0; - // Return loads missing path from driver. - virtual PinSet unannotatedLoads(Parasitic *parasitic_network, - const Pin *drvr_pin) = 0; + // Coupling capacitor between parasitic nodes on a net. + virtual void makeCapacitor(Parasitic *parasitic, + size_t id, + float cap, + ParasiticNode *node1, + ParasiticNode *node2) = 0; + virtual size_t id(const ParasiticCapacitor *capacitor) const = 0; + virtual float value(const ParasiticCapacitor *capacitor) const = 0; + virtual ParasiticNode *node1(const ParasiticCapacitor *capacitor) const = 0; + virtual ParasiticNode *node2(const ParasiticCapacitor *capacitor) const = 0; + virtual ParasiticNode *otherNode(const ParasiticCapacitor *capacitor, + ParasiticNode *node) const; + + virtual void makeResistor(Parasitic *parasitic, + size_t id, + float res, + ParasiticNode *node1, + ParasiticNode *node2) = 0; + virtual size_t id(const ParasiticResistor *resistor) const = 0; + virtual float value(const ParasiticResistor *resistor) const = 0; + virtual ParasiticNode *node1(const ParasiticResistor *resistor) const = 0; + virtual ParasiticNode *node2(const ParasiticResistor *resistor) const = 0; + virtual ParasiticNode *otherNode(const ParasiticResistor *capacitor, + ParasiticNode *node) const; + + // Iteration over resistors connected to a nodes. + // ParasiticNodeResistorMap resistor_map = + // parasitics_->parasiticNodeResistorMap(parasitic_network); + // ParasiticResistorSeq &resistors = resistor_map_[node]; + // for (ParasiticResistor *resistor : resistors) { + // } + ParasiticNodeResistorMap parasiticNodeResistorMap(const Parasitic *parasitic) const; + ParasiticNodeCapacitorMap parasiticNodeCapacitorMap(const Parasitic *parasitic) const; + + // Filters loads that are missing path from driver. + virtual PinSet unannotatedLoads(const Parasitic *parasitic, + const Pin *drvr_pin) const = 0; + // unannotatedLoads helper. + PinSet loads(const Pin *drvr_pin) const; - // Reduce parasitic network to reduce_to model. - virtual void reduceTo(const Parasitic *parasitic, - const Net *net, - ReducedParasiticType reduce_to, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap) = 0; - // Reduce parasitic network to pi elmore models. - virtual void reduceToPiElmore(const Parasitic *parasitic, - const Net *net, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap) = 0; // Reduce parasitic network to pi elmore model for drvr_pin. - virtual void reduceToPiElmore(const Parasitic *parasitic, - const Pin *drvr_pin, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap) = 0; - // Reduce parasitic network to pi and 2nd order pole/residue models. - virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, - const Net *net, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap) = 0; + Parasitic *reduceToPiElmore(const Parasitic *parasitic, + const Pin *drvr_pin, + const RiseFall *rf, + const Corner *corner, + const MinMax *cnst_min_max, + const ParasiticAnalysisPt *ap); // Reduce parasitic network to pi and 2nd order pole/residue models // for drvr_pin. - virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, - const Pin *drvr_pin, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap) = 0; + Parasitic *reduceToPiPoleResidue2(const Parasitic *parasitic, + const Pin *drvr_pin, + const RiseFall *rf, + const Corner *corner, + const MinMax *cnst_min_max, + const ParasiticAnalysisPt *ap); // Estimate parasitic as pi elmore using wireload model. - virtual Parasitic *estimatePiElmore(const Pin *drvr_pin, - const RiseFall *rf, - const Wireload *wireload, - float fanout, - float net_pin_cap, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *min_max, - const ParasiticAnalysisPt *ap) = 0; + Parasitic *estimatePiElmore(const Pin *drvr_pin, + const RiseFall *rf, + const Wireload *wireload, + float fanout, + float net_pin_cap, + const Corner *corner, + const MinMax *min_max); Parasitic *makeWireloadNetwork(const Pin *drvr_pin, const Wireload *wireload, float fanout, - const OperatingConditions *op_cond, + const MinMax *min_max, const ParasiticAnalysisPt *ap); // Network edit before/after methods. - virtual void disconnectPinBefore(const Pin *pin) = 0; + virtual void disconnectPinBefore(const Pin *pin, + const Network *network) = 0; virtual void loadPinCapacitanceChanged(const Pin *pin) = 0; protected: @@ -296,20 +265,17 @@ protected: const Pin *drvr_pin, float wireload_cap, float wireload_res, - float fanout, - const ParasiticAnalysisPt *ap); + float fanout); void makeWireloadNetworkBest(Parasitic *parasitic, const Pin *drvr_pin, float wireload_cap, float wireload_res, - float fanout, - const ParasiticAnalysisPt *ap); + float fanout); void makeWireloadNetworkBalanced(Parasitic *parasitic, const Pin *drvr_pin, float wireload_cap, float wireload_res, - float fanout, - const ParasiticAnalysisPt *ap); + float fanout); const Net *findParasiticNet(const Pin *pin) const; }; @@ -320,19 +286,18 @@ class ParasiticAnalysisPt public: ParasiticAnalysisPt(const char *name, int index, - const MinMax *min_max); - ~ParasiticAnalysisPt(); - const char *name() const { return name_; } + int index_max); + const char *name() const { return name_.c_str(); } int index() const { return index_; } - const MinMax *minMax() const { return min_max_; } + int indexMax() const { return index_max_; } // Coupling capacitor factor used by all reduction functions. float couplingCapFactor() const { return coupling_cap_factor_; } void setCouplingCapFactor(float factor); private: - const char *name_; + string name_; int index_; - const MinMax *min_max_; + int index_max_; float coupling_cap_factor_; }; diff --git a/include/sta/ParasiticsClass.hh b/include/sta/ParasiticsClass.hh index f9b20155..b898effe 100644 --- a/include/sta/ParasiticsClass.hh +++ b/include/sta/ParasiticsClass.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -20,10 +20,9 @@ namespace sta { class Parasitics; class Parasitic; -class ParasiticDevice; class ParasiticNode; class ParasiticAnalysisPt; - -enum class ReducedParasiticType { pi_elmore, pi_pole_residue2, arnoldi, none }; +class ParasiticResistor; +class ParasiticCapacitor; } // namespace diff --git a/include/sta/ParseBus.hh b/include/sta/ParseBus.hh index 395cd1f0..ebefd23a 100644 --- a/include/sta/ParseBus.hh +++ b/include/sta/ParseBus.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Path.hh b/include/sta/Path.hh index dd5f2a6c..78bdfb1e 100644 --- a/include/sta/Path.hh +++ b/include/sta/Path.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PathAnalysisPt.hh b/include/sta/PathAnalysisPt.hh index 34d5fc07..6ed6c1b4 100644 --- a/include/sta/PathAnalysisPt.hh +++ b/include/sta/PathAnalysisPt.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PathEnd.hh b/include/sta/PathEnd.hh index 76063d9a..932d8eab 100644 --- a/include/sta/PathEnd.hh +++ b/include/sta/PathEnd.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PathExpanded.hh b/include/sta/PathExpanded.hh index 93b59d9b..f62b302a 100644 --- a/include/sta/PathExpanded.hh +++ b/include/sta/PathExpanded.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PathGroup.hh b/include/sta/PathGroup.hh index 44822c14..167c45b5 100644 --- a/include/sta/PathGroup.hh +++ b/include/sta/PathGroup.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PathRef.hh b/include/sta/PathRef.hh index 299cd4d4..2d4a55a9 100644 --- a/include/sta/PathRef.hh +++ b/include/sta/PathRef.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PathVertex.hh b/include/sta/PathVertex.hh index ab264d97..dd0f6f0c 100644 --- a/include/sta/PathVertex.hh +++ b/include/sta/PathVertex.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PathVertexRep.hh b/include/sta/PathVertexRep.hh index 97dac3f2..a7dca24e 100644 --- a/include/sta/PathVertexRep.hh +++ b/include/sta/PathVertexRep.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PatternMatch.hh b/include/sta/PatternMatch.hh index 74171caa..e266be85 100644 --- a/include/sta/PatternMatch.hh +++ b/include/sta/PatternMatch.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PinPair.hh b/include/sta/PinPair.hh index e74a25b9..0a8c38d0 100644 --- a/include/sta/PinPair.hh +++ b/include/sta/PinPair.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PortDelay.hh b/include/sta/PortDelay.hh index 84606e5f..7bb486e6 100644 --- a/include/sta/PortDelay.hh +++ b/include/sta/PortDelay.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PortDirection.hh b/include/sta/PortDirection.hh index ad2e081f..dd2a81cb 100644 --- a/include/sta/PortDirection.hh +++ b/include/sta/PortDirection.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PortExtCap.hh b/include/sta/PortExtCap.hh index d8965223..ce221edb 100644 --- a/include/sta/PortExtCap.hh +++ b/include/sta/PortExtCap.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/PowerClass.hh b/include/sta/PowerClass.hh index 57c9ad0a..63665609 100644 --- a/include/sta/PowerClass.hh +++ b/include/sta/PowerClass.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Property.hh b/include/sta/Property.hh index 68a2f273..698d1948 100644 --- a/include/sta/Property.hh +++ b/include/sta/Property.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Report.hh b/include/sta/Report.hh index 552d9fb3..8e74494d 100644 --- a/include/sta/Report.hh +++ b/include/sta/Report.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ReportStd.hh b/include/sta/ReportStd.hh index a2352f4c..eb0ef89f 100644 --- a/include/sta/ReportStd.hh +++ b/include/sta/ReportStd.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/ReportTcl.hh b/include/sta/ReportTcl.hh index 7fd16198..b878549e 100644 --- a/include/sta/ReportTcl.hh +++ b/include/sta/ReportTcl.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/RiseFallMinMax.hh b/include/sta/RiseFallMinMax.hh index 9b7581db..11ba437e 100644 --- a/include/sta/RiseFallMinMax.hh +++ b/include/sta/RiseFallMinMax.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/RiseFallValues.hh b/include/sta/RiseFallValues.hh index d11d51c0..827bad22 100644 --- a/include/sta/RiseFallValues.hh +++ b/include/sta/RiseFallValues.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index eb471f20..a8cb921e 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -267,7 +267,7 @@ public: float limit); void setLatchBorrowLimit(const Clock *clk, float limit); - // Return the latch borrow limit respecting precidence if multiple + // Return the latch borrow limit respecting precedence if multiple // limits apply. void latchBorrowLimit(const Pin *data_pin, const Pin *enable_pin, @@ -286,7 +286,7 @@ public: void setMinPulseWidth(const Clock *clk, const RiseFallBoth *rf, float min_width); - // Return min pulse with respecting precidence. + // Return min pulse with respecting precedence. void minPulseWidth(const Pin *pin, const Clock *clk, const RiseFall *hi_low, @@ -606,7 +606,6 @@ public: // Pin capacitance derated by operating conditions and instance pvt. float pinCapacitance(const Pin *pin, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max); void setResistance(const Net *net, @@ -825,7 +824,7 @@ public: LogicValueMap &logicValues() { return logic_value_map_; } LogicValueMap &caseLogicValues() { return case_value_map_; } // Returns nullptr if set_operating_conditions has not been called. - OperatingConditions *operatingConditions(const MinMax *min_max); + OperatingConditions *operatingConditions(const MinMax *min_max) const; // Instance specific process/voltage/temperature. const Pvt *pvt(const Instance *inst, const MinMax *min_max) const; @@ -946,7 +945,6 @@ public: // wire_cap = port external wire capacitance + net wire capacitance void connectedCap(const Pin *pin, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, float &pin_cap, @@ -1233,7 +1231,6 @@ protected: ClockLatency *latency); void pinCaps(const Pin *pin, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, float &pin_cap, @@ -1241,7 +1238,6 @@ protected: float &fanout) const; void netCaps(const Pin *drvr_pin, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, // Return values. @@ -1252,12 +1248,10 @@ protected: // connectedCap pin_cap. float connectedPinCap(const Pin *pin, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max); float portCapacitance(Instance *inst, LibertyPort *port, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max) const; void removeClockGroups(ClockGroups *groups); diff --git a/include/sta/SdcClass.hh b/include/sta/SdcClass.hh index 2cbfd448..c8a9460a 100644 --- a/include/sta/SdcClass.hh +++ b/include/sta/SdcClass.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/SdcCmdComment.hh b/include/sta/SdcCmdComment.hh index ac275e54..e344c840 100644 --- a/include/sta/SdcCmdComment.hh +++ b/include/sta/SdcCmdComment.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/SdcNetwork.hh b/include/sta/SdcNetwork.hh index 91f7abea..f2859f46 100644 --- a/include/sta/SdcNetwork.hh +++ b/include/sta/SdcNetwork.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 85a59916..dc73d6ed 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/SearchClass.hh b/include/sta/SearchClass.hh index 17d67618..66e82e7d 100644 --- a/include/sta/SearchClass.hh +++ b/include/sta/SearchClass.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/SearchPred.hh b/include/sta/SearchPred.hh index 3de7309a..18bac219 100644 --- a/include/sta/SearchPred.hh +++ b/include/sta/SearchPred.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Sequential.hh b/include/sta/Sequential.hh index 2e4cee4c..6f10b2cd 100644 --- a/include/sta/Sequential.hh +++ b/include/sta/Sequential.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Set.hh b/include/sta/Set.hh index a18c42ae..f3c632cd 100644 --- a/include/sta/Set.hh +++ b/include/sta/Set.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 56344d09..34fd2375 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -937,8 +937,8 @@ public: void delaysInvalid(); // Invalidate all arrival and required times. void arrivalsInvalid(); - void visitStartpoints(VertexVisitor *visitor); - void visitEndpoints(VertexVisitor *visitor); + PinSet startpointPins(); + PinSet endpointPins(); VertexSet *endpoints(); int endpointViolationCount(const MinMax *min_max); // Find the fanin vertices for a group path. @@ -1107,18 +1107,14 @@ public: // with normal constant propagate for timing. void clearLogicConstants(); - // Iterator for instances sorted by max driver pin slew. - // Caller owns iterator and iterator->container(). - SlowDrvrIterator *slowDrvrIterator(); + // Instances sorted by max driver pin slew. + InstanceSeq slowDrivers(int count); // Make parasitic analysis points. - // per_corner per_min_max ap_count - // false false 1 - // false true 2 - // true false corners - // true true corners*2 - void setParasiticAnalysisPts(bool per_corner, - bool per_min_max); + // per_corner ap_count + // false 2 + // true corners*2 + void setParasiticAnalysisPts(bool per_corner); // Annotate hierarchical "instance" with parasitics. // The parasitic analysis point is ap_name. // The parasitic memory footprint is much smaller if parasitic @@ -1132,9 +1128,7 @@ public: bool pin_cap_included, bool keep_coupling_caps, float coupling_cap_factor, - ReducedParasiticType reduce_to, - bool delete_after_reduce, - bool quiet); + bool reduce); void reportParasiticAnnotation(bool report_unannotated, const Corner *corner); // Parasitics. diff --git a/include/sta/StaMain.hh b/include/sta/StaMain.hh index 4f4106cd..f576aa0a 100644 --- a/include/sta/StaMain.hh +++ b/include/sta/StaMain.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/StaState.hh b/include/sta/StaState.hh index 49d54081..9fc24a5d 100644 --- a/include/sta/StaState.hh +++ b/include/sta/StaState.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Stats.hh b/include/sta/Stats.hh index 2eb24c6e..36cf29b8 100644 --- a/include/sta/Stats.hh +++ b/include/sta/Stats.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/StringSeq.hh b/include/sta/StringSeq.hh index 24ca33ad..6188a576 100644 --- a/include/sta/StringSeq.hh +++ b/include/sta/StringSeq.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/StringSet.hh b/include/sta/StringSet.hh index 810e8798..6670b3b1 100644 --- a/include/sta/StringSet.hh +++ b/include/sta/StringSet.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -13,15 +13,17 @@ // // You should have received a copy of the GNU General Public License // along with this program. If not, see . - #pragma once +#include + #include "StringUtil.hh" #include "Set.hh" namespace sta { typedef Set StringSet; +typedef std::set StdStringSet; void deleteContents(StringSet *strings); diff --git a/include/sta/StringUtil.hh b/include/sta/StringUtil.hh index 0b1e547d..9f87180f 100644 --- a/include/sta/StringUtil.hh +++ b/include/sta/StringUtil.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index b7d91e6b..ceb475bb 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -62,15 +62,21 @@ public: void gateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, // Return values. ArcDelay &gate_delay, Slew &drvr_slew) const override; + // related_out_cap arg removed. + void gateDelay(const Pvt *pvt, + float in_slew, + float load_cap, + float related_out_cap, + bool pocv_enabled, + ArcDelay &gate_delay, + Slew &drvr_slew) const __attribute__ ((deprecated)); string reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, int digits) const override; float driveResistance(const Pvt *pvt) const override; @@ -130,13 +136,11 @@ public: TableModel *model, TableModel *sigma_models[EarlyLate::index_count]); virtual ~CheckTableModel(); - void checkDelay(const Pvt *pvt, - float from_slew, - float to_slew, - float related_out_cap, - bool pocv_enabled, - // Return values. - ArcDelay &margin) const override; + ArcDelay checkDelay(const Pvt *pvt, + float from_slew, + float to_slew, + float related_out_cap, + bool pocv_enabled) const override; string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, @@ -344,7 +348,6 @@ public: bool &extrapolated) const; float findValue(float axis_value1) const; float findValueClip(float axis_value1) const; - float findValueClipZero(float axis_value1) const; FloatSeq *values() const { return values_; } using Table::findValue; @@ -499,23 +502,31 @@ public: float timeCurrent(float slew, float cap, float time); + float timeVoltage(float slew, + float cap, + float time); float voltageCurrent(float slew, float cap, float volt); float referenceTime(float slew); - void setVdd(float vdd); + void makeVoltageWaveforms(float vdd); static bool checkAxes(const TableTemplate *tbl_template); private: - float voltageTime1(float voltage, - size_t wave_index, - float cap); - FloatSeq *voltageTimes(size_t wave_index, - float cap); void findVoltages(size_t wave_index, float cap); - const Table1 *voltageCurrents(size_t wave_index, - float cap); + float waveformValue(float slew, + float cap, + float axis_value, + Table1Seq &waveforms); + float voltageTime1(float voltage, + size_t wave_index); + void waveformMinMaxTime(float slew, + float cap, + Table1Seq &waveforms, + // Return values. + float &min_time, + float &max_time); // Row. TableAxisPtr slew_axis_; @@ -523,6 +534,7 @@ private: TableAxisPtr cap_axis_; const RiseFall *rf_; Table1Seq current_waveforms_; + Table1Seq voltage_waveforms_; Table1Seq voltage_currents_; FloatTable voltage_times_; Table1 *ref_times_; diff --git a/include/sta/TimingArc.hh b/include/sta/TimingArc.hh index 1c30b77c..87142e7a 100644 --- a/include/sta/TimingArc.hh +++ b/include/sta/TimingArc.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -229,9 +229,7 @@ public: LibertyPort *from() const { return set_->from(); } LibertyPort *to() const { return set_->to(); } Transition *fromEdge() const { return from_rf_; } - Transition *fromTrans() const __attribute__ ((deprecated)) { return from_rf_; } Transition *toEdge() const { return to_rf_; } - Transition *toTrans() const __attribute__ ((deprecated)) { return to_rf_; } TimingRole *role() const { return set_->role(); } TimingArcSet *set() const { return set_; } TimingSense sense() const; diff --git a/include/sta/TimingModel.hh b/include/sta/TimingModel.hh index e6b2fd04..9819b7b2 100644 --- a/include/sta/TimingModel.hh +++ b/include/sta/TimingModel.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -46,7 +46,6 @@ public: virtual void gateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, // Return values. ArcDelay &gate_delay, @@ -54,7 +53,6 @@ public: virtual string reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, int digits) const = 0; virtual float driveResistance(const Pvt *pvt) const = 0; @@ -66,13 +64,11 @@ class CheckTimingModel : public TimingModel public: CheckTimingModel(LibertyCell *cell); // Timing check margin delay calculation. - virtual void checkDelay(const Pvt *pvt, - float from_slew, - float to_slew, - float related_out_cap, - bool pocv_enabled, - // Return values. - ArcDelay &margin) const = 0; + virtual ArcDelay checkDelay(const Pvt *pvt, + float from_slew, + float to_slew, + float related_out_cap, + bool pocv_enabled) const = 0; virtual string reportCheckDelay(const Pvt *pvt, float from_slew, const char *from_slew_annotation, diff --git a/include/sta/TimingRole.hh b/include/sta/TimingRole.hh index be20a04a..51cbf6b7 100644 --- a/include/sta/TimingRole.hh +++ b/include/sta/TimingRole.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/TokenParser.hh b/include/sta/TokenParser.hh index 0320f386..23888477 100644 --- a/include/sta/TokenParser.hh +++ b/include/sta/TokenParser.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Transition.hh b/include/sta/Transition.hh index f4035d20..e4f3d44a 100644 --- a/include/sta/Transition.hh +++ b/include/sta/Transition.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Units.hh b/include/sta/Units.hh index d8b1b509..c9e5baa6 100644 --- a/include/sta/Units.hh +++ b/include/sta/Units.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/UnorderedMap.hh b/include/sta/UnorderedMap.hh index 5c6c9bf5..3e06c879 100644 --- a/include/sta/UnorderedMap.hh +++ b/include/sta/UnorderedMap.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/UnorderedSet.hh b/include/sta/UnorderedSet.hh index ef589088..ecb1525e 100644 --- a/include/sta/UnorderedSet.hh +++ b/include/sta/UnorderedSet.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Vector.hh b/include/sta/Vector.hh index ca0f1e0d..3d69e147 100644 --- a/include/sta/Vector.hh +++ b/include/sta/Vector.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/VerilogNamespace.hh b/include/sta/VerilogNamespace.hh index 830e11ee..13a8e3a8 100644 --- a/include/sta/VerilogNamespace.hh +++ b/include/sta/VerilogNamespace.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/VerilogReader.hh b/include/sta/VerilogReader.hh index 8429426c..7f31b353 100644 --- a/include/sta/VerilogReader.hh +++ b/include/sta/VerilogReader.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/VerilogWriter.hh b/include/sta/VerilogWriter.hh index 56a6f6b4..375f76b3 100644 --- a/include/sta/VerilogWriter.hh +++ b/include/sta/VerilogWriter.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/VertexId.hh b/include/sta/VertexId.hh index 1fa39f5b..3dffcfde 100644 --- a/include/sta/VertexId.hh +++ b/include/sta/VertexId.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/VertexVisitor.hh b/include/sta/VertexVisitor.hh index 2138543c..dfa6ef06 100644 --- a/include/sta/VertexVisitor.hh +++ b/include/sta/VertexVisitor.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/VisitPathEnds.hh b/include/sta/VisitPathEnds.hh index 92359244..b9eee013 100644 --- a/include/sta/VisitPathEnds.hh +++ b/include/sta/VisitPathEnds.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Wireload.hh b/include/sta/Wireload.hh index 629097c1..eb7d8c79 100644 --- a/include/sta/Wireload.hh +++ b/include/sta/Wireload.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/WritePathSpice.hh b/include/sta/WritePathSpice.hh index a54c9c95..ce43c42e 100644 --- a/include/sta/WritePathSpice.hh +++ b/include/sta/WritePathSpice.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -19,13 +19,13 @@ #include #include +#include "StringSet.hh" + namespace sta { using std::string; using std::set; -typedef set StdStringSet; - class Path; class StaState; @@ -45,6 +45,7 @@ writePathSpice(Path *path, StdStringSet *off_path_pin_names, const char *power_name, const char *gnd_name, + bool measure_stmts, StaState *sta); } // namespace diff --git a/include/sta/WriteSdc.hh b/include/sta/WriteSdc.hh index c725b65d..198c15c2 100644 --- a/include/sta/WriteSdc.hh +++ b/include/sta/WriteSdc.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/include/sta/Zlib.hh b/include/sta/Zlib.hh index 9234b929..0dd14157 100644 --- a/include/sta/Zlib.hh +++ b/include/sta/Zlib.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/EquivCells.cc b/liberty/EquivCells.cc index a50493d4..84543d97 100644 --- a/liberty/EquivCells.cc +++ b/liberty/EquivCells.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/FuncExpr.cc b/liberty/FuncExpr.cc index 8e9cc9e9..894ad09f 100644 --- a/liberty/FuncExpr.cc +++ b/liberty/FuncExpr.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/InternalPower.cc b/liberty/InternalPower.cc index 1fef8e5e..40520cc2 100644 --- a/liberty/InternalPower.cc +++ b/liberty/InternalPower.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -189,7 +189,7 @@ InternalPowerModel::findAxisValues(float in_slew, axis_value1 = 0.0; axis_value2 = 0.0; axis_value3 = 0.0; - criticalError(229, "unsupported table order"); + criticalError(225, "unsupported table order"); } } @@ -204,7 +204,7 @@ InternalPowerModel::axisValue(const TableAxis *axis, else if (var == TableAxisVariable::total_output_net_capacitance) return load_cap; else { - criticalError(230, "unsupported table axes"); + criticalError(226, "unsupported table axes"); return 0.0; } } diff --git a/liberty/LeakagePower.cc b/liberty/LeakagePower.cc index 40014d6b..30d95166 100644 --- a/liberty/LeakagePower.cc +++ b/liberty/LeakagePower.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index b9125ab5..3cec13a0 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -84,7 +84,8 @@ LibertyLibrary::LibertyLibrary(const char *name, default_ocv_derate_(nullptr), buffers_(nullptr), inverters_(nullptr), - driver_waveform_default_(nullptr) + driver_waveform_default_(nullptr), + have_voltage_waveforms_(false) { // Scalar templates are builtin. for (int i = 0; i != table_template_type_count; i++) { @@ -362,7 +363,7 @@ LibertyLibrary::degradeWireSlew(const TableModel *model, else if (var1 == TableAxisVariable::connect_delay) return model->findValue(wire_delay, 0.0, 0.0); else { - criticalError(231, "unsupported slew degradation table axes"); + criticalError(1116, "unsupported slew degradation table axes"); return 0.0; } } @@ -378,12 +379,12 @@ LibertyLibrary::degradeWireSlew(const TableModel *model, && var2 == TableAxisVariable::output_pin_transition) return model->findValue(wire_delay, in_slew, 0.0); else { - criticalError(232, "unsupported slew degradation table axes"); + criticalError(1117, "unsupported slew degradation table axes"); return 0.0; } } default: - criticalError(233, "unsupported slew degradation table order"); + criticalError(1118, "unsupported slew degradation table order"); return 0.0; } } @@ -413,7 +414,7 @@ LibertyLibrary::checkSlewDegradationAxes(const TablePtr &table) && var2 == TableAxisVariable::output_pin_transition); } default: - criticalError(234, "unsupported slew degradation table axes"); + criticalError(1119, "unsupported slew degradation table axes"); return 0.0; } } @@ -763,7 +764,7 @@ LibertyLibrary::makeCornerMap(LibertyCell *cell1, port1->setCornerPort(port2, ap_index); } else - report->warn(2, "cell %s/%s port %s not found in cell %s/%s.", + report->warn(1110, "cell %s/%s port %s not found in cell %s/%s.", cell1->library()->name(), cell1->name(), port_name, @@ -789,7 +790,7 @@ LibertyLibrary::makeCornerMap(LibertyCell *cell1, } } else - report->warn(3, "cell %s/%s %s -> %s timing group %s not found in cell %s/%s.", + report->warn(1111, "cell %s/%s %s -> %s timing group %s not found in cell %s/%s.", cell1->library()->name(), cell1->name(), arc_set1->from()->name(), @@ -808,7 +809,7 @@ LibertyLibrary::checkCorners(LibertyCell *cell, for (const Corner *corner : *corners) { for (auto min_max : MinMax::range()) { if (!cell->checkCornerCell(corner, min_max)) - report->error(705, "Liberty cell %s/%s for corner %s/%s not found.", + report->error(1112, "Liberty cell %s/%s for corner %s/%s not found.", cell->libertyLibrary()->name(), cell->name(), corner->name(), @@ -894,6 +895,33 @@ LibertyLibrary::addDriverWaveform(DriverWaveform *driver_waveform) } } +void +LibertyLibrary::ensureVoltageWaveforms() +{ + if (!have_voltage_waveforms_) { + float vdd; + bool vdd_exists; + supplyVoltage("VDD", vdd, vdd_exists); + if (!vdd_exists || vdd == 0.0) + criticalError(1120, "library missing vdd"); + LibertyCellIterator cell_iter(this); + while (cell_iter.hasNext()) { + LibertyCell *cell = cell_iter.next(); + for (TimingArcSet *arc_set : cell->timingArcSets(nullptr, nullptr)) { + for (TimingArc *arc : arc_set->arcs()) { + GateTableModel*model = dynamic_cast(arc->model()); + if (model) { + OutputWaveforms *output_waveforms = model->outputWaveforms(); + if (output_waveforms) + output_waveforms->makeVoltageWaveforms(vdd); + } + } + } + } + have_voltage_waveforms_ = true; + } +} + //////////////////////////////////////////////////////////////// LibertyCellIterator::LibertyCellIterator(const LibertyLibrary *library) : @@ -1384,7 +1412,7 @@ LibertyCell::makeTimingArcMap(Report *) timing_arc_sets_.resize(j); if (timing_arc_set_map_.size() != timing_arc_sets_.size()) - criticalError(205, "timing arc count mismatch"); + criticalError(1121, "timing arc count mismatch"); } void @@ -1745,7 +1773,7 @@ LibertyCell::makeLatchEnables(Report *report, RiseFall *en_rf = latch_enable->enableEdge(); RiseFall *check_rf = check_arc->fromEdge()->asRiseFall(); if (check_rf == en_rf) - report->warn(4, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with %s -> %s setup_%s check.", + report->warn(1113, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with %s -> %s setup_%s check.", library_->name(), name_, en->name(), @@ -1759,7 +1787,7 @@ LibertyCell::makeLatchEnables(Report *report, TimingSense en_sense = en_func->portTimingSense(en); if (en_sense == TimingSense::positive_unate && en_rf != RiseFall::rise()) - report->warn(5, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense.", + report->warn(1114, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense.", library_->name(), name_, en->name(), @@ -1767,7 +1795,7 @@ LibertyCell::makeLatchEnables(Report *report, en_rf == RiseFall::rise()?"rising":"falling"); else if (en_sense == TimingSense::negative_unate && en_rf != RiseFall::fall()) - report->warn(6, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense.", + report->warn(1115, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense.", library_->name(), name_, en->name(), @@ -2583,7 +2611,7 @@ LibertyPort::clockTreePathDelays() GateTimingModel *gate_model = dynamic_cast(model); ArcDelay delay; Slew slew; - gate_model->gateDelay(nullptr, 0.0, 0.0, 0.0, false, delay, slew); + gate_model->gateDelay(nullptr, 0.0, 0.0, false, delay, slew); const RiseFall *rf = arc->toEdge()->asRiseFall(); const MinMax *min_max = (role == TimingRole::clockTreePathMin()) ? MinMax::min() diff --git a/liberty/LibertyBuilder.cc b/liberty/LibertyBuilder.cc index c80a1de7..89a82662 100644 --- a/liberty/LibertyBuilder.cc +++ b/liberty/LibertyBuilder.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -182,17 +182,13 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, && seq->data()->hasPort(from_port)) // Latch D->Q timing arcs. return makeLatchDtoQArcs(cell, from_port, to_port, - seq->data()->portTimingSense(from_port), - related_out, attrs); + seq->data()->portTimingSense(from_port), attrs); else - return makeCombinationalArcs(cell, from_port, to_port, related_out, - true, true, attrs); + return makeCombinationalArcs(cell, from_port, to_port, true, true, attrs); case TimingType::combinational_fall: - return makeCombinationalArcs(cell, from_port, to_port, related_out, - false, true, attrs); + return makeCombinationalArcs(cell, from_port, to_port, false, true, attrs); case TimingType::combinational_rise: - return makeCombinationalArcs(cell, from_port, to_port, related_out, - true, false, attrs); + return makeCombinationalArcs(cell, from_port, to_port, true, false, attrs); case TimingType::setup_rising: return makeFromTransitionArcs(cell, from_port, to_port, related_out, RiseFall::rise(), TimingRole::setup(), @@ -210,17 +206,13 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, RiseFall::fall(), TimingRole::hold(), attrs); case TimingType::rising_edge: - return makeRegLatchArcs(cell, from_port, to_port, related_out, - RiseFall::rise(), attrs); + return makeRegLatchArcs(cell, from_port, to_port, RiseFall::rise(), attrs); case TimingType::falling_edge: - return makeRegLatchArcs(cell, from_port, to_port, related_out, - RiseFall::fall(), attrs); + return makeRegLatchArcs(cell, from_port, to_port, RiseFall::fall(), attrs); case TimingType::preset: - return makePresetClrArcs(cell, from_port, to_port, related_out, - RiseFall::rise(), attrs); + return makePresetClrArcs(cell, from_port, to_port, RiseFall::rise(), attrs); case TimingType::clear: - return makePresetClrArcs(cell, from_port, to_port, related_out, - RiseFall::fall(), attrs); + return makePresetClrArcs(cell, from_port, to_port, RiseFall::fall(), attrs); case TimingType::recovery_rising: return makeFromTransitionArcs(cell, from_port, to_port, related_out, RiseFall::rise(),TimingRole::recovery(), @@ -238,23 +230,17 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, RiseFall::fall(), TimingRole::removal(), attrs); case TimingType::three_state_disable: - return makeTristateDisableArcs(cell, from_port, to_port, related_out, - true, true, attrs); + return makeTristateDisableArcs(cell, from_port, to_port, true, true, attrs); case TimingType::three_state_disable_fall: - return makeTristateDisableArcs(cell, from_port, to_port, related_out, - false, true, attrs); + return makeTristateDisableArcs(cell, from_port, to_port, false, true, attrs); case TimingType::three_state_disable_rise: - return makeTristateDisableArcs(cell, from_port, to_port, related_out, - true, false, attrs); + return makeTristateDisableArcs(cell, from_port, to_port, true, false, attrs); case TimingType::three_state_enable: - return makeTristateEnableArcs(cell, from_port, to_port, related_out, - true, true, attrs); + return makeTristateEnableArcs(cell, from_port, to_port, true, true, attrs); case TimingType::three_state_enable_fall: - return makeTristateEnableArcs(cell, from_port, to_port, related_out, - false, true, attrs); + return makeTristateEnableArcs(cell, from_port, to_port, false, true, attrs); case TimingType::three_state_enable_rise: - return makeTristateEnableArcs(cell, from_port, to_port, related_out, - true, false, attrs); + return makeTristateEnableArcs(cell, from_port, to_port, true, false, attrs); case TimingType::skew_falling: return makeFromTransitionArcs(cell, from_port, to_port, related_out, RiseFall::fall(), TimingRole::skew(), @@ -282,12 +268,10 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, TimingRole::nonSeqHold(), attrs); case TimingType::min_clock_tree_path: - return makeClockTreePathArcs(cell, to_port, related_out, - TimingRole::clockTreePathMin(), + return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMin(), attrs); case TimingType::max_clock_tree_path: - return makeClockTreePathArcs(cell, to_port, related_out, - TimingRole::clockTreePathMax(), + return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMax(), attrs); case TimingType::min_pulse_width: case TimingType::minimum_period: @@ -307,14 +291,13 @@ TimingArcSet * LibertyBuilder::makeCombinationalArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs) { FuncExpr *func = to_port->function(); FuncExpr *enable = to_port->tristateEnable(); - TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out, + TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, TimingRole::combinational(), attrs); TimingSense sense = attrs->timingSense(); if (sense == TimingSense::unknown) { @@ -393,11 +376,9 @@ LibertyBuilder::makeLatchDtoQArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, TimingSense sense, - LibertyPort *related_out, TimingArcAttrsPtr attrs) { TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, - related_out, TimingRole::latchDtoQ(), attrs); TimingModel *model; RiseFall *to_rf = RiseFall::rise(); @@ -421,7 +402,6 @@ TimingArcSet * LibertyBuilder::makeRegLatchArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, RiseFall *from_rf, TimingArcAttrsPtr attrs) { @@ -434,24 +414,24 @@ LibertyBuilder::makeRegLatchArcs(LibertyCell *cell, if (seq->clock() && seq->clock()->hasPort(from_port)) { TimingRole *role = seq->isRegister() ? TimingRole::regClkToQ() : TimingRole::latchEnToQ(); - return makeFromTransitionArcs(cell, from_port, to_port, related_out, - from_rf, role, attrs); + return makeFromTransitionArcs(cell, from_port, to_port, nullptr, + from_rf, role, attrs); } else if (seq->isLatch() && seq->data() && seq->data()->hasPort(from_port)) - return makeFromTransitionArcs(cell, from_port, to_port, related_out, - from_rf, TimingRole::latchDtoQ(), attrs); + return makeFromTransitionArcs(cell, from_port, to_port, nullptr, + from_rf, TimingRole::latchDtoQ(), attrs); else if ((seq->clear() && seq->clear()->hasPort(from_port)) || (seq->preset() && seq->preset()->hasPort(from_port))) - return makeFromTransitionArcs(cell, from_port, to_port, related_out, - from_rf, TimingRole::regSetClr(), attrs); + return makeFromTransitionArcs(cell, from_port, to_port, nullptr, + from_rf, TimingRole::regSetClr(), attrs); } } // No associated ff/latch - assume register clk->q. cell->setHasInferedRegTimingArcs(true); - return makeFromTransitionArcs(cell, from_port, to_port, related_out, - from_rf, TimingRole::regClkToQ(), attrs); + return makeFromTransitionArcs(cell, from_port, to_port, nullptr, + from_rf, TimingRole::regClkToQ(), attrs); } TimingArcSet * @@ -477,14 +457,13 @@ TimingArcSet * LibertyBuilder::makePresetClrArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, RiseFall *to_rf, TimingArcAttrsPtr attrs) { TimingArcSet *arc_set = nullptr; TimingModel *model = attrs->model(to_rf); if (model) { - arc_set = makeTimingArcSet(cell, from_port, to_port, related_out, + arc_set = makeTimingArcSet(cell, from_port, to_port, TimingRole::regSetClr(), attrs); RiseFall *opp_rf = to_rf->opposite(); switch (attrs->timingSense()) { @@ -513,12 +492,11 @@ TimingArcSet * LibertyBuilder::makeTristateEnableArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs) { - TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out, + TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, TimingRole::tristateEnable(), attrs); FuncExpr *tristate_enable = to_port->tristateEnable(); TimingSense sense = attrs->timingSense(); @@ -584,13 +562,11 @@ TimingArcSet * LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs) { TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, - related_out, TimingRole::tristateDisable(), attrs); TimingSense sense = attrs->timingSense(); @@ -655,21 +631,29 @@ LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell, TimingArcSet * LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell, - LibertyPort *to_port, - LibertyPort *related_out, - TimingRole *role, - TimingArcAttrsPtr attrs) + LibertyPort *to_port, + TimingRole *role, + TimingArcAttrsPtr attrs) { - TimingArcSet *arc_set = makeTimingArcSet(cell, nullptr, to_port, - related_out, role, attrs); + TimingArcSet *arc_set = makeTimingArcSet(cell, nullptr, to_port, role, attrs); for (auto to_rf : RiseFall::range()) { TimingModel *model = attrs->model(to_rf); if (model) - makeTimingArc(arc_set, nullptr, to_rf, model); + makeTimingArc(arc_set, nullptr, to_rf->asTransition(), model); } return arc_set; } +TimingArcSet * +LibertyBuilder::makeTimingArcSet(LibertyCell *cell, + LibertyPort *from, + LibertyPort *to, + TimingRole *role, + TimingArcAttrsPtr attrs) +{ + return new TimingArcSet(cell, from, to, nullptr, role, attrs); +} + TimingArcSet * LibertyBuilder::makeTimingArcSet(LibertyCell *cell, LibertyPort *from, diff --git a/liberty/LibertyBuilder.hh b/liberty/LibertyBuilder.hh index f6b64b86..3b4896e4 100644 --- a/liberty/LibertyBuilder.hh +++ b/liberty/LibertyBuilder.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -75,13 +75,11 @@ public: TimingArcSet *makeCombinationalArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs); TimingArcSet *makeClockTreePathArcs(LibertyCell *cell, LibertyPort *to_port, - LibertyPort *related_out, TimingRole *role, TimingArcAttrsPtr attrs); @@ -105,6 +103,11 @@ protected: ConcretePort *bus_port, const char *bus_name, int index); + virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell, + LibertyPort *from, + LibertyPort *to, + TimingRole *role, + TimingArcAttrsPtr attrs); virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell, LibertyPort *from, LibertyPort *to, @@ -123,31 +126,26 @@ protected: LibertyPort *from_port, LibertyPort *to_port, TimingSense sense, - LibertyPort *related_out, TimingArcAttrsPtr attrs); TimingArcSet *makeRegLatchArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, RiseFall *from_rf, TimingArcAttrsPtr attrs); TimingArcSet *makePresetClrArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, RiseFall *to_rf, TimingArcAttrsPtr attrs); TimingArcSet *makeTristateEnableArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs); TimingArcSet *makeTristateDisableArcs(LibertyCell *cell, LibertyPort *from_port, LibertyPort *to_port, - LibertyPort *related_out, bool to_rise, bool to_fall, TimingArcAttrsPtr attrs); diff --git a/liberty/LibertyExpr.cc b/liberty/LibertyExpr.cc index a551c907..3252212f 100644 --- a/liberty/LibertyExpr.cc +++ b/liberty/LibertyExpr.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -79,7 +79,7 @@ LibExprParser::makeFuncExprPort(const char *port_name) if (port) expr = FuncExpr::makePort(port); else - report_->warn(7, "%s references unknown port %s.", + report_->warn(1130, "%s references unknown port %s.", error_msg_, port_name); stringDelete(port_name); return expr; @@ -172,7 +172,7 @@ LibExprParser::tokenAppend(char ch) void LibExprParser::parseError(const char *msg) { - report_->error(206, "%s %s.", error_msg_, msg); + report_->error(1131, "%s %s.", error_msg_, msg); } } // namespace diff --git a/liberty/LibertyExpr.hh b/liberty/LibertyExpr.hh index 2b2cacb8..0bd84c7c 100644 --- a/liberty/LibertyExpr.hh +++ b/liberty/LibertyExpr.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/LibertyExprLex.ll b/liberty/LibertyExprLex.ll index 836a731a..3784e134 100644 --- a/liberty/LibertyExprLex.ll +++ b/liberty/LibertyExprLex.ll @@ -1,7 +1,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/LibertyExprParse.yy b/liberty/LibertyExprParse.yy index f9847b6d..c2b58222 100644 --- a/liberty/LibertyExprParse.yy +++ b/liberty/LibertyExprParse.yy @@ -1,7 +1,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/LibertyExprPvt.hh b/liberty/LibertyExprPvt.hh index 14420e4f..e9a05bd3 100644 --- a/liberty/LibertyExprPvt.hh +++ b/liberty/LibertyExprPvt.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/LibertyExt.cc b/liberty/LibertyExt.cc index 86a13418..dc928bff 100644 --- a/liberty/LibertyExt.cc +++ b/liberty/LibertyExt.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/LibertyLex.ll b/liberty/LibertyLex.ll index 773688a3..a69d736a 100644 --- a/liberty/LibertyLex.ll +++ b/liberty/LibertyLex.ll @@ -1,6 +1,6 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/LibertyParse.yy b/liberty/LibertyParse.yy index c683340d..1424fa29 100644 --- a/liberty/LibertyParse.yy +++ b/liberty/LibertyParse.yy @@ -1,6 +1,6 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/LibertyParser.cc b/liberty/LibertyParser.cc index 3a49c186..45a79802 100644 --- a/liberty/LibertyParser.cc +++ b/liberty/LibertyParser.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -307,7 +307,7 @@ LibertySimpleAttr::~LibertySimpleAttr() LibertyAttrValueSeq * LibertySimpleAttr::values() const { - criticalError(236, "valueIterator called for LibertySimpleAttribute"); + criticalError(1125, "valueIterator called for LibertySimpleAttribute"); return nullptr; } @@ -387,7 +387,7 @@ LibertyStringAttrValue::~LibertyStringAttrValue() float LibertyStringAttrValue::floatValue() { - criticalError(237, "LibertyStringAttrValue called for float value"); + criticalError(1126, "LibertyStringAttrValue called for float value"); return 0.0; } @@ -417,7 +417,7 @@ LibertyFloatAttrValue::floatValue() const char * LibertyFloatAttrValue::stringValue() { - criticalError(238, "LibertyStringAttrValue called for float value"); + criticalError(1127, "LibertyStringAttrValue called for float value"); return nullptr; } diff --git a/liberty/LibertyParser.hh b/liberty/LibertyParser.hh index fcfd62bd..bd3a8804 100644 --- a/liberty/LibertyParser.hh +++ b/liberty/LibertyParser.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index a5350d7a..f26d7076 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -595,7 +595,7 @@ LibertyReader::beginLibrary(LibertyGroup *group) if (name) { LibertyLibrary *library = network_->findLiberty(name); if (library) - libWarn(53, group, "library %s already exists.", name); + libWarn(1140, group, "library %s already exists.", name); // Make a new library even if a library with the same name exists. // Both libraries may be accessed by min/max analysis points. library_ = network_->makeLibertyLibrary(name, filename_); @@ -629,7 +629,7 @@ LibertyReader::beginLibrary(LibertyGroup *group) library_->setScaleFactors(scale_factors_); } else - libError(30, group, "library missing name."); + libError(1141, group, "library missing name."); } // Energy scale is derived. @@ -655,7 +655,7 @@ LibertyReader::endLibraryAttrs(LibertyGroup *group) if (wireload) library_->setDefaultWireload(wireload); else - libWarn(31, group, "default_wire_load %s not found.", default_wireload_); + libWarn(1142, group, "default_wire_load %s not found.", default_wireload_); stringDelete(default_wireload_); default_wireload_ = nullptr; } @@ -666,7 +666,7 @@ LibertyReader::endLibraryAttrs(LibertyGroup *group) if (selection) library_->setDefaultWireloadSelection(selection); else - libWarn(32, group, "default_wire_selection %s not found.", + libWarn(1143, group, "default_wire_selection %s not found.", default_wireload_selection_); stringDelete(default_wireload_selection_); default_wireload_selection_ = nullptr; @@ -678,7 +678,7 @@ LibertyReader::endLibraryAttrs(LibertyGroup *group) if (op_cond) library_->setDefaultOperatingConditions(op_cond); else - libWarn(60, group, "default_operating_condition %s not found.", + libWarn(1144, group, "default_operating_condition %s not found.", default_operating_condition_); stringDelete(default_operating_condition_); default_operating_condition_ = nullptr; @@ -688,24 +688,24 @@ LibertyReader::endLibraryAttrs(LibertyGroup *group) for (auto tr : RiseFall::range()) { int tr_index = tr->index(); if (!have_input_threshold_[tr_index]) { - libWarn(33, group, "input_threshold_pct_%s not found.", tr->name()); + libWarn(1145, group, "input_threshold_pct_%s not found.", tr->name()); missing_threshold = true; } if (!have_output_threshold_[tr_index]) { - libWarn(34, group, "output_threshold_pct_%s not found.", tr->name()); + libWarn(1146, group, "output_threshold_pct_%s not found.", tr->name()); missing_threshold = true; } if (!have_slew_lower_threshold_[tr_index]) { - libWarn(35, group, "slew_lower_threshold_pct_%s not found.", tr->name()); + libWarn(1147, group, "slew_lower_threshold_pct_%s not found.", tr->name()); missing_threshold = true; } if (!have_slew_upper_threshold_[tr_index]) { - libWarn(36, group, "slew_upper_threshold_pct_%s not found.", tr->name()); + libWarn(1148, group, "slew_upper_threshold_pct_%s not found.", tr->name()); missing_threshold = true; } } if (missing_threshold) - libError(37, group, "Library %s is missing one or more thresholds.", + libError(1149, group, "Library %s is missing one or more thresholds.", library_->name()); } @@ -784,7 +784,7 @@ LibertyReader::parseUnits(LibertyAttr *attr, else if (unit_mult == "100") mult = 100.0F; else - libWarn(38, attr, "unknown unit multiplier %s.", unit_mult.c_str()); + libWarn(1150, attr, "unknown unit multiplier %s.", unit_mult.c_str()); } else scale_suffix = units; @@ -807,13 +807,13 @@ LibertyReader::parseUnits(LibertyAttr *attr, else if (scale_char == 'f') scale_mult = 1E-15F; else - libWarn(39, attr, "unknown unit scale %c.", scale_char); + libWarn(1151, attr, "unknown unit scale %c.", scale_char); } else - libWarn(40, attr, "unknown unit suffix %s.", suffix.c_str()); + libWarn(1152, attr, "unknown unit suffix %s.", suffix.c_str()); } else if (!stringEqual(scale_suffix.c_str(), unit_suffix)) - libWarn(171, attr, "unknown unit suffix %s.", scale_suffix.c_str()); + libWarn(1153, attr, "unknown unit suffix %s.", scale_suffix.c_str()); scale_var = scale_mult * mult; unit->setScale(scale_var); } @@ -838,22 +838,22 @@ LibertyReader::visitCapacitiveLoadUnit(LibertyAttr *attr) else if (stringEqual(suffix, "pf")) cap_scale_ = scale * 1E-12F; else - libWarn(41, attr, "capacitive_load_units are not ff or pf."); + libWarn(1154, attr, "capacitive_load_units are not ff or pf."); } else - libWarn(42, attr, "capacitive_load_units are not a string."); + libWarn(1155, attr, "capacitive_load_units are not a string."); } else - libWarn(43, attr, "capacitive_load_units missing suffix."); + libWarn(1156, attr, "capacitive_load_units missing suffix."); } else - libWarn(44, attr, "capacitive_load_units scale is not a float."); + libWarn(1157, attr, "capacitive_load_units scale is not a float."); } else - libWarn(45, attr, "capacitive_load_units missing scale and suffix."); + libWarn(1158, attr, "capacitive_load_units missing scale and suffix."); } else - libWarn(46, attr, "capacitive_load_unit missing values suffix."); + libWarn(1159, attr, "capacitive_load_unit missing values suffix."); library_->units()->capacitanceUnit()->setScale(cap_scale_); setEnergyScale(); } @@ -871,23 +871,23 @@ LibertyReader::visitDelayModel(LibertyAttr *attr) library_->setDelayModelType(DelayModelType::cmos_linear); else if (stringEq(type_name, "piecewise_cmos")) { library_->setDelayModelType(DelayModelType::cmos_pwl); - libWarn(47, attr, "delay_model %s not supported.", type_name); + libWarn(1160, attr, "delay_model %s not supported.", type_name); } else if (stringEq(type_name, "cmos2")) { library_->setDelayModelType(DelayModelType::cmos2); - libWarn(48, attr, "delay_model %s not supported.", type_name); + libWarn(1161, attr, "delay_model %s not supported.", type_name); } else if (stringEq(type_name, "polynomial")) { library_->setDelayModelType(DelayModelType::polynomial); - libWarn(49, attr, "delay_model %s not supported.", type_name); + libWarn(1162, attr, "delay_model %s not supported.", type_name); } // Evil IBM garbage. else if (stringEq(type_name, "dcm")) { library_->setDelayModelType(DelayModelType::dcm); - libWarn(50, attr, "delay_model %s not supported.\n.", type_name); + libWarn(1163, attr, "delay_model %s not supported.\n.", type_name); } else - libWarn(51, attr, "unknown delay_model %s\n.", type_name); + libWarn(1164, attr, "unknown delay_model %s\n.", type_name); } } } @@ -906,7 +906,7 @@ LibertyReader::visitBusStyle(LibertyAttr *attr) && bus_style[4] == 'd') library_->setBusBrkts(bus_style[2], bus_style[5]); else - libWarn(52, attr, "unknown bus_naming_style format."); + libWarn(1165, attr, "unknown bus_naming_style format."); } } @@ -927,19 +927,19 @@ LibertyReader::visitVoltageMap(LibertyAttr *attr) library_->addSupplyVoltage(supply_name, voltage); } else - libWarn(54, attr, "voltage_map voltage is not a float."); + libWarn(1166, attr, "voltage_map voltage is not a float."); } else - libWarn(55, attr, "voltage_map missing voltage."); + libWarn(1167, attr, "voltage_map missing voltage."); } else - libWarn(56, attr, "voltage_map supply name is not a string."); + libWarn(1168, attr, "voltage_map supply name is not a string."); } else - libWarn(57, attr, "voltage_map missing supply name and voltage."); + libWarn(1169, attr, "voltage_map missing supply name and voltage."); } else - libWarn(58, attr, "voltage_map missing values suffix."); + libWarn(1170, attr, "voltage_map missing values suffix."); } } @@ -1024,7 +1024,7 @@ LibertyReader::visitDefaultMaxTransition(LibertyAttr *attr) getAttrFloat(attr, value, exists); if (exists) { if (value == 0.0) - libWarn(160, attr, "default_max_transition is 0.0."); + libWarn(1171, attr, "default_max_transition is 0.0."); library_->setDefaultMaxSlew(value * time_scale_); } } @@ -1039,7 +1039,7 @@ LibertyReader::visitDefaultMaxFanout(LibertyAttr *attr) getAttrFloat(attr, value, exists); if (exists) { if (value == 0.0) - libWarn(16, attr, "default_max_fanout is 0.0."); + libWarn(1172, attr, "default_max_fanout is 0.0."); library_->setDefaultMaxFanout(value); } } @@ -1129,7 +1129,7 @@ LibertyReader::visitDefaultFanoutLoad(LibertyAttr *attr) getAttrFloat(attr, value, exists); if (exists) { if (value == 0.0) - libWarn(163, attr, "default_fanout_load is 0.0."); + libWarn(1173, attr, "default_fanout_load is 0.0."); library_->setDefaultFanoutLoad(value); } } @@ -1157,7 +1157,7 @@ LibertyReader::visitDefaultWireLoadMode(LibertyAttr *attr) if (mode != WireloadMode::unknown) library_->setDefaultWireloadMode(mode); else - libWarn(59, attr, "default_wire_load_mode %s not found.", + libWarn(1174, attr, "default_wire_load_mode %s not found.", wire_load_mode); } } @@ -1328,7 +1328,7 @@ LibertyReader::beginTableTemplate(LibertyGroup *group, library_->addTableTemplate(tbl_template_, type); } else - libWarn(61, group, "table template missing name."); + libWarn(1175, group, "table template missing name."); axis_var_[0] = axis_var_[1] = axis_var_[2] = TableAxisVariable::unknown; clearAxisValues(); } @@ -1373,7 +1373,7 @@ LibertyReader::makeAxis(int index, return make_shared(axis_var, axis_values); } else if (axis_values) { - libWarn(62, group, "missing variable_%d attribute.", index + 1); + libWarn(1176, group, "missing variable_%d attribute.", index + 1); delete axis_values; axis_values_[index] = nullptr; } @@ -1415,7 +1415,7 @@ LibertyReader::visitVariable(int index, const char *type = getAttrString(attr); TableAxisVariable var = stringTableAxisVariable(type); if (var == TableAxisVariable::unknown) - libWarn(63, attr, "axis type %s not supported.", type); + libWarn(1297, attr, "axis type %s not supported.", type); else axis_var_[index] = var; } @@ -1449,13 +1449,13 @@ LibertyReader::visitIndex(int index, FloatSeq *axis_values = readFloatSeq(attr, 1.0F); if (axis_values) { if (axis_values->empty()) - libWarn(172, attr, "missing table index values."); + libWarn(1177, attr, "missing table index values."); else { float prev = (*axis_values)[0]; for (size_t i = 1; i < axis_values->size(); i++) { float value = (*axis_values)[i]; if (value <= prev) - libWarn(173, attr, "non-increasing table index values."); + libWarn(1178, attr, "non-increasing table index values."); prev = value; } } @@ -1487,13 +1487,13 @@ LibertyReader::endType(LibertyGroup *group) } else { if (!type_bit_from_exists_) - libWarn(64, group, "bus type %s missing bit_from.", name); + libWarn(1179, group, "bus type %s missing bit_from.", name); if (!type_bit_to_exists_) - libWarn(65, group, "bus type %s missing bit_to.", name); + libWarn(1180, group, "bus type %s missing bit_to.", name); } } else - libWarn(66, group, "type missing name."); + libWarn(1181, group, "type missing name."); } void @@ -1520,7 +1520,7 @@ LibertyReader::beginScalingFactors(LibertyGroup *group) library_->addScaleFactors(scale_factors_); } else - libWarn(67, group, "scaling_factors do not have a name."); + libWarn(1182, group, "scaling_factors do not have a name."); } void @@ -1689,7 +1689,7 @@ LibertyReader::beginOpCond(LibertyGroup *group) library_->addOperatingConditions(op_cond_); } else - libWarn(68, group, "operating_conditions missing name."); + libWarn(1183, group, "operating_conditions missing name."); } } @@ -1760,7 +1760,7 @@ LibertyReader::beginWireload(LibertyGroup *group) } } else - libWarn(69, group, "wire_load missing name."); + libWarn(1184, group, "wire_load missing name."); } void @@ -1803,7 +1803,7 @@ LibertyReader::visitFanoutLength(LibertyAttr *attr) if (exists) wireload_->addFanoutLength(fanout, length); else - libWarn(70, attr, "fanout_length is missing length and fanout."); + libWarn(1185, attr, "fanout_length is missing length and fanout."); } } @@ -1818,7 +1818,7 @@ LibertyReader::beginWireloadSelection(LibertyGroup *group) } } else - libWarn(71, group, "wire_load_selection missing name."); + libWarn(1186, group, "wire_load_selection missing name."); } void @@ -1849,23 +1849,23 @@ LibertyReader::visitWireloadFromArea(LibertyAttr *attr) wireload_selection_->addWireloadFromArea(min_area, max_area, wireload); else - libWarn(72, attr, "wireload %s not found.", wireload_name); + libWarn(1187, attr, "wireload %s not found.", wireload_name); } else - libWarn(73, attr, + libWarn(1188, attr, "wire_load_from_area wireload name not a string."); } else - libWarn(74, attr, "wire_load_from_area min not a float."); + libWarn(1189, attr, "wire_load_from_area min not a float."); } else - libWarn(75, attr, "wire_load_from_area max not a float."); + libWarn(1190, attr, "wire_load_from_area max not a float."); } else - libWarn(76, attr, "wire_load_from_area missing parameters."); + libWarn(1191, attr, "wire_load_from_area missing parameters."); } else - libWarn(77, attr, "wire_load_from_area missing parameters."); + libWarn(1192, attr, "wire_load_from_area missing parameters."); } } @@ -1884,7 +1884,7 @@ LibertyReader::beginCell(LibertyGroup *group) } } else - libWarn(78, group, "cell missing name."); + libWarn(1193, group, "cell missing name."); } void @@ -1907,7 +1907,7 @@ LibertyReader::endCell(LibertyGroup *group) if (derate) cell_->setOcvDerate(derate); else - libWarn(79, group, "cell %s ocv_derate_group %s not found.", + libWarn(1194, group, "cell %s ocv_derate_group %s not found.", cell_->name(), ocv_derate_name_); stringDelete(ocv_derate_name_); ocv_derate_name_ = nullptr; @@ -1938,7 +1938,7 @@ LibertyReader::checkPort(LibertyPort *port, FuncExpr *func_expr = port->function(); if (func_expr) { if (func_expr->checkSize(port)) { - libWarn(80, line, "port %s function size does not match port size.", + libWarn(1195, line, "port %s function size does not match port size.", port->name()); } } @@ -1994,7 +1994,7 @@ LibertyReader::makeCellSequential(SequentialGroup *seq) const char *clk_attr = is_register ? "clocked_on" : "enable"; clk_expr = parseFunc(clk, clk_attr, line); if (clk_expr && clk_expr->checkSize(size)) { - libWarn(81, line, "%s %s bus width mismatch.", type, clk_attr); + libWarn(1196, line, "%s %s bus width mismatch.", type, clk_attr); clk_expr->deleteSubexprs(); clk_expr = nullptr; } @@ -2005,7 +2005,7 @@ LibertyReader::makeCellSequential(SequentialGroup *seq) const char *data_attr = is_register ? "next_state" : "data_in"; data_expr = parseFunc(data, data_attr, line); if (data_expr && data_expr->checkSize(size)) { - libWarn(82, line, "%s %s bus width mismatch.", type, data_attr); + libWarn(1197, line, "%s %s bus width mismatch.", type, data_attr); data_expr->deleteSubexprs(); data_expr = nullptr; } @@ -2015,7 +2015,7 @@ LibertyReader::makeCellSequential(SequentialGroup *seq) if (clr) { clr_expr = parseFunc(clr, "clear", line); if (clr_expr && clr_expr->checkSize(size)) { - libWarn(83, line, "%s %s bus width mismatch.", type, "clear"); + libWarn(1198, line, "%s %s bus width mismatch.", type, "clear"); clr_expr->deleteSubexprs(); clr_expr = nullptr; } @@ -2025,7 +2025,7 @@ LibertyReader::makeCellSequential(SequentialGroup *seq) if (preset) { preset_expr = parseFunc(preset, "preset", line); if (preset_expr && preset_expr->checkSize(size)) { - libWarn(84, line, "%s %s bus width mismatch.", type, "preset"); + libWarn(1199, line, "%s %s bus width mismatch.", type, "preset"); preset_expr->deleteSubexprs(); preset_expr = nullptr; } @@ -2061,12 +2061,12 @@ LibertyReader::checkLatchEnableSense(FuncExpr *enable_func, case TimingSense::negative_unate: break; case TimingSense::non_unate: - libWarn(85, line, "latch enable function is non-unate for port %s.", + libWarn(1200, line, "latch enable function is non-unate for port %s.", enable_port->name()); break; case TimingSense::none: case TimingSense::unknown: - libWarn(86, line, "latch enable function is unknown for port %s.", + libWarn(1201, line, "latch enable function is unknown for port %s.", enable_port->name()); break; } @@ -2138,16 +2138,16 @@ LibertyReader::beginScaledCell(LibertyGroup *group) cell_ = library_->makeScaledCell(name, filename_); } else - libWarn(87, group, "operating conditions %s not found.", op_cond_name); + libWarn(1202, group, "operating conditions %s not found.", op_cond_name); } else - libWarn(88, group, "scaled_cell missing operating condition."); + libWarn(1203, group, "scaled_cell missing operating condition."); } else - libWarn(89, group, "scaled_cell cell %s has not been defined.", name); + libWarn(1204, group, "scaled_cell cell %s has not been defined.", name); } else - libWarn(90, group, "scaled_cell missing name."); + libWarn(1205, group, "scaled_cell missing name."); } void @@ -2173,14 +2173,14 @@ LibertyReader::checkScaledCell(LibertyGroup *group) { if (equivCellPorts(cell_, scaled_cell_owner_)) { if (!equivCellPortsAndFuncs(cell_, scaled_cell_owner_)) - libWarn(91, group, "scaled_cell %s, %s port functions do not match cell port functions.", + libWarn(1206, group, "scaled_cell %s, %s port functions do not match cell port functions.", cell_->name(), op_cond_->name()); } else - libWarn(92, group, "scaled_cell ports do not match cell ports."); + libWarn(1207, group, "scaled_cell ports do not match cell ports."); if (!equivCellTimingArcSets(cell_, scaled_cell_owner_)) - libWarn(93, group, "scaled_cell %s, %s timing does not match cell timing.", + libWarn(1208, group, "scaled_cell %s, %s timing does not match cell timing.", cell_->name(), op_cond_->name()); } @@ -2199,7 +2199,7 @@ LibertyReader::makeTimingArcs(LibertyPort *to_port, TimingType type = timing->attrs()->timingType(); if (type == TimingType::combinational && to_port_dir->isInput()) - libWarn(94, line, "combinational timing to an input port."); + libWarn(1209, line, "combinational timing to an input port."); if (timing->relatedPortNames()) { for (const char *from_port_name : *timing->relatedPortNames()) { PortNameBitIterator from_port_iter(cell_, from_port_name, this, line); @@ -2294,9 +2294,9 @@ TimingGroup::makeTableModels(LibertyCell *cell, || timing_type == TimingType::three_state_enable_fall || timing_type == TimingType::three_state_enable_rise) { if (transition == nullptr) - reader->libWarn(95, line_, "missing %s_transition.", rf->name()); + reader->libWarn(1210, line_, "missing %s_transition.", rf->name()); if (delay == nullptr) - reader->libWarn(96, line_, "missing cell_%s.", rf->name()); + reader->libWarn(1211, line_, "missing cell_%s.", rf->name()); } } else if (constraint) attrs_->setModel(rf, new CheckTableModel(cell, constraint, @@ -2316,7 +2316,7 @@ LibertyReader::makeTimingArcs(const char *from_port_name, if (from_port_iter.hasNext()) { LibertyPort *from_port = from_port_iter.next(); if (from_port->direction()->isOutput()) - libWarn(164, timing->line(), "timing group from output port."); + libWarn(1212, timing->line(), "timing group from output port."); builder_.makeTimingArcs(cell_, from_port, to_port, related_out_port, timing->attrs(), timing->line()); } @@ -2326,7 +2326,7 @@ LibertyReader::makeTimingArcs(const char *from_port_name, while (from_port_iter.hasNext()) { LibertyPort *from_port = from_port_iter.next(); if (from_port->direction()->isOutput()) - libWarn(165, timing->line(), "timing group from output port."); + libWarn(1213, timing->line(), "timing group from output port."); builder_.makeTimingArcs(cell_, from_port, to_port, related_out_port, timing->attrs(), timing->line()); } @@ -2336,7 +2336,7 @@ LibertyReader::makeTimingArcs(const char *from_port_name, if (from_port_iter.hasNext()) { LibertyPort *from_port = from_port_iter.next(); if (from_port->direction()->isOutput()) - libWarn(166, timing->line(), "timing group from output port."); + libWarn(1214, timing->line(), "timing group from output port."); LibertyPortMemberIterator bit_iter(to_port); while (bit_iter.hasNext()) { LibertyPort *to_port_bit = bit_iter.next(); @@ -2354,14 +2354,14 @@ LibertyReader::makeTimingArcs(const char *from_port_name, LibertyPort *from_port_bit = from_port_iter.next(); LibertyPort *to_port_bit = to_iter.next(); if (from_port_bit->direction()->isOutput()) - libWarn(167, timing->line(), "timing group from output port."); + libWarn(1215, timing->line(), "timing group from output port."); builder_.makeTimingArcs(cell_, from_port_bit, to_port_bit, related_out_port, timing->attrs(), timing->line()); } } else - libWarn(97, timing->line(), + libWarn(1216, timing->line(), "timing port %s and related port %s are different sizes.", from_port_name, to_port->name()); @@ -2370,7 +2370,7 @@ LibertyReader::makeTimingArcs(const char *from_port_name, while (from_port_iter.hasNext()) { LibertyPort *from_port_bit = from_port_iter.next(); if (from_port_bit->direction()->isOutput()) - libWarn(168, timing->line(), "timing group from output port."); + libWarn(1217, timing->line(), "timing group from output port."); LibertyPortMemberIterator to_iter(to_port); while (to_iter.hasNext()) { LibertyPort *to_port_bit = to_iter.next(); @@ -2457,7 +2457,7 @@ LibertyReader::beginReceiverCapacitance(LibertyGroup *group, index_ = index; } else - libWarn(904, group, "receiver_capacitance group not in timing or pin group."); + libWarn(1218, group, "receiver_capacitance group not in timing or pin group."); } void @@ -2474,7 +2474,7 @@ LibertyReader::endReceiverCapacitanceRiseFall(LibertyGroup *group) receiver_model_->setCapacitanceModel(table_model, index_, rf_); } else - libWarn(902, group, "unsupported model axis."); + libWarn(1219, group, "unsupported model axis."); } endTableModel(); } @@ -2502,7 +2502,7 @@ LibertyReader::beginOutputCurrent(RiseFall *rf, output_currents_.clear(); } else - libWarn(907, group, "output_current_%s group not in timing group.", + libWarn(1220, group, "output_current_%s group not in timing group.", rf->name()); } @@ -2543,7 +2543,7 @@ LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group) (*ref_times)[slew_index] = waveform->referenceTime(); } else - libWarn(913, group, "output current waveform %.2e %.2e not found.", + libWarn(1221, group, "output current waveform %.2e %.2e not found.", waveform->slew(), waveform->cap()); } @@ -2563,7 +2563,7 @@ LibertyReader::beginVector(LibertyGroup *group) scale_factor_type_ = ScaleFactorType::unknown; reference_time_exists_ = false; if (tbl_template_ && !OutputWaveforms::checkAxes(tbl_template_)) - libWarn(118, group, "unsupported model axis."); + libWarn(1222, group, "unsupported model axis."); } } @@ -2605,9 +2605,9 @@ LibertyReader::endVector(LibertyGroup *group) output_currents_.push_back(waveform); } else - libWarn(912,group->line(), "vector index_1 and index_2 must have exactly one value."); + libWarn(1223,group->line(), "vector index_1 and index_2 must have exactly one value."); if (!reference_time_exists_) - libWarn(908, group->line(), "vector reference_time not found."); + libWarn(1224, group->line(), "vector reference_time not found."); reference_time_exists_ = false; } } @@ -2640,10 +2640,10 @@ LibertyReader::endNormalizedDriverWaveform(LibertyGroup *group) } else - libWarn(914, group, "normalized_driver_waveform variable_2 must be normalized_voltage"); + libWarn(1225, group, "normalized_driver_waveform variable_2 must be normalized_voltage"); } else - libWarn(915, group, "normalized_driver_waveform variable_1 must be input_net_transition"); + libWarn(1226, group, "normalized_driver_waveform variable_1 must be input_net_transition"); } endTableModel(); } @@ -2748,7 +2748,7 @@ LibertyReader::makeInternalPowers(LibertyPort *port, } } else - libWarn(98, power_group->line(), + libWarn(1227, power_group->line(), "internal_power port %s and related port %s are different sizes.", related_port_name, port->name()); @@ -2865,7 +2865,7 @@ LibertyReader::visitLevelShifterType(LibertyAttr *attr) else if (stringEq(level_shifter_type, "HL_LH")) cell_->setLevelShifterType(LevelShifterType::HL_LH); else - libWarn(900, attr, "level_shifter_type must be HL, LH, or HL_LH"); + libWarn(1228, attr, "level_shifter_type must be HL, LH, or HL_LH"); } } @@ -2901,7 +2901,7 @@ LibertyReader::visitSwitchCellType(LibertyAttr *attr) else if (stringEq(switch_cell_type, "fine_grain")) cell_->setSwitchCellType(SwitchCellType::fine_grain); else - libWarn(901, attr, "switch_cell_type must be coarse_grain or fine_grain"); + libWarn(1229, attr, "switch_cell_type must be coarse_grain or fine_grain"); } } @@ -2925,7 +2925,7 @@ LibertyReader::visitScalingFactors(LibertyAttr *attr) if (scales) cell_->setScaleFactors(scales); else - libWarn(99, attr, "scaling_factors %s not found.", scale_factors_name); + libWarn(1230, attr, "scaling_factors %s not found.", scale_factors_name); } } @@ -2966,7 +2966,7 @@ LibertyReader::beginPin(LibertyGroup *group) } } else - libWarn(100, group, "pin name is not a string."); + libWarn(1231, group, "pin name is not a string."); } } else if (in_bundle_) { @@ -2983,7 +2983,7 @@ LibertyReader::beginPin(LibertyGroup *group) ports_->push_back(port); } else - libWarn(101, group, "pin name is not a string."); + libWarn(1232, group, "pin name is not a string."); } } else { @@ -2997,7 +2997,7 @@ LibertyReader::beginPin(LibertyGroup *group) ports_->push_back(port); } else - libWarn(102, group, "pin name is not a string."); + libWarn(1233, group, "pin name is not a string."); } } port_group_ = new PortGroup(ports_, group->line()); @@ -3075,7 +3075,7 @@ LibertyReader::endBus(LibertyGroup *group) { if (cell_) { if (ports_->empty()) - libWarn(103, group, "bus %s bus_type not found.", group->firstName()); + libWarn(1234, group, "bus %s bus_type not found.", group->firstName()); endBusOrBundle(); in_bus_ = false; } @@ -3127,10 +3127,10 @@ LibertyReader::visitBusType(LibertyAttr *attr) } } else - libWarn(104, attr, "bus_type %s not found.", bus_type); + libWarn(1235, attr, "bus_type %s not found.", bus_type); } else - libWarn(105, attr, "bus_type is not a string."); + libWarn(1236, attr, "bus_type is not a string."); } } @@ -3148,7 +3148,7 @@ LibertyReader::endBundle(LibertyGroup *group) { if (cell_) { if (ports_->empty()) - libWarn(106, group, "bundle %s member not found.", group->firstName()); + libWarn(1237, group, "bundle %s member not found.", group->firstName()); endBusOrBundle(); in_bundle_ = false; } @@ -3171,14 +3171,14 @@ LibertyReader::visitMembers(LibertyAttr *attr) members->push_back(port); } else - libWarn(107, attr, "member is not a string."); + libWarn(1238, attr, "member is not a string."); } LibertyPort *port = builder_.makeBundlePort(cell_, name, members); ports_->push_back(port); } } else - libWarn(108, attr,"members attribute is missing values."); + libWarn(1239, attr,"members attribute is missing values."); } } @@ -3229,7 +3229,7 @@ LibertyReader::visitDirection(LibertyAttr *attr) else if (stringEq(dir, "internal")) port_dir = PortDirection::internal(); else - libWarn(109, attr, "unknown port direction."); + libWarn(1240, attr, "unknown port direction."); for (LibertyPort *port : *ports_) { // Tristate enable function sets direction to tristate; don't @@ -3463,7 +3463,7 @@ LibertyReader::visitMinMaxTransition(LibertyAttr *attr, MinMax *min_max) getAttrFloat(attr, value, exists); if (exists) { if (min_max == MinMax::max() && value == 0.0) - libWarn(161, attr, "max_transition is 0.0."); + libWarn(1241, attr, "max_transition is 0.0."); value *= time_scale_; visitPorts([&] (LibertyPort *port) { port->setSlewLimit(value, min_max); @@ -3569,7 +3569,7 @@ LibertyReader::visitPulseClock(LibertyAttr *attr) sense = RiseFall::fall(); } else - libWarn(110,attr, "pulse_latch unknown pulse type."); + libWarn(1242,attr, "pulse_latch unknown pulse type."); if (trigger) { for (LibertyPort *port : *ports_) port->setPulseClk(trigger, sense); @@ -3858,7 +3858,7 @@ LibertyReader::endTiming(LibertyGroup *group) if (timing_->relatedPortNames() == nullptr && !(timing_type == TimingType::min_clock_tree_path || timing_type == TimingType::max_clock_tree_path)) - libWarn(170, group, "timing group missing related_pin/related_bus_pin."); + libWarn(1243, group, "timing group missing related_pin/related_bus_pin."); } timing_ = nullptr; receiver_model_ = nullptr; @@ -3939,7 +3939,7 @@ LibertyReader::visitTimingType(LibertyAttr *attr) if (type_name) { TimingType type = findTimingType(type_name); if (type == TimingType::unknown) - libWarn(111, attr, "unknown timing_type %s.", type_name); + libWarn(1244, attr, "unknown timing_type %s.", type_name); else timing_->attrs()->setTimingType(type); } @@ -3959,7 +3959,7 @@ LibertyReader::visitTimingSense(LibertyAttr *attr) else if (stringEq(sense_name, "negative_unate")) timing_->attrs()->setTimingSense(TimingSense::negative_unate); else - libWarn(112, attr, "unknown timing_sense %s.", sense_name); + libWarn(1245, attr, "unknown timing_sense %s.", sense_name); } } } @@ -3999,19 +3999,19 @@ LibertyReader::visitMode(LibertyAttr *attr) if (value->isString()) timing_->attrs()->setModeValue(value->stringValue()); else - libWarn(113, attr, "mode value is not a string."); + libWarn(1246, attr, "mode value is not a string."); } else - libWarn(114, attr, "missing mode value."); + libWarn(1247, attr, "missing mode value."); } else - libWarn(115, attr, "mode name is not a string."); + libWarn(1248, attr, "mode name is not a string."); } else - libWarn(116, attr, "mode missing values."); + libWarn(1249, attr, "mode missing values."); } else - libWarn(117, attr, "mode missing mode name and value."); + libWarn(1250, attr, "mode missing mode name and value."); } } @@ -4087,7 +4087,7 @@ LibertyReader::endCellRiseFall(LibertyGroup *group) timing_->setCell(rf_, table_model); } else - libWarn(906, group, "unsupported model axis."); + libWarn(1251, group, "unsupported model axis."); } endTableModel(); } @@ -4114,7 +4114,7 @@ LibertyReader::endRiseFallTransition(LibertyGroup *group) timing_->setTransition(rf_, table_model); } else - libWarn(119, group, "unsupported model axis."); + libWarn(1252, group, "unsupported model axis."); } endTableModel(); } @@ -4143,7 +4143,7 @@ LibertyReader::endRiseFallConstraint(LibertyGroup *group) timing_->setConstraint(rf_, table_model); } else - libWarn(120, group, "unsupported model axis."); + libWarn(1253, group, "unsupported model axis."); } endTableModel(); } @@ -4178,7 +4178,7 @@ LibertyReader::endRiseFallTransitionDegredation(LibertyGroup *group) library_->setWireSlewDegradationTable(table_model, rf_); } else - libWarn(121, group, "unsupported model axis."); + libWarn(1254, group, "unsupported model axis."); } endTableModel(); } @@ -4194,7 +4194,7 @@ LibertyReader::beginTimingTableModel(LibertyGroup *group, beginTableModel(group, TableTemplateType::delay, rf, time_scale_, scale_factor_type); else - libWarn(903, group, "%s group not in timing group.", group->firstName()); + libWarn(1255, group, "%s group not in timing group.", group->firstName()); } void @@ -4233,7 +4233,7 @@ LibertyReader::beginTable(LibertyGroup *group, axis_[2] = tbl_template_->axis3ptr(); } else { - libWarn(122, group, "table template %s not found.", template_name); + libWarn(1256, group, "table template %s not found.", template_name); axis_[0] = nullptr; axis_[1] = nullptr; axis_[2] = nullptr; @@ -4317,7 +4317,7 @@ LibertyReader::makeTable(LibertyAttr *attr, } } else - libWarn(123, attr, "%s is missing values.", attr->name()); + libWarn(1257, attr, "%s is missing values.", attr->name()); } FloatTable * @@ -4340,9 +4340,9 @@ LibertyReader::makeFloatTable(LibertyAttr *attr, // Scalar value. row->push_back(value->floatValue() * scale); else - libWarn(124, attr, "%s is not a list of floats.", attr->name()); + libWarn(1258, attr, "%s is not a list of floats.", attr->name()); if (row->size() != cols) { - libWarn(125, attr, "table row has %u columns but axis has %d.", + libWarn(1259, attr, "table row has %u columns but axis has %d.", // size_t is long on 64 bit ports. static_cast(row->size()), static_cast(cols)); @@ -4352,7 +4352,7 @@ LibertyReader::makeFloatTable(LibertyAttr *attr, } } if (table->size() != rows) { - libWarn(126, attr, "table has %u rows but axis has %d.", + libWarn(1260, attr, "table has %u rows but axis has %d.", // size_t is long on 64 bit ports. static_cast(table->size()), static_cast(rows)); @@ -4403,7 +4403,7 @@ LibertyReader::beginLut(LibertyGroup *group) } } else - libWarn(127, group, "lut output is not a string."); + libWarn(1261, group, "lut output is not a string."); } } } @@ -4420,7 +4420,7 @@ void LibertyReader::beginTestCell(LibertyGroup *group) { if (cell_ && cell_->testCell()) - libWarn(169, group, "cell %s test_cell redefinition.", cell_->name()); + libWarn(1262, group, "cell %s test_cell redefinition.", cell_->name()); else { test_cell_ = new TestCell; cell_->setTestCell(test_cell_); @@ -4445,7 +4445,7 @@ LibertyReader::beginModeDef(LibertyGroup *group) if (name) mode_def_ = cell_->makeModeDef(name); else - libWarn(128, group, "mode definition missing name."); + libWarn(1263, group, "mode definition missing name."); } void @@ -4462,7 +4462,7 @@ LibertyReader::beginModeValue(LibertyGroup *group) if (name) mode_value_ = mode_def_->defineValue(name, nullptr, nullptr); else - libWarn(129, group, "mode value missing name."); + libWarn(1264, group, "mode value missing name."); } } @@ -4476,7 +4476,7 @@ void LibertyReader::visitWhen(LibertyAttr *attr) { if (tbl_template_) - libWarn(130, attr, "when attribute inside table model."); + libWarn(1265, attr, "when attribute inside table model."); if (mode_value_) { const char *func = getAttrString(attr); if (func) @@ -4525,10 +4525,10 @@ LibertyReader::getAttrString(LibertyAttr *attr) if (value->isString()) return value->stringValue(); else - libWarn(131, attr, "%s attribute is not a string.", attr->name()); + libWarn(1266, attr, "%s attribute is not a string.", attr->name()); } else - libWarn(132, attr, "%s is not a simple attribute.", attr->name()); + libWarn(1267, attr, "%s is not a simple attribute.", attr->name()); return nullptr; } @@ -4548,10 +4548,10 @@ LibertyReader::getAttrInt(LibertyAttr *attr, exists = true; } else - libWarn(162, attr, "%s attribute is not an integer.",attr->name()); + libWarn(1268, attr, "%s attribute is not an integer.",attr->name()); } else - libWarn(133, attr, "%s is not a simple attribute.", attr->name()); + libWarn(1269, attr, "%s is not a simple attribute.", attr->name()); } void @@ -4564,7 +4564,7 @@ LibertyReader::getAttrFloat(LibertyAttr *attr, if (attr->isSimple()) getAttrFloat(attr, attr->firstValue(), value, valid); else - libWarn(134, attr, "%s is not a simple attribute.", attr->name()); + libWarn(1270, attr, "%s is not a simple attribute.", attr->name()); } void @@ -4590,7 +4590,7 @@ LibertyReader::getAttrFloat(LibertyAttr *attr, if ((*end && !isspace(*end)) // strtof support INF as a valid float. || stringEqual(string, "inf")) - libWarn(135, attr, "%s value %s is not a float.", + libWarn(1271, attr, "%s value %s is not a float.", attr->name(), string); valid = true; @@ -4619,14 +4619,14 @@ LibertyReader::getAttrFloat2(LibertyAttr *attr, getAttrFloat(attr, value, value2, exists); } else - libWarn(136, attr, "%s missing values.", attr->name()); + libWarn(1272, attr, "%s missing values.", attr->name()); } } else - libWarn(137, attr, "%s missing values.", attr->name()); + libWarn(1273, attr, "%s missing values.", attr->name()); } else - libWarn(138, attr, "%s is not a complex attribute.", attr->name()); + libWarn(1274, attr, "%s is not a complex attribute.", attr->name()); } // Parse string of comma separated floats. @@ -4652,7 +4652,7 @@ LibertyReader::parseStringFloatList(const char *float_list, || isspace(*end) || strchr(delimiters, *end) != nullptr || *end == '}'))) - libWarn(139, attr, "%s is not a float.", token); + libWarn(1275, attr, "%s is not a float.", token); values->push_back(value); } } @@ -4675,10 +4675,10 @@ LibertyReader::readFloatSeq(LibertyAttr *attr, values->push_back(value->floatValue()); } else - libWarn(140, attr, "%s is missing values.", attr->name()); + libWarn(1276, attr, "%s is missing values.", attr->name()); } if (value_iter.hasNext()) - libWarn(141, attr, "%s has more than one string.", attr->name()); + libWarn(1277, attr, "%s has more than one string.", attr->name()); } else { LibertyAttrValue *value = attr->firstValue(); @@ -4687,7 +4687,7 @@ LibertyReader::readFloatSeq(LibertyAttr *attr, parseStringFloatList(value->stringValue(), scale, values, attr); } else - libWarn(142, attr, "%s is missing values.", attr->name()); + libWarn(1278, attr, "%s is missing values.", attr->name()); } return values; } @@ -4712,13 +4712,13 @@ LibertyReader::getAttrBool(LibertyAttr *attr, exists = true; } else - libWarn(143, attr, "%s attribute is not boolean.", attr->name()); + libWarn(1279, attr, "%s attribute is not boolean.", attr->name()); } else - libWarn(144, attr, "%s attribute is not boolean.", attr->name()); + libWarn(1280, attr, "%s attribute is not boolean.", attr->name()); } else - libWarn(145, attr, "%s is not a simple attribute.", attr->name()); + libWarn(1281, attr, "%s is not a simple attribute.", attr->name()); } // Read L/H/X string attribute values as bool. @@ -4734,7 +4734,7 @@ LibertyReader::getAttrLogicValue(LibertyAttr *attr) else if (stringEq(str, "X")) return LogicValue::unknown; else - libWarn(146, attr, "attribute %s value %s not recognized.", + libWarn(1282, attr, "attribute %s value %s not recognized.", attr->name(), str); // fall thru } @@ -4765,7 +4765,7 @@ LibertyReader::getAttrEarlyLate(LibertyAttr *attr) else if (stringEq(value, "early_and_late")) return EarlyLateAll::all(); else { - libWarn(147, attr, "unknown early/late value."); + libWarn(1283, attr, "unknown early/late value."); return EarlyLateAll::all(); } } @@ -4985,7 +4985,7 @@ LibertyReader::visitDefaultOcvDerateGroup(LibertyAttr *attr) if (derate) library_->setDefaultOcvDerate(derate); else - libWarn(148, attr, "OCV derate group named %s not found.", derate_name); + libWarn(1284, attr, "OCV derate group named %s not found.", derate_name); } void @@ -5001,7 +5001,7 @@ LibertyReader::beginOcvDerate(LibertyGroup *group) if (name) ocv_derate_ = new OcvDerate(stringCopy(name)); else - libWarn(149, group, "ocv_derate missing name."); + libWarn(1285, group, "ocv_derate missing name."); } void @@ -5054,7 +5054,7 @@ LibertyReader::visitRfType(LibertyAttr *attr) else if (stringEq(rf_name, "rise_and_fall")) rf_type_ = RiseFallBoth::riseFall(); else - libError(150, attr, "unknown rise/fall."); + libError(1286, attr, "unknown rise/fall."); } void @@ -5074,7 +5074,7 @@ LibertyReader::visitPathType(LibertyAttr *attr) else if (stringEq(path_type, "clock_and_data")) path_type_ = PathType::clk_and_data; else - libWarn(151, attr, "unknown derate type."); + libWarn(1287, attr, "unknown derate type."); } //////////////////////////////////////////////////////////////// @@ -5106,7 +5106,7 @@ LibertyReader::endOcvSigmaCell(LibertyGroup *group) timing_->setDelaySigma(rf_, sigma_type_->asMinMax(), table_model); } else - libWarn(152, group, "unsupported model axis."); + libWarn(1288, group, "unsupported model axis."); } endTableModel(); } @@ -5138,7 +5138,7 @@ LibertyReader::endOcvSigmaTransition(LibertyGroup *group) timing_->setSlewSigma(rf_, sigma_type_->asMinMax(), table_model); } else - libWarn(153, group, "unsupported model axis."); + libWarn(1289, group, "unsupported model axis."); } endTableModel(); } @@ -5170,7 +5170,7 @@ LibertyReader::endOcvSigmaConstraint(LibertyGroup *group) timing_->setConstraintSigma(rf_, sigma_type_->asMinMax(), table_model); } else - libWarn(154, group, "unsupported model axis."); + libWarn(1290, group, "unsupported model axis."); } endTableModel(); } @@ -5241,7 +5241,7 @@ LibertyReader::visitPgType(LibertyAttr *attr) type = LibertyPgPort::PgType::deeppwell; else - libError(155, attr, "unknown pg_type."); + libError(1291, attr, "unknown pg_type."); pg_port_->setPgType(type); } } @@ -5636,11 +5636,11 @@ PortNameBitIterator::init(const char *port_name) range_bit_ = from; } else - visitor_->libWarn(156, line_, "port %s subscript out of range.", + visitor_->libWarn(1292, line_, "port %s subscript out of range.", port_name); } else - visitor_->libWarn(157, line_, "port range %s of non-bus port %s.", + visitor_->libWarn(1293, line_, "port range %s of non-bus port %s.", port_name, bus_name.c_str()); } @@ -5654,7 +5654,7 @@ PortNameBitIterator::init(const char *port_name) size_ = abs(from - to) + 1; } else - visitor_->libWarn(158, line_, "port %s not found.", port_name); + visitor_->libWarn(1294, line_, "port %s not found.", port_name); } } @@ -5724,7 +5724,7 @@ PortNameBitIterator::findRangeBusNameNext() range_bit_++; } else - visitor_->libWarn(159, line_, "port %s not found.", bus_bit_name.c_str()); + visitor_->libWarn(1295, line_, "port %s not found.", bus_bit_name.c_str()); } else range_name_next_ = nullptr; diff --git a/liberty/LibertyReader.hh b/liberty/LibertyReader.hh index b839b49e..f83340bc 100644 --- a/liberty/LibertyReader.hh +++ b/liberty/LibertyReader.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index 6c7ea2d1..6a088619 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/LibertyWriter.cc b/liberty/LibertyWriter.cc index 2a05a59c..5a94f482 100644 --- a/liberty/LibertyWriter.cc +++ b/liberty/LibertyWriter.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -283,7 +283,7 @@ LibertyWriter::writeCell(const LibertyCell *cell) if (port->isBus()) writeBusPort(port); else if (port->isBundle()) - report_->error(704, "%s/%s bundled ports not supported.", + report_->error(1330, "%s/%s bundled ports not supported.", library_->name(), cell->name()); else @@ -414,7 +414,7 @@ LibertyWriter::writeTimingModels(const TimingArc *arc, fprintf(stream_, " }\n"); } else - report_->error(701, "%s/%s/%s timing model not supported.", + report_->error(1331, "%s/%s/%s timing model not supported.", library_->name(), arc->from()->libertyCell()->name(), arc->from()->name()); @@ -434,7 +434,7 @@ LibertyWriter::writeTableModel(const TableModel *model) writeTableModel2(model); break; case 3: - report_->error(702, "3 axis table models not supported."); + report_->error(1332, "3 axis table models not supported."); break; } } @@ -578,7 +578,7 @@ LibertyWriter::timingTypeString(const TimingArcSet *arc_set) else if (role == TimingRole::clockTreePathMax()) return "max_clock_tree_path"; else { - report_->error(703, "%s/%s/%s timing arc type %s not supported.", + report_->error(1333, "%s/%s/%s timing arc type %s not supported.", library_->name(), arc_set->to()->libertyCell()->name(), arc_set->to()->name(), diff --git a/liberty/LinearModel.cc b/liberty/LinearModel.cc index 1ba8ff8b..6abebfcf 100644 --- a/liberty/LinearModel.cc +++ b/liberty/LinearModel.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -34,7 +34,6 @@ void GateLinearModel::gateDelay(const Pvt *, float, float load_cap, - float, bool, // return values ArcDelay &gate_delay, @@ -48,7 +47,6 @@ string GateLinearModel::reportGateDelay(const Pvt *, float, float load_cap, - float, bool, int digits) const { @@ -87,15 +85,14 @@ CheckLinearModel::CheckLinearModel(LibertyCell *cell, { } -void +ArcDelay CheckLinearModel::checkDelay(const Pvt *, float, float, float, - bool, - ArcDelay &margin) const + bool) const { - margin = intrinsic_; + return intrinsic_; } string diff --git a/liberty/Sequential.cc b/liberty/Sequential.cc index 5f95bbd9..3348789f 100644 --- a/liberty/Sequential.cc +++ b/liberty/Sequential.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 43063b56..5604b7fb 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -104,67 +104,77 @@ void GateTableModel::gateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, // return values ArcDelay &gate_delay, Slew &drvr_slew) const { - float delay = findValue(pvt, delay_model_, in_slew, load_cap, related_out_cap); + float delay = findValue(pvt, delay_model_, in_slew, load_cap, 0.0); float sigma_early = 0.0; float sigma_late = 0.0; if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()]) sigma_early = findValue(pvt, delay_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, related_out_cap); + in_slew, load_cap, 0.0); if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()]) sigma_late = findValue(pvt, delay_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, related_out_cap); + in_slew, load_cap, 0.0); gate_delay = makeDelay(delay, sigma_early, sigma_late); - float slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap); + float slew = findValue(pvt, slew_model_, in_slew, load_cap, 0.0); if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()]) sigma_early = findValue(pvt, slew_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, related_out_cap); + in_slew, load_cap, 0.0); if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()]) sigma_late = findValue(pvt, slew_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, related_out_cap); + in_slew, load_cap, 0.0); // Clip negative slews to zero. if (slew < 0.0) slew = 0.0; drvr_slew = makeDelay(slew, sigma_early, sigma_late); } +void +GateTableModel::gateDelay(const Pvt *pvt, + float in_slew, + float load_cap, + float, + bool pocv_enabled, + ArcDelay &gate_delay, + Slew &drvr_slew) const +{ + gateDelay(pvt, in_slew, load_cap, pocv_enabled, gate_delay, drvr_slew); +} + string GateTableModel::reportGateDelay(const Pvt *pvt, float in_slew, float load_cap, - float related_out_cap, bool pocv_enabled, int digits) const { string result = reportPvt(cell_, pvt, digits); result += reportTableLookup("Delay", pvt, delay_model_, in_slew, - load_cap, related_out_cap, digits); + load_cap, 0.0, digits); if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()]) result += reportTableLookup("Delay sigma(early)", pvt, delay_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, related_out_cap, digits); + in_slew, load_cap, 0.0, digits); if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()]) result += reportTableLookup("Delay sigma(late)", pvt, delay_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, related_out_cap, digits); + in_slew, load_cap, 0.0, digits); result += '\n'; result += reportTableLookup("Slew", pvt, slew_model_, in_slew, - load_cap, related_out_cap, digits); + load_cap, 9.0, digits); if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()]) result += reportTableLookup("Slew sigma(early)", pvt, slew_sigma_models_[EarlyLate::earlyIndex()], - in_slew, load_cap, related_out_cap, digits); + in_slew, load_cap, 0.0, digits); if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()]) result += reportTableLookup("Slew sigma(late)", pvt, slew_sigma_models_[EarlyLate::lateIndex()], - in_slew, load_cap, related_out_cap, digits); - float drvr_slew = findValue(pvt, slew_model_, in_slew, load_cap, related_out_cap); + in_slew, load_cap, 0.0, digits); + float drvr_slew = findValue(pvt, slew_model_, in_slew, load_cap, 0.0); if (drvr_slew < 0.0) result += "Negative slew clipped to 0.0\n"; return result; @@ -407,14 +417,12 @@ CheckTableModel::setIsScaled(bool is_scaled) model_->setIsScaled(is_scaled); } -void +ArcDelay CheckTableModel::checkDelay(const Pvt *pvt, float from_slew, float to_slew, float related_out_cap, - bool pocv_enabled, - // Return values. - ArcDelay &margin) const + bool pocv_enabled) const { if (model_) { float mean = findValue(pvt, model_, from_slew, to_slew, related_out_cap); @@ -426,10 +434,10 @@ CheckTableModel::checkDelay(const Pvt *pvt, if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()]) sigma_late = findValue(pvt, sigma_models_[EarlyLate::lateIndex()], from_slew, to_slew, related_out_cap); - margin = makeDelay(mean, sigma_early, sigma_late); + return makeDelay(mean, sigma_early, sigma_late); } else - margin = 0.0; + return 0.0; } float @@ -876,7 +884,7 @@ Table1::findValueClip(float axis_value1) const float x1l = axis1_->axisValue(axis_index1); float x1u = axis1_->axisValue(axis_index1 + 1); if (x1 < x1l) - return this->value(0); + return 0.0; else if (x1 > x1u) return this->value(axis1_->size() - 1); else { @@ -888,27 +896,6 @@ Table1::findValueClip(float axis_value1) const } } -float -Table1::findValueClipZero(float axis_value1) const -{ - if (axis1_->size() == 1) - return this->value(axis_value1); - else { - size_t axis_index1 = axis1_->findAxisIndex(axis_value1); - float x1 = axis_value1; - float x1l = axis1_->axisValue(axis_index1); - float x1u = axis1_->axisValue(axis_index1 + 1); - if (x1 < x1l || x1 > x1u) - return 0.0; - else { - float y1 = this->value(axis_index1); - float y2 = this->value(axis_index1 + 1); - float dx1 = (x1 - x1l) / (x1u - x1l); - return (1 - dx1) * y1 + dx1 * y2; - } - } -} - string Table1::reportValue(const char *result_name, const LibertyCell *cell, @@ -1588,8 +1575,6 @@ OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis, cap_axis_(cap_axis), rf_(rf), current_waveforms_(current_waveforms), - voltage_currents_(current_waveforms.size()), - voltage_times_(current_waveforms.size()), ref_times_(ref_times), vdd_(0.0) { @@ -1598,6 +1583,7 @@ OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis, OutputWaveforms::~OutputWaveforms() { current_waveforms_.deleteContents(); + voltage_waveforms_.deleteContents(); voltage_currents_.deleteContents(); voltage_times_.deleteContents(); delete ref_times_; @@ -1620,6 +1606,83 @@ OutputWaveforms::checkAxes(const TableTemplate *tbl_template) && axis3->variable() == TableAxisVariable::time); } +void +OutputWaveforms::makeVoltageWaveforms(float vdd) +{ + vdd_ = 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++) { + size_t wave_index = slew_index * cap_count + cap_index; + findVoltages(wave_index, cap_axis_->axisValue(cap_index)); + } + } +} + +void +OutputWaveforms::findVoltages(size_t wave_index, + float cap) +{ + // Integrate current waveform to find voltage waveform. + // i = C dv/dt + FloatSeq *volts = new FloatSeq; + Table1 *currents = current_waveforms_[wave_index]; + const TableAxis *time_axis = currents->axis1(); + float prev_time = time_axis->axisValue(0); + float prev_current = currents->value(0); + float voltage = 0.0; + volts->push_back(voltage); + bool always_rise = true; + bool invert = (always_rise && rf_ == RiseFall::fall()); + for (size_t i = 1; i < time_axis->size(); i++) { + float time = time_axis->axisValue(i); + float current = currents->value(i); + float dv = (current + prev_current) / 2.0 * (time - prev_time) / cap; + voltage += invert ? -dv : dv; + volts->push_back(voltage); + prev_time = time; + prev_current = current; + } + Table1 *volt_table = new Table1(volts, currents->axis1ptr()); + voltage_waveforms_[wave_index] = volt_table; + + // Make voltage -> current table. + FloatSeq *axis_volts = new FloatSeq(*volts); + TableAxisPtr volt_axis = + make_shared(TableAxisVariable::input_voltage, axis_volts); + 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 * OutputWaveforms::currentWaveform(float slew, float cap) @@ -1634,6 +1697,31 @@ float OutputWaveforms::timeCurrent(float slew, float cap, float time) +{ + return waveformValue(slew, cap, time, current_waveforms_); +} + +float +OutputWaveforms::timeVoltage(float slew, + float cap, + float time) +{ + return waveformValue(slew, cap, time, voltage_waveforms_); +} + +float +OutputWaveforms::voltageCurrent(float slew, + float cap, + float volt) +{ + return waveformValue(slew, cap, volt, voltage_currents_); +} + +float +OutputWaveforms::waveformValue(float slew, + float cap, + float axis_value, + Table1Seq &waveforms) { size_t slew_index = slew_axis_->findAxisIndex(slew); size_t cap_index = cap_axis_->findAxisIndex(cap); @@ -1643,10 +1731,10 @@ OutputWaveforms::timeCurrent(float slew, 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]; + const Table1 *waveform00 = waveforms[wave_index00]; + const Table1 *waveform01 = waveforms[wave_index01]; + const Table1 *waveform10 = waveforms[wave_index10]; + const Table1 *waveform11 = waveforms[wave_index11]; // Interpolate waveform samples at voltage steps. size_t index1 = slew_index; @@ -1660,16 +1748,16 @@ OutputWaveforms::timeCurrent(float slew, float x2u = cap_axis_->axisValue(index2 + 1); float dx2 = (x2 - x2l) / (x2u - x2l); - float y00 = waveform00->findValueClipZero(time); - float y01 = waveform01->findValueClipZero(time); - float y10 = waveform10->findValueClipZero(time); - float y11 = waveform11->findValueClipZero(time); - float current + float y00 = waveform00->findValueClip(axis_value); + float y01 = waveform01->findValueClip(axis_value); + float y10 = waveform10->findValueClip(axis_value); + float y11 = waveform11->findValueClip(axis_value); + float wave_value = (1 - dx1) * (1 - dx2) * y00 + dx1 * (1 - dx2) * y10 + dx1 * dx2 * y11 + (1 - dx1) * dx2 * y01; - return current; + return wave_value; } float @@ -1678,22 +1766,18 @@ OutputWaveforms::referenceTime(float slew) return ref_times_->findValue(slew); } -void -OutputWaveforms::setVdd(float vdd) -{ - vdd_ = vdd; -} - Table1 OutputWaveforms::voltageWaveform(float slew, float cap) { - float volt_step = vdd_ / voltage_waveform_step_count_; + 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 v = 0; v <= voltage_waveform_step_count_; v++) { - float volt = v * volt_step; - float time = voltageTime(slew, cap, volt); + for (size_t i = 0; i < voltage_waveform_step_count_; i++) { + float time = min_time + i * time_step; + float volt = timeVoltage(slew, cap, time); times->push_back(time); volts->push_back(volt); } @@ -1701,6 +1785,38 @@ 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) +{ + 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 = 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()); +} + float OutputWaveforms::voltageTime(float slew, float cap, @@ -1713,8 +1829,6 @@ OutputWaveforms::voltageTime(float slew, 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); - float cap0 = cap_axis_->axisValue(cap_index); - float cap1 = cap_axis_->axisValue(cap_index + 1); // Interpolate waveform samples at voltage steps. size_t index1 = slew_index; @@ -1728,10 +1842,10 @@ OutputWaveforms::voltageTime(float slew, float x2u = cap_axis_->axisValue(index2 + 1); float dx2 = (x2 - x2l) / (x2u - x2l); - float y00 = voltageTime1(volt, wave_index00, cap0); - float y01 = voltageTime1(volt, wave_index01, cap1); - float y10 = voltageTime1(volt, wave_index10, cap0); - float y11 = voltageTime1(volt, wave_index11, cap1); + float y00 = voltageTime1(volt, wave_index00); + float y01 = voltageTime1(volt, wave_index01); + float y10 = voltageTime1(volt, wave_index10); + float y11 = voltageTime1(volt, wave_index11); float time = (1 - dx1) * (1 - dx2) * y00 + dx1 * (1 - dx2) * y10 @@ -1742,144 +1856,19 @@ OutputWaveforms::voltageTime(float slew, float OutputWaveforms::voltageTime1(float voltage, - size_t wave_index, - float cap) -{ - FloatSeq *voltage_times = voltageTimes(wave_index, cap); - float volt_step = vdd_ / voltage_waveform_step_count_; - size_t volt_idx = voltage / volt_step; - float time0 = (*voltage_times)[volt_idx]; - float time1 = (*voltage_times)[volt_idx + 1]; - float time = time0 + (time1 - time0) * (voltage - volt_step * volt_idx); - return time; -} - -FloatSeq * -OutputWaveforms::voltageTimes(size_t wave_index, - float cap) + size_t wave_index) { FloatSeq *voltage_times = voltage_times_[wave_index]; - if (voltage_times == nullptr) { - findVoltages(wave_index, cap); - voltage_times = voltage_times_[wave_index]; - } - return voltage_times; -} - -void -OutputWaveforms::findVoltages(size_t wave_index, - float cap) -{ - if (vdd_ == 0.0) - criticalError(239, "output waveform vdd = 0.0"); - // Integrate current waveform to find voltage waveform. - // i = C dv/dt - FloatSeq volts; - Table1 *currents = current_waveforms_[wave_index]; - const TableAxis *time_axis = currents->axis1(); - float prev_time = time_axis->axisValue(0); - float prev_current = currents->value(0); - float voltage = 0.0; - volts.push_back(voltage); - bool always_rise = true; - bool invert = (always_rise && rf_ == RiseFall::fall()); - for (size_t i = 1; i < time_axis->size(); i++) { - float time = time_axis->axisValue(i); - float current = currents->value(i); - float dv = (current + prev_current) / 2.0 * (time - prev_time) / cap; - voltage += invert ? -dv : dv; - volts.push_back(voltage); - prev_time = time; - prev_current = current; - } - - // Make voltage -> current table. - FloatSeq *axis_volts = new FloatSeq(volts); - TableAxisPtr volt_axis = - make_shared(TableAxisVariable::input_voltage, axis_volts); - 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); + size_t volt_idx = voltage / volt_step; + if (volt_idx >= voltage_times->size() - 1) + return (*voltage_times)[voltage_times->size() - 1]; + else { + float time0 = (*voltage_times)[volt_idx]; + float time1 = (*voltage_times)[volt_idx + 1]; + float time = time0 + (time1 - time0) * (voltage - volt_step * volt_idx); + return time; } - voltage_times_[wave_index] = voltage_times; -} - -float -OutputWaveforms::voltageCurrent(float slew, - float cap, - float volt) -{ - 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); - float cap0 = cap_axis_->axisValue(cap_index); - float cap1 = cap_axis_->axisValue(cap_index + 1); - - // 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); - - const Table1 *waveform00 = voltageCurrents(wave_index00, cap0); - const Table1 *waveform01 = voltageCurrents(wave_index01, cap1); - const Table1 *waveform10 = voltageCurrents(wave_index10, cap0); - const Table1 *waveform11 = voltageCurrents(wave_index11, cap1); - - float y00 = waveform00->findValueClipZero(volt); - float y01 = waveform01->findValueClipZero(volt); - float y10 = waveform10->findValueClipZero(volt); - float y11 = waveform11->findValueClipZero(volt); - float current - = (1 - dx1) * (1 - dx2) * y00 - + dx1 * (1 - dx2) * y10 - + dx1 * dx2 * y11 - + (1 - dx1) * dx2 * y01; - return current; -} - -const Table1 * -OutputWaveforms::voltageCurrents(size_t wave_index, - float cap) -{ - const Table1 *waveform = voltage_currents_[wave_index]; - if (waveform == nullptr) { - findVoltages(wave_index, cap); - waveform = voltage_currents_[wave_index]; - } - return waveform; } //////////////////////////////////////////////////////////////// diff --git a/liberty/TimingArc.cc b/liberty/TimingArc.cc index 0f1532e3..29be2abf 100644 --- a/liberty/TimingArc.cc +++ b/liberty/TimingArc.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -162,7 +162,7 @@ TimingArc::intrinsicDelay() const if (model) { ArcDelay arc_delay; Slew slew; - model->gateDelay(nullptr, 0.0, 0.0, 0.0, false, arc_delay, slew); + model->gateDelay(nullptr, 0.0, 0.0, false, arc_delay, slew); return arc_delay; } else @@ -240,11 +240,13 @@ TimingArcSet::addTimingArc(TimingArc *arc) criticalError(243, "timing arc max index exceeded\n"); arcs_.push_back(arc); - int from_rf_index = arc->fromEdge()->asRiseFall()->index(); - if (from_arc1_[from_rf_index] == nullptr) - from_arc1_[from_rf_index] = arc; - else if (from_arc2_[from_rf_index] == nullptr) - from_arc2_[from_rf_index] = arc; + if (arc->fromEdge()) { + int from_rf_index = arc->fromEdge()->asRiseFall()->index(); + if (from_arc1_[from_rf_index] == nullptr) + from_arc1_[from_rf_index] = arc; + else if (from_arc2_[from_rf_index] == nullptr) + from_arc2_[from_rf_index] = arc; + } int to_rf_index = arc->toEdge()->asRiseFall()->index(); to_arc_[to_rf_index] = arc; @@ -476,8 +478,8 @@ timingArcsLess(const TimingArcSet *arc_set1, arc_itr1++, arc_itr2++) { const TimingArc *arc1 = *arc_itr1; const TimingArc *arc2 = *arc_itr2; - int from_index1 = arc1->fromEdge()->index(); - int from_index2 = arc2->fromEdge()->index(); + int from_index1 = arc1->fromEdge() ? arc1->fromEdge()->index() : -1; + int from_index2 = arc2->fromEdge() ? arc2->fromEdge()->index() : -1; if (from_index1 < from_index2) return true; if (from_index1 > from_index2) diff --git a/liberty/TimingModel.cc b/liberty/TimingModel.cc index efb73cf6..9436b47b 100644 --- a/liberty/TimingModel.cc +++ b/liberty/TimingModel.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/TimingRole.cc b/liberty/TimingRole.cc index ae37ce8c..221f7305 100644 --- a/liberty/TimingRole.cc +++ b/liberty/TimingRole.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/Units.cc b/liberty/Units.cc index c21f24f1..9b24173c 100644 --- a/liberty/Units.cc +++ b/liberty/Units.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/liberty/Wireload.cc b/liberty/Wireload.cc index e9abfe9c..a501af03 100644 --- a/liberty/Wireload.cc +++ b/liberty/Wireload.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/messages.txt b/messages.txt deleted file mode 100644 index 7fb38f8f..00000000 --- a/messages.txt +++ /dev/null @@ -1,509 +0,0 @@ -0001 DmpCeff.cc:1597 cell %s delay model not supported on SPF parasitics by DMP delay calculator -0002 Liberty.cc:770 cell %s/%s port %s not found in cell %s/%s. -0003 Liberty.cc:796 cell %s/%s %s -> %s timing group %s not found in cell %s/%s. -0004 Liberty.cc:1745 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with %s -> %s setup_%s check. -0005 Liberty.cc:1759 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense. -0006 Liberty.cc:1767 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense. -0007 LibertyExpr.cc:82 %s references unknown port %s. -0008 ConcreteNetwork.cc:1909 cell type %s can not be linked. -0009 CycleAccting.cc:87 No common period was found between clocks %s and %s. -0010 Genclks.cc:274 no master clock found for generated clock %s. -0013 Genclks.cc:938 generated clock %s source pin %s missing paths from master clock %s. -0015 Sim.cc:865 propagated logic value %c differs from constraint value of %c on pin %s. -0016 LibertyReader.cc:1041 default_max_fanout is 0.0. -0017 Sta.cc:2093 '%s' is not a valid endpoint. -0018 Sta.cc:2017 '%s' is not a valid start point. -0021 SpefParse.yy:805 %d is not positive. -0022 SpefParse.yy:814 %.4f is not positive. -0023 SpefParse.yy:820 %.4f is not positive. -0024 WritePathSpice.cc:508 pg_pin %s/%s voltage %s not found, -0025 WritePathSpice.cc:515 Liberty pg_port %s/%s missing voltage_name attribute, -0026 WritePathSpice.cc:1094 %s pg_port %s not found, -0027 WritePathSpice.cc:1149 no register/latch found for path from %s to %s, -0028 WritePathSpice.cc:1615 The subkct file %s is missing definitions for %s -0029 WritePathSpice.cc:1713 subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground. -0030 LibertyReader.cc:631 library missing name. -0031 LibertyReader.cc:657 default_wire_load %s not found. -0032 LibertyReader.cc:668 default_wire_selection %s not found. -0033 LibertyReader.cc:690 input_threshold_pct_%s not found. -0034 LibertyReader.cc:694 output_threshold_pct_%s not found. -0035 LibertyReader.cc:698 slew_lower_threshold_pct_%s not found. -0036 LibertyReader.cc:702 slew_upper_threshold_pct_%s not found. -0037 LibertyReader.cc:707 Library %s is missing one or more thresholds. -0038 LibertyReader.cc:786 unknown unit multiplier %s. -0039 LibertyReader.cc:809 unknown unit scale %c. -0040 LibertyReader.cc:812 unknown unit suffix %s. -0041 LibertyReader.cc:840 capacitive_load_units are not ff or pf. -0042 LibertyReader.cc:843 capacitive_load_units are not a string. -0043 LibertyReader.cc:846 capacitive_load_units missing suffix. -0044 LibertyReader.cc:849 capacitive_load_units scale is not a float. -0045 LibertyReader.cc:852 capacitive_load_units missing scale and suffix. -0046 LibertyReader.cc:855 capacitive_load_unit missing values suffix. -0047 LibertyReader.cc:873 delay_model %s not supported. -0048 LibertyReader.cc:877 delay_model %s not supported. -0049 LibertyReader.cc:881 delay_model %s not supported. -0050 LibertyReader.cc:886 delay_model %s not supported. -. -0051 LibertyReader.cc:889 unknown delay_model %s -. -0052 LibertyReader.cc:908 unknown bus_naming_style format. -0053 LibertyReader.cc:597 library %s already exists. -0054 LibertyReader.cc:929 voltage_map voltage is not a float. -0055 LibertyReader.cc:932 voltage_map missing voltage. -0056 LibertyReader.cc:935 voltage_map supply name is not a string. -0057 LibertyReader.cc:938 voltage_map missing supply name and voltage. -0058 LibertyReader.cc:941 voltage_map missing values suffix. -0059 LibertyReader.cc:1159 default_wire_load_mode %s not found. -0060 LibertyReader.cc:680 default_operating_condition %s not found. -0061 LibertyReader.cc:1330 table template missing name. -0062 LibertyReader.cc:1375 missing variable_%d attribute. -0063 LibertyReader.cc:1418 axis type %s not supported. -0064 LibertyReader.cc:1478 bus type %s missing bit_from. -0065 LibertyReader.cc:1480 bus type %s missing bit_to. -0066 LibertyReader.cc:1484 type missing name. -0067 LibertyReader.cc:1511 scaling_factors do not have a name. -0068 LibertyReader.cc:1679 operating_conditions missing name. -0069 LibertyReader.cc:1749 wire_load missing name. -0070 LibertyReader.cc:1792 fanout_length is missing length and fanout. -0071 LibertyReader.cc:1807 wire_load_selection missing name. -0072 LibertyReader.cc:1838 wireload %s not found. -0074 LibertyReader.cc:1845 wire_load_from_area min not a float. -0075 LibertyReader.cc:1848 wire_load_from_area max not a float. -0076 LibertyReader.cc:1851 wire_load_from_area missing parameters. -0077 LibertyReader.cc:1854 wire_load_from_area missing parameters. -0078 LibertyReader.cc:1871 cell missing name. -0079 LibertyReader.cc:1894 cell %s ocv_derate_group %s not found. -0080 LibertyReader.cc:1925 port %s function size does not match port size. -0081 LibertyReader.cc:1981 %s %s bus width mismatch. -0082 LibertyReader.cc:1992 %s %s bus width mismatch. -0083 LibertyReader.cc:2002 clear -0084 LibertyReader.cc:2012 preset -0085 LibertyReader.cc:2048 latch enable function is non-unate for port %s. -0086 LibertyReader.cc:2053 latch enable function is unknown for port %s. -0087 LibertyReader.cc:2125 operating conditions %s not found. -0088 LibertyReader.cc:2128 scaled_cell missing operating condition. -0089 LibertyReader.cc:2131 scaled_cell cell %s has not been defined. -0090 LibertyReader.cc:2134 scaled_cell missing name. -0091 LibertyReader.cc:2160 scaled_cell %s, %s port functions do not match cell port functions. -0092 LibertyReader.cc:2165 scaled_cell ports do not match cell ports. -0093 LibertyReader.cc:2167 scaled_cell %s, %s timing does not match cell timing. -0094 LibertyReader.cc:2186 combinational timing to an input port. -0095 LibertyReader.cc:2277 missing %s_transition. -0096 LibertyReader.cc:2279 missing cell_%s. -0099 LibertyReader.cc:2877 scaling_factors %s not found. -0100 LibertyReader.cc:2918 pin name is not a string. -0101 LibertyReader.cc:2935 pin name is not a string. -0102 LibertyReader.cc:2949 pin name is not a string. -0103 LibertyReader.cc:3027 bus %s bus_type not found. -0104 LibertyReader.cc:3079 bus_type %s not found. -0105 LibertyReader.cc:3082 bus_type is not a string. -0106 LibertyReader.cc:3100 bundle %s member not found. -0107 LibertyReader.cc:3123 member is not a string. -0108 LibertyReader.cc:3130 members attribute is missing values. -0109 LibertyReader.cc:3181 unknown port direction. -0110 LibertyReader.cc:3521 pulse_latch unknown pulse type. -0111 LibertyReader.cc:3891 unknown timing_type %s. -0112 LibertyReader.cc:3911 unknown timing_sense %s. -0113 LibertyReader.cc:3951 mode value is not a string. -0114 LibertyReader.cc:3954 missing mode value. -0115 LibertyReader.cc:3957 mode name is not a string. -0116 LibertyReader.cc:3960 mode missing values. -0117 LibertyReader.cc:3963 mode missing mode name and value. -0118 LibertyReader.cc:2526 unsupported model axis. -0119 LibertyReader.cc:4066 unsupported model axis. -0120 LibertyReader.cc:4095 unsupported model axis. -0121 LibertyReader.cc:4130 unsupported model axis. -0122 LibertyReader.cc:4185 table template %s not found. -0123 LibertyReader.cc:4264 %s is missing values. -0124 LibertyReader.cc:4287 %s is not a list of floats. -0125 LibertyReader.cc:4289 table row has %u columns but axis has %d. -0126 LibertyReader.cc:4299 table has %u rows but axis has %d. -0127 LibertyReader.cc:4350 lut output is not a string. -0128 LibertyReader.cc:4392 mode definition missing name. -0129 LibertyReader.cc:4409 mode value missing name. -0130 LibertyReader.cc:4423 when attribute inside table model. -0131 LibertyReader.cc:4472 %s attribute is not a string. -0132 LibertyReader.cc:4475 %s is not a simple attribute. -0133 LibertyReader.cc:4498 %s is not a simple attribute. -0134 LibertyReader.cc:4511 %s is not a simple attribute. -0135 LibertyReader.cc:4537 %s value %s is not a float. -0136 LibertyReader.cc:4566 %s missing values. -0137 LibertyReader.cc:4570 %s missing values. -0138 LibertyReader.cc:4573 %s is not a complex attribute. -0139 LibertyReader.cc:4599 %s is not a float. -0140 LibertyReader.cc:4622 %s is missing values. -0141 LibertyReader.cc:4625 %s has more than one string. -0142 LibertyReader.cc:4634 %s is missing values. -0143 LibertyReader.cc:4659 %s attribute is not boolean. -0144 LibertyReader.cc:4662 %s attribute is not boolean. -0145 LibertyReader.cc:4665 %s is not a simple attribute. -0146 LibertyReader.cc:4681 attribute %s value %s not recognized. -0147 LibertyReader.cc:4712 unknown early/late value. -0148 LibertyReader.cc:4932 OCV derate group named %s not found. -0149 LibertyReader.cc:4948 ocv_derate missing name. -0150 LibertyReader.cc:5001 unknown rise/fall. -0151 LibertyReader.cc:5021 unknown derate type. -0152 LibertyReader.cc:5053 unsupported model axis. -0153 LibertyReader.cc:5085 unsupported model axis. -0154 LibertyReader.cc:5117 unsupported model axis. -0155 LibertyReader.cc:5188 unknown pg_type. -0156 LibertyReader.cc:5583 port %s subscript out of range. -0157 LibertyReader.cc:5587 port range %s of non-bus port %s. -0158 LibertyReader.cc:5601 port %s not found. -0159 LibertyReader.cc:5671 port %s not found. -0160 LibertyReader.cc:1026 default_max_transition is 0.0. -0161 LibertyReader.cc:3415 max_transition is 0.0. -0162 LibertyReader.cc:4495 %s attribute is not an integer. -0163 LibertyReader.cc:1131 default_fanout_load is 0.0. -0164 LibertyReader.cc:2299 timing group from output port. -0165 LibertyReader.cc:2309 timing group from output port. -0166 LibertyReader.cc:2319 timing group from output port. -0167 LibertyReader.cc:2337 timing group from output port. -0168 LibertyReader.cc:2353 timing group from output port. -0169 LibertyReader.cc:4367 cell %s test_cell redefinition. -0170 LibertyReader.cc:3810 timing group missing related_pin/related_bus_pin. -0171 LibertyReader.cc:815 unknown unit suffix %s. -0179 SpefReader.cc:734 %s. -0201 StaTcl.i:118 no network has been linked. -0202 StaTcl.i:132 network does not support edits. -0204 StaTcl.i:4129 POCV support requires compilation with SSTA=1. -0206 LibertyExpr.cc:175 %s %s. -0207 GraphDelayCalc1.cc:738 port not found in cell -0208 Graph.cc:793 arc_delay_annotated array bounds exceeded -0209 Graph.cc:808 arc_delay_annotated array bounds exceeded -0210 Graph.cc:820 arc_delay_annotated array bounds exceeded -0211 SdcNetwork.cc:1095 inst path string lenth estimate busted -0212 SdcNetwork.cc:1167 inst path string lenth estimate exceeded -0213 Sdc.cc:4021 group path name and is_default are mutually exclusive. -0214 WriteSdc.cc:1254 unknown exception type -0215 WriteSdc.cc:1795 illegal set_logic value -0216 WriteSdc.cc:1836 invalid set_case_analysis value -0228 Graph.cc:833 arc_delay_annotated array bounds exceeded -0251 PathEnumed.cc:126 enumerated path required time -0252 PathEnumed.cc:135 enumerated path required time -0253 PathGroup.cc:399 unknown path end type -0254 PathVertexRep.cc:145 tag group missing tag -0255 ReportPath.cc:289 unsupported path type -0256 ReportPath.cc:310 unsupported path type -0257 ReportPath.cc:349 unsupported path type -0259 ReportPath.cc:2378 unsupported path type -0260 Search.cc:2654 max tag group index exceeded -0261 Search.cc:2890 max tag index exceeded -0262 Search.cc:3617 unexpected filter path -0263 Search.cc:3785 tns incr existing vertex -0264 Sta.cc:4215 corresponding timing arc set not found in equiv cells -0265 TagGroup.cc:297 tag group missing tag -0266 Sta.cc:2090 '%s' is not a valid endpoint. -0267 Sta.cc:2014 '%s' is not a valid start point. -0272 StaTcl.i:4115 unknown common clk pessimism mode. -0273 StaTcl.i:5064 unknown clock sense -0274 VerilogReader.cc:1782 %s is not a verilog module. -0275 VerilogReader.cc:1787 %s is not a verilog module. -0299 Power.tcl:241 activity cannot be set on clock ports. -0300 CmdUtil.tcl:44 no commands match '$pattern'. -0301 Power.tcl:218 activity should be 0.0 to 1.0 or 2.0 -0302 Power.tcl:226 duty should be 0.0 to 1.0 -0303 Sdc.tcl:1586 -clock ignored for clock objects. -0304 Sdc.tcl:2178 -from/-to keywords ignored for lib_pin, port and pin arguments. -0305 CmdArgs.tcl:166 object '$obj' not found. -0313 CmdArgs.tcl:873 unsupported object type $object_type. -0314 CmdArgs.tcl:888 $arg_name must be a single net. -0315 CmdArgs.tcl:894 $arg_name '$object_type' is not a net. -0316 CmdArgs.tcl:899 $arg_name '$arg' not found. -0318 Search.tcl:1060 unknown path group '$name'. -0319 Sdc.tcl:288 $unit scale [format %.0e $scale] does not match library scale [format %.0e $unit_scale]. -0320 Sdc.tcl:437 current_design for other than top cell not supported. -0321 Sdc.tcl:474 patterns argument not supported with -of_objects. -0322 Sdc.tcl:509 instance '$pattern' not found. -0323 Sdc.tcl:570 clock '$pattern' not found. -0324 Sdc.tcl:597 positional arguments not supported with -of_objects. -0325 Sdc.tcl:623 library '$lib_name' not found. -0326 Sdc.tcl:635 cell '$cell_pattern' not found. -0327 Sdc.tcl:682 library/cell/port '$pattern' not found. -0328 Sdc.tcl:702 port '$port_pattern' not found. -0329 Sdc.tcl:707 library '$lib_name' not found. -0330 Sdc.tcl:717 -nocase ignored without -regexp. -0331 Sdc.tcl:743 library '$pattern' not found. -0332 Sdc.tcl:806 patterns argument not supported with -of_objects. -0333 Sdc.tcl:830 net '$pattern' not found. -0334 Sdc.tcl:859 patterns argument not supported with -of_objects. -0335 Sdc.tcl:896 pin '$pattern' not found. -0336 Sdc.tcl:953 patterns argument not supported with -of_objects. -0337 Sdc.tcl:967 port '$pattern' not found. -0338 Sdc.tcl:1065 non-increasing clock -waveform edge times. -0339 Sdc.tcl:1068 -waveform time greater than two periods. -0341 Sdc.tcl:1443 extra positional argument $arg. -0342 Sdc.tcl:1536 -clock ignored for clock objects. -0343 Sdc.tcl:1626 set_sense -type data not supported. -0344 Sdc.tcl:1641 set_clock_sense is deprecated as of SDC 2.1. Use set_sense -type clock. -0345 Sdc.tcl:1653 -pulse argument not supported. -0346 Sdc.tcl:1662 -positive, -negative, -stop_propagation and -pulse are mutually exclusive. -0347 Sdc.tcl:1675 hierarchical pin '[get_full_name $pin]' not supported. -0348 Sdc.tcl:2041 -from/-to keywords ignored for lib_pin, port and pin arguments. -0349 Sdc.tcl:1441 unknown keyword argument $arg. -0350 Sdc.tcl:2288 -from, -through or -to required. -0351 Sdc.tcl:2367 -source_latency_included ignored with -reference_pin. -0352 Sdc.tcl:2370 -network_latency_included ignored with -reference_pin. -0353 Sdc.tcl:2389 $cmd not allowed on [pin_direction $pin] port '[get_full_name $pin]'. -0354 Sdc.tcl:2391 $cmd relative to a clock defined on the same port/pin not allowed. -0355 Sdc.tcl:2445 '$args' ignored. -0356 Sdc.tcl:2575 '$args' ignored. -0357 Sdc.tcl:2710 virtual clock [get_name $clk] can not be propagated. -0358 Sdc.tcl:2884 -multiply_by ignored. -0359 Sdc.tcl:2887 -dont_scale ignored. -0360 Sdc.tcl:2890 -no_design_rule ignored. -0361 Sdc.tcl:2937 -clock not supported. -0362 Sdc.tcl:2940 -clock_fall not supported. -0363 Sdc.tcl:2986 -pin_load not allowed for net objects. -0364 Sdc.tcl:2989 -wire_load not allowed for net objects. -0365 Sdc.tcl:2992 -rise/-fall not allowed for net objects. -0366 Sdc.tcl:3125 -data_path, -clock_path, -rise, -fall ignored for ports and designs. -0367 Sdc.tcl:3196 derating factor greater than 2.0. -0368 Sdc.tcl:3233 -cell_delay and -cell_check flags ignored for net objects. -0369 Sdc.tcl:3303 no valid objects specified for $key. -0370 Sdc.tcl:3336 no valid objects specified for $key -0371 Sdc.tcl:3497 set_wire_load_min_block_size not supported. -0372 NetworkEdit.tcl:137 connect_pins is deprecated. Use connect_pin. -0373 Sdc.tcl:3663 define_corners must be called before read_liberty. -0374 Sta.cc:2416 maximum corner count exceeded -0400 Util.tcl:44 $cmd $key missing value. -0401 Util.tcl:61 $cmd $key missing value. -0402 Util.tcl:71 $cmd $arg is not a known keyword or flag. -0403 Util.tcl:93 $cmd $arg is not a known keyword or flag. -0404 CmdUtil.tcl:89 Usage: $cmd $cmd_args($cmd) -0405 CmdUtil.tcl:91 Usage: $cmd argument error -0406 Util.tcl:241 $cmd positional arguments not supported. -0407 Util.tcl:247 $cmd requires one positional argument. -0408 Util.tcl:254 $cmd requires zero or one positional arguments. -0409 Util.tcl:260 $cmd requires two positional arguments. -0410 Util.tcl:267 $cmd requires one or two positional arguments. -0411 Util.tcl:273 $cmd requires three positional arguments. -0412 Util.tcl:279 $cmd requires four positional arguments. -0413 Util.tcl:287 $cmd_arg '$arg' is not a float. -0414 Util.tcl:293 $cmd_arg '$arg' is not a positive float. -0415 Util.tcl:299 $cmd_arg '$arg' is not an integer. -0416 Util.tcl:305 $cmd_arg '$arg' is not a positive integer. -0417 Util.tcl:311 $cmd_arg '$arg' is not an integer greater than or equal to one. -0418 Util.tcl:317 $cmd_arg '$arg' is not between 0 and 100. -0419 Search.tcl:326 report_clock_skew -setup and -hold are mutually exclusive options. -0420 Search.tcl:136 $cmd -path_delay must be min, min_rise, min_fall, max, max_rise, max_fall or min_max. -0421 Search.tcl:146 $cmd command failed. -0422 Search.tcl:165 -endpoint_count must be a positive integer. -0423 Search.tcl:174 -group_count must be >= 1. -0424 Search.tcl:205 '$arg' is not a known keyword or flag. -0425 Search.tcl:207 positional arguments not supported. -0426 Search.tcl:510 analysis type single is not consistent with doing both setup/max and hold/min checks. -0427 Search.tcl:515 positional arguments not supported. -0428 DelayCalc.tcl:350 set_assigned_transition transition is not a float. -0430 Sdf.tcl:46 -cond_use min_max cannot be used with analysis type single. -0432 Sdf.tcl:157 SDF -divider must be / or . -0433 Parasitics.tcl:45 path instance '$path' not found. -0434 Parasitics.tcl:62 -reduce_to must be pi_elmore or pi_pole_residue2. -0435 DelayCalc.tcl:119 delay calculator $alg not found. -0436 Variables.tcl:45 sta_report_default_digits must be a positive integer. -0437 Variables.tcl:70 sta_crpr_mode must be pin or transition. -0438 Variables.tcl:187 $var_name value must be 0 or 1. -0439 CmdUtil.tcl:209 unsupported object type $list_type. -0440 Sta.tcl:158 -from/-to arguments not supported with -of_objects. -0441 Sta.tcl:286 unsupported -filter expression. -0442 DelayCalc.tcl:148 $cmd missing -from argument. -0443 DelayCalc.tcl:153 $cmd missing -to argument. -0444 DelayCalc.tcl:158 $cmd delay is not a float. -0445 DelayCalc.tcl:163 set_annotated_delay -cell and -net options are mutually excluive. -0446 DelayCalc.tcl:169 $cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]. -0447 DelayCalc.tcl:174 $cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst] -0448 DelayCalc.tcl:179 $cmd -cell or -net required. -0449 DelayCalc.tcl:243 $cmd missing -from argument. -0450 DelayCalc.tcl:252 $cmd -clock must be rise or fall. -0451 DelayCalc.tcl:259 $cmd missing -to argument. -0452 DelayCalc.tcl:274 $cmd missing -setup|-hold|-recovery|-removal check type.. -0453 DelayCalc.tcl:282 $cmd check_value is not a float. -0454 Sdc.tcl:1472 the -all and -name options are mutually exclusive. -0455 Sdc.tcl:1475 either -all or -name options must be specified. -0456 Sdc.tcl:1483 one of -logically_exclusive, -physically_exclusive or -asynchronous is required. -0457 Sdc.tcl:1486 the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive. -0458 Sdc.tcl:1598 -source '[$pin path_name]' is not a clock pin. -0459 Sdc.tcl:1866 -from/-to must be used together. -0460 Sdc.tcl:1886 -rise, -fall options not allowed for single clock uncertainty. -0461 Sdc.tcl:1987 missing -from, -rise_from or -fall_from argument. -0462 Sdc.tcl:1999 missing -to, -rise_to or -fall_to argument. -0463 Sdc.tcl:2230 -from/-to hierarchical instance not supported. -0464 Sdc.tcl:2632 $cmd command failed. -0465 Sdc.tcl:2639 positional arguments not supported. -0466 Sdc.tcl:2643 -from, -through or -to required. -0467 CmdArgs.tcl:108 unsupported object type $object_type. -0468 CmdArgs.tcl:405 $corner_name is not the name of process corner. -0469 CmdArgs.tcl:410 -corner keyword required with multi-corner analysis. -0470 CmdArgs.tcl:425 $corner_name is not the name of process corner. -0471 CmdArgs.tcl:430 missing -corner arg. -0472 CmdArgs.tcl:441 $corner_name is not the name of process corner. -0473 CmdArgs.tcl:458 $corner_name is not the name of process corner. -0474 CmdArgs.tcl:483 both -min and -max specified. -0475 CmdArgs.tcl:497 both -min and -max specified. -0476 CmdArgs.tcl:524 only one of -early and -late can be specified. -0477 CmdArgs.tcl:530 -early or -late must be specified. -0478 CmdArgs.tcl:537 both -early and -late specified. -0479 CmdArgs.tcl:552 $arg_name must be a single library. -0480 CmdArgs.tcl:558 $arg_name type '$object_type' is not a library. -0481 CmdArgs.tcl:563 library '$arg' not found. -0482 CmdArgs.tcl:580 $arg_name must be a single lib cell. -0483 CmdArgs.tcl:667 $arg_name must be a single instance. -0484 CmdArgs.tcl:673 $arg_name type '$object_type' is not an instance. -0485 CmdArgs.tcl:678 instance '$arg' not found. -0486 CmdArgs.tcl:697 $arg_name type '$object_type' is not an instance. -0487 CmdArgs.tcl:704 instance '$arg' not found. -0488 CmdArgs.tcl:765 $arg_name type '$object_type' is not a pin or port. -0489 CmdArgs.tcl:772 pin '$arg' not found. -0490 CmdArgs.tcl:792 $arg_name type '$object_type' is not a port. -0491 Property.tcl:32 $cmd object is null. -0492 Property.tcl:37 $cmd $type_key must be specified with object name argument. -0493 Property.tcl:80 get_property $object is not an object. -0494 Property.tcl:107 $object_type not supported. -0495 Property.tcl:110 $object_type '$object_name' not found. -0496 WritePathSpice.tcl:35 Directory $spice_dir not found. -0497 WritePathSpice.tcl:38 $spice_dir is not a directory. -0498 WritePathSpice.tcl:41 Cannot write in $spice_dir. -0499 WritePathSpice.tcl:44 No -spice_directory specified. -0500 WritePathSpice.tcl:50 -lib_subckt_file $lib_subckt_file is not readable. -0501 WritePathSpice.tcl:53 No -lib_subckt_file specified. -0502 WritePathSpice.tcl:59 -model_file $model_file is not readable. -0503 WritePathSpice.tcl:62 No -model_file specified. -0504 WritePathSpice.tcl:68 No -power specified. -0505 WritePathSpice.tcl:74 No -ground specified. -0506 WritePathSpice.tcl:78 No -path_args specified. -0507 WritePathSpice.tcl:83 No paths found for -path_args $path_args. -0508 Search.tcl:778 -min and -max cannot both be specified. -0509 Search.tcl:798 pin '$pin_arg' is hierarchical. -0510 Search.tcl:864 -format $format not recognized. -0511 Sdc.tcl:73 cannot open '$filename'. -0512 Sdc.tcl:128 incomplete command at end of file. -0513 Sdc.tcl:212 hierarchy separator must be one of '$sdc_dividers'. -0514 Sdc.tcl:259 unknown unit $unit '$suffix'. -0515 CmdUtil.tcl:161 unknown $unit unit '$suffix'. -0516 Sdc.tcl:543 unsupported instance -filter expression. -0517 Sdc.tcl:928 unsupported pin -filter expression. -0518 Sdc.tcl:1004 unsupported port -filter expression. -0519 Sdc.tcl:1037 -add requires -name. -0520 Sdc.tcl:1042 -name or port_pin_list must be specified. -0521 Sdc.tcl:1050 missing -period argument. -0522 Sdc.tcl:1056 -waveform edge_list must have an even number of edge times. -0523 Sdc.tcl:1126 empty ports/pins/nets argument. -0524 Sdc.tcl:1134 -add requires -name. -0525 Sdc.tcl:1139 name or port_pin_list must be specified. -0526 Sdc.tcl:1146 missing -source argument. -0527 Sdc.tcl:1161 -master_clock argument empty. -0528 Sdc.tcl:1164 -add requireds -master_clock. -0529 Sdc.tcl:1168 -multiply_by and -divide_by options are exclusive. -0530 Sdc.tcl:1172 -divide_by is not an integer greater than one. -0531 Sdc.tcl:1175 -combinational implies -divide_by 1. -0532 Sdc.tcl:1180 -multiply_by is not an integer greater than one. -0533 Sdc.tcl:1186 -duty_cycle is not a float between 0 and 100. -0534 Sdc.tcl:1192 -edges only supported for three edges. -0535 Sdc.tcl:1198 edges times are not monotonically increasing. -0536 Sdc.tcl:1207 -edge_shift length does not match -edges length. -0537 Sdc.tcl:1213 missing -multiply_by, -divide_by, -combinational or -edges argument. -0538 Sdc.tcl:1221 cannot specify -invert without -multiply_by, -divide_by or -combinational. -0539 Sdc.tcl:1227 -duty_cycle requires -multiply_by value. -0545 Sdc.tcl:1287 group_path command failed. -0546 Sdc.tcl:1294 positional arguments not supported. -0547 Sdc.tcl:1298 -from, -through or -to required. -0548 Sdc.tcl:1304 -name and -default are mutually exclusive. -0549 Sdc.tcl:1306 -name or -default option is required. -0550 Sdc.tcl:1347 cannot specify both -high and -low. -0551 Sdc.tcl:1355 missing -setup or -hold argument. -0552 Sdc.tcl:1369 -high and -low only permitted for pins and instances. -0553 Sdc.tcl:1376 -high and -low only permitted for pins and instances. -0554 Sdc.tcl:1419 one of -logically_exclusive, -physically_exclusive or -asynchronous is required. -0555 Sdc.tcl:1422 the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive. -0556 Sdc.tcl:1550 -source '[get_full_name $pin]' is not a clock pin. -0557 Sdc.tcl:1557 -early/-late is only allowed with -source. -0558 Sdc.tcl:1630 set_sense -type clock|data -0559 Sdc.tcl:1699 transition time can not be specified for virtual clocks. -0560 Sdc.tcl:1732 missing uncertainty value. -0561 Sdc.tcl:1780 -from/-to must be used together. -0562 Sdc.tcl:1800 -rise, -fall options not allowed for single clock uncertainty. -0563 Sdc.tcl:1927 missing -from, -rise_from or -fall_from argument. -0564 Sdc.tcl:1939 missing -to, -rise_to or -fall_to argument. -0565 Sdc.tcl:2071 -from/-to hierarchical instance not supported. -0566 Sdc.tcl:2103 pin '[get_full_name $inst]${hierarchy_separator}${port_name}' not found. -0567 Sdc.tcl:2144 pin '[get_name $cell]${hierarchy_separator}${port_name}' not found. -0568 Sdc.tcl:2439 missing delay argument. -0569 Sdc.tcl:2570 missing path multiplier argument. -0570 Sdc.tcl:2582 cannot use -start with -end. -0571 Sdc.tcl:2752 value must be 0, zero, 1, one, rise, rising, fall, or falling. -0572 Sdc.tcl:2821 cell '$lib_name:$cell_name' not found. -0573 Sdc.tcl:2827 '$cell_name' not found. -0574 Sdc.tcl:2831 missing -lib_cell argument. -0575 Sdc.tcl:2839 port '$to_port_name' not found. -0576 Sdc.tcl:2851 -pin argument required for cells with multiple outputs. -0577 Sdc.tcl:2866 port '$from_port_name' not found. -0578 Sdc.tcl:3079 port '[get_name $port]' is not an input. -0579 Sdc.tcl:3453 operating condition '$op_cond_name' not found. -0580 Sdc.tcl:3471 operating condition '$op_cond_name' not found. -0581 Sdc.tcl:3485 -analysis_type must be single, bc_wc or on_chip_variation. -0582 Sdc.tcl:3510 mode must be top, enclosed or segmented. -0583 Sdc.tcl:3525 no wire load model specified. -0584 Sdc.tcl:3586 wire load selection group '$selection_name' not found. -0585 Sdc.tcl:3733 no default operating conditions found. -0586 NetworkEdit.tcl:107 unsupported object type $object_type. -0587 NetworkEdit.tcl:206 unsupported object type $object_type. -0588 NetworkEdit.tcl:224 unsupported object type $object_type. -0589 CmdUtil.tcl:226 unknown namespace $namespc. -0590 Network.tcl:35 instance $instance_path not found. -0591 Network.tcl:221 net $net_path not found. -0592 Network.tcl:224 net $net_path not found. -0593 Link.tcl:34 missing top_cell_name argument and no current_design. -0594 DelayNormal1.cc:203 unknown early/late value. -0595 DelayNormal2.cc:378 unknown early/late value. -0596 Sim.cc:210 unknown function operator -0597 EstimateParasitics.cc:188 load pin not leaf or top level -0600 Sdc.tcl:2284 '$args' ignored. -0601 Sdc.tcl:2913 set_fanout_load not supported. -0602 Sdc.tcl:3385 no valid objects specified for $key. -0604 Sdc.tcl:281 unknown $unit prefix '$prefix'. -0605 Sdc.tcl:3547 wire load model '$model_name' not found. -0606 Property.tcl:77 get_property unsupported object type $object_type. -0607 StaTcl.i:4367 unknown report path field %s -0608 StaTcl.i:4379 unknown report path field %s -0609 Search.tcl:411 -all_violators is deprecated. Use -violators -0610 Search.tcl:491 -max_transition deprecated. Use -max_slew. -0611 Search.tcl:496 -min_transition deprecated. Use -min_slew. -0612 Sdf.tcl:41 -cond_use must be min, max or min_max. -0616 Search.tcl:1011 specify one of -setup and -hold. -0617 Sdf.tcl:50 -analysis_type is deprecated. Use set_operating_conditions -analysis_type. -0618 DmpCeff.cc:1581 parasitic Pi model has NaNs. -0619 PathEnum.cc:474 path diversion missing edge. -0620 PathVertex.cc:236 missing arrivals. -0621 PathVertex.cc:250 missing arrivals. -0622 PathVertex.cc:279 missing requireds. -0623 PathVertexRep.cc:153 missing arrivals. -0624 PathVertexRep.cc:150 missing arrivals -0625 Liberty.tcl:33 -no_latch_infer is deprecated. -0701 LibertyWriter.cc:413 %s/%s/%s timing model not supported. -0702 LibertyWriter.cc:433 3 axis table models not supported. -0703 LibertyWriter.cc:573 %s/%s/%s timing arc type %s not supported. -0704 LibertyWriter.cc:286 %s/%s bundled ports not supported. -0705 Liberty.cc:815 Liberty cell %s/%s for corner %s/%s not found. -0706 Parasitics.tcl:70 read_spef -increment is deprecated. -0710 LumpedCapDelayCalc.cc:173 gate delay input variable is NaN -0800 VcdReader.cc:110 unhandled vcd command. -0801 VcdReader.cc:146 timescale syntax error. -0802 VcdReader.cc:160 Unknown timescale unit. -0804 VcdReader.cc:212 Variable syntax error. -0805 Vcd.cc:172 Unknown variable %s ID %s -0806 ReadVcdActivities.cc:247 clock %s vcd period %s differs from SDC clock period %s -0807 Sdc.tcl:394 only one of -cells, -data_pins, -clock_pins, -async_pins, -output_pins are suppported. -0810 MakeTimingModel.cc:203 clock %s pin %s is inside model block. -0900 LibertyReader.cc:2817 level_shifter_type must be HL, LH, or HL_LH -0901 LibertyReader.cc:2853 switch_cell_type must be coarse_grain or fine_grain -0902 LibertyReader.cc:2437 unsupported model axis. -0903 LibertyReader.cc:4146 %s group not in timing group. -0904 LibertyReader.cc:2420 receiver_capacitance group not in timing or pin group. -0906 LibertyReader.cc:4039 unsupported model axis. -0907 LibertyReader.cc:2465 output_current_%s group not in timing group. -0908 LibertyReader.cc:2570 vector reference_time not found. -0912 LibertyReader.cc:2568 vector index_1 and index_2 must have exactly one value. -0913 LibertyReader.cc:2506 output current waveform %.2e %.2e not found. -0914 LibertyReader.cc:2603 normalized_driver_waveform variable_2 must be normalized_voltage -0915 LibertyReader.cc:2606 normalized_driver_waveform variable_1 must be input_net_transition -1640 Search.tcl:904 The transition_time field is deprecated. Use slew instead. diff --git a/network/ConcreteLibrary.cc b/network/ConcreteLibrary.cc index 154efaa5..86627833 100644 --- a/network/ConcreteLibrary.cc +++ b/network/ConcreteLibrary.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/network/ConcreteNetwork.cc b/network/ConcreteNetwork.cc index 8c141511..24084ef5 100644 --- a/network/ConcreteNetwork.cc +++ b/network/ConcreteNetwork.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -1920,7 +1920,7 @@ ConcreteNetwork::linkNetwork(const char *top_cell_name, return top_instance_ != nullptr; } else { - report->error(8, "cell type %s can not be linked.", top_cell_name); + report->error(1000, "cell type %s can not be linked.", top_cell_name); return false; } } diff --git a/network/HpinDrvrLoad.cc b/network/HpinDrvrLoad.cc index e68ed7d9..5a9126d9 100644 --- a/network/HpinDrvrLoad.cc +++ b/network/HpinDrvrLoad.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/network/Network.cc b/network/Network.cc index 4180072d..7160d5ab 100644 --- a/network/Network.cc +++ b/network/Network.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -1189,6 +1189,19 @@ Network::leafPinCount() return count; } +InstanceSeq +Network::leafInstances() +{ + InstanceSeq insts; + LeafInstanceIterator *iter = leafInstanceIterator(); + while (iter->hasNext()) { + const Instance *inst = iter->next(); + insts.push_back(inst); + } + delete iter; + return insts; +} + void Network::setPathDivider(char divider) { diff --git a/network/NetworkCmp.cc b/network/NetworkCmp.cc index 650963e8..16378cbf 100644 --- a/network/NetworkCmp.cc +++ b/network/NetworkCmp.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/network/ParseBus.cc b/network/ParseBus.cc index f7da16e5..0df07559 100644 --- a/network/ParseBus.cc +++ b/network/ParseBus.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/network/PortDirection.cc b/network/PortDirection.cc index cc504cd2..7d82e793 100644 --- a/network/PortDirection.cc +++ b/network/PortDirection.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/network/SdcNetwork.cc b/network/SdcNetwork.cc index 586ba3f8..e5eb36bb 100644 --- a/network/SdcNetwork.cc +++ b/network/SdcNetwork.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -1092,7 +1092,7 @@ SdcNetwork::parsePath(const char *path, else *p++ = ch; if (p - inst_path + 1 > inst_path_length) - report_->critical(211, "inst path string lenth estimate busted"); + report_->critical(1500, "inst path string lenth estimate busted"); } *p = '\0'; stringDelete(inst_path); @@ -1164,7 +1164,7 @@ SdcNetwork::visitMatches(const Instance *parent, *p++ = ch; } if (p - inst_path + 1 > inst_path_length) - report_->critical(212, "inst path string lenth estimate exceeded"); + report_->critical(1501, "inst path string lenth estimate exceeded"); } *p = '\0'; if (!found_match) { diff --git a/network/VerilogNamespace.cc b/network/VerilogNamespace.cc index 8486e40a..48d182a7 100644 --- a/network/VerilogNamespace.cc +++ b/network/VerilogNamespace.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/parasitics/ConcreteParasitics.cc b/parasitics/ConcreteParasitics.cc index 4de6827f..cd4cc8a6 100644 --- a/parasitics/ConcreteParasitics.cc +++ b/parasitics/ConcreteParasitics.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -29,9 +29,7 @@ #include "Liberty.hh" #include "Sdc.hh" #include "Parasitics.hh" -#include "ReduceParasitics.hh" #include "MakeConcreteParasitics.hh" -#include "Parasitics.hh" #include "ConcreteParasiticsPvt.hh" #include "Corner.hh" @@ -129,18 +127,6 @@ ConcreteParasitic::setPoleResidue(const Pin *, { } -ParasiticDeviceIterator * -ConcreteParasitic::deviceIterator() const -{ - return nullptr; -} - -ParasiticNodeIterator * -ConcreteParasitic::nodeIterator() const -{ - return nullptr; -} - //////////////////////////////////////////////////////////////// ConcretePi::ConcretePi(float c2, @@ -190,16 +176,10 @@ ConcretePi::setIsReduced(bool reduced) ConcretePiElmore::ConcretePiElmore(float c2, float rpi, float c1) : - ConcretePi(c2, rpi, c1), - loads_(nullptr) + ConcretePi(c2, rpi, c1) { } -ConcretePiElmore::~ConcretePiElmore() -{ - delete loads_; -} - float ConcretePiElmore::capacitance() const { @@ -239,93 +219,46 @@ ConcretePiElmore::findElmore(const Pin *load_pin, float &elmore, bool &exists) const { - if (loads_) - loads_->findKey(load_pin, elmore, exists); - else + auto itr = loads_.find(load_pin); + if (itr == loads_.end()) exists = false; + else { + elmore = itr->second; + exists = true; + } } void ConcretePiElmore::setElmore(const Pin *load_pin, float elmore) { - if (loads_ == nullptr) - loads_ = new ConcreteElmoreLoadMap; - (*loads_)[load_pin] = elmore; + loads_[load_pin] = elmore; } void ConcretePiElmore::deleteLoad(const Pin *load_pin) { - loads_->erase(load_pin); + loads_.erase(load_pin); } -//////////////////////////////////////////////////////////////// - -ConcretePiElmoreEstimated::ConcretePiElmoreEstimated(float c2, - float rpi, - float c1, - float elmore_res, - float elmore_cap, - bool elmore_use_load_cap, - const RiseFall *rf, - const OperatingConditions *op, - const Corner *corner, - const MinMax *min_max, - Sdc *sdc): - ConcretePi(c2, rpi, c1), - elmore_res_(elmore_res), - elmore_cap_(elmore_cap), - elmore_use_load_cap_(elmore_use_load_cap), - rf_(rf), - op_cond_(op), - corner_(corner), - min_max_(min_max), - sdc_(sdc) +PinSet +ConcretePiElmore::unannotatedLoads(const Pin *drvr_pin, + const Parasitics *parasitics) const { -} - -float -ConcretePiElmoreEstimated::capacitance() const -{ - return ConcretePi::capacitance(); -} - -void -ConcretePiElmoreEstimated::piModel(float &c2, - float &rpi, - float &c1) const -{ - ConcretePi::piModel(c2, rpi, c1); -} - -void -ConcretePiElmoreEstimated::findElmore(const Pin *load_pin, - float &elmore, - bool &exists) const -{ - float load_cap = 0.0; - if (elmore_use_load_cap_) - load_cap = sdc_->pinCapacitance(load_pin, rf_, op_cond_, - corner_, min_max_); - elmore = elmore_res_ * (elmore_cap_ + load_cap); - exists = true; -} - -void -ConcretePiElmoreEstimated::setElmore(const Pin *, - float) -{ - // Cannot set elmore on estimated parasitic. + PinSet loads = parasitics->loads(drvr_pin); + for (auto pin_elmore : loads_) { + const Pin *load = pin_elmore.first; + loads.erase(load); + } + return loads; } //////////////////////////////////////////////////////////////// ConcretePoleResidue:: -ConcretePoleResidue(ComplexFloatSeq *poles, - ComplexFloatSeq *residues) : - poles_(poles), - residues_(residues) +ConcretePoleResidue() : + poles_(nullptr), + residues_(nullptr) { } @@ -358,24 +291,22 @@ ConcretePoleResidue::setPoleResidue(ComplexFloatSeq *poles, residues_ = residues; } +PinSet +ConcretePoleResidue::unannotatedLoads(const Pin *, + const Parasitics *) const +{ + return PinSet(); +} + //////////////////////////////////////////////////////////////// ConcretePiPoleResidue::ConcretePiPoleResidue(float c2, float rpi, float c1) : - ConcretePi(c2, rpi, c1), - load_pole_residue_(nullptr) + ConcretePi(c2, rpi, c1) { } -ConcretePiPoleResidue::~ConcretePiPoleResidue() -{ - if (load_pole_residue_) { - load_pole_residue_->deleteContents(); - delete load_pole_residue_; - } -} - float ConcretePiPoleResidue::capacitance() const { @@ -413,10 +344,11 @@ ConcretePiPoleResidue::setIsReduced(bool reduced) Parasitic * ConcretePiPoleResidue::findPoleResidue(const Pin *load_pin) const { - if (load_pole_residue_) - return load_pole_residue_->findKey(load_pin); - else + auto itr = load_pole_residue_.find(load_pin); + if (itr == load_pole_residue_.end()) return nullptr; + else + return &const_cast(itr->second); } void @@ -424,32 +356,48 @@ ConcretePiPoleResidue::setPoleResidue(const Pin *load_pin, ComplexFloatSeq *poles, ComplexFloatSeq *residues) { - if (load_pole_residue_ == nullptr) - load_pole_residue_ = new ConcretePoleResidueMap; - ConcretePoleResidue *pole_residue = load_pole_residue_->findKey(load_pin); - if (pole_residue == nullptr) { - pole_residue = new ConcretePoleResidue(poles, residues); - (*load_pole_residue_)[load_pin] = pole_residue; - } - else - pole_residue->setPoleResidue(poles, residues); + ConcretePoleResidue &pole_residue = load_pole_residue_[load_pin]; + pole_residue.setPoleResidue(poles, residues); } void ConcretePiPoleResidue::deleteLoad(const Pin *load_pin) { - ConcretePoleResidue *pole_residue = load_pole_residue_->findKey(load_pin); - if (pole_residue) { - load_pole_residue_->erase(load_pin); - delete pole_residue; + load_pole_residue_.erase(load_pin); +} + +PinSet +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; + loads.erase(load); } + return loads; } //////////////////////////////////////////////////////////////// -ConcreteParasiticNode::ConcreteParasiticNode() : +ConcreteParasiticNode::ConcreteParasiticNode(const Net *net, + int id, + bool is_external) : + is_net_(true), + is_external_(is_external), + id_(id), cap_(0.0) { + net_pin_.net_ = net; +} + +ConcreteParasiticNode::ConcreteParasiticNode(const Pin *pin, + bool is_external) : + is_net_(false), + is_external_(is_external), + cap_(0.0) +{ + net_pin_.pin_ = pin; } void @@ -458,201 +406,89 @@ ConcreteParasiticNode::incrCapacitance(float cap) cap_ += cap; } -float -ConcreteParasiticNode::capacitance() const +const char * +ConcreteParasiticNode::name(const Network *network) const { - return cap_; + if (is_net_) { + const char *net_name = network->pathName(net_pin_.net_); + return stringPrintTmp("%s:%d", net_name, id_); + } + else + return network->pathName(net_pin_.pin_); } -void -ConcreteParasiticNode::addDevice(ConcreteParasiticDevice *device) +const Pin * +ConcreteParasiticNode::pin() const { - devices_.push_back(device); + if (is_net_) + return nullptr; + else + return net_pin_.pin_; +} + +const Net * +ConcreteParasiticNode::net(const Network *network) const +{ + if (is_net_) + return net_pin_.net_; + else { + Net *net = network->net(net_pin_.pin_); + // Pins on the top level instance may not have nets. + // Use the net connected to the pin's terminal. + if (net == nullptr && network->isTopLevelPort(net_pin_.pin_)) { + Term *term = network->term(net_pin_.pin_); + if (term) + return network->net(term); + } + return net; + } } //////////////////////////////////////////////////////////////// -ConcreteParasiticSubNode::ConcreteParasiticSubNode(const Net *net, - int id) : - ConcreteParasiticNode(), + +ConcreteParasiticDevice::ConcreteParasiticDevice(size_t id, + float value, + ConcreteParasiticNode *node1, + ConcreteParasiticNode *node2) : + id_(id), + value_(value), + node1_(node1), + node2_(node2) +{ +} + +void +ConcreteParasiticDevice::replaceNode(ConcreteParasiticNode *from_node, + ConcreteParasiticNode *to_node) +{ + if (from_node == node1_) + node1_ = to_node; + else if (from_node == node2_) + node2_ = to_node; +} + +ConcreteParasiticResistor::ConcreteParasiticResistor(size_t id, + float value, + ConcreteParasiticNode *node1, + ConcreteParasiticNode *node2) : + ConcreteParasiticDevice(id, value, node1, node2) +{ +} + +ConcreteParasiticCapacitor::ConcreteParasiticCapacitor(size_t id, + float value, + ConcreteParasiticNode *node1, + ConcreteParasiticNode *node2) : + ConcreteParasiticDevice(id, value, node1, node2) +{ +} + +//////////////////////////////////////////////////////////////// + +ConcreteParasiticNetwork::ConcreteParasiticNetwork(const Net *net, + bool includes_pin_caps) : net_(net), - id_(id) -{ -} - -const char * -ConcreteParasiticSubNode::name(const Network *network) const -{ - const char *net_name = network->pathName(net_); - return stringPrintTmp("%s:%d", net_name, id_); -} - -//////////////////////////////////////////////////////////////// - -ConcreteParasiticPinNode::ConcreteParasiticPinNode(const Pin *pin) : - ConcreteParasiticNode(), - pin_(pin) -{ -} - -const char * -ConcreteParasiticPinNode::name(const Network *network) const -{ - return network->pathName(pin_); -} - -//////////////////////////////////////////////////////////////// - -ConcreteParasiticDevice::ConcreteParasiticDevice(const char *name, - ConcreteParasiticNode *node, - float value) : - name_(name), - node_(node), - value_(value) -{ -} - -ConcreteParasiticDevice::~ConcreteParasiticDevice() -{ - if (name_) - stringDelete(name_); -} - -ConcreteParasiticResistor:: -ConcreteParasiticResistor(const char *name, - ConcreteParasiticNode *node, - ConcreteParasiticNode *other_node, - float res) : - ConcreteParasiticDevice(name, node, res), - other_node_(other_node) -{ -} - -ParasiticNode * -ConcreteParasiticResistor::otherNode(ParasiticNode *node) const -{ - if (node == node_) - return other_node_; - else if (node == other_node_) - return node_; - else - return nullptr; -} - -void -ConcreteParasiticResistor::replaceNode(ConcreteParasiticNode *from_node, - ConcreteParasiticNode *to_node) -{ - if (from_node == node_) - node_ = to_node; - else - other_node_ = to_node; -} - -//////////////////////////////////////////////////////////////// - -ConcreteCouplingCap::ConcreteCouplingCap(const char *name, - ConcreteParasiticNode *node, - float cap) : - ConcreteParasiticDevice(name, node, cap) -{ -} - -void -ConcreteCouplingCap::replaceNode(ConcreteParasiticNode *from_node, - ConcreteParasiticNode *to_node) -{ - if (from_node == node_) - node_ = to_node; -} - -//////////////////////////////////////////////////////////////// - -ConcreteCouplingCapInt:: -ConcreteCouplingCapInt(const char *name, - ConcreteParasiticNode *node, - ConcreteParasiticNode *other_node, - float cap) : - ConcreteCouplingCap(name, node, cap), - other_node_(other_node) -{ -} - -ParasiticNode * -ConcreteCouplingCapInt::otherNode(ParasiticNode *node) const -{ - if (node == node_) - return other_node_; - else if (node == other_node_) - return node_; - else - return nullptr; -} - -void -ConcreteCouplingCapInt::replaceNode(ConcreteParasiticNode *from_node, - ConcreteParasiticNode *to_node) -{ - if (from_node == node_) - node_ = to_node; - else - other_node_ = to_node; -} - -//////////////////////////////////////////////////////////////// - -ConcreteCouplingCapExtNode:: -ConcreteCouplingCapExtNode(const char *name, - ConcreteParasiticNode *node, - Net *, - int, - float cap) : - ConcreteCouplingCap(name, node, cap) -{ -} - -ParasiticNode * -ConcreteCouplingCapExtNode::otherNode(ParasiticNode *) const -{ - return nullptr; -} - -void -ConcreteCouplingCapExtNode::replaceNode(ConcreteParasiticNode *from_node, - ConcreteParasiticNode *to_node) -{ - if (from_node == node_) - node_ = to_node; -} - -//////////////////////////////////////////////////////////////// - -ConcreteCouplingCapExtPin:: -ConcreteCouplingCapExtPin(const char *name, - ConcreteParasiticNode *node, - Pin *, - float cap) : - ConcreteCouplingCap(name, node, cap) -{ -} - -ParasiticNode * -ConcreteCouplingCapExtPin::otherNode(ParasiticNode *) const -{ - return nullptr; -} - -void -ConcreteCouplingCapExtPin::replaceNode(ConcreteParasiticNode *from_node, - ConcreteParasiticNode *to_node) -{ - if (from_node == node_) - node_ = to_node; -} - -//////////////////////////////////////////////////////////////// - -ConcreteParasiticNetwork::ConcreteParasiticNetwork(bool includes_pin_caps) : max_node_id_(0), includes_pin_caps_(includes_pin_caps) { @@ -667,128 +503,209 @@ ConcreteParasiticNetwork::~ConcreteParasiticNetwork() void ConcreteParasiticNetwork::deleteNodes() { - ConcreteParasiticSubNodeMap::Iterator node_iter1(sub_nodes_); - while (node_iter1.hasNext()) { - NetIdPair *net_id; - ConcreteParasiticSubNode *node; - node_iter1.next(net_id, node); - delete net_id; + for (auto id_node : sub_nodes_) { + ConcreteParasiticNode *node = id_node.second; + delete node; + } + for (auto pin_node : pin_nodes_) { + ParasiticNode *node = pin_node.second; delete node; } - pin_nodes_.deleteContents(); } void ConcreteParasiticNetwork::deleteDevices() { - ConcreteParasiticDeviceSet devices1; - devices(&devices1); - devices1.deleteContents(); -} - -ParasiticNodeIterator * -ConcreteParasiticNetwork::nodeIterator() const -{ - ConcreteParasiticNodeSeq *nodes = new ConcreteParasiticNodeSeq(); - ConcreteParasiticPinNodeMap::ConstIterator node_iter2(pin_nodes_); - while (node_iter2.hasNext()) { - ConcreteParasiticPinNode *node = node_iter2.next(); - nodes->push_back(node); + for (ParasiticResistor *resistor : resistors_) { + ConcreteParasiticResistor *cresistor = + reinterpret_cast(resistor); + delete cresistor; } - ConcreteParasiticSubNodeMap::ConstIterator node_iter1(sub_nodes_); - while (node_iter1.hasNext()) { - ConcreteParasiticSubNode *node = node_iter1.next(); - nodes->push_back(node); + for (ParasiticCapacitor *capacitor : capacitors_) { + ConcreteParasiticCapacitor *ccapacitor = + reinterpret_cast(capacitor); + delete ccapacitor; } - return new ConcreteParasiticNodeSeqIterator(nodes); -} - -ParasiticDeviceIterator * -ConcreteParasiticNetwork::deviceIterator() const -{ - ConcreteParasiticDeviceSet *devices1 = new ConcreteParasiticDeviceSet(); - devices(devices1); - return new ConcreteParasiticDeviceSetIterator(devices1); } void -ConcreteParasiticNetwork::devices(ConcreteParasiticDeviceSet *devices) const +ConcreteParasiticNetwork::addResistor(ParasiticResistor *resistor) { - // Collect devices into a set so they are only deleted once - // because multiple sub-nodes or pin nodes can refer to them. - ConcreteParasiticSubNodeMap::ConstIterator node_iter1(sub_nodes_); - while (node_iter1.hasNext()) { - ConcreteParasiticSubNode *node = node_iter1.next(); - ConcreteParasiticDeviceSeq::Iterator device_iter(node->devices()); - while (device_iter.hasNext()) { - ConcreteParasiticDevice *device = device_iter.next(); - devices->insert(device); - } - } + resistors_.push_back(resistor); +} - ConcreteParasiticPinNodeMap::ConstIterator node_iter2(pin_nodes_); - while (node_iter2.hasNext()) { - ConcreteParasiticPinNode *node = node_iter2.next(); - ConcreteParasiticDeviceSeq::ConstIterator device_iter(node->devices()); - while (device_iter.hasNext()) { - ConcreteParasiticDevice *device = device_iter.next(); - devices->insert(device); - } +void +ConcreteParasiticNetwork::addCapacitor(ParasiticCapacitor *capacitor) +{ + capacitors_.push_back(capacitor); +} + +ParasiticNodeSeq +ConcreteParasiticNetwork::nodes() const +{ + ParasiticNodeSeq nodes; + for (auto pin_node : pin_nodes_) { + ParasiticNode *node = pin_node.second; + nodes.push_back(node); } + for (auto id_node : sub_nodes_) { + ParasiticNode *node = id_node.second; + nodes.push_back(node); + } + return nodes; } float ConcreteParasiticNetwork::capacitance() const { float cap = 0.0; - ConcreteParasiticSubNodeMap::ConstIterator sub_node_iter(sub_nodes_); - while (sub_node_iter.hasNext()) { - ConcreteParasiticSubNode *node = sub_node_iter.next(); - cap += node->capacitance(); + for (auto id_node : sub_nodes_) { + ConcreteParasiticNode *node = id_node.second; + if (!node->isExternal()) + cap += node->capacitance(); } - ConcreteParasiticPinNodeMap::ConstIterator pin_node_iter(pin_nodes_); - while (pin_node_iter.hasNext()) { - ConcreteParasiticPinNode *node = pin_node_iter.next(); - cap += node->capacitance(); + for (auto pin_node : pin_nodes_) { + ConcreteParasiticNode *node = pin_node.second; + if (!node->isExternal()) + cap += node->capacitance(); } + + for (ParasiticCapacitor *capacitor : capacitors_) { + ConcreteParasiticCapacitor *ccap = + static_cast(capacitor); + cap += ccap->value(); + } + return cap; } ConcreteParasiticNode * ConcreteParasiticNetwork::ensureParasiticNode(const Net *net, - int id) + int id, + const Network *) { + ConcreteParasiticNode *node; NetIdPair net_id(net, id); - ConcreteParasiticSubNode *node = sub_nodes_.findKey(&net_id); - if (node == nullptr) { - node = new ConcreteParasiticSubNode(net, id); - sub_nodes_[new NetIdPair(net, id)] = node; + auto id_node = sub_nodes_.find(net_id); + 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); } + else + node = id_node->second; + return node; +} + +ConcreteParasiticNode * +ConcreteParasiticNetwork::ensureParasiticNode(const Pin *pin, + const Network *network) +{ + ConcreteParasiticNode *node; + auto pin_node = pin_nodes_.find(pin); + if (pin_node == pin_nodes_.end()) { + Net *net = network->net(pin); + // Pins on the top level instance may not have nets. + // Use the net connected to the pin's terminal. + if (net == nullptr && network->isTopLevelPort(pin)) { + Term *term = network->term(pin); + if (term) + net = network->net(term); + } + else + net = network->highestNetAbove(net); + node = new ConcreteParasiticNode(pin, net != net_); + pin_nodes_[pin] = node; + } + else + node = pin_node->second; return node; } ConcreteParasiticNode * ConcreteParasiticNetwork::findNode(const Pin *pin) const { - return pin_nodes_.findKey(pin); + auto pin_node = pin_nodes_.find(pin); + if (pin_node == pin_nodes_.end()) + return nullptr; + else + return pin_node->second; +} + +PinSet +ConcreteParasiticNetwork::unannotatedLoads(const Pin *drvr_pin, + const Parasitics *parasitics) const +{ + PinSet loads = parasitics->loads(drvr_pin); + ParasiticNode *drvr_node = findNode(drvr_pin); + if (drvr_node) { + ParasiticNodeResistorMap resistor_map = + parasitics->parasiticNodeResistorMap(this); + ParasiticNodeSet visited_nodes; + ParasiticResistorSet loop_resistors; + unannotatedLoads(drvr_node, nullptr, loads, visited_nodes, + loop_resistors, resistor_map, parasitics); + } + return loads; } void -ConcreteParasiticNetwork::disconnectPin(const Pin *pin, - const Net *net) +ConcreteParasiticNetwork::unannotatedLoads(ParasiticNode *node, + ParasiticResistor *from_res, + PinSet &loads, + ParasiticNodeSet &visited_nodes, + ParasiticResistorSet &loop_resistors, + ParasiticNodeResistorMap &resistor_map, + const Parasitics *parasitics) const { - ConcreteParasiticNode *node = pin_nodes_.findKey(pin); - if (node) { + const Pin *pin = parasitics->pin(node); + if (pin) + loads.erase(const_cast(pin)); + + visited_nodes.insert(node); + ParasiticResistorSeq &resistors = resistor_map[node]; + for (ParasiticResistor *resistor : resistors) { + if (loop_resistors.find(resistor) == loop_resistors.end()) { + ParasiticNode *onode = parasitics->otherNode(resistor, node); + // One commercial extractor creates resistors with identical from/to nodes. + if (onode != node + && resistor != from_res) { + if (visited_nodes.find(onode) == visited_nodes.end()) + unannotatedLoads(onode, resistor, loads, visited_nodes, + loop_resistors, resistor_map, parasitics); + else + // resistor loop + loop_resistors.insert(resistor); + } + } + } + visited_nodes.erase(node); +} + +//////////////////////////////////////////////////////////////// + +void +ConcreteParasiticNetwork::disconnectPin(const Pin *pin, + const Net *net, + const Network *network) +{ + auto pin_node = pin_nodes_.find(pin); + if (pin_node != pin_nodes_.end()) { + ConcreteParasiticNode *node = pin_node->second; // Make a subnode to replace the pin node. - ConcreteParasiticNode *subnode = ensureParasiticNode(net,max_node_id_+1); + ConcreteParasiticNode *subnode = ensureParasiticNode(net,max_node_id_+1, + network); // Hand over the devices. - ConcreteParasiticDeviceSeq::Iterator device_iter(node->devices()); - while (device_iter.hasNext()) { - ConcreteParasiticDevice *device = device_iter.next(); - subnode->addDevice(device); - device->replaceNode(node, subnode); + for (ParasiticResistor *resistor : resistors_) { + ConcreteParasiticResistor *cresistor = + reinterpret_cast(resistor); + cresistor->replaceNode(node, subnode); + } + for (ParasiticCapacitor *capacitor : capacitors_) { + ConcreteParasiticCapacitor *ccapacitor = + reinterpret_cast(capacitor); + ccapacitor->replaceNode(node, subnode); } pin_nodes_.erase(pin); @@ -796,25 +713,14 @@ ConcreteParasiticNetwork::disconnectPin(const Pin *pin, } } -ConcreteParasiticNode * -ConcreteParasiticNetwork::ensureParasiticNode(const Pin *pin) -{ - ConcreteParasiticPinNode *node = pin_nodes_.findKey(pin); - if (node == nullptr) { - node = new ConcreteParasiticPinNode(pin); - pin_nodes_[pin] = node; - } - return node; -} - bool -NetIdPairLess::operator()(const NetIdPair *net_id1, - const NetIdPair *net_id2) const +NetIdPairLess::operator()(const NetIdPair &net_id1, + const NetIdPair &net_id2) const { - const Net *net1 = net_id1->first; - const Net *net2 = net_id2->first; - int id1 = net_id1->second; - int id2 = net_id2->second; + const Net *net1 = net_id1.first; + const Net *net2 = net_id2.first; + int id1 = net_id1.second; + int id2 = net_id2.second; return net1 < net2 || (net1 == net2 && id1 < id2); @@ -913,19 +819,6 @@ ConcreteParasitics::deleteParasitics(const Net *net, } } -void -ConcreteParasitics::deleteUnsavedParasitic(Parasitic *parasitic) -{ - ConcreteParasitic *cparasitic = static_cast(parasitic); - delete cparasitic; -} - -void -ConcreteParasitics::save() -{ - // No database to save to. -} - float ConcreteParasitics::capacitance(const Parasitic *parasitic) const { @@ -949,7 +842,8 @@ ConcreteParasitics::setIsReducedParasiticNetwork(Parasitic *parasitic, } void -ConcreteParasitics::disconnectPinBefore(const Pin *pin) +ConcreteParasitics::disconnectPinBefore(const Pin *pin, + const Network *network) { if (haveParasitics()) { deleteReducedParasitics(pin); @@ -962,7 +856,7 @@ ConcreteParasitics::disconnectPinBefore(const Pin *pin) for (int i = 0; i < ap_count; i++) { ConcreteParasiticNetwork *parasitic = parasitics[i]; if (parasitic) - parasitic->disconnectPin(pin, net); + parasitic->disconnectPin(pin, net, network); } } } @@ -1050,10 +944,6 @@ ConcreteParasitics::findPiElmore(const Pin *drvr_pin, ConcreteParasitic **parasitics = drvr_parasitic_map_.findKey(drvr_pin); if (parasitics) { ConcreteParasitic *parasitic = parasitics[ap_rf_index]; - if (parasitic == nullptr && rf == RiseFall::fall()) { - ap_rf_index = parasiticAnalysisPtIndex(ap, RiseFall::rise()); - parasitic = parasitics[ap_rf_index]; - } if (parasitic && parasitic->isPiElmore()) return parasitic; } @@ -1286,8 +1176,12 @@ ConcreteParasitics::findParasiticNetwork(const Net *net, UniqueLock lock(lock_); if (!parasitic_network_map_.empty()) { ConcreteParasiticNetwork **parasitics=parasitic_network_map_.findKey(net); - if (parasitics) - return parasitics[ap->index()]; + if (parasitics) { + ConcreteParasiticNetwork *parasitic = parasitics[ap->index()]; + if (parasitic == nullptr) + parasitic = parasitics[ap->indexMax()]; + return parasitic; + } } } return nullptr; @@ -1303,8 +1197,12 @@ ConcreteParasitics::findParasiticNetwork(const Pin *pin, // Only call findParasiticNet if parasitics exist. const Net *net = findParasiticNet(pin); ConcreteParasiticNetwork **parasitics=parasitic_network_map_.findKey(net); - if (parasitics) - return parasitics[ap->index()]; + if (parasitics) { + ConcreteParasiticNetwork *parasitic = parasitics[ap->index()]; + if (parasitic == nullptr) + parasitic = parasitics[ap->indexMax()]; + return parasitic; + } } } return nullptr; @@ -1326,9 +1224,12 @@ ConcreteParasitics::makeParasiticNetwork(const Net *net, } int ap_index = ap->index(); ConcreteParasiticNetwork *parasitic = parasitics[ap_index]; - if (parasitic) + if (parasitic) { delete parasitic; - parasitic = new ConcreteParasiticNetwork(includes_pin_caps); + for (const Pin *drvr_pin : *network_->drivers(net)) + deleteParasitics(drvr_pin, ap); + } + parasitic = new ConcreteParasiticNetwork(net, includes_pin_caps); parasitics[ap_index] = parasitic; return parasitic; } @@ -1343,14 +1244,20 @@ ConcreteParasitics::deleteParasiticNetwork(const Net *net, if (parasitics) { int ap_index = ap->index(); delete parasitics[ap_index]; + parasitics[ap_index] = nullptr; + int ap_count = corners_->parasiticAnalysisPtCount(); - if (ap_count == 1) { - // If there is only one parasitic we can remove the array and map entry. + bool have_parasitics = false; + for (int i = 0; i < ap_count; i++) { + if (parasitics[i]) { + have_parasitics = true; + break; + } + } + if (!have_parasitics) { delete [] parasitics; parasitic_network_map_.erase(net); } - else - parasitics[ap_index] = nullptr; } } } @@ -1382,113 +1289,89 @@ ConcreteParasitics::includesPinCaps(const Parasitic *parasitic) const ParasiticNode * ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic, const Net *net, - int id) + int id, + const Network *network) { ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); - return cparasitic->ensureParasiticNode(net, id); + return cparasitic->ensureParasiticNode(net, id, network); } ParasiticNode * ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic, - const Pin *pin) + const Pin *pin, + const Network *network) { ConcreteParasiticNetwork *cparasitic = static_cast(parasitic); - return cparasitic->ensureParasiticNode(pin); + return cparasitic->ensureParasiticNode(pin, network); } void ConcreteParasitics::incrCap(ParasiticNode *node, - float cap, - const ParasiticAnalysisPt *) + float cap) { ConcreteParasiticNode *cnode = static_cast(node); cnode->incrCapacitance(cap); } void -ConcreteParasitics::makeCouplingCap(const char *name, - ParasiticNode *node, - ParasiticNode *other_node, - float cap, - const ParasiticAnalysisPt *) -{ - ConcreteParasiticNode *cnode = static_cast(node); - ConcreteParasiticNode *other_cnode = - static_cast(other_node); - ConcreteCouplingCap *coupling_cap = - new ConcreteCouplingCapInt(name, cnode, other_cnode, cap); - cnode->addDevice(coupling_cap); - other_cnode->addDevice(coupling_cap); -} - -void -ConcreteParasitics::makeCouplingCap(const char *name, - ParasiticNode *node, - Net *other_node_net, - int other_node_id, - float cap, - const ParasiticAnalysisPt *) -{ - ConcreteParasiticNode *cnode = static_cast(node); - ConcreteCouplingCap *coupling_cap = - new ConcreteCouplingCapExtNode(name, cnode, other_node_net, - other_node_id, cap); - cnode->addDevice(coupling_cap); -} - -void -ConcreteParasitics::makeCouplingCap(const char *name, - ParasiticNode *node, - Pin *other_node_pin, - float cap, - const ParasiticAnalysisPt *) -{ - ConcreteParasiticNode *cnode = static_cast(node); - ConcreteCouplingCap *coupling_cap = - new ConcreteCouplingCapExtPin(name, cnode, other_node_pin, cap); - cnode->addDevice(coupling_cap); -} - -void -ConcreteParasitics::makeResistor(const char *name, - ParasiticNode *node1, - ParasiticNode *node2, - float res, - const ParasiticAnalysisPt *) +ConcreteParasitics::makeCapacitor(Parasitic *parasitic, + size_t index, + float cap, + ParasiticNode *node1, + ParasiticNode *node2) { ConcreteParasiticNode *cnode1 = static_cast(node1); ConcreteParasiticNode *cnode2 = static_cast(node2); - ConcreteParasiticDevice *resistor = - new ConcreteParasiticResistor(name, cnode1, cnode2, res); - cnode1->addDevice(resistor); - cnode2->addDevice(resistor); + ConcreteParasiticCapacitor *capacitor = + new ConcreteParasiticCapacitor(index, cap, cnode1, cnode2); + ConcreteParasiticNetwork *cparasitic = + static_cast(parasitic); + cparasitic->addCapacitor(capacitor); } -ParasiticDeviceIterator * -ConcreteParasitics::deviceIterator(const Parasitic *parasitic) +void +ConcreteParasitics::makeResistor(Parasitic *parasitic, + size_t index, + float res, + ParasiticNode *node1, + ParasiticNode *node2) { - const ConcreteParasitic *cparasitic = static_cast(parasitic); - return cparasitic->deviceIterator(); + ConcreteParasiticNode *cnode1 = static_cast(node1); + ConcreteParasiticNode *cnode2 = static_cast(node2); + ParasiticResistor *resistor = new ConcreteParasiticResistor(index, res, + cnode1, cnode2); + ConcreteParasiticNetwork *cparasitic = + static_cast(parasitic); + cparasitic->addResistor(resistor); } -ParasiticNodeIterator * -ConcreteParasitics::nodeIterator(const Parasitic *parasitic) +ParasiticNodeSeq +ConcreteParasitics::nodes(const Parasitic *parasitic) const { - const ConcreteParasitic *cparasitic = static_cast(parasitic); - return cparasitic->nodeIterator(); + const ConcreteParasiticNetwork *cparasitic = + static_cast(parasitic); + return cparasitic->nodes(); } -float -ConcreteParasitics::nodeGndCap(const ParasiticNode *node, - const ParasiticAnalysisPt *) const +ParasiticResistorSeq +ConcreteParasitics::resistors(const Parasitic *parasitic) const { - const ConcreteParasiticNode *cnode = - static_cast(node); - return cnode->capacitance(); + const ConcreteParasiticNetwork *cparasitic = + static_cast(parasitic); + return cparasitic->resistors(); } +ParasiticCapacitorSeq +ConcreteParasitics::capacitors(const Parasitic *parasitic) const +{ + const ConcreteParasiticNetwork *cparasitic = + static_cast(parasitic); + return cparasitic->capacitors(); +} + + const char * ConcreteParasitics::name(const ParasiticNode *node) { @@ -1497,18 +1380,37 @@ ConcreteParasitics::name(const ParasiticNode *node) return cnode->name(network_); } -const Pin * -ConcreteParasitics::connectionPin(const ParasiticNode *node) const +float +ConcreteParasitics::nodeGndCap(const ParasiticNode *node) const { const ConcreteParasiticNode *cnode = static_cast(node); - if (cnode->isPinNode()) { - const ConcreteParasiticPinNode *pin_node = - dynamic_cast(cnode); - return pin_node->pin(); - } - else - return nullptr; + return cnode->capacitance(); +} + +const Pin * +ConcreteParasitics::pin(const ParasiticNode *node) const +{ + const ConcreteParasiticNode *cnode = + static_cast(node); + return cnode->pin(); +} + +const Net * +ConcreteParasitics::net(const ParasiticNode *node, + const Network *network) const +{ + const ConcreteParasiticNode *cnode = + static_cast(node); + return cnode->net(network); +} + +bool +ConcreteParasitics::isExternal(const ParasiticNode *node) const +{ + const ConcreteParasiticNode *cnode = + static_cast(node); + return cnode->isExternal(); } ParasiticNode * @@ -1520,305 +1422,82 @@ ConcreteParasitics::findNode(const Parasitic *parasitic, return cparasitic->findNode(pin); } -ParasiticDeviceIterator * -ConcreteParasitics::deviceIterator(ParasiticNode *node) const -{ - ConcreteParasiticNode *cnode = static_cast(node); - return new ConcreteParasiticDeviceSeqIterator(cnode->devices()); -} +//////////////////////////////////////////////////////////////// -const char * -ConcreteParasitics::name(const ParasiticDevice *device) const +size_t +ConcreteParasitics::id(const ParasiticResistor *resistor) const { - const ConcreteParasiticDevice *cdevice = - static_cast(device); - return cdevice->name(); -} - -bool -ConcreteParasitics::isResistor(const ParasiticDevice *device) const -{ - const ConcreteParasiticDevice *cdevice = - static_cast(device); - return cdevice->isResistor(); -} - -bool -ConcreteParasitics::isCouplingCap(const ParasiticDevice *device) const -{ - const ConcreteParasiticDevice *cdevice = - static_cast(device); - return cdevice->isCouplingCap(); + const ConcreteParasiticResistor *cresistor = + static_cast(resistor); + return cresistor->id(); } float -ConcreteParasitics::value(const ParasiticDevice *device, - const ParasiticAnalysisPt *) const +ConcreteParasitics::value(const ParasiticResistor *resistor) const { - const ConcreteParasiticDevice *cdevice = - static_cast(device); - return cdevice->value(); + const ConcreteParasiticResistor *cresistor = + static_cast(resistor); + return cresistor->value(); } ParasiticNode * -ConcreteParasitics::node1(const ParasiticDevice *device) const +ConcreteParasitics::node1(const ParasiticResistor *resistor) const { - const ConcreteParasiticDevice *cdevice = - static_cast(device); - return cdevice->node1(); + const ConcreteParasiticResistor *cresistor = + static_cast(resistor); + return cresistor->node1(); } ParasiticNode * -ConcreteParasitics::node2(const ParasiticDevice *device) const +ConcreteParasitics::node2(const ParasiticResistor *resistor) const { - const ConcreteParasiticDevice *cdevice = - static_cast(device); - return cdevice->node2(); -} - -ParasiticNode * -ConcreteParasitics::otherNode(const ParasiticDevice *device, - ParasiticNode *node) const -{ - const ConcreteParasiticDevice *cdevice = - static_cast(device); - return cdevice->otherNode(node); + const ConcreteParasiticResistor *cresistor = + static_cast(resistor); + return cresistor->node2(); } //////////////////////////////////////////////////////////////// -bool -ConcreteParasitics::checkAnnotation(Parasitic *parasitic_network, - const Pin *drvr_pin) +size_t +ConcreteParasitics::id(const ParasiticCapacitor *capacitor) const { - ParasiticNode *drvr_node = findNode(parasitic_network, drvr_pin); - if (drvr_node) - return checkAnnotation(drvr_pin, drvr_node); - return false; + const ConcreteParasiticCapacitor *ccapacitor = + static_cast(capacitor); + return ccapacitor->id(); } -bool -ConcreteParasitics::checkAnnotation(const Pin *drvr_pin, - ParasiticNode *drvr_node) +float +ConcreteParasitics::value(const ParasiticCapacitor *capacitor) const { - PinSet unannotated_loads = checkAnnotation1(drvr_pin, drvr_node); - return unannotated_loads.empty(); + const ConcreteParasiticCapacitor *ccapacitor = + static_cast(capacitor); + return ccapacitor->value(); } +ParasiticNode * +ConcreteParasitics::node1(const ParasiticCapacitor *capacitor) const +{ + const ConcreteParasiticCapacitor *ccapacitor = + static_cast(capacitor); + return ccapacitor->node1(); +} + +ParasiticNode * +ConcreteParasitics::node2(const ParasiticCapacitor *capacitor) const +{ + const ConcreteParasiticCapacitor *ccapacitor = + static_cast(capacitor); + return ccapacitor->node2(); +} + +//////////////////////////////////////////////////////////////// + PinSet -ConcreteParasitics::unannotatedLoads(Parasitic *parasitic_network, - const Pin *drvr_pin) +ConcreteParasitics::unannotatedLoads(const Parasitic *parasitic, + const Pin *drvr_pin) const { - ParasiticNode *drvr_node = findNode(parasitic_network, drvr_pin); - if (drvr_node) - return checkAnnotation1(drvr_pin, drvr_node); - return PinSet(network_); -} - -PinSet -ConcreteParasitics::checkAnnotation1(const Pin *drvr_pin, - ParasiticNode *drvr_node) -{ - PinSet loads(network_); - NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(drvr_pin); - while (pin_iter->hasNext()) { - const Pin *pin = pin_iter->next(); - if (network_->isLoad(pin) && !network_->isHierarchical(pin)) - loads.insert(pin); - } - delete pin_iter; - - ParasiticNodeSet visited_nodes; - ParasiticDeviceSet loop_resistors; - checkAnnotation2(drvr_pin, drvr_node, nullptr, loads, - visited_nodes, loop_resistors); - return loads; -} - -void -ConcreteParasitics::checkAnnotation2(const Pin *drvr_pin, - ParasiticNode *node, - ParasiticDevice *from_res, - PinSet &loads, - ParasiticNodeSet &visited_nodes, - ParasiticDeviceSet &loop_resistors) -{ - const Pin *pin = parasitics_->connectionPin(node); - if (pin) - loads.erase(const_cast(pin)); - - visited_nodes.insert(node); - ParasiticDeviceIterator *device_iter = parasitics_->deviceIterator(node); - while (device_iter->hasNext()) { - ParasiticDevice *device = device_iter->next(); - if (parasitics_->isResistor(device) - && loop_resistors.find(device) == loop_resistors.end()) { - ParasiticNode *onode = parasitics_->otherNode(device, node); - // One commercial extractor creates resistors with identical from/to nodes. - if (onode != node - && device != from_res) { - if (visited_nodes.find(onode) == visited_nodes.end()) - checkAnnotation2(drvr_pin, onode, device, loads, - visited_nodes, loop_resistors); - else - // resistor loop - loop_resistors.insert(device); - } - } - } - delete device_iter; - visited_nodes.erase(node); -} - -//////////////////////////////////////////////////////////////// - -void -ConcreteParasitics::reduceTo(const Parasitic *parasitic, - const Net *net, - ReducedParasiticType reduce_to, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap) -{ - switch (reduce_to) { - case ReducedParasiticType::pi_elmore: - reduceToPiElmore(parasitic, net, op_cond, corner, cnst_min_max, ap); - break; - case ReducedParasiticType::pi_pole_residue2: - reduceToPiPoleResidue2(parasitic, net, op_cond, corner, - cnst_min_max, ap); - break; - case ReducedParasiticType::arnoldi: - case ReducedParasiticType::none: - break; - } -} - -void -ConcreteParasitics::reduceToPiElmore(const Parasitic *parasitic, - const Net *net, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap) -{ - debugPrint(debug_, "parasitic_reduce", 1, "Reduce net %s", - network_->pathName(net)); - NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net); - while (pin_iter->hasNext()) { - const Pin *pin = pin_iter->next(); - if (network_->isDriver(pin)) { - sta::reduceToPiElmore(parasitic, pin, ap->couplingCapFactor(), - op_cond, corner, cnst_min_max, ap, this); - } - } - delete pin_iter; -} - -void -ConcreteParasitics::reduceToPiElmore(const Parasitic *parasitic, - const Pin *drvr_pin, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap) -{ - sta::reduceToPiElmore(parasitic, drvr_pin, ap->couplingCapFactor(), - op_cond, corner, cnst_min_max, ap, this); -} - -void -ConcreteParasitics::reduceToPiPoleResidue2(const Parasitic *parasitic, - const Net *net, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap) -{ - debugPrint(debug_, "parasitic_reduce", 1, "Reduce net %s", - network_->pathName(net)); - NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net); - while (pin_iter->hasNext()) { - const Pin *pin = pin_iter->next(); - if (network_->isDriver(pin)) - sta::reduceToPiPoleResidue2(parasitic, pin, ap->couplingCapFactor(), - op_cond, corner, cnst_min_max, ap, this); - } - delete pin_iter; -} - -void -ConcreteParasitics::reduceToPiPoleResidue2(const Parasitic *parasitic, - const Pin *drvr_pin, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap) -{ - sta::reduceToPiPoleResidue2(parasitic, drvr_pin, - ap->couplingCapFactor(), - op_cond, corner, cnst_min_max, - ap, this); -} - -//////////////////////////////////////////////////////////////// - -Parasitic * -ConcreteParasitics::estimatePiElmore(const Pin *drvr_pin, - const RiseFall *rf, - const Wireload *wireload, - float fanout, - float net_pin_cap, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *min_max, - const ParasiticAnalysisPt *) -{ - float c2, rpi, c1, elmore_res, elmore_cap; - bool elmore_use_load_cap; - estimatePiElmore(drvr_pin, rf, wireload, fanout, net_pin_cap, - op_cond, corner, min_max, this, - c2, rpi, c1, - elmore_res, elmore_cap, elmore_use_load_cap); - - if (c1 > 0.0 || c2 > 0.0) - return new ConcretePiElmoreEstimated(c2, rpi, c1, elmore_res, elmore_cap, - elmore_use_load_cap, - rf, op_cond, corner, min_max, - sdc_); - else - return nullptr; -} - -//////////////////////////////////////////////////////////////// - -ConcreteParasiticDeviceSeqIterator:: -ConcreteParasiticDeviceSeqIterator(ConcreteParasiticDeviceSeq *devices) : - iter_(devices) -{ -} - -ConcreteParasiticDeviceSetIterator:: -ConcreteParasiticDeviceSetIterator(ConcreteParasiticDeviceSet *devices) : - iter_(devices) -{ -} - -ConcreteParasiticDeviceSetIterator::~ConcreteParasiticDeviceSetIterator() -{ - delete iter_.container(); -} - -ConcreteParasiticNodeSeqIterator:: -ConcreteParasiticNodeSeqIterator(ConcreteParasiticNodeSeq *nodes) : - iter_(nodes) -{ -} - -ConcreteParasiticNodeSeqIterator::~ConcreteParasiticNodeSeqIterator() -{ - delete iter_.container(); + const ConcreteParasitic *cparasitic = static_cast(parasitic); + return cparasitic->unannotatedLoads(drvr_pin, this); } } // namespace diff --git a/parasitics/ConcreteParasitics.hh b/parasitics/ConcreteParasitics.hh index c4323c34..842b3046 100644 --- a/parasitics/ConcreteParasitics.hh +++ b/parasitics/ConcreteParasitics.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -21,203 +21,148 @@ #include "Map.hh" #include "Set.hh" #include "MinMax.hh" -#include "EstimateParasitics.hh" #include "Parasitics.hh" namespace sta { class ConcreteParasitic; -class ConcretePiElmore; -class ConcretePiPoleResidue; class ConcreteParasiticNetwork; -class ConcreteParasiticNode; -class ConcreteParasiticDevice; typedef Map ConcreteParasiticMap; typedef Map ConcreteParasiticNetworkMap; -typedef Set ParasiticNodeSet; -typedef Set ParasiticDeviceSet; -// This class acts as a BUILDER for all parasitics. -class ConcreteParasitics : public Parasitics, public EstimateParasitics +// This class acts as a BUILDER for parasitics. +class ConcreteParasitics : public Parasitics { public: ConcreteParasitics(StaState *sta); virtual ~ConcreteParasitics(); - virtual bool haveParasitics(); - virtual void clear(); + bool haveParasitics() override; + void clear() override; - virtual void save(); - virtual void deleteParasitics(); - virtual void deleteParasitics(const Net *net, - const ParasiticAnalysisPt *ap); - virtual void deleteParasitics(const Pin *drvr_pin, - const ParasiticAnalysisPt *ap); - virtual void deleteUnsavedParasitic(Parasitic *parasitic); + void deleteParasitics() override; + void deleteParasitics(const Net *net, + const ParasiticAnalysisPt *ap) override; + void deleteParasitics(const Pin *drvr_pin, + const ParasiticAnalysisPt *ap) override; - virtual bool isReducedParasiticNetwork(const Parasitic *parasitic) const; - virtual void setIsReducedParasiticNetwork(Parasitic *parasitic, - bool is_reduced); + bool isReducedParasiticNetwork(const Parasitic *parasitic) const override; + void setIsReducedParasiticNetwork(Parasitic *parasitic, + bool is_reduced) override; - virtual float capacitance(const Parasitic *parasitic) const; + float capacitance(const Parasitic *parasitic) const override; - virtual bool isPiElmore(const Parasitic *parasitic) const; - virtual Parasitic *findPiElmore(const Pin *drvr_pin, - const RiseFall *rf, - const ParasiticAnalysisPt *ap) const; - virtual Parasitic *makePiElmore(const Pin *drvr_pin, - const RiseFall *rf, - const ParasiticAnalysisPt *ap, - float c2, - float rpi, - float c1); - - virtual bool isPiModel(const Parasitic *parasitic) const; - virtual void piModel(const Parasitic *parasitic, - float &c2, - float &rpi, - float &c1) const; - virtual void setPiModel(Parasitic *parasitic, + bool isPiElmore(const Parasitic *parasitic) const override; + Parasitic *findPiElmore(const Pin *drvr_pin, + const RiseFall *rf, + const ParasiticAnalysisPt *ap) const override; + Parasitic *makePiElmore(const Pin *drvr_pin, + const RiseFall *rf, + const ParasiticAnalysisPt *ap, float c2, float rpi, - float c1); + float c1) override; - virtual void findElmore(const Parasitic *parasitic, - const Pin *load_pin, - float &elmore, - bool &exists) const; - virtual void setElmore(Parasitic *parasitic, - const Pin *load_pin, - float elmore); + bool isPiModel(const Parasitic *parasitic) const override; + void piModel(const Parasitic *parasitic, + float &c2, + float &rpi, + float &c1) const override; + void setPiModel(Parasitic *parasitic, + float c2, + float rpi, + float c1) override; - virtual bool isPiPoleResidue(const Parasitic* parasitic) const; - virtual Parasitic *findPiPoleResidue(const Pin *drvr_pin, - const RiseFall *rf, - const ParasiticAnalysisPt *ap) const; - virtual Parasitic *findPoleResidue(const Parasitic *parasitic, - const Pin *load_pin) const; - virtual Parasitic *makePiPoleResidue(const Pin *drvr_pin, - const RiseFall *rf, - const ParasiticAnalysisPt *ap, - float c2, float rpi, float c1); - virtual void setPoleResidue(Parasitic *parasitic, const Pin *load_pin, - ComplexFloatSeq *poles, - ComplexFloatSeq *residues); - virtual bool isPoleResidue(const Parasitic* parasitic) const; - virtual size_t poleResidueCount(const Parasitic *parasitic) const; - virtual void poleResidue(const Parasitic *parasitic, int pole_index, - ComplexFloat &pole, ComplexFloat &residue) const; + void findElmore(const Parasitic *parasitic, + const Pin *load_pin, + float &elmore, + bool &exists) const override; + void setElmore(Parasitic *parasitic, + const Pin *load_pin, + float elmore) override; - virtual bool isParasiticNetwork(const Parasitic *parasitic) const; - virtual Parasitic *findParasiticNetwork(const Net *net, - const ParasiticAnalysisPt *ap) const; - virtual Parasitic *findParasiticNetwork(const Pin *pin, - const ParasiticAnalysisPt *ap) const; - virtual Parasitic *makeParasiticNetwork(const Net *net, - bool includes_pin_caps, - const ParasiticAnalysisPt *ap); - virtual void deleteParasiticNetwork(const Net *net, - const ParasiticAnalysisPt *ap); - virtual void deleteParasiticNetworks(const Net *net); - virtual bool includesPinCaps(const Parasitic *parasitic) const; - virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, - const Net *net, - int id); - virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, - const Pin *pin); - virtual void incrCap(ParasiticNode *node, float cap, - const ParasiticAnalysisPt *ap); - virtual void makeCouplingCap(const char *name, - ParasiticNode *node, - ParasiticNode *other_node, - float cap, const ParasiticAnalysisPt *ap); - virtual void makeCouplingCap(const char *name, - ParasiticNode *node, - Net *other_node_net, int other_node_id, - float cap, const ParasiticAnalysisPt *ap); - virtual void makeCouplingCap(const char *name, - ParasiticNode *node, - Pin *other_node_pin, - float cap, const ParasiticAnalysisPt *ap); - virtual void makeResistor(const char *name, ParasiticNode *node1, - ParasiticNode *node2, - float res, const ParasiticAnalysisPt *ap); - virtual ParasiticDeviceIterator *deviceIterator(const Parasitic *parasitic); - virtual ParasiticNodeIterator *nodeIterator(const Parasitic *parasitic); + bool isPiPoleResidue(const Parasitic* parasitic) const override; + Parasitic *findPiPoleResidue(const Pin *drvr_pin, + const RiseFall *rf, + const ParasiticAnalysisPt *ap) const override; + Parasitic *findPoleResidue(const Parasitic *parasitic, + const Pin *load_pin) const override; + Parasitic *makePiPoleResidue(const Pin *drvr_pin, + const RiseFall *rf, + const ParasiticAnalysisPt *ap, + float c2, float rpi, float c1) override; + void setPoleResidue(Parasitic *parasitic, const Pin *load_pin, + ComplexFloatSeq *poles, + ComplexFloatSeq *residues) override; + bool isPoleResidue(const Parasitic* parasitic) const override; + size_t poleResidueCount(const Parasitic *parasitic) const override; + void poleResidue(const Parasitic *parasitic, + int pole_index, + ComplexFloat &pole, + ComplexFloat &residue) const override; - virtual const char *name(const ParasiticNode *node); - virtual const Pin *connectionPin(const ParasiticNode *node) const; - virtual ParasiticNode *findNode(const Parasitic *parasitic, - const Pin *pin) const; - virtual float nodeGndCap(const ParasiticNode *node, - const ParasiticAnalysisPt *ap) const; - virtual ParasiticDeviceIterator * - deviceIterator(ParasiticNode *node) const; - virtual bool isResistor(const ParasiticDevice *device) const; - virtual bool isCouplingCap(const ParasiticDevice *device) const; - virtual const char *name(const ParasiticDevice *device) const; - virtual float value(const ParasiticDevice *device, - const ParasiticAnalysisPt *ap) const; - virtual ParasiticNode *node1(const ParasiticDevice *device) const; - virtual ParasiticNode *node2(const ParasiticDevice *device) const; - virtual ParasiticNode *otherNode(const ParasiticDevice *device, - ParasiticNode *node) const; + bool isParasiticNetwork(const Parasitic *parasitic) const override; + Parasitic *findParasiticNetwork(const Net *net, + const ParasiticAnalysisPt *ap) const override; + Parasitic *findParasiticNetwork(const Pin *pin, + const ParasiticAnalysisPt *ap) const override; + Parasitic *makeParasiticNetwork(const Net *net, + bool includes_pin_caps, + const ParasiticAnalysisPt *ap) override; + void deleteParasiticNetwork(const Net *net, + const ParasiticAnalysisPt *ap) override; + void deleteParasiticNetworks(const Net *net) override; + bool includesPinCaps(const Parasitic *parasitic) const override; + ParasiticNode *ensureParasiticNode(Parasitic *parasitic, + const Net *net, + int id, + const Network *network) override; + ParasiticNode *ensureParasiticNode(Parasitic *parasitic, + const Pin *pin, + const Network *network) override; + ParasiticNodeSeq nodes(const Parasitic *parasitic) const override; + void incrCap(ParasiticNode *node, + float cap) override; + const char *name(const ParasiticNode *node) override; + ParasiticNode *findNode(const Parasitic *parasitic, + const Pin *pin) const override; + const Pin *pin(const ParasiticNode *node) const override; + const Net *net(const ParasiticNode *node, + const Network *network) const override; + bool isExternal(const ParasiticNode *node) const override; + float nodeGndCap(const ParasiticNode *node) const override; - // Return true if all loads are annoatated. - virtual bool checkAnnotation(Parasitic *parasitic_network, - const Pin *drvr_pin); - virtual bool checkAnnotation(const Pin *drvr_pin, - ParasiticNode *drvr_node); - // Return loads missing path from driver. - virtual PinSet unannotatedLoads(Parasitic *parasitic_network, - const Pin *drvr_pin); + ParasiticResistorSeq resistors(const Parasitic *parasitic) const override; + void makeResistor(Parasitic *parasitic, + size_t id, + float res, + ParasiticNode *node1, + ParasiticNode *node2) override; + size_t id(const ParasiticResistor *resistor) const override; + float value(const ParasiticResistor *resistor) const override; + ParasiticNode *node1(const ParasiticResistor *resistor) const override; + ParasiticNode *node2(const ParasiticResistor *resistor) const override; + ParasiticCapacitorSeq capacitors(const Parasitic *parasitic) const override; + void makeCapacitor(Parasitic *parasitic, + size_t id, + float cap, + ParasiticNode *node1, + ParasiticNode *node2) override; + size_t id(const ParasiticCapacitor *capacitor) const override; + float value(const ParasiticCapacitor *capacitor) const override; + ParasiticNode *node1(const ParasiticCapacitor *capacitor) const override; + ParasiticNode *node2(const ParasiticCapacitor *capacitor) const override; - virtual Parasitic *estimatePiElmore(const Pin *drvr_pin, - const RiseFall *rf, - const Wireload *wireload, - float fanout, - float net_pin_cap, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *min_max, - const ParasiticAnalysisPt *ap); - virtual void disconnectPinBefore(const Pin *pin); - virtual void loadPinCapacitanceChanged(const Pin *pin); + PinSet unannotatedLoads(const Parasitic *parasitic, + const Pin *drvr_pin) const override; + + void disconnectPinBefore(const Pin *pin, + const Network *network) override; + void loadPinCapacitanceChanged(const Pin *pin) override; - virtual void reduceTo(const Parasitic *parasitic, - const Net *net, - ReducedParasiticType reduce_to, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); - virtual void reduceToPiElmore(const Parasitic *parasitic, - const Net *net, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); - virtual void reduceToPiElmore(const Parasitic *parasitic, - const Pin *drvr_pin, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); - virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, - const Net *net, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); - virtual void reduceToPiPoleResidue2(const Parasitic *parasitic, - const Pin *drvr_pin, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); void deleteReducedParasitics(const Net *net, - const ParasiticAnalysisPt *ap); - virtual void deleteDrvrReducedParasitics(const Pin *drvr_pin); + const ParasiticAnalysisPt *ap) override; + void deleteDrvrReducedParasitics(const Pin *drvr_pin) override; protected: int parasiticAnalysisPtIndex(const ParasiticAnalysisPt *ap, @@ -227,14 +172,6 @@ protected: void deleteReducedParasitics(const Pin *pin); void deleteDrvrReducedParasitics(const Pin *drvr_pin, const ParasiticAnalysisPt *ap); - PinSet checkAnnotation1(const Pin *drvr_pin, - ParasiticNode *drvr_node); - void checkAnnotation2(const Pin *drvr_pin, - ParasiticNode *node, - ParasiticDevice *from_res, - PinSet &loads, - ParasiticNodeSet &visited_nodes, - ParasiticDeviceSet &loop_resistors); // Driver pin to array of parasitics indexed by analysis pt index // and transition. @@ -242,10 +179,8 @@ protected: ConcreteParasiticNetworkMap parasitic_network_map_; mutable std::mutex lock_; - using EstimateParasitics::estimatePiElmore; friend class ConcretePiElmore; friend class ConcreteParasiticNode; - friend class ConcreteParasiticResistor; friend class ConcreteParasiticNetwork; }; diff --git a/parasitics/ConcreteParasiticsPvt.hh b/parasitics/ConcreteParasiticsPvt.hh index 0444b0f6..c4bcc346 100644 --- a/parasitics/ConcreteParasiticsPvt.hh +++ b/parasitics/ConcreteParasiticsPvt.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -16,38 +16,38 @@ #pragma once +#include +#include + #include "Parasitics.hh" namespace sta { class ConcretePoleResidue; class ConcreteParasiticDevice; -class ConcreteParasiticPinNode; -class ConcreteParasiticSubNode; class ConcreteParasiticNode; -typedef Map ConcreteElmoreLoadMap; -typedef ConcreteElmoreLoadMap::Iterator ConcretePiElmoreLoadIterator; -typedef Map ConcretePoleResidueMap; +typedef std::map ConcreteElmoreLoadMap; +typedef std::map ConcretePoleResidueMap; typedef std::pair NetIdPair; struct NetIdPairLess { - bool operator()(const NetIdPair *net_id1, - const NetIdPair *net_id2) const; + bool operator()(const NetIdPair &net_id1, + const NetIdPair &net_id2) const; }; -typedef Map ConcreteParasiticSubNodeMap; -typedef Map ConcreteParasiticPinNodeMap; -typedef Vector ConcreteParasiticDeviceSeq; -typedef Set ConcreteParasiticDeviceSet; -typedef Vector ConcreteParasiticNodeSeq; +typedef std::map ConcreteParasiticSubNodeMap; +typedef std::map ConcreteParasiticPinNodeMap; +typedef std::set ParasiticNodeSet; +typedef std::set ParasiticResistorSet; +typedef std::vector ParasiticResistorSeq; // Empty base class definitions so casts are not required on returned // objects. class Parasitic {}; class ParasiticNode {}; -class ParasiticDevice {}; +class ParasiticResistor {}; +class ParasiticCapacitor {}; class ParasiticNetwork {}; // Base class for parasitics. @@ -78,8 +78,8 @@ public: virtual void setPoleResidue(const Pin *load_pin, ComplexFloatSeq *poles, ComplexFloatSeq *residues); - virtual ParasiticDeviceIterator *deviceIterator() const; - virtual ParasiticNodeIterator *nodeIterator() const; + virtual PinSet unannotatedLoads(const Pin *drvr_pin, + const Parasitics *parasitics) const = 0; }; // Pi model for a driver pin. @@ -114,70 +114,46 @@ public: ConcretePiElmore(float c2, float rpi, float c1); - virtual ~ConcretePiElmore(); - virtual bool isPiElmore() const { return true; } - virtual bool isPiModel() const { return true; } - virtual float capacitance() const; - virtual void piModel(float &c2, float &rpi, float &c1) const; - virtual void setPiModel(float c2, float rpi, float c1); - virtual bool isReducedParasiticNetwork() const; - virtual void setIsReduced(bool reduced); - virtual void findElmore(const Pin *load_pin, float &elmore, - bool &exists) const; - virtual void setElmore(const Pin *load_pin, float elmore); + bool isPiElmore() const override { return true; } + bool isPiModel() const override { return true; } + float capacitance() const override; + void piModel(float &c2, + float &rpi, + float &c1) const override; + void setPiModel(float c2, + float rpi, + float c1) override; + bool isReducedParasiticNetwork() const override; + void setIsReduced(bool reduced) override; + void findElmore(const Pin *load_pin, + float &elmore, + bool &exists) const override; + void setElmore(const Pin *load_pin, + float elmore) override; + PinSet unannotatedLoads(const Pin *drvr_pin, + const Parasitics *parasitics) const override; void deleteLoad(const Pin *load_pin); private: - ConcreteElmoreLoadMap *loads_; -}; - -// PiElmore from wireload model estimate. -class ConcretePiElmoreEstimated : public ConcretePi, - public ConcreteParasitic -{ -public: - ConcretePiElmoreEstimated(float c2, - float rpi, - float c1, - float elmore_res, - float elmore_cap, - bool elmore_use_load_cap, - const RiseFall *rf, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *min_max, - Sdc *sdc); - virtual float capacitance() const; - virtual bool isPiElmore() const { return true; } - virtual bool isPiModel() const { return true; } - virtual void piModel(float &c2, float &rpi, float &c1) const; - virtual void findElmore(const Pin *load_pin, float &elmore, - bool &exists) const; - virtual void setElmore(const Pin *load_pin, float elmore); - -private: - float elmore_res_; - float elmore_cap_; - bool elmore_use_load_cap_; - const RiseFall *rf_; - const OperatingConditions *op_cond_; - const Corner *corner_; - const MinMax *min_max_; - Sdc *sdc_; + ConcreteElmoreLoadMap loads_; }; class ConcretePoleResidue : public ConcreteParasitic { public: - ConcretePoleResidue(ComplexFloatSeq *poles, - ComplexFloatSeq *residues); + ConcretePoleResidue(); virtual ~ConcretePoleResidue(); - virtual bool isPoleResidue() const { return true; } - size_t poleResidueCount() const; - void poleResidue(int index, ComplexFloat &pole, ComplexFloat &residue) const; - void setPoleResidue(ComplexFloatSeq *poles, ComplexFloatSeq *residues); - float capacitance() const { return 0.0; } + virtual bool isPoleResidue() const override { return true; } + float capacitance() const override { return 0.0; } + PinSet unannotatedLoads(const Pin *drvr_pin, + const Parasitics *parasitics) const override; + void setPoleResidue(ComplexFloatSeq *poles, + ComplexFloatSeq *residues); + void poleResidue(int index, + ComplexFloat &pole, + ComplexFloat &residue) const; + size_t poleResidueCount() const; using ConcreteParasitic::setPoleResidue; private: @@ -193,240 +169,147 @@ public: ConcretePiPoleResidue(float c2, float rpi, float c1); - virtual ~ConcretePiPoleResidue(); - virtual bool isPiPoleResidue() const { return true; } - virtual bool isPiModel() const { return true; } - virtual float capacitance() const; + virtual bool isPiPoleResidue() const override { return true; } + virtual bool isPiModel() const override { return true; } + virtual float capacitance() const override; virtual void piModel(float &c2, float &rpi, - float &c1) const; + float &c1) const override; virtual void setPiModel(float c2, float rpi, - float c1); - virtual bool isReducedParasiticNetwork() const; - virtual void setIsReduced(bool reduced); - virtual Parasitic *findPoleResidue(const Pin *load_pin) const; + float c1) override; + virtual bool isReducedParasiticNetwork() const override; + virtual void setIsReduced(bool reduced) override; + virtual Parasitic *findPoleResidue(const Pin *load_pin) const override; virtual void setPoleResidue(const Pin *load_pin, ComplexFloatSeq *poles, - ComplexFloatSeq *residues); + ComplexFloatSeq *residues) override; + virtual PinSet unannotatedLoads(const Pin *drvr_pin, + const Parasitics *parasitics) const override; void deleteLoad(const Pin *load_pin); private: - ConcretePoleResidueMap *load_pole_residue_; -}; - -class ConcreteParasiticNode : public ParasiticNode -{ -public: - virtual ~ConcreteParasiticNode() {} - float capacitance() const; - virtual const char *name(const Network *network) const = 0; - virtual bool isPinNode() const { return false; } - ConcreteParasiticDeviceSeq *devices() { return &devices_; } - void incrCapacitance(float cap); - void addDevice(ConcreteParasiticDevice *device); - -protected: - ConcreteParasiticNode(); - - float cap_; - ConcreteParasiticDeviceSeq devices_; - - friend class ConcreteParasiticNetwork; -}; - -class ConcreteParasiticSubNode : public ConcreteParasiticNode -{ -public: - ConcreteParasiticSubNode(const Net *net, - int id); - virtual const char *name(const Network *network) const; - -private: - const Net *net_; - int id_; -}; - -class ConcreteParasiticPinNode : public ConcreteParasiticNode -{ -public: - ConcreteParasiticPinNode(const Pin *pin); - const Pin *pin() const { return pin_; } - virtual bool isPinNode() const { return true; } - virtual const char *name(const Network *network) const; - -private: - const Pin *pin_; -}; - -class ConcreteParasiticDevice : public ParasiticDevice -{ -public: - ConcreteParasiticDevice(const char *name, - ConcreteParasiticNode *node, - float value); - virtual ~ConcreteParasiticDevice(); - virtual bool isResistor() const { return false; } - virtual bool isCouplingCap() const { return false; } - const char *name() const { return name_; } - float value() const { return value_; } - ConcreteParasiticNode *node1() const { return node_; } - virtual ConcreteParasiticNode *node2() const = 0; - virtual ParasiticNode *otherNode(ParasiticNode *node) const = 0; - virtual void replaceNode(ConcreteParasiticNode *from_node, - ConcreteParasiticNode *to_node) = 0; - -protected: - const char *name_; - ConcreteParasiticNode *node_; - float value_; - - friend class ConcreteParasiticNetwork; -}; - -class ConcreteParasiticResistor : public ConcreteParasiticDevice -{ -public: - ConcreteParasiticResistor(const char *name, - ConcreteParasiticNode *node, - ConcreteParasiticNode *other_node, - float res); - virtual bool isResistor() const { return true; } - virtual ConcreteParasiticNode *node2() const { return other_node_; } - virtual ParasiticNode *otherNode(ParasiticNode *node) const; - virtual void replaceNode(ConcreteParasiticNode *from_node, - ConcreteParasiticNode *to_node); - -private: - ConcreteParasiticNode *other_node_; -}; - -// Base class for coupling capacitors. -class ConcreteCouplingCap : public ConcreteParasiticDevice -{ -public: - ConcreteCouplingCap(const char *name, - ConcreteParasiticNode *node, - float cap); - virtual bool isCouplingCap() const { return true; } - virtual ConcreteParasiticNode *node2() const { return nullptr; } - virtual void replaceNode(ConcreteParasiticNode *from_node, - ConcreteParasiticNode *to_node); -}; - -class ConcreteCouplingCapInt : public ConcreteCouplingCap -{ -public: - ConcreteCouplingCapInt(const char *name, - ConcreteParasiticNode *node, - ConcreteParasiticNode *other_node, - float cap); - virtual bool isCouplingCap() const { return true; } - virtual ConcreteParasiticNode *node2() const { return other_node_; } - virtual ParasiticNode *otherNode(ParasiticNode *node) const; - virtual void replaceNode(ConcreteParasiticNode *from_node, - ConcreteParasiticNode *to_node); - -private: - ConcreteParasiticNode *other_node_; -}; - -class ConcreteCouplingCapExtNode : public ConcreteCouplingCap -{ -public: - ConcreteCouplingCapExtNode(const char *name, - ConcreteParasiticNode *node, - Net *other_node_net, - int other_node_id, - float cap); - virtual bool isCouplingCap() const { return true; } - virtual ParasiticNode *otherNode(ParasiticNode *node) const; - virtual void replaceNode(ConcreteParasiticNode *from_node, - ConcreteParasiticNode *to_node); - -private: -}; - -class ConcreteCouplingCapExtPin : public ConcreteCouplingCap -{ -public: - ConcreteCouplingCapExtPin(const char *name, - ConcreteParasiticNode *node, - Pin *other_node_pin, - float cap); - virtual bool isCouplingCap() const { return true; } - virtual ParasiticNode *otherNode(ParasiticNode *node) const; - virtual void replaceNode(ConcreteParasiticNode *from_node, - ConcreteParasiticNode *to_node); - -private: -}; - -class ConcreteParasiticDeviceSetIterator : public ParasiticDeviceIterator -{ -public: - ConcreteParasiticDeviceSetIterator(ConcreteParasiticDeviceSet *devices); - virtual ~ConcreteParasiticDeviceSetIterator(); - bool hasNext() { return iter_.hasNext(); } - ParasiticDevice *next() { return iter_.next(); } - -private: - ConcreteParasiticDeviceSet::ConstIterator iter_; -}; - -class ConcreteParasiticDeviceSeqIterator : public ParasiticDeviceIterator -{ -public: - ConcreteParasiticDeviceSeqIterator(ConcreteParasiticDeviceSeq *devices); - bool hasNext() { return iter_.hasNext(); } - ParasiticDevice *next() { return iter_.next(); } - -private: - ConcreteParasiticDeviceSeq::ConstIterator iter_; -}; - -class ConcreteParasiticNodeSeqIterator : public ParasiticNodeIterator -{ -public: - ConcreteParasiticNodeSeqIterator(ConcreteParasiticNodeSeq *devices); - virtual ~ConcreteParasiticNodeSeqIterator(); - bool hasNext() { return iter_.hasNext(); } - ParasiticNode *next() { return iter_.next(); } - -private: - ConcreteParasiticNodeSeq::ConstIterator iter_; + ConcretePoleResidueMap load_pole_residue_; }; class ConcreteParasiticNetwork : public ParasiticNetwork, public ConcreteParasitic { public: - ConcreteParasiticNetwork(bool includes_pin_caps); + ConcreteParasiticNetwork(const Net *net, + bool includes_pin_caps); virtual ~ConcreteParasiticNetwork(); virtual bool isParasiticNetwork() const { return true; } + const Net *net() { return net_; } bool includesPinCaps() const { return includes_pin_caps_; } ConcreteParasiticNode *ensureParasiticNode(const Net *net, - int id); + int id, + const Network *network); + ConcreteParasiticNode *ensureParasiticNode(const Pin *pin, + const Network *network); ConcreteParasiticNode *findNode(const Pin *pin) const; - ConcreteParasiticNode *ensureParasiticNode(const Pin *pin); virtual float capacitance() const; - ConcreteParasiticPinNodeMap *pinNodes() { return &pin_nodes_; } - ConcreteParasiticSubNodeMap *subNodes() { return &sub_nodes_; } + ParasiticNodeSeq nodes() const; void disconnectPin(const Pin *pin, - const Net *net); - virtual ParasiticDeviceIterator *deviceIterator() const; - virtual ParasiticNodeIterator *nodeIterator() const; - virtual void devices(// Return value. - ConcreteParasiticDeviceSet *devices) const; + const Net *net, + const Network *network); + ParasiticResistorSeq resistors() const { return resistors_; } + void addResistor(ParasiticResistor *resistor); + ParasiticCapacitorSeq capacitors() const { return capacitors_; } + void addCapacitor(ParasiticCapacitor *capacitor); + virtual PinSet unannotatedLoads(const Pin *drvr_pin, + const Parasitics *parasitics) const; private: + void unannotatedLoads(ParasiticNode *node, + ParasiticResistor *from_res, + PinSet &loads, + ParasiticNodeSet &visited_nodes, + ParasiticResistorSet &loop_resistors, + ParasiticNodeResistorMap &resistor_map, + const Parasitics *parasitics) const; + void deleteNodes(); void deleteDevices(); + const Net *net_; ConcreteParasiticSubNodeMap sub_nodes_; ConcreteParasiticPinNodeMap pin_nodes_; + ParasiticResistorSeq resistors_; + ParasiticCapacitorSeq capacitors_; unsigned max_node_id_:31; bool includes_pin_caps_:1; }; +class ConcreteParasiticNode : public ParasiticNode +{ +public: + ConcreteParasiticNode(const Net *net, + int id, + bool is_external); + ConcreteParasiticNode(const Pin *pin, + bool is_external); + float capacitance() const { return cap_; } + const char *name(const Network *network) const; + const Net *net(const Network *network) const; + bool isExternal() const { return is_external_; } + const Pin *pin() const; + void incrCapacitance(float cap); + +protected: + ConcreteParasiticNode(); + + union { + const Net *net_; + const Pin *pin_; + } net_pin_; + bool is_net_:1; + bool is_external_:1; + unsigned id_:30; + float cap_; + + friend class ConcreteParasiticNetwork; +}; + +class ConcreteParasiticDevice +{ +public: + ConcreteParasiticDevice(size_t id, + float value, + ConcreteParasiticNode *node1, + ConcreteParasiticNode *node2); + int id() const { return id_; } + float value() const { return value_; } + ConcreteParasiticNode *node1() const { return node1_; } + ConcreteParasiticNode *node2() const { return node2_; } + void replaceNode(ConcreteParasiticNode *from_node, + ConcreteParasiticNode *to_node); + +protected: + size_t id_; + float value_; + ConcreteParasiticNode *node1_; + ConcreteParasiticNode *node2_; +}; + +class ConcreteParasiticResistor : public ParasiticResistor, + public ConcreteParasiticDevice +{ +public: + ConcreteParasiticResistor(size_t id, + float value, + ConcreteParasiticNode *node1, + ConcreteParasiticNode *node2); +}; + +class ConcreteParasiticCapacitor : public ParasiticCapacitor, + public ConcreteParasiticDevice +{ +public: + ConcreteParasiticCapacitor(size_t id, + float value, + ConcreteParasiticNode *node1, + ConcreteParasiticNode *node2); +}; + } // namespace diff --git a/parasitics/EstimateParasitics.cc b/parasitics/EstimateParasitics.cc index e14eaa2a..fa6d0cbc 100644 --- a/parasitics/EstimateParasitics.cc +++ b/parasitics/EstimateParasitics.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -24,6 +24,11 @@ namespace sta { +EstimateParasitics::EstimateParasitics(StaState *sta) : + StaState(sta) +{ +} + // For multiple driver nets, output pin capacitances are treated as // loads when driven by a different pin. void @@ -32,10 +37,8 @@ EstimateParasitics::estimatePiElmore(const Pin *drvr_pin, const Wireload *wireload, float fanout, float net_pin_cap, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, - const StaState *sta, float &c2, float &rpi, float &c1, @@ -43,6 +46,7 @@ EstimateParasitics::estimatePiElmore(const Pin *drvr_pin, float &elmore_cap, bool &elmore_use_load_cap) { + const OperatingConditions *op_cond = sdc_->operatingConditions(min_max); float wireload_cap, wireload_res; wireload->findWireload(fanout, op_cond, wireload_cap, wireload_res); @@ -52,22 +56,20 @@ EstimateParasitics::estimatePiElmore(const Pin *drvr_pin, switch (tree) { case WireloadTree::worst_case: estimatePiElmoreWorst(drvr_pin, wireload_cap, wireload_res, - fanout, net_pin_cap, rf, op_cond, corner, - min_max, sta, + fanout, net_pin_cap, rf, corner, min_max, c2, rpi, c1, elmore_res, elmore_cap, elmore_use_load_cap); break; case WireloadTree::balanced: case WireloadTree::unknown: estimatePiElmoreBalanced(drvr_pin, wireload_cap, wireload_res, - fanout, net_pin_cap, rf, op_cond, - corner, min_max,sta, + fanout, net_pin_cap, rf, corner, min_max, c2, rpi, c1, elmore_res, elmore_cap, elmore_use_load_cap); break; case WireloadTree::best_case: - estimatePiElmoreBest(drvr_pin, wireload_cap, net_pin_cap, rf, - op_cond, corner, min_max, + estimatePiElmoreBest(drvr_pin, wireload_cap, net_pin_cap, + rf, corner, min_max, c2, rpi, c1, elmore_res, elmore_cap, elmore_use_load_cap); break; @@ -80,7 +82,6 @@ EstimateParasitics::estimatePiElmoreBest(const Pin *, float wireload_cap, float net_pin_cap, const RiseFall *, - const OperatingConditions *, const Corner *, const MinMax *, float &c2, @@ -107,10 +108,8 @@ EstimateParasitics::estimatePiElmoreWorst(const Pin *drvr_pin, float, float net_pin_cap, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, - const StaState *sta, float &c2, float &rpi, float &c1, @@ -118,9 +117,8 @@ EstimateParasitics::estimatePiElmoreWorst(const Pin *drvr_pin, float &elmore_cap, bool &elmore_use_load_cap) { - Sdc *sdc = sta->sdc(); float drvr_pin_cap = 0.0; - drvr_pin_cap = sdc->pinCapacitance(drvr_pin, rf, op_cond, corner, min_max); + drvr_pin_cap = sdc_->pinCapacitance(drvr_pin, rf, corner, min_max); c2 = drvr_pin_cap; rpi = wireload_res; c1 = net_pin_cap - drvr_pin_cap + wireload_cap; @@ -139,10 +137,8 @@ EstimateParasitics::estimatePiElmoreBalanced(const Pin *drvr_pin, float fanout, float net_pin_cap, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, - const StaState *sta, float &c2, float &rpi, float &c1, @@ -161,31 +157,27 @@ EstimateParasitics::estimatePiElmoreBalanced(const Pin *drvr_pin, elmore_use_load_cap = false; } else { - Sdc *sdc = sta->sdc(); - Network *network = sta->network(); - Report *report = sta->report(); double res_fanout = wireload_res / fanout; double cap_fanout = wireload_cap / fanout; // Find admittance moments. double y1 = 0.0; double y2 = 0.0; double y3 = 0.0; - y1 = sdc->pinCapacitance(drvr_pin, rf, op_cond, corner, min_max); + y1 = sdc_->pinCapacitance(drvr_pin, rf, corner, min_max); PinConnectedPinIterator *load_iter = - network->connectedPinIterator(drvr_pin); + network_->connectedPinIterator(drvr_pin); while (load_iter->hasNext()) { const Pin *load_pin = load_iter->next(); // Bidirects don't count themselves as loads. - if (load_pin != drvr_pin && network->isLoad(load_pin)) { - Port *port = network->port(load_pin); + 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, op_cond, - corner, min_max); - else if (network->isTopLevelPort(load_pin)) - load_cap = sdc->portExtCap(port, rf, corner, min_max); + 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(597, "load pin not leaf or top level"); + report_->critical(1050, "load pin not leaf or top level"); double cap = load_cap + cap_fanout; double y2_ = res_fanout * cap * cap; y1 += cap; diff --git a/parasitics/EstimateParasitics.hh b/parasitics/EstimateParasitics.hh index aab65039..48cc6aee 100644 --- a/parasitics/EstimateParasitics.hh +++ b/parasitics/EstimateParasitics.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -16,6 +16,7 @@ #pragma once +#include "StaState.hh" #include "LibertyClass.hh" #include "NetworkClass.hh" #include "SdcClass.hh" @@ -26,21 +27,18 @@ namespace sta { class Corner; class StaState; -class EstimateParasitics +class EstimateParasitics : public StaState { public: - -protected: + EstimateParasitics(StaState *sta); // Helper function for wireload estimation. void estimatePiElmore(const Pin *drvr_pin, const RiseFall *rf, const Wireload *wireload, float fanout, float net_pin_cap, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, - const StaState *sta, // Return values. float &c2, float &rpi, @@ -48,11 +46,12 @@ protected: float &elmore_res, float &elmore_cap, bool &elmore_use_load_cap); + +protected: void estimatePiElmoreBest(const Pin *drvr_pin, float net_pin_cap, float wireload_cap, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, // Return values. @@ -68,10 +67,8 @@ protected: float fanout, float net_pin_cap, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, - const StaState *sta, // Return values. float &c2, float &rpi, float &c1, float &elmore_res, float &elmore_cap, @@ -82,10 +79,8 @@ protected: float fanout, float net_pin_cap, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, - const StaState *sta, // Return values. float &c2, float &rpi, float &c1, float &elmore_res, float &elmore_cap, diff --git a/parasitics/NullParasitics.cc b/parasitics/NullParasitics.cc deleted file mode 100644 index 351bea3b..00000000 --- a/parasitics/NullParasitics.cc +++ /dev/null @@ -1,467 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, 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 "NullParasitics.hh" - -namespace sta { - -NullParasitics::NullParasitics(StaState *sta) : - Parasitics(sta) -{ -} - -bool -NullParasitics::haveParasitics() -{ - return false; -} - -void -NullParasitics::clear() -{ -} - -void -NullParasitics::save() -{ -} - -void -NullParasitics::deleteParasitics() -{ -} - -void -NullParasitics::deleteParasitics(const Net *, - const ParasiticAnalysisPt *) -{ -} - -void -NullParasitics::deleteParasitics(const Pin *, const ParasiticAnalysisPt *) -{ -} - -void -NullParasitics::deleteUnsavedParasitic(Parasitic *) -{ -} - -void -NullParasitics::deleteReducedParasitics(const Net *, - const ParasiticAnalysisPt *) -{ -} - -void -NullParasitics::deleteDrvrReducedParasitics(const Pin *) -{ -} - -float -NullParasitics::capacitance(const Parasitic *) const -{ - return 0.0; -} - -Parasitic * -NullParasitics::findPiElmore(const Pin *, - const RiseFall *, - const ParasiticAnalysisPt *) const -{ - return nullptr; -} - -Parasitic * -NullParasitics::makePiElmore(const Pin *, - const RiseFall *, - const ParasiticAnalysisPt *, - float, - float, - float) -{ - return nullptr; -} - -bool -NullParasitics::isPiElmore(const Parasitic *) const -{ - return false; -} - -bool -NullParasitics::isReducedParasiticNetwork(const Parasitic *) const -{ - return false; -} - -void -NullParasitics::setIsReducedParasiticNetwork(Parasitic *, - bool) -{ -} - -void -NullParasitics::piModel(const Parasitic *, - float &, - float &, - float &) const -{ -} - -void -NullParasitics::setPiModel(Parasitic *, - float, - float, - float) -{ -} - -void -NullParasitics::findElmore(const Parasitic *, - const Pin *, - float &, - bool &) const -{ -} - -void -NullParasitics::setElmore(Parasitic *, - const Pin *, - float) -{ -} - -bool -NullParasitics::isPiModel(const Parasitic*) const -{ - return false; -} - -bool -NullParasitics::isPiPoleResidue(const Parasitic* ) const -{ - return false; -} - -Parasitic * -NullParasitics::findPiPoleResidue(const Pin *, - const RiseFall *, - const ParasiticAnalysisPt *) const -{ - return nullptr; -} - -Parasitic * -NullParasitics::makePiPoleResidue(const Pin *, - const RiseFall *, - const ParasiticAnalysisPt *, - float, - float, - float) -{ - return nullptr; -} - -Parasitic * -NullParasitics::findPoleResidue(const Parasitic *, - const Pin *) const -{ - return nullptr; -} - -void -NullParasitics::setPoleResidue(Parasitic *, - const Pin *, - ComplexFloatSeq *, - ComplexFloatSeq *) -{ -} - -bool -NullParasitics::isPoleResidue(const Parasitic *) const -{ - return false; -} - -size_t -NullParasitics::poleResidueCount(const Parasitic *) const -{ - return 0; -} - -void -NullParasitics::poleResidue(const Parasitic *, - int, - ComplexFloat &, - ComplexFloat &) const -{ -} - -bool -NullParasitics::isParasiticNetwork(const Parasitic *) const -{ - return false; -} - -Parasitic * -NullParasitics::findParasiticNetwork(const Net *, - const ParasiticAnalysisPt *) const -{ - return nullptr; -} - -Parasitic * -NullParasitics::findParasiticNetwork(const Pin *, - const ParasiticAnalysisPt *) const -{ - return nullptr; -} - -Parasitic * -NullParasitics::makeParasiticNetwork(const Net *, - bool, - const ParasiticAnalysisPt *) -{ - return nullptr; -} - -bool -NullParasitics::includesPinCaps(const Parasitic *) const -{ - return false; -} - -void -NullParasitics::deleteParasiticNetwork(const Net *, - const ParasiticAnalysisPt *) -{ -} - -void -NullParasitics::deleteParasiticNetworks(const Net *) -{ -} - -ParasiticNode * -NullParasitics::ensureParasiticNode(Parasitic *, - const Net *, - int) -{ - return nullptr; -} - -ParasiticNode * -NullParasitics::ensureParasiticNode(Parasitic *, - const Pin *) -{ - return nullptr; -} - -void -NullParasitics::incrCap(ParasiticNode *, - float, - const ParasiticAnalysisPt *) -{ -} - -void -NullParasitics::makeCouplingCap(const char *, - ParasiticNode *, - ParasiticNode *, - float, - const ParasiticAnalysisPt *) -{ -} - -void NullParasitics::makeCouplingCap(const char *, - ParasiticNode *, - Net *, - int, - float, - const ParasiticAnalysisPt *) -{ -} - -void -NullParasitics::makeCouplingCap(const char *, - ParasiticNode *, - Pin *, - float, - const ParasiticAnalysisPt *) -{ -} - -void -NullParasitics::makeResistor(const char *, - ParasiticNode *, - ParasiticNode *, - float, - const ParasiticAnalysisPt *) -{ -} - -const char * -NullParasitics::name(const ParasiticNode *) -{ - return nullptr; -} - -const Pin * -NullParasitics::connectionPin(const ParasiticNode *) const -{ - return nullptr; -} - -ParasiticNode * -NullParasitics::findNode(const Parasitic *, - const Pin *) const -{ - return nullptr; -} - -float -NullParasitics::nodeGndCap(const ParasiticNode *, - const ParasiticAnalysisPt *) const -{ - return 0.0; -} - -ParasiticDeviceIterator * -NullParasitics::deviceIterator(ParasiticNode *) const -{ - return 0; -} - -bool -NullParasitics::isResistor(const ParasiticDevice *) const -{ - return false; -} - -bool -NullParasitics::isCouplingCap(const ParasiticDevice *) const -{ - return false; -} - -const char * -NullParasitics::name(const ParasiticDevice *) const -{ - return nullptr; -} - -float -NullParasitics::value(const ParasiticDevice *, - const ParasiticAnalysisPt *) const -{ - return 0.0; -} - -ParasiticNode * -NullParasitics::node1(const ParasiticDevice *) const -{ - return nullptr; -} - -ParasiticNode * -NullParasitics::node2(const ParasiticDevice *) const -{ - return nullptr; -} - -ParasiticNode * -NullParasitics::otherNode(const ParasiticDevice *, - ParasiticNode *) const -{ - return nullptr; -} - -void -NullParasitics::reduceTo(const Parasitic *, - const Net *, - ReducedParasiticType , - const OperatingConditions *, - const Corner *, - const MinMax *, - const ParasiticAnalysisPt *) -{ -} - -void -NullParasitics::reduceToPiElmore(const Parasitic *, - const Net *, - const OperatingConditions *, - const Corner *, - const MinMax *, - const ParasiticAnalysisPt *) -{ -} - -void -NullParasitics::reduceToPiElmore(const Parasitic *, - const Pin *, - const OperatingConditions *, - const Corner *, - const MinMax *, - const ParasiticAnalysisPt *) -{ -} - -void -NullParasitics::reduceToPiPoleResidue2(const Parasitic *, const Net *, - const OperatingConditions *, - const Corner *, - const MinMax *, - const ParasiticAnalysisPt *) -{ -} - -void -NullParasitics::reduceToPiPoleResidue2(const Parasitic *, - const Pin *, - const OperatingConditions *, - const Corner *, - const MinMax *, - const ParasiticAnalysisPt *) -{ -} - -Parasitic * -NullParasitics::estimatePiElmore(const Pin *, - const RiseFall *, - const Wireload *, - float, - float, - const OperatingConditions *, - const Corner *, - const MinMax *, - const ParasiticAnalysisPt *) -{ - return nullptr; -} - -void -NullParasitics::disconnectPinBefore(const Pin *) -{ -} - -void -NullParasitics::loadPinCapacitanceChanged(const Pin *) -{ -} - -} // namespace diff --git a/parasitics/Parasitics.cc b/parasitics/Parasitics.cc index 8f40b07b..605ab87e 100644 --- a/parasitics/Parasitics.cc +++ b/parasitics/Parasitics.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -23,7 +23,9 @@ #include "Network.hh" #include "PortDirection.hh" #include "Sdc.hh" +#include "Corner.hh" #include "ReduceParasitics.hh" +#include "EstimateParasitics.hh" namespace sta { @@ -51,28 +53,138 @@ Parasitics::findParasiticNet(const Pin *pin) const return nullptr; } -void -Parasitics::check(Parasitic *) const +PinSet +Parasitics::loads(const Pin *drvr_pin) const { -#if 0 - ConcreteParasiticSubNodeMap::Iterator sub_node_iter(sub_nodes_); - while (sub_node_iter.hasNext()) { - ConcreteParasiticSubNode *node = sub_node_iter.next(); - ConcreteParasiticDeviceSeq::Iterator device_iter(node->devices()); - int res_count = 0; - while (device_iter.hasNext()) { - ConcreteParasiticDevice *device = device_iter.next(); - if (device->isResistor()) - res_count++; - } - if (res_count == 0) - report->warn("sub node %s has no resistor connections", - node->name(network)); - else if (res_count == 1) - report->warn("sub node %s has one resistor connection", - node->name(network)); + PinSet loads(network_); + NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(drvr_pin); + while (pin_iter->hasNext()) { + const Pin *pin = pin_iter->next(); + if (network_->isLoad(pin) && !network_->isHierarchical(pin)) + loads.insert(pin); } -#endif + delete pin_iter; + return loads; +} + +ParasiticNodeResistorMap +Parasitics::parasiticNodeResistorMap(const Parasitic *parasitic) const +{ + ParasiticNodeResistorMap resistor_map; + for (ParasiticResistor *resistor : resistors(parasitic)) { + ParasiticNode *n1 = node1(resistor); + ParasiticNode *n2 = node2(resistor); + resistor_map[n1].push_back(resistor); + resistor_map[n2].push_back(resistor); + } + return resistor_map; +} + +ParasiticNodeCapacitorMap +Parasitics::parasiticNodeCapacitorMap(const Parasitic *parasitic) const +{ + ParasiticNodeCapacitorMap capacitor_map; + for (ParasiticCapacitor *capacitor : capacitors(parasitic)) { + ParasiticNode *n1 = node1(capacitor); + ParasiticNode *n2 = node2(capacitor); + capacitor_map[n1].push_back(capacitor); + capacitor_map[n2].push_back(capacitor); + } + return capacitor_map; +} + +ParasiticNode * +Parasitics::otherNode(const ParasiticResistor *resistor, + ParasiticNode *node) const +{ + ParasiticNode *n1 = node1(resistor); + if (node == n1) + return node2(resistor); + else if (node == node2(resistor)) + return n1; + else + return nullptr; +} + +ParasiticNode * +Parasitics::otherNode(const ParasiticCapacitor *capacitor, + ParasiticNode *node) const +{ + ParasiticNode *n1 = node1(capacitor); + if (node == n1) + return node2(capacitor); + else if (node == node2(capacitor)) + return n1; + else + return nullptr; +} + +//////////////////////////////////////////////////////////////// + +Parasitic * +Parasitics::reduceToPiElmore(const Parasitic *parasitic, + const Pin *drvr_pin, + const RiseFall *rf, + const Corner *corner, + const MinMax *cnst_min_max, + const ParasiticAnalysisPt *ap) +{ + return sta::reduceToPiElmore(parasitic, drvr_pin, rf, ap->couplingCapFactor(), + corner, cnst_min_max, ap, this); +} + +Parasitic * +Parasitics::reduceToPiPoleResidue2(const Parasitic *parasitic, + const Pin *drvr_pin, + const RiseFall *rf, + const Corner *corner, + const MinMax *cnst_min_max, + const ParasiticAnalysisPt *ap) +{ + return sta::reduceToPiPoleResidue2(parasitic, drvr_pin, rf, + ap->couplingCapFactor(), + corner, cnst_min_max, + ap, this); +} + +//////////////////////////////////////////////////////////////// + +Parasitic * +Parasitics::estimatePiElmore(const Pin *drvr_pin, + const RiseFall *rf, + const Wireload *wireload, + float fanout, + float net_pin_cap, + const Corner *corner, + const MinMax *min_max) +{ + EstimateParasitics estimate(this); + float c2, rpi, c1, elmore_res, elmore_cap; + bool elmore_use_load_cap; + estimate.estimatePiElmore(drvr_pin, rf, wireload, fanout, net_pin_cap, + corner, min_max, + c2, rpi, c1, + elmore_res, elmore_cap, elmore_use_load_cap); + + if (c1 > 0.0 || c2 > 0.0) { + ParasiticAnalysisPt *ap = corner->findParasiticAnalysisPt(min_max); + Parasitic *parasitic = makePiElmore(drvr_pin, rf, ap, c2, rpi, c1); + NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(drvr_pin); + while (pin_iter->hasNext()) { + const Pin *pin = pin_iter->next(); + if (network_->isLoad(pin)) { + float load_cap = 0.0; + if (elmore_use_load_cap) + load_cap = sdc_->pinCapacitance(pin, rf, corner, min_max); + float elmore = elmore_res * (elmore_cap + load_cap); + setElmore(parasitic, pin, elmore); + } + } + delete pin_iter; + return parasitic; + } + else + return nullptr; } //////////////////////////////////////////////////////////////// @@ -81,11 +193,12 @@ Parasitic * Parasitics::makeWireloadNetwork(const Pin *drvr_pin, const Wireload *wireload, float fanout, - const OperatingConditions *op_cond, + const MinMax *min_max, const ParasiticAnalysisPt *ap) { Net *net = network_->net(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); @@ -95,16 +208,16 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin, switch (tree) { case WireloadTree::worst_case: makeWireloadNetworkWorst(parasitic, drvr_pin, wireload_cap, - wireload_res, fanout, ap); + wireload_res, fanout); break; case WireloadTree::balanced: makeWireloadNetworkBalanced(parasitic, drvr_pin, wireload_cap, - wireload_res, fanout, ap); + wireload_res, fanout); break; case WireloadTree::best_case: case WireloadTree::unknown: makeWireloadNetworkBest(parasitic, drvr_pin, wireload_cap, - wireload_res, fanout, ap); + wireload_res, fanout); break; } return parasitic; @@ -117,22 +230,22 @@ Parasitics::makeWireloadNetworkWorst(Parasitic *parasitic, const Pin *drvr_pin, float wireload_cap, float wireload_res, - float /* fanout */, - const ParasiticAnalysisPt *ap) + float /* fanout */) { - ParasiticNode *drvr_node = ensureParasiticNode(parasitic, drvr_pin); + ParasiticNode *drvr_node = ensureParasiticNode(parasitic, drvr_pin, network_); Net *net = network_->net(drvr_pin); - ParasiticNode *load_node = ensureParasiticNode(parasitic, net, 0); - makeResistor(nullptr, drvr_node, load_node, wireload_res, ap); - parasitics_->incrCap(load_node, wireload_cap, ap); + size_t resistor_index = 1; + ParasiticNode *load_node = ensureParasiticNode(parasitic, net, 0, network_); + makeResistor(parasitic, resistor_index++, wireload_res, drvr_node, load_node); + parasitics_->incrCap(load_node, wireload_cap); PinConnectedPinIterator *load_iter = network_->connectedPinIterator(drvr_pin); while (load_iter->hasNext()) { const Pin *load_pin = load_iter->next(); if (load_pin != drvr_pin && network_->isLoad(load_pin)) { - ParasiticNode *load_node1 = ensureParasiticNode(parasitic, load_pin); - makeResistor(nullptr, load_node, load_node1, 0.0, ap); + ParasiticNode *load_node1 = ensureParasiticNode(parasitic, load_pin, network_); + makeResistor(parasitic, resistor_index++, 0.0, load_node, load_node1); } } } @@ -143,19 +256,19 @@ Parasitics::makeWireloadNetworkBest(Parasitic *parasitic, const Pin *drvr_pin, float wireload_cap, float /* wireload_res */, - float /* fanout */, - const ParasiticAnalysisPt *ap) + float /* fanout */) { - ParasiticNode *drvr_node = ensureParasiticNode(parasitic, drvr_pin); - parasitics_->incrCap(drvr_node, wireload_cap, ap); + ParasiticNode *drvr_node = ensureParasiticNode(parasitic, drvr_pin, network_); + parasitics_->incrCap(drvr_node, wireload_cap); PinConnectedPinIterator *load_iter = network_->connectedPinIterator(drvr_pin); + size_t resistor_index = 1; while (load_iter->hasNext()) { const Pin *load_pin = load_iter->next(); if (load_pin != drvr_pin && network_->isLoad(load_pin)) { - ParasiticNode *load_node1 = ensureParasiticNode(parasitic, load_pin); - makeResistor(nullptr, drvr_node, load_node1, 0.0, ap); + ParasiticNode *load_node1 = ensureParasiticNode(parasitic, load_pin, network_); + makeResistor(parasitic, resistor_index++, 0.0, drvr_node, load_node1); } } } @@ -167,21 +280,21 @@ Parasitics::makeWireloadNetworkBalanced(Parasitic *parasitic, const Pin *drvr_pin, float wireload_cap, float wireload_res, - float fanout, - const ParasiticAnalysisPt *ap) + float fanout) { float fanout_cap = wireload_cap / fanout; float fanout_res = wireload_res / fanout; - ParasiticNode *drvr_node = ensureParasiticNode(parasitic, drvr_pin); + ParasiticNode *drvr_node = ensureParasiticNode(parasitic, drvr_pin, network_); PinConnectedPinIterator *load_iter = network_->connectedPinIterator(drvr_pin); + size_t resistor_index = 1; while (load_iter->hasNext()) { const Pin *load_pin = load_iter->next(); if (load_pin != drvr_pin && network_->isLoad(load_pin)) { - ParasiticNode *load_node1 = ensureParasiticNode(parasitic, load_pin); - makeResistor(nullptr, drvr_node, load_node1, fanout_res, ap); - parasitics_->incrCap(load_node1, fanout_cap, ap); + ParasiticNode *load_node1 = ensureParasiticNode(parasitic, load_pin, network_); + makeResistor(parasitic, resistor_index++, fanout_res, drvr_node, load_node1); + parasitics_->incrCap(load_node1, fanout_cap); } } } @@ -190,19 +303,14 @@ Parasitics::makeWireloadNetworkBalanced(Parasitic *parasitic, ParasiticAnalysisPt::ParasiticAnalysisPt(const char *name, int index, - const MinMax *min_max) : - name_(stringCopy(name)), + int index_max) : + name_(name), index_(index), - min_max_(min_max), + index_max_(index_max), coupling_cap_factor_(1.0) { } -ParasiticAnalysisPt::~ParasiticAnalysisPt() -{ - stringDelete(name_); -} - void ParasiticAnalysisPt::setCouplingCapFactor(float factor) { diff --git a/parasitics/Parasitics.i b/parasitics/Parasitics.i index b183dbd1..64d33e51 100644 --- a/parasitics/Parasitics.i +++ b/parasitics/Parasitics.i @@ -3,7 +3,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -24,7 +24,6 @@ using sta::Sta; using sta::cmdLinkedNetwork; using sta::Instance; using sta::MinMaxAll; -using sta::ReducedParasiticType; using sta::RiseFall; using sta::Pin; @@ -40,15 +39,12 @@ read_spef_cmd(const char *filename, bool pin_cap_included, bool keep_coupling_caps, float coupling_cap_factor, - ReducedParasiticType reduce_to, - bool delete_after_reduce, - bool quiet) + bool reduce) { cmdLinkedNetwork(); return Sta::sta()->readSpef(filename, instance, corner, min_max, pin_cap_included, keep_coupling_caps, - coupling_cap_factor, reduce_to, - delete_after_reduce, quiet); + coupling_cap_factor, reduce); } void diff --git a/parasitics/Parasitics.tcl b/parasitics/Parasitics.tcl index 8e569ad3..e648c622 100644 --- a/parasitics/Parasitics.tcl +++ b/parasitics/Parasitics.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -26,23 +26,36 @@ define_cmd_args "read_spef" \ [-coupling_reduction_factor factor]\ [-reduce_to pi_elmore|pi_pole_residue2]\ [-delete_after_reduce]\ - [-quiet]\ - [-save]\ filename} proc_redirect read_spef { parse_key_args "read_spef" args \ keys {-path -coupling_reduction_factor -reduce_to -corner} \ flags {-min -max -increment -pin_cap_included -keep_capacitive_coupling \ - -delete_after_reduce -quiet -save} - check_argc_eq1 "report_spef" $args + -reduce -delete_after_reduce -quiet -save} + check_argc_eq1 "read_spef" $args + + set reduce [info exists flags(-reduce)] + if { [info exists flags(-quiet)] } { + sta_warn 272 "read_spef -quiet is deprecated." + } + if { [info exists keys(-reduce_to)] } { + sta_warn 273 "read_spef -reduce_to is deprecated. Use -reduce instead." + set reduce 1 + } + if { [info exists flags(-delete_after_reduce)] } { + sta_warn 274 "read_spef -delete_after_reduce is deprecated." + } + if { [info exists flags(-save)] } { + sta_warn 275 "read_spef -save is deprecated." + } set instance [top_instance] if [info exists keys(-path)] { set path $keys(-path) set instance [find_instance $path] if { $instance == "NULL" } { - sta_error 433 "path instance '$path' not found." + sta_error 276 "path instance '$path' not found." } } set corner [parse_corner_or_all keys] @@ -55,23 +68,10 @@ proc_redirect read_spef { set keep_coupling_caps [info exists flags(-keep_capacitive_coupling)] set pin_cap_included [info exists flags(-pin_cap_included)] - set reduce_to "none" - if [info exists keys(-reduce_to)] { - set reduce_to $keys(-reduce_to) - if { !($reduce_to == "pi_elmore" || $reduce_to == "pi_pole_residue2") } { - sta_error 434 "-reduce_to must be pi_elmore or pi_pole_residue2." - } - } - set delete_after_reduce [info exists flags(-delete_after_reduce)] - set quiet [info exists flags(-quiet)] - set save [info exists flags(-save)] set filename [file nativename [lindex $args 0]] - if { [info exists flags(-increment)] } { - sta_warn 706 "read_spef -increment is deprecated." - } return [read_spef_cmd $filename $instance $corner $min_max \ - $pin_cap_included $keep_coupling_caps $coupling_reduction_factor \ - $reduce_to $delete_after_reduce $quiet] + $pin_cap_included $keep_coupling_caps \ + $coupling_reduction_factor $reduce] } define_cmd_args "report_parasitic_annotation" {-report_unannotated} diff --git a/parasitics/ReduceParasitics.cc b/parasitics/ReduceParasitics.cc index be1b3093..f6a692d1 100644 --- a/parasitics/ReduceParasitics.cc +++ b/parasitics/ReduceParasitics.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -30,22 +30,21 @@ namespace sta { using std::max; typedef Map ParasiticNodeValueMap; -typedef Map ParasiticDeviceValueMap; -typedef Set ParasiticDeviceSet; +typedef Map ResistorCurrentMap; +typedef Set ParasiticResistorSet; typedef Set ParasiticNodeSet; class ReduceToPi : public StaState { public: ReduceToPi(StaState *sta); - void reduceToPi(const Pin *drvr_pin, + void reduceToPi(const Parasitic *parasitic_network, + const Pin *drvr_pin, ParasiticNode *drvr_node, - bool includes_pin_caps, float coupling_cap_factor, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, - const MinMax *cnst_min_max, + const MinMax *min_max, const ParasiticAnalysisPt *ap, float &c2, float &rpi, @@ -55,8 +54,7 @@ public: protected: void reducePiDfs(const Pin *drvr_pin, ParasiticNode *node, - ParasiticDevice *from_res, - const ParasiticAnalysisPt *ap, + ParasiticResistor *from_res, double src_resistance, double &y1, double &y2, @@ -70,18 +68,21 @@ protected: float cap); float downstreamCap(ParasiticNode *node); float pinCapacitance(ParasiticNode *node); - bool isLoopResistor(ParasiticDevice *device); - void markLoopResistor(ParasiticDevice *device); + bool isLoopResistor(ParasiticResistor *resistor); + void markLoopResistor(ParasiticResistor *resistor); bool includes_pin_caps_; float coupling_cap_multiplier_; const RiseFall *rf_; - const OperatingConditions *op_cond_; const Corner *corner_; - const MinMax *cnst_min_max_; + const MinMax *min_max_; + const ParasiticAnalysisPt *ap_; + ParasiticNodeResistorMap resistor_map_; + ParasiticNodeCapacitorMap capacitor_map_; + ParasiticNodeSet visited_nodes_; ParasiticNodeValueMap node_values_; - ParasiticDeviceSet loop_resistors_; + ParasiticResistorSet loop_resistors_; bool pin_caps_one_value_; }; @@ -89,9 +90,8 @@ ReduceToPi::ReduceToPi(StaState *sta) : StaState(sta), coupling_cap_multiplier_(1.0), rf_(nullptr), - op_cond_(nullptr), corner_(nullptr), - cnst_min_max_(nullptr), + min_max_(nullptr), pin_caps_one_value_(true) { } @@ -101,29 +101,30 @@ ReduceToPi::ReduceToPi(StaState *sta) : // Thomas Savarino, Proceedings of the 1989 Design Automation // Conference. void -ReduceToPi::reduceToPi(const Pin *drvr_pin, +ReduceToPi::reduceToPi(const Parasitic *parasitic_network, + const Pin *drvr_pin, ParasiticNode *drvr_node, - bool includes_pin_caps, float coupling_cap_factor, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, - const MinMax *cnst_min_max, + const MinMax *min_max, const ParasiticAnalysisPt *ap, float &c2, float &rpi, float &c1) { - includes_pin_caps_ = includes_pin_caps; + includes_pin_caps_ = parasitics_->includesPinCaps(parasitic_network), coupling_cap_multiplier_ = coupling_cap_factor; rf_ = rf; - op_cond_ = op_cond; corner_ = corner; - cnst_min_max_ = cnst_min_max; + min_max_ = min_max; + ap_ = ap; + resistor_map_ = parasitics_->parasiticNodeResistorMap(parasitic_network); + capacitor_map_ = parasitics_->parasiticNodeCapacitorMap(parasitic_network); double y1, y2, y3, dcap; double max_resistance = 0.0; - reducePiDfs(drvr_pin, drvr_node, nullptr, ap, 0.0, + reducePiDfs(drvr_pin, drvr_node, nullptr, 0.0, y1, y2, y3, dcap, max_resistance); if (y2 == 0.0 && y3 == 0.0) { @@ -146,8 +147,7 @@ ReduceToPi::reduceToPi(const Pin *drvr_pin, void ReduceToPi::reducePiDfs(const Pin *drvr_pin, ParasiticNode *node, - ParasiticDevice *from_res, - const ParasiticAnalysisPt *ap, + ParasiticResistor *from_res, double src_resistance, double &y1, double &y2, @@ -155,78 +155,78 @@ ReduceToPi::reducePiDfs(const Pin *drvr_pin, double &dwn_cap, double &max_resistance) { - double coupling_cap = 0.0; - ParasiticDeviceIterator *device_iter1 = parasitics_->deviceIterator(node); - while (device_iter1->hasNext()) { - ParasiticDevice *device = device_iter1->next(); - if (parasitics_->isCouplingCap(device)) - coupling_cap += parasitics_->value(device, ap); + if (parasitics_->isExternal(node)) { + y1 = y2 = y3 = 0.0; + max_resistance = 0.0; + dwn_cap = 0.0; } - delete device_iter1; + else { + double coupling_cap = 0.0; + ParasiticCapacitorSeq &capacitors = capacitor_map_[node]; + for (ParasiticCapacitor *capacitor : capacitors) + coupling_cap += parasitics_->value(capacitor); - y1 = dwn_cap = parasitics_->nodeGndCap(node, ap) - + coupling_cap * coupling_cap_multiplier_ - + pinCapacitance(node); - y2 = y3 = 0.0; - max_resistance = max(max_resistance, src_resistance); + dwn_cap = parasitics_->nodeGndCap(node) + + coupling_cap * coupling_cap_multiplier_ + + pinCapacitance(node); + y1 = dwn_cap; + y2 = y3 = 0.0; + max_resistance = max(max_resistance, src_resistance); - visit(node); - ParasiticDeviceIterator *device_iter2 = parasitics_->deviceIterator(node); - while (device_iter2->hasNext()) { - ParasiticDevice *device = device_iter2->next(); - if (parasitics_->isResistor(device) - && !isLoopResistor(device)) { - ParasiticNode *onode = parasitics_->otherNode(device, node); - // One commercial extractor creates resistors with identical from/to nodes. - if (onode != node - && device != from_res) { - if (isVisited(onode)) { - // Resistor loop. - debugPrint(debug_, "parasitic_reduce", 2, " loop detected thru resistor %s", - parasitics_->name(device)); - markLoopResistor(device); - } - else { - double r = parasitics_->value(device, ap); - double yd1, yd2, yd3, dcap; - reducePiDfs(drvr_pin, onode, device, ap, src_resistance + r, - yd1, yd2, yd3, dcap, max_resistance); - // Rule 3. Upstream traversal of a series resistor. - // Rule 4. Parallel admittances add. - y1 += yd1; - y2 += yd2 - r * yd1 * yd1; - y3 += yd3 - 2 * r * yd1 * yd2 + r * r * yd1 * yd1 * yd1; - dwn_cap += dcap; + visit(node); + ParasiticResistorSeq &resistors = resistor_map_[node]; + for (ParasiticResistor *resistor : resistors) { + if (!isLoopResistor(resistor)) { + ParasiticNode *onode = parasitics_->otherNode(resistor, node); + // One commercial extractor creates resistors with identical from/to nodes. + if (onode != node + && resistor != from_res) { + if (isVisited(onode)) { + // Resistor loop. + debugPrint(debug_, "parasitic_reduce", 2, " loop detected thru resistor %lu", + parasitics_->id(resistor)); + markLoopResistor(resistor); + } + else { + double r = parasitics_->value(resistor); + double yd1, yd2, yd3, dcap; + reducePiDfs(drvr_pin, onode, resistor, src_resistance + r, + yd1, yd2, yd3, dcap, max_resistance); + // Rule 3. Upstream traversal of a series resistor. + // Rule 4. Parallel admittances add. + y1 += yd1; + y2 += yd2 - r * yd1 * yd1; + y3 += yd3 - 2 * r * yd1 * yd2 + r * r * yd1 * yd1 * yd1; + dwn_cap += dcap; + } } } } - } - delete device_iter2; - setDownstreamCap(node, dwn_cap); - leave(node); - debugPrint(debug_, "parasitic_reduce", 3, - " node %s y1=%.3g y2=%.3g y3=%.3g cap=%.3g", - parasitics_->name(node), y1, y2, y3, dwn_cap); + setDownstreamCap(node, dwn_cap); + leave(node); + debugPrint(debug_, "parasitic_reduce", 3, + " node %s y1=%.3g y2=%.3g y3=%.3g cap=%.3g", + parasitics_->name(node), y1, y2, y3, dwn_cap); + } } float ReduceToPi::pinCapacitance(ParasiticNode *node) { - const Pin *pin = parasitics_->connectionPin(node); + const Pin *pin = parasitics_->pin(node); float pin_cap = 0.0; if (pin) { Port *port = network_->port(pin); LibertyPort *lib_port = network_->libertyPort(port); if (lib_port) { if (!includes_pin_caps_) { - pin_cap = sdc_->pinCapacitance(pin, rf_, op_cond_, corner_, - cnst_min_max_); + pin_cap = sdc_->pinCapacitance(pin, rf_, corner_, min_max_); pin_caps_one_value_ &= lib_port->capacitanceIsOneValue(); } } else if (network_->isTopLevelPort(pin)) - pin_cap = sdc_->portExtCap(port, rf_, corner_, cnst_min_max_); + pin_cap = sdc_->portExtCap(port, rf_, corner_, min_max_); } return pin_cap; } @@ -250,15 +250,15 @@ ReduceToPi::leave(ParasiticNode *node) } bool -ReduceToPi::isLoopResistor(ParasiticDevice *device) +ReduceToPi::isLoopResistor(ParasiticResistor *resistor) { - return loop_resistors_.hasKey(device); + return loop_resistors_.hasKey(resistor); } void -ReduceToPi::markLoopResistor(ParasiticDevice *device) +ReduceToPi::markLoopResistor(ParasiticResistor *resistor) { - loop_resistors_.insert(device); + loop_resistors_.insert(resistor); } void @@ -280,50 +280,44 @@ class ReduceToPiElmore : public ReduceToPi { public: ReduceToPiElmore(StaState *sta); - void makePiElmore(const Parasitic *parasitic_network, - const Pin *drvr_pin, - ParasiticNode *drvr_node, - float coupling_cap_factor, - const RiseFall *rf, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); + Parasitic *makePiElmore(const Parasitic *parasitic_network, + const Pin *drvr_pin, + ParasiticNode *drvr_node, + float coupling_cap_factor, + const RiseFall *rf, + const Corner *corner, + const MinMax *min_max, + const ParasiticAnalysisPt *ap); void reduceElmoreDfs(const Pin *drvr_pin, ParasiticNode *node, - ParasiticDevice *from_res, + ParasiticResistor *from_res, double elmore, - Parasitic *pi_elmore, - const ParasiticAnalysisPt *ap); + Parasitic *pi_elmore); }; -void +Parasitic * reduceToPiElmore(const Parasitic *parasitic_network, const Pin *drvr_pin, - float coupling_cap_factor, - const OperatingConditions *op_cond, + const RiseFall *rf, + float coupling_cap_factor, const Corner *corner, - const MinMax *cnst_min_max, + const MinMax *min_max, const ParasiticAnalysisPt *ap, StaState *sta) { Parasitics *parasitics = sta->parasitics(); - ParasiticNode *drvr_node = parasitics->findNode(parasitic_network, - drvr_pin); + ParasiticNode *drvr_node = parasitics->findNode(parasitic_network, drvr_pin); if (drvr_node) { - debugPrint(sta->debug(), "parasitic_reduce", 1, "Reduce driver %s", - sta->network()->pathName(drvr_pin)); + debugPrint(sta->debug(), "parasitic_reduce", 1, "Reduce driver %s %s %s", + sta->network()->pathName(drvr_pin), + rf->asString(), + min_max->asString()); ReduceToPiElmore reducer(sta); - if (parasitics->checkAnnotation(drvr_pin, drvr_node)) { - reducer.makePiElmore(parasitic_network, drvr_pin, drvr_node, - coupling_cap_factor, RiseFall::rise(), - op_cond, corner, cnst_min_max, ap); - if (!reducer.pinCapsOneValue()) - reducer.makePiElmore(parasitic_network, drvr_pin, drvr_node, - coupling_cap_factor, RiseFall::fall(), - op_cond, corner, cnst_min_max, ap); - } + return reducer.makePiElmore(parasitic_network, drvr_pin, drvr_node, + coupling_cap_factor, rf, corner, + min_max, ap); } + return nullptr; } ReduceToPiElmore::ReduceToPiElmore(StaState *sta) : @@ -331,27 +325,24 @@ ReduceToPiElmore::ReduceToPiElmore(StaState *sta) : { } -void +Parasitic * ReduceToPiElmore::makePiElmore(const Parasitic *parasitic_network, const Pin *drvr_pin, ParasiticNode *drvr_node, float coupling_cap_factor, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, - const MinMax *cnst_min_max, + const MinMax *min_max, const ParasiticAnalysisPt *ap) { float c2, rpi, c1; - reduceToPi(drvr_pin, drvr_node, - parasitics_->includesPinCaps(parasitic_network), - coupling_cap_factor, - rf, op_cond, corner, cnst_min_max, ap, - c2, rpi, c1); + reduceToPi(parasitic_network, drvr_pin, drvr_node, coupling_cap_factor, + rf, corner, min_max, ap, c2, rpi, c1); Parasitic *pi_elmore = parasitics_->makePiElmore(drvr_pin, rf, ap, c2, rpi, c1); parasitics_->setIsReducedParasiticNetwork(pi_elmore, true); - reduceElmoreDfs(drvr_pin, drvr_node, 0, 0.0, pi_elmore, ap); + reduceElmoreDfs(drvr_pin, drvr_node, 0, 0.0, pi_elmore); + return pi_elmore; } // Find elmore delays on 2nd DFS search using downstream capacitances @@ -359,12 +350,11 @@ ReduceToPiElmore::makePiElmore(const Parasitic *parasitic_network, void ReduceToPiElmore::reduceElmoreDfs(const Pin *drvr_pin, ParasiticNode *node, - ParasiticDevice *from_res, + ParasiticResistor *from_res, double elmore, - Parasitic *pi_elmore, - const ParasiticAnalysisPt *ap) + Parasitic *pi_elmore) { - const Pin *pin = parasitics_->connectionPin(node); + const Pin *pin = parasitics_->pin(node); if (from_res && pin) { if (network_->isLoad(pin)) { debugPrint(debug_, "parasitic_reduce", 2, " Load %s elmore=%.3g", @@ -374,22 +364,17 @@ ReduceToPiElmore::reduceElmoreDfs(const Pin *drvr_pin, } } visit(node); - ParasiticDeviceIterator *device_iter = parasitics_->deviceIterator(node); - while (device_iter->hasNext()) { - ParasiticDevice *device = device_iter->next(); - if (parasitics_->isResistor(device)) { - ParasiticNode *onode = parasitics_->otherNode(device, node); - if (device != from_res - && !isVisited(onode) - && !isLoopResistor(device)) { - float r = parasitics_->value(device, ap); - double onode_elmore = elmore + r * downstreamCap(onode); - reduceElmoreDfs(drvr_pin, onode, device, onode_elmore, - pi_elmore, ap); - } + ParasiticResistorSeq &resistors = resistor_map_[node]; + for (ParasiticResistor *resistor : resistors) { + ParasiticNode *onode = parasitics_->otherNode(resistor, node); + if (resistor != from_res + && !isVisited(onode) + && !isLoopResistor(resistor)) { + float r = parasitics_->value(resistor); + double onode_elmore = elmore + r * downstreamCap(onode); + reduceElmoreDfs(drvr_pin, onode, resistor, onode_elmore, pi_elmore); } } - delete device_iter; leave(node); } @@ -401,43 +386,38 @@ public: ReduceToPiPoleResidue2(StaState *sta); ~ReduceToPiPoleResidue2(); void findPolesResidues(const Parasitic *parasitic_network, - Parasitic *pi_pole_residue, + Parasitic *pi_pole_residue, const Pin *drvr_pin, - ParasiticNode *drvr_node, - const ParasiticAnalysisPt *ap); - void makePiPoleResidue2(const Parasitic *parasitic_network, - const Pin *drvr_pin, - ParasiticNode *drvr_node, - float coupling_cap_factor, - const RiseFall *rf, - const OperatingConditions *op_cond, - const Corner *corner, - const MinMax *cnst_min_max, - const ParasiticAnalysisPt *ap); + ParasiticNode *drvr_node); + Parasitic *makePiPoleResidue2(const Parasitic *parasitic_network, + const Pin *drvr_pin, + ParasiticNode *drvr_node, + float coupling_cap_factor, + const RiseFall *rf, + const Corner *corner, + const MinMax *min_max, + const ParasiticAnalysisPt *ap); private: void findMoments(const Pin *drvr_pin, ParasiticNode *drvr_node, - int moment_count, - const ParasiticAnalysisPt *ap); + int moment_count); void findMoments(const Pin *drvr_pin, ParasiticNode *node, double from_volt, - ParasiticDevice *from_res, - int moment_index, - const ParasiticAnalysisPt *ap); + ParasiticResistor *from_res, + int moment_index); double findBranchCurrents(const Pin *drvr_pin, ParasiticNode *node, - ParasiticDevice *from_res, - int moment_index, - const ParasiticAnalysisPt *ap); + ParasiticResistor *from_res, + int moment_index); double moment(ParasiticNode *node, int moment_index); void setMoment(ParasiticNode *node, double moment, int moment_index); - double current(ParasiticDevice *res); - void setCurrent(ParasiticDevice *res, + double current(ParasiticResistor *res); + void setCurrent(ParasiticResistor *res, double i); void findPolesResidues(Parasitic *pi_pole_residue, const Pin *drvr_pin, @@ -445,7 +425,7 @@ private: ParasiticNode *load_node); // Resistor/capacitor currents. - ParasiticDeviceValueMap currents_; + ResistorCurrentMap currents_; ParasiticNodeValueMap *moments_; }; @@ -465,13 +445,13 @@ ReduceToPiPoleResidue2::ReduceToPiPoleResidue2(StaState *sta) : // "An Explicit RC-Circuit Delay Approximation Based on the First // Three Moments of the Impulse Response", Proceedings of the 33rd // Design Automation Conference, 1996, pg 611-616. -void +Parasitic * reduceToPiPoleResidue2(const Parasitic *parasitic_network, const Pin *drvr_pin, + const RiseFall *rf, float coupling_cap_factor, - const OperatingConditions *op_cond, const Corner *corner, - const MinMax *cnst_min_max, + const MinMax *min_max, const ParasiticAnalysisPt *ap, StaState *sta) { @@ -481,41 +461,33 @@ reduceToPiPoleResidue2(const Parasitic *parasitic_network, debugPrint(sta->debug(), "parasitic_reduce", 1, "Reduce driver %s", sta->network()->pathName(drvr_pin)); ReduceToPiPoleResidue2 reducer(sta); - if (parasitics->checkAnnotation(drvr_pin, drvr_node)) { - reducer.makePiPoleResidue2(parasitic_network, drvr_pin, drvr_node, - coupling_cap_factor, RiseFall::rise(), - op_cond, corner, cnst_min_max, ap); - if (!reducer.pinCapsOneValue()) - reducer.makePiPoleResidue2(parasitic_network, drvr_pin, drvr_node, - coupling_cap_factor, RiseFall::fall(), - op_cond, corner, cnst_min_max, ap); - } + return reducer.makePiPoleResidue2(parasitic_network, drvr_pin, drvr_node, + coupling_cap_factor, rf, + corner, min_max, ap); } + return nullptr; } -void +Parasitic * ReduceToPiPoleResidue2::makePiPoleResidue2(const Parasitic *parasitic_network, const Pin *drvr_pin, ParasiticNode *drvr_node, float coupling_cap_factor, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, - const MinMax *cnst_min_max, + const MinMax *min_max, const ParasiticAnalysisPt *ap) { float c2, rpi, c1; - reduceToPi(drvr_pin, drvr_node, - parasitics_->includesPinCaps(parasitic_network), - coupling_cap_factor, - rf, op_cond, corner, cnst_min_max, ap, + reduceToPi(parasitic_network, drvr_pin, drvr_node, + coupling_cap_factor, rf, corner, min_max, ap, c2, rpi, c1); Parasitic *pi_pole_residue = parasitics_->makePiPoleResidue(drvr_pin, rf, ap, c2, rpi, c1); parasitics_->setIsReducedParasiticNetwork(pi_pole_residue, true); - findPolesResidues(parasitic_network, pi_pole_residue, - drvr_pin, drvr_node, ap); + findPolesResidues(parasitic_network, pi_pole_residue, drvr_pin, drvr_node); + return pi_pole_residue; } ReduceToPiPoleResidue2::~ReduceToPiPoleResidue2() @@ -525,13 +497,12 @@ ReduceToPiPoleResidue2::~ReduceToPiPoleResidue2() void ReduceToPiPoleResidue2::findPolesResidues(const Parasitic *parasitic_network, - Parasitic *pi_pole_residue, + Parasitic *pi_pole_residue, const Pin *drvr_pin, - ParasiticNode *drvr_node, - const ParasiticAnalysisPt *ap) + ParasiticNode *drvr_node) { moments_ = new ParasiticNodeValueMap[4]; - findMoments(drvr_pin, drvr_node, 4, ap); + findMoments(drvr_pin, drvr_node, 4); PinConnectedPinIterator *pin_iter = network_->connectedPinIterator(drvr_pin); while (pin_iter->hasNext()) { @@ -549,8 +520,7 @@ ReduceToPiPoleResidue2::findPolesResidues(const Parasitic *parasitic_network, void ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin, ParasiticNode *drvr_node, - int moment_count, - const ParasiticAnalysisPt *ap) + int moment_count) { // Driver model thevenin resistance. double rd = 0.0; @@ -558,43 +528,38 @@ ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin, // current thru the resistors. Thus, there is no point in doing a // pass to find the zero'th moments. for (int moment_index = 1; moment_index < moment_count; moment_index++) { - double rd_i = findBranchCurrents(drvr_pin, drvr_node, 0, - moment_index, ap); + double rd_i = findBranchCurrents(drvr_pin, drvr_node, 0, moment_index); double rd_volt = rd_i * rd; setMoment(drvr_node, 0.0, moment_index); - findMoments(drvr_pin, drvr_node, -rd_volt, 0, moment_index, ap); + findMoments(drvr_pin, drvr_node, -rd_volt, 0, moment_index); } } double ReduceToPiPoleResidue2::findBranchCurrents(const Pin *drvr_pin, ParasiticNode *node, - ParasiticDevice *from_res, - int moment_index, - const ParasiticAnalysisPt *ap) + ParasiticResistor *from_res, + int moment_index) { visit(node); double branch_i = 0.0; double coupling_cap = 0.0; - ParasiticDeviceIterator *device_iter = parasitics_->deviceIterator(node); - while (device_iter->hasNext()) { - ParasiticDevice *device = device_iter->next(); - if (parasitics_->isResistor(device)) { - ParasiticNode *onode = parasitics_->otherNode(device, node); - // One commercial extractor creates resistors with identical from/to nodes. - if (onode != node - && device != from_res - && !isVisited(onode) - && !isLoopResistor(device)) { - branch_i += findBranchCurrents(drvr_pin, onode, device, - moment_index, ap); - } + ParasiticResistorSeq &resistors = resistor_map_[node]; + for (ParasiticResistor *resistor : resistors) { + ParasiticNode *onode = parasitics_->otherNode(resistor, node); + // One commercial extractor creates resistors with identical from/to nodes. + if (onode != node + && resistor != from_res + && !isVisited(onode) + && !isLoopResistor(resistor)) { + branch_i += findBranchCurrents(drvr_pin, onode, resistor, moment_index); } - else if (parasitics_->isCouplingCap(device)) - coupling_cap += parasitics_->value(device, ap); } - delete device_iter; - double cap = parasitics_->nodeGndCap(node, ap) + ParasiticCapacitorSeq &capacitors = capacitor_map_[node]; + for (ParasiticCapacitor *capacitor : capacitors) + coupling_cap += parasitics_->value(capacitor); + + double cap = parasitics_->nodeGndCap(node) + coupling_cap * coupling_cap_multiplier_ + pinCapacitance(node); branch_i += cap * moment(node, moment_index - 1); @@ -610,34 +575,29 @@ void ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin, ParasiticNode *node, double from_volt, - ParasiticDevice *from_res, - int moment_index, - const ParasiticAnalysisPt *ap) + ParasiticResistor *from_res, + int moment_index) { visit(node); - ParasiticDeviceIterator *device_iter = parasitics_->deviceIterator(node); - while (device_iter->hasNext()) { - ParasiticDevice *device = device_iter->next(); - if (parasitics_->isResistor(device)) { - ParasiticNode *onode = parasitics_->otherNode(device, node); - // One commercial extractor creates resistors with identical from/to nodes. - if (onode != node - && device != from_res - && !isVisited(onode) - && !isLoopResistor(device)) { - double r = parasitics_->value(device, ap); - double r_volt = r * current(device); - double onode_volt = from_volt - r_volt; - setMoment(onode, onode_volt, moment_index); - debugPrint(debug_, "parasitic_reduce", 3, " moment %s %d %.3g", - parasitics_->name(onode), - moment_index, - onode_volt); - findMoments(drvr_pin, onode, onode_volt, device, moment_index, ap); - } + ParasiticResistorSeq &resistors = resistor_map_[node]; + for (ParasiticResistor *resistor : resistors) { + ParasiticNode *onode = parasitics_->otherNode(resistor, node); + // One commercial extractor creates resistors with identical from/to nodes. + if (onode != node + && resistor != from_res + && !isVisited(onode) + && !isLoopResistor(resistor)) { + double r = parasitics_->value(resistor); + double r_volt = r * current(resistor); + double onode_volt = from_volt - r_volt; + setMoment(onode, onode_volt, moment_index); + debugPrint(debug_, "parasitic_reduce", 3, " moment %s %d %.3g", + parasitics_->name(onode), + moment_index, + onode_volt); + findMoments(drvr_pin, onode, onode_volt, resistor, moment_index); } } - delete device_iter; leave(node); } @@ -667,13 +627,13 @@ ReduceToPiPoleResidue2::setMoment(ParasiticNode *node, } double -ReduceToPiPoleResidue2::current(ParasiticDevice *res) +ReduceToPiPoleResidue2::current(ParasiticResistor *res) { return currents_[res]; } void -ReduceToPiPoleResidue2::setCurrent(ParasiticDevice *res, +ReduceToPiPoleResidue2::setCurrent(ParasiticResistor *res, double i) { currents_[res] = i; diff --git a/parasitics/ReduceParasitics.hh b/parasitics/ReduceParasitics.hh index 105e34b7..ec7f8d3d 100644 --- a/parasitics/ReduceParasitics.hh +++ b/parasitics/ReduceParasitics.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -27,25 +27,25 @@ class ParasiticAnalysisPt; class StaState; // Reduce parasitic network to pi elmore model for drvr_pin. -void +Parasitic * reduceToPiElmore(const Parasitic *parasitic_network, const Pin *drvr_pin, + const RiseFall *rf, float coupling_cap_factor, - const OperatingConditions *op_cond, const Corner *corner, - const MinMax *cnst_min_max, + const MinMax *min_max, const ParasiticAnalysisPt *ap, StaState *sta); // Reduce parasitic network to pi and 2nd order pole/residue models // for drvr_pin. -void +Parasitic * reduceToPiPoleResidue2(const Parasitic *parasitic_network, const Pin *drvr_pin, + const RiseFall *rf, float coupling_cap_factor, - const OperatingConditions *op_cond, const Corner *corner, - const MinMax *cnst_min_max, + const MinMax *min_max, const ParasiticAnalysisPt *ap, StaState *sta); diff --git a/parasitics/ReportParasiticAnnotation.cc b/parasitics/ReportParasiticAnnotation.cc index 6d307b56..bc6c9b6e 100644 --- a/parasitics/ReportParasiticAnnotation.cc +++ b/parasitics/ReportParasiticAnnotation.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -95,9 +95,11 @@ ReportParasiticAnnotation::reportAnnotationCounts() report_->reportLine(" %s", network_->pathName(drvr_pin)); Parasitic *parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap_); - PinSet unannotated_loads = parasitics_->unannotatedLoads(parasitic, drvr_pin); - for (const Pin *load_pin : unannotated_loads) - report_->reportLine(" %s", network_->pathName(load_pin)); + if (parasitic) { + PinSet unannotated_loads = parasitics_->unannotatedLoads(parasitic, drvr_pin); + for (const Pin *load_pin : unannotated_loads) + report_->reportLine(" %s", network_->pathName(load_pin)); + } } } } @@ -105,6 +107,7 @@ ReportParasiticAnnotation::reportAnnotationCounts() void ReportParasiticAnnotation::findCounts() { + DcalcAnalysisPt *dcalc_ap = corner_->findDcalcAnalysisPt(min_max_); VertexIterator vertex_iter(graph_); while (vertex_iter.hasNext()) { Vertex *vertex = vertex_iter.next(); @@ -113,8 +116,11 @@ ReportParasiticAnnotation::findCounts() if (vertex->isDriver(network_) && !dir->isInternal()) { Parasitic *parasitic = parasitics_->findParasiticNetwork(pin, parasitic_ap_); + if (parasitic == nullptr) + parasitic = arc_delay_calc_->findParasitic(pin, RiseFall::rise(), dcalc_ap); if (parasitic) { - if (!parasitics_->checkAnnotation(parasitic, pin)) + PinSet unannotated_loads = parasitics_->unannotatedLoads(parasitic, pin); + if (unannotated_loads.size() > 0) partially_annotated_.push_back(pin); } else diff --git a/parasitics/ReportParasiticAnnotation.hh b/parasitics/ReportParasiticAnnotation.hh index a31034b6..1607a9bb 100644 --- a/parasitics/ReportParasiticAnnotation.hh +++ b/parasitics/ReportParasiticAnnotation.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/parasitics/SpefLex.ll b/parasitics/SpefLex.ll index cdcb764a..2fd939c1 100644 --- a/parasitics/SpefLex.ll +++ b/parasitics/SpefLex.ll @@ -1,7 +1,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/parasitics/SpefNamespace.cc b/parasitics/SpefNamespace.cc index 5164be65..b58eb7e8 100644 --- a/parasitics/SpefNamespace.cc +++ b/parasitics/SpefNamespace.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/parasitics/SpefNamespace.hh b/parasitics/SpefNamespace.hh index d21085f0..77bff0c9 100644 --- a/parasitics/SpefNamespace.hh +++ b/parasitics/SpefNamespace.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/parasitics/SpefParse.yy b/parasitics/SpefParse.yy index a92d9251..c61a8a7e 100755 --- a/parasitics/SpefParse.yy +++ b/parasitics/SpefParse.yy @@ -1,7 +1,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -802,7 +802,7 @@ pos_integer: INTEGER { int value = $1; if (value < 0) - sta::spef_reader->warn(21, "%d is not positive.", value); + sta::spef_reader->warn(1525, "%d is not positive.", value); $$ = value; } ; @@ -811,13 +811,13 @@ pos_number: INTEGER { float value = static_cast($1); if (value < 0) - sta::spef_reader->warn(22, "%.4f is not positive.", value); + sta::spef_reader->warn(1526, "%.4f is not positive.", value); $$ = value; } | FLOAT { float value = static_cast($1); if (value < 0) - sta::spef_reader->warn(23, "%.4f is not positive.", value); + sta::spef_reader->warn(1527, "%.4f is not positive.", value); $$ = value; } ; diff --git a/parasitics/SpefReader.cc b/parasitics/SpefReader.cc index cdff33a4..d0efbd27 100644 --- a/parasitics/SpefReader.cc +++ b/parasitics/SpefReader.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -27,6 +27,8 @@ #include "PortDirection.hh" #include "Sdc.hh" #include "Parasitics.hh" +#include "Corner.hh" +#include "ArcDelayCalc.hh" #include "SpefReaderPvt.hh" #include "SpefNamespace.hh" @@ -37,6 +39,7 @@ spefResetScanner(); namespace sta { +// Referenced by parser. SpefReader *spef_reader; bool @@ -46,15 +49,10 @@ readSpefFile(const char *filename, bool pin_cap_included, bool keep_coupling_caps, float coupling_cap_factor, - ReducedParasiticType reduce_to, - bool delete_after_reduce, - const OperatingConditions *op_cond, + bool reduce, const Corner *corner, - const MinMax *cnst_min_max, - bool quiet, - Report *report, - Network *network, - Parasitics *parasitics) + const MinMaxAll *min_max, + StaState *sta) { bool success = false; // Use zlib to uncompress gzip'd files automagically. @@ -62,8 +60,7 @@ readSpefFile(const char *filename, if (stream) { SpefReader reader(filename, stream, instance, ap, pin_cap_included, keep_coupling_caps, coupling_cap_factor, - reduce_to, delete_after_reduce, op_cond, corner, - cnst_min_max, quiet, report, network, parasitics); + reduce, corner, min_max, sta); spef_reader = &reader; ::spefResetScanner(); // yyparse returns 0 on success. @@ -83,27 +80,19 @@ SpefReader::SpefReader(const char *filename, bool pin_cap_included, bool keep_coupling_caps, float coupling_cap_factor, - ReducedParasiticType reduce_to, - bool delete_after_reduce, - const OperatingConditions *op_cond, + bool reduce, const Corner *corner, - const MinMax *cnst_min_max, - bool quiet, - Report *report, - Network *network, - Parasitics *parasitics) : + const MinMaxAll *min_max, + StaState *sta) : + StaState(sta), filename_(filename), instance_(instance), ap_(ap), pin_cap_included_(pin_cap_included), keep_coupling_caps_(keep_coupling_caps), - reduce_to_(reduce_to), - delete_after_reduce_(delete_after_reduce), - op_cond_(op_cond), + reduce_(reduce), corner_(corner), - cnst_min_max_(cnst_min_max), - keep_device_names_(false), - quiet_(quiet), + min_max_(min_max), stream_(stream), line_(1), // defaults @@ -112,9 +101,6 @@ SpefReader::SpefReader(const char *filename, bus_brkt_left_('\0'), bus_brkt_right_('\0'), net_(nullptr), - report_(report), - network_(network), - parasitics_(parasitics), triple_index_(0), time_scale_(1.0), cap_scale_(1.0), @@ -134,11 +120,8 @@ SpefReader::~SpefReader() design_flow_ = nullptr; } - SpefNameMap::Iterator map_iter(name_map_); - while (map_iter.hasNext()) { - int index; - char *name; - map_iter.next(index, name); + for (auto index_name : name_map_) { + char *name = index_name.second; stringDelete(name); } } @@ -164,7 +147,7 @@ SpefReader::setBusBrackets(char left, char right) || (left == '<' && right == '>') || (left == ':' && right == '\0') || (left == '.' && right == '\0'))) - warn(167, "illegal bus delimiters."); + warn(1640, "illegal bus delimiters."); bus_brkt_left_ = left; bus_brkt_right_ = right; } @@ -248,7 +231,7 @@ SpefReader::setTimeScale(float scale, else if (stringEq(units, "PS")) time_scale_ = scale * 1E-12F; else - warn(168, "unknown units %s.", units); + warn(1641, "unknown units %s.", units); stringDelete(units); } @@ -261,7 +244,7 @@ SpefReader::setCapScale(float scale, else if (stringEq(units, "FF")) cap_scale_ = scale * 1E-15F; else - warn(168, "unknown units %s.", units); + warn(1642, "unknown units %s.", units); stringDelete(units); } @@ -274,7 +257,7 @@ SpefReader::setResScale(float scale, else if (stringEq(units, "KOHM")) res_scale_ = scale * 1E+3F; else - warn(170, "unknown units %s.", units); + warn(1643, "unknown units %s.", units); stringDelete(units); } @@ -289,7 +272,7 @@ SpefReader::setInductScale(float scale, else if (stringEq(units, "UH")) induct_scale_ = scale * 1E-6F; else - warn(168, "unknown units %s.", units); + warn(1644, "unknown units %s.", units); stringDelete(units); } @@ -305,14 +288,12 @@ char * SpefReader::nameMapLookup(char *name) { if (name && name[0] == '*') { - char *mapped_name; - bool exists; int index = atoi(name + 1); - name_map_.findKey(index, mapped_name, exists); - if (exists) - return mapped_name; + auto itr = name_map_.find(index); + if (itr != name_map_.end()) + return itr->second; else { - warn(169, "no name map entry for %d.", index); + warn(1645, "no name map entry for %d.", index); return nullptr; } } @@ -331,7 +312,7 @@ SpefReader::portDirection(char *spef_dir) else if (stringEq(spef_dir, "B")) direction = PortDirection::bidirect(); else - warn(170, "unknown port direction %s.", spef_dir); + warn(1646, "unknown port direction %s.", spef_dir); return direction; } @@ -358,16 +339,16 @@ SpefReader::findPin(char *name) if (inst) { pin = network_->findPin(inst, port_name); if (pin == nullptr) - warn(171, "pin %s not found.", name); + warn(1647, "pin %s not found.", name); } else - warn(172, "instance %s not found.", name); + warn(1648, "instance %s not found.", name); } } else { pin = findPortPinRelative(name); if (pin == nullptr) - warn(173, "pin %s not found.", name); + warn(1649, "pin %s not found.", name); } } return pin; @@ -381,7 +362,7 @@ SpefReader::findNet(char *name) if (name) { net = findNetRelative(name); if (net == nullptr) - warn(174, "net %s not found.", name); + warn(1650, "net %s not found.", name); } return net; } @@ -409,12 +390,9 @@ SpefReader::rspfDrvrBegin(Pin *drvr_pin, float c2 = pi->c2()->value(triple_index_) * cap_scale_; float rpi = pi->r1()->value(triple_index_) * res_scale_; float c1 = pi->c1()->value(triple_index_) * cap_scale_; - // Delete pi model and elmore delays. - parasitics_->deleteParasitics(drvr_pin, ap_); // Only one parasitic, save it under rise transition. - parasitic_ = parasitics_->makePiElmore(drvr_pin, - RiseFall::rise(), - ap_, c2, rpi, c1); + parasitic_ = parasitics_->makePiElmore(drvr_pin, RiseFall::rise(), ap_, + c2, rpi, c1); } delete pi; } @@ -472,115 +450,84 @@ SpefReader::dspfBegin(Net *net, void SpefReader::dspfFinish() { - if (parasitic_) { - if (!quiet_) - parasitics_->check(parasitic_); - if (reduce_to_ != ReducedParasiticType::none) { - parasitics_->reduceTo(parasitic_, net_, reduce_to_, op_cond_, - corner_, cnst_min_max_, ap_); - if (delete_after_reduce_) - parasitics_->deleteParasiticNetwork(net_, ap_); - } + if (parasitic_ && reduce_) { + arc_delay_calc_->reduceParasitic(parasitic_, net_, corner_, min_max_); + parasitics_->deleteParasiticNetwork(net_, ap_); } parasitic_ = nullptr; net_ = nullptr; } -// Caller is only interested in nodes on net_. ParasiticNode * -SpefReader::findParasiticNode(char *name) -{ - ParasiticNode *node; - Net *ext_net; - int ext_node_id; - Pin *ext_pin; - findParasiticNode(name, node, ext_net, ext_node_id, ext_pin); - if (node == nullptr - && (ext_net || ext_pin)) - warn(175, "%s not connected to net %s.", name, network_->pathName(net_)); - return node; -} - -void SpefReader::findParasiticNode(char *name, - ParasiticNode *&node, - Net *&ext_net, - int &ext_node_id, - Pin *&ext_pin) + bool local_only) { - node = nullptr; - ext_net = nullptr; - ext_node_id = 0; - ext_pin = nullptr; - if (name) { - if (parasitic_) { - char *delim = strrchr(name, delimiter_); - if (delim) { - *delim = '\0'; - char *name2 = delim + 1; - name = nameMapLookup(name); - Instance *inst = findInstanceRelative(name); - if (inst) { - // : - Pin *pin = network_->findPin(inst, name2); - if (pin) { - if (network_->isConnected(net_, pin)) - node = parasitics_->ensureParasiticNode(parasitic_, pin); - else - ext_pin = pin; - } - else { - // Replace delimiter for error message. - *delim = delimiter_; - warn(176, "pin %s not found.", name); - } - } - else { - Net *net = findNet(name); - // Replace delimiter for error messages. - *delim = delimiter_; - if (net) { - // : - const char *id_str = delim + 1; - if (isDigits(id_str)) { - int id = atoi(id_str); - if (network_->isConnected(net, net_)) - node = parasitics_->ensureParasiticNode(parasitic_, net, id); - else { - ext_net = net; - ext_node_id = id; - } - } - else - warn(177, "node %s not a pin or net:number", name); - } - } + if (name && parasitic_) { + char *delim = strrchr(name, delimiter_); + if (delim) { + *delim = '\0'; + char *name2 = delim + 1; + name = nameMapLookup(name); + Instance *inst = findInstanceRelative(name); + if (inst) { + // : + Pin *pin = network_->findPin(inst, name2); + if (pin) { + if (local_only + && !network_->isConnected(net_, pin)) + warn(1651, "%s not connected to net %s.", name, network_->pathName(net_)); + return parasitics_->ensureParasiticNode(parasitic_, pin, network_); + } + else { + // Replace delimiter for error message. + *delim = delimiter_; + warn(1652, "pin %s not found.", name); + } } else { - // - name = nameMapLookup(name); - Pin *pin = findPortPinRelative(name); - if (pin) { - if (network_->isConnected(net_, pin)) - node = parasitics_->ensureParasiticNode(parasitic_, pin); - else - ext_pin = pin; - } - else - warn(178, "pin %s not found.", name); + Net *net = findNet(name); + // Replace delimiter for error messages. + *delim = delimiter_; + if (net) { + // : + const char *id_str = delim + 1; + if (isDigits(id_str)) { + int id = atoi(id_str); + if (local_only + && !network_->isConnected(net, net_)) + warn(1653, "%s not connected to net %s.", name, network_->pathName(net_)); + return parasitics_->ensureParasiticNode(parasitic_, net, id, network_); + } + else + warn(1654, "node %s not a pin or net:number", name); + } } } + else { + // + name = nameMapLookup(name); + Pin *pin = findPortPinRelative(name); + if (pin) { + if (local_only + && !network_->isConnected(net_, pin)) + warn(1655, "%s not connected to net %s.", name, network_->pathName(net_)); + return parasitics_->ensureParasiticNode(parasitic_, pin, network_); + } + else + warn(1656, "pin %s not found.", name); + } } + return nullptr; } void SpefReader::makeCapacitor(int, char *node_name, SpefTriple *cap) { - ParasiticNode *node = findParasiticNode(node_name); + ParasiticNode *node = findParasiticNode(node_name, true); if (node) { float cap1 = cap->value(triple_index_) * cap_scale_; - parasitics_->incrCap(node, cap1, ap_); + parasitics_->incrCap(node, cap1); } delete cap; stringDelete(node_name); @@ -592,81 +539,36 @@ SpefReader::makeCapacitor(int id, char *node_name2, SpefTriple *cap) { + ParasiticNode *node1 = findParasiticNode(node_name1, false); + ParasiticNode *node2 = findParasiticNode(node_name2, false); float cap1 = cap->value(triple_index_) * cap_scale_; - if (keep_coupling_caps_) - makeCouplingCap(id, node_name1, node_name2, cap1); - else { - ParasiticNode *node1, *node2; - Net *ext_net1, *ext_net2; - int ext_node_id1, ext_node_id2; - Pin *ext_pin1, *ext_pin2; - findParasiticNode(node_name1, node1, ext_net1, ext_node_id1, ext_pin1); - findParasiticNode(node_name2, node2, ext_net2, ext_node_id2, ext_pin2); - float scaled_cap = cap1 * ap_->couplingCapFactor(); - if (node1) - parasitics_->incrCap(node1, scaled_cap, ap_); - if (node2) - parasitics_->incrCap(node2, scaled_cap, ap_); + if (cap1 > 0.0) { + if (keep_coupling_caps_) + parasitics_->makeCapacitor(parasitic_, id, cap1, node1, node2); + else { + float scaled_cap = cap1 * ap_->couplingCapFactor(); + if (node1 && parasitics_->net(node1, network_) == net_) + parasitics_->incrCap(node1, scaled_cap); + if (node2 && parasitics_->net(node2, network_) == net_) + parasitics_->incrCap(node2, scaled_cap); + } } delete cap; stringDelete(node_name1); stringDelete(node_name2); } -void -SpefReader::makeCouplingCap(int id, - char *node_name1, - char *node_name2, - float cap) -{ - const char *name = nullptr; - const char *name_tmp = nullptr; - if (keep_device_names_) - // Prepend device type because OA uses one namespace for all devices. - name = name_tmp = stringPrint("C%d", id); - - ParasiticNode *node1, *node2; - Net *ext_net1, *ext_net2; - int ext_node_id1, ext_node_id2; - Pin *ext_pin1, *ext_pin2; - findParasiticNode(node_name1, node1, ext_net1, ext_node_id1, ext_pin1); - findParasiticNode(node_name2, node2, ext_net2, ext_node_id2, ext_pin2); - if (node1 && node2) - parasitics_->makeCouplingCap(name, node1, node2, cap, ap_); - if (node1 && node2 == nullptr) { - if (ext_net2) - parasitics_->makeCouplingCap(name, node1, ext_net2, ext_node_id2, - cap, ap_); - else if (ext_pin2) - parasitics_->makeCouplingCap(name, node1, ext_pin2, cap, ap_); - } - else if (node1 == nullptr && node2) { - if (ext_net1) - parasitics_->makeCouplingCap(name, node2, ext_net1, ext_node_id1, - cap, ap_); - else if (ext_pin1) - parasitics_->makeCouplingCap(name, node2, ext_pin1, cap, ap_); - } - stringDelete(name_tmp); -} - void SpefReader::makeResistor(int id, char *node_name1, char *node_name2, SpefTriple *res) { - ParasiticNode *node1 = findParasiticNode(node_name1); - ParasiticNode *node2 = findParasiticNode(node_name2); + ParasiticNode *node1 = findParasiticNode(node_name1, true); + ParasiticNode *node2 = findParasiticNode(node_name2, true); if (node1 && node2) { float res1 = res->value(triple_index_) * res_scale_; - const char *name = nullptr; - const char *name_tmp = nullptr; - if (keep_device_names_) - // Prepend device type because OA uses one namespace for all devices. - name = name_tmp = stringPrint("R%d", id); - parasitics_->makeResistor(name, node1, node2, res1, ap_); - stringDelete(name_tmp); + parasitics_->makeResistor(parasitic_, id, res1, node1, node2); } delete res; stringDelete(node_name1); @@ -729,6 +631,6 @@ int SpefParse_error(const char *msg) { spefFlushBuffer(); - sta::spef_reader->warn(707, "%s.", msg); + sta::spef_reader->warn(1657, "%s.", msg); return 0; } diff --git a/parasitics/SpefReader.hh b/parasitics/SpefReader.hh index 39a50536..105f5dd1 100644 --- a/parasitics/SpefReader.hh +++ b/parasitics/SpefReader.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -22,13 +22,11 @@ namespace sta { -class Report; -class Network; -class Parasitics; class ParasiticAnalysisPt; class Instance; class Corner; class OperatingConditions; +class StaState; // Read a file single value parasitics into analysis point ap. // In a Spef file with triplet values the first value is used. @@ -42,14 +40,9 @@ readSpefFile(const char *filename, bool pin_cap_included, bool keep_coupling_caps, float coupling_cap_factor, - ReducedParasiticType reduce_to, - bool delete_after_reduce, - const OperatingConditions *op_cond, + bool reduce, const Corner *corner, - const MinMax *cnst_min_max, - bool quiet, - Report *report, - Network *network, - Parasitics *parasitics); + const MinMaxAll *min_max, + StaState *sta); } // namespace diff --git a/parasitics/SpefReaderPvt.hh b/parasitics/SpefReaderPvt.hh index 7a23ff2e..44fc7af2 100644 --- a/parasitics/SpefReaderPvt.hh +++ b/parasitics/SpefReaderPvt.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -16,11 +16,13 @@ #pragma once +#include + #include "Zlib.hh" -#include "Map.hh" #include "StringSeq.hh" #include "NetworkClass.hh" #include "ParasiticsClass.hh" +#include "StaState.hh" // Global namespace. #define YY_INPUT(buf,result,max_size) \ @@ -34,15 +36,14 @@ SpefParse_error(const char *msg); namespace sta { class Report; -class OperatingConditions; -class MinMax; +class MinMaxAll; class SpefRspfPi; class SpefTriple; class Corner; -typedef Map > SpefNameMap; +typedef std::map> SpefNameMap; -class SpefReader +class SpefReader : public StaState { public: SpefReader(const char *filename, @@ -52,15 +53,10 @@ public: bool pin_cap_included, bool keep_coupling_caps, float coupling_cap_factor, - ReducedParasiticType reduce_to, - bool delete_after_reduce, - const OperatingConditions *op_cond, + bool reduce, const Corner *corner, - const MinMax *cnst_min_max, - bool quiet, - Report *report, - Network *network, - Parasitics *parasitics); + const MinMaxAll *min_max, + StaState *sta); virtual ~SpefReader(); char divider() const { return divider_; } void setDivider(char divider); @@ -128,30 +124,18 @@ private: Pin *findPortPinRelative(const char *name); Net *findNetRelative(const char *name); Instance *findInstanceRelative(const char *name); - void makeCouplingCap(int id, - char *node_name1, - char *node_name2, - float cap); - ParasiticNode *findParasiticNode(char *name); - void findParasiticNode(char *name, - ParasiticNode *&node, - Net *&ext_net, - int &ext_node_id, - Pin *&ext_pin); + ParasiticNode *findParasiticNode(char *name, + bool local_only); const char *filename_; Instance *instance_; const ParasiticAnalysisPt *ap_; bool pin_cap_included_; bool keep_coupling_caps_; - ReducedParasiticType reduce_to_; - bool delete_after_reduce_; - const OperatingConditions *op_cond_; + bool reduce_; const Corner *corner_; - const MinMax *cnst_min_max_; + const MinMaxAll *min_max_; // Normally no need to keep device names. - bool keep_device_names_; - bool quiet_; gzFile stream_; int line_; char divider_; @@ -159,9 +143,6 @@ private: char bus_brkt_left_; char bus_brkt_right_; Net *net_; - Report *report_; - Network *network_; - Parasitics *parasitics_; int triple_index_; float time_scale_; diff --git a/power/Power.cc b/power/Power.cc index 5350a331..f46b3f2a 100644 --- a/power/Power.cc +++ b/power/Power.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -607,7 +607,7 @@ Power::funcBdd(const FuncExpr *expr) result = Cudd_ReadLogicZero(cudd_mgr_); break; default: - report_->critical(596, "unknown function operator"); + report_->critical(1440, "unknown function operator"); } if (result) Cudd_Ref(result); diff --git a/power/Power.hh b/power/Power.hh index f3075fb8..81c13de1 100644 --- a/power/Power.hh +++ b/power/Power.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/power/Power.i b/power/Power.i index 962d7313..aaf3ff23 100644 --- a/power/Power.i +++ b/power/Power.i @@ -3,7 +3,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/power/Power.tcl b/power/Power.tcl index 3d2fae13..c5122bc6 100644 --- a/power/Power.tcl +++ b/power/Power.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -240,7 +240,7 @@ proc set_power_activity { args } { foreach port $ports { if { [get_property $port "direction"] == "input" } { if { [sta::is_clock_src [sta::get_port_pin $port]] } { - sta_warn 299 "activity cannot be set on clock ports." + sta_warn 303 "activity cannot be set on clock ports." } else { set_power_input_port_activity $port $activity $duty } diff --git a/power/ReadVcdActivities.cc b/power/ReadVcdActivities.cc index 3abaf594..59a4c91a 100644 --- a/power/ReadVcdActivities.cc +++ b/power/ReadVcdActivities.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -104,7 +104,7 @@ ReadVcdActivities::readActivities() if (vcd_.timeMax() > 0) setActivities(); else - report_->warn(808, "VCD max time is zero."); + report_->warn(1450, "VCD max time is zero."); report_->reportLine("Annotated %lu pin activities.", annotated_pins_.size()); } @@ -171,7 +171,7 @@ ReadVcdActivities::setVarActivity(VcdVar *var, } } else - report_->warn(809, "problem parsing bus %s.", var_name.c_str()); + report_->warn(1451, "problem parsing bus %s.", var_name.c_str()); } } @@ -248,7 +248,7 @@ ReadVcdActivities::checkClkPeriod(const Pin *pin, double clk_period = clk->period(); if (abs((clk_period - sim_period) / clk_period) > .1) // Warn if sim clock period differs from SDC by 10%. - report_->warn(806, "clock %s vcd period %s differs from SDC clock period %s", + report_->warn(1452, "clock %s vcd period %s differs from SDC clock period %s", clk->name(), delayAsString(sim_period, this), delayAsString(clk_period, this)); diff --git a/power/ReadVcdActivities.hh b/power/ReadVcdActivities.hh index 5c7c26ac..c7a2a662 100644 --- a/power/ReadVcdActivities.hh +++ b/power/ReadVcdActivities.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/power/Vcd.cc b/power/Vcd.cc index 6033dbd9..b04ebc8d 100644 --- a/power/Vcd.cc +++ b/power/Vcd.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -169,7 +169,7 @@ VcdValues & Vcd::values(VcdVar *var) { if (id_values_map_.find(var->id()) == id_values_map_.end()) { - report_->error(805, "Unknown variable %s ID %s", + report_->error(1360, "Unknown variable %s ID %s", var->name().c_str(), var->id().c_str()); static VcdValues empty; diff --git a/power/Vcd.hh b/power/Vcd.hh index b61d3935..6c62eca6 100644 --- a/power/Vcd.hh +++ b/power/Vcd.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/power/VcdReader.cc b/power/VcdReader.cc index e30be19d..b917f3e1 100644 --- a/power/VcdReader.cc +++ b/power/VcdReader.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -189,7 +189,7 @@ VcdReader::parseVar() string type_name = tokens[0]; VcdVarType type = vcd_var_type_map.find(type_name, VcdVarType::unknown); if (type == VcdVarType::unknown) - report_->fileWarn(803, filename_, stmt_line_, + report_->fileWarn(1370, filename_, stmt_line_, "Unknown variable type %s.", type_name.c_str()); else { diff --git a/power/VcdReader.hh b/power/VcdReader.hh index 13db5386..63299ac3 100644 --- a/power/VcdReader.hh +++ b/power/VcdReader.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/Clock.cc b/sdc/Clock.cc index 5e87df91..f6c322a3 100644 --- a/sdc/Clock.cc +++ b/sdc/Clock.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/ClockGatingCheck.cc b/sdc/ClockGatingCheck.cc index adc0c180..9f003bc2 100644 --- a/sdc/ClockGatingCheck.cc +++ b/sdc/ClockGatingCheck.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/ClockGroups.cc b/sdc/ClockGroups.cc index c2656f6e..97c6a9ff 100644 --- a/sdc/ClockGroups.cc +++ b/sdc/ClockGroups.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/ClockInsertion.cc b/sdc/ClockInsertion.cc index 4b38107c..78e57224 100644 --- a/sdc/ClockInsertion.cc +++ b/sdc/ClockInsertion.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/ClockLatency.cc b/sdc/ClockLatency.cc index a8f4ffcd..a2e8bbe8 100644 --- a/sdc/ClockLatency.cc +++ b/sdc/ClockLatency.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/CycleAccting.cc b/sdc/CycleAccting.cc index 1012743d..9de3e939 100644 --- a/sdc/CycleAccting.cc +++ b/sdc/CycleAccting.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -84,7 +84,7 @@ CycleAcctings::reportClkToClkMaxCycleWarnings(Report *report) ClockPair clk_pair2(tgt_clk, src_clk); if (!clk_warnings.hasKey(clk_pair1) && !clk_warnings.hasKey(clk_pair2)) { - report->warn(9, "No common period was found between clocks %s and %s.", + report->warn(1010, "No common period was found between clocks %s and %s.", src_clk->name(), tgt_clk->name()); clk_warnings.insert(clk_pair1); diff --git a/sdc/DataCheck.cc b/sdc/DataCheck.cc index 83afc8b5..6e1ca132 100644 --- a/sdc/DataCheck.cc +++ b/sdc/DataCheck.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/DeratingFactors.cc b/sdc/DeratingFactors.cc index 29b54223..843f5655 100644 --- a/sdc/DeratingFactors.cc +++ b/sdc/DeratingFactors.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/DisabledPorts.cc b/sdc/DisabledPorts.cc index 7b81a8e7..c2e50d0b 100644 --- a/sdc/DisabledPorts.cc +++ b/sdc/DisabledPorts.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/ExceptionPath.cc b/sdc/ExceptionPath.cc index 9cf06ec9..204a75a3 100644 --- a/sdc/ExceptionPath.cc +++ b/sdc/ExceptionPath.cc @@ -1,6 +1,6 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/InputDrive.cc b/sdc/InputDrive.cc index 6584e653..f17f8c00 100644 --- a/sdc/InputDrive.cc +++ b/sdc/InputDrive.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/PinPair.cc b/sdc/PinPair.cc index 772f463e..586bb3aa 100644 --- a/sdc/PinPair.cc +++ b/sdc/PinPair.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/PortDelay.cc b/sdc/PortDelay.cc index 7fdd6ca6..cabd7d0a 100644 --- a/sdc/PortDelay.cc +++ b/sdc/PortDelay.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/PortExtCap.cc b/sdc/PortExtCap.cc index 7456dcf9..ca1663e8 100644 --- a/sdc/PortExtCap.cc +++ b/sdc/PortExtCap.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index c4c071d8..2f345a13 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -465,7 +465,7 @@ Sdc::setOperatingConditions(OperatingConditions *op_cond, } OperatingConditions * -Sdc::operatingConditions(const MinMax *min_max) +Sdc::operatingConditions(const MinMax *min_max) const { int mm_index = min_max->index(); return operating_conditions_[mm_index]; @@ -2958,8 +2958,7 @@ Sdc::setPortExtWireCap(const Port *port, PortExtCap *port_cap = ensurePortExtPinCap(port, corner); if (subtract_pin_cap) { Pin *pin = network_->findPin(network_->name(port)); - const OperatingConditions *op_cond = operatingConditions(min_max); - cap -= connectedPinCap(pin, rf, op_cond, corner, min_max); + cap -= connectedPinCap(pin, rf, corner, min_max); if (cap < 0.0) cap = 0.0; } @@ -3066,14 +3065,11 @@ Sdc::setNetWireCap(const Net *net, { float wire_cap = cap; if (subtract_pin_cap) { - OperatingConditions *op_cond = operatingConditions(min_max); NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net); if (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); - float pin_cap_rise = connectedPinCap(pin, RiseFall::rise(), - op_cond, corner, min_max); - float pin_cap_fall = connectedPinCap(pin, RiseFall::fall(), - op_cond, corner, min_max); + float pin_cap_rise = connectedPinCap(pin, RiseFall::rise(), corner, min_max); + float pin_cap_fall = connectedPinCap(pin, RiseFall::fall(), corner, min_max); float pin_cap = (pin_cap_rise + pin_cap_fall) / 2.0F; wire_cap -= pin_cap; if ((wire_cap + pin_cap) < 0.0) @@ -3108,7 +3104,6 @@ Sdc::hasNetWireCap(const Net *net) const void Sdc::connectedCap(const Pin *pin, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, // Return values. @@ -3117,8 +3112,7 @@ Sdc::connectedCap(const Pin *pin, float &fanout, bool &has_net_load) const { - netCaps(pin, rf, op_cond, corner, min_max, - pin_cap, wire_cap, fanout, has_net_load); + netCaps(pin, rf, corner, min_max, pin_cap, wire_cap, fanout, has_net_load); float net_wire_cap; drvrPinWireCap(pin, corner, min_max, net_wire_cap, has_net_load); if (has_net_load) @@ -3128,13 +3122,12 @@ Sdc::connectedCap(const Pin *pin, float Sdc::connectedPinCap(const Pin *pin, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max) { float pin_cap, wire_cap, fanout; bool has_net_load; - connectedCap(pin, rf, op_cond, corner, min_max, + connectedCap(pin, rf, corner, min_max, pin_cap, wire_cap, fanout, has_net_load); return pin_cap; } @@ -3143,7 +3136,6 @@ class FindNetCaps : public PinVisitor { public: FindNetCaps(const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, float &pin_cap, @@ -3155,7 +3147,6 @@ public: protected: const RiseFall *rf_; - const OperatingConditions *op_cond_; const Corner *corner_; const MinMax *min_max_; float &pin_cap_; @@ -3166,7 +3157,6 @@ protected: }; FindNetCaps::FindNetCaps(const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, float &pin_cap, @@ -3176,7 +3166,6 @@ FindNetCaps::FindNetCaps(const RiseFall *rf, const Sdc *sdc) : PinVisitor(), rf_(rf), - op_cond_(op_cond), corner_(corner), min_max_(min_max), pin_cap_(pin_cap), @@ -3190,7 +3179,7 @@ FindNetCaps::FindNetCaps(const RiseFall *rf, void FindNetCaps::operator()(const Pin *pin) { - sdc_->pinCaps(pin, rf_, op_cond_, corner_, min_max_, + sdc_->pinCaps(pin, rf_, corner_, min_max_, pin_cap_, wire_cap_, fanout_); } @@ -3198,7 +3187,6 @@ FindNetCaps::operator()(const Pin *pin) void Sdc::netCaps(const Pin *drvr_pin, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, // Return values. @@ -3211,7 +3199,7 @@ Sdc::netCaps(const Pin *drvr_pin, wire_cap = 0.0; fanout = 0.0; has_net_load = false; - FindNetCaps visitor(rf, op_cond, corner, min_max, pin_cap, + FindNetCaps visitor(rf, corner, min_max, pin_cap, wire_cap, fanout, has_net_load, this); network_->visitConnectedPins(drvr_pin, visitor); } @@ -3219,7 +3207,6 @@ Sdc::netCaps(const Pin *drvr_pin, void Sdc::pinCaps(const Pin *pin, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max, // Return values. @@ -3252,7 +3239,7 @@ Sdc::pinCaps(const Pin *pin, LibertyPort *port = network_->libertyPort(pin); if (port) { Instance *inst = network_->instance(pin); - pin_cap += portCapacitance(inst, port, rf, op_cond, corner, min_max); + pin_cap += portCapacitance(inst, port, rf, corner, min_max); if (port->direction()->isAnyInput()) fanout++; } @@ -3263,7 +3250,6 @@ float Sdc::portCapacitance(Instance *inst, LibertyPort *port, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max) const { @@ -3271,20 +3257,20 @@ Sdc::portCapacitance(Instance *inst, if (inst) inst_pvt = pvt(inst, min_max); LibertyPort *corner_port = port->cornerPort(corner, min_max); + OperatingConditions *op_cond = operatingConditions(min_max); return corner_port->capacitance(rf, min_max, op_cond, inst_pvt); } float Sdc::pinCapacitance(const Pin *pin, const RiseFall *rf, - const OperatingConditions *op_cond, const Corner *corner, const MinMax *min_max) { LibertyPort *port = network_->libertyPort(pin); if (port) { Instance *inst = network_->instance(pin); - return portCapacitance(inst, port, rf, op_cond, corner, min_max); + return portCapacitance(inst, port, rf, corner, min_max); } else return 0.0; @@ -4055,7 +4041,7 @@ Sdc::makeGroupPath(const char *name, { checkFromThrusTo(from, thrus, to); if (name && is_default) - report_->critical(213, "group path name and is_default are mutually exclusive."); + report_->critical(1490, "group path name and is_default are mutually exclusive."); else if (name) { GroupPath *group_path = new GroupPath(name, is_default, from, thrus, to, true, comment); diff --git a/sdc/SdcCmdComment.cc b/sdc/SdcCmdComment.cc index f6ab6178..41aa411a 100644 --- a/sdc/SdcCmdComment.cc +++ b/sdc/SdcCmdComment.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/SdcGraph.cc b/sdc/SdcGraph.cc index 1f49312e..1e5a2bbb 100644 --- a/sdc/SdcGraph.cc +++ b/sdc/SdcGraph.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index e937abac..5fd36b28 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -1251,7 +1251,7 @@ WriteSdc::writeExceptionCmd(ExceptionPath *exception) const gzprintf(stream_, "group_path -name %s", exception->name()); } else - report_->critical(214, "unknown exception type"); + report_->critical(1620, "unknown exception type"); } void @@ -1793,7 +1793,7 @@ WriteSdc::setConstantCmd(const Pin *pin) const case LogicValue::rise: case LogicValue::fall: default: - report_->critical(215, "illegal set_logic value"); + report_->critical(1621, "illegal set_logic value"); return nullptr; } } @@ -1834,7 +1834,7 @@ WriteSdc::caseAnalysisValueStr(const Pin *pin) const return "falling"; case LogicValue::unknown: default: - report_->critical(216, "invalid set_case_analysis value"); + report_->critical(1622, "invalid set_case_analysis value"); return nullptr; } } diff --git a/sdc/WriteSdcPvt.hh b/sdc/WriteSdcPvt.hh index 5e07de2b..cb4768fd 100644 --- a/sdc/WriteSdcPvt.hh +++ b/sdc/WriteSdcPvt.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdf/ReportAnnotation.cc b/sdf/ReportAnnotation.cc index b99ad936..f51858ba 100644 --- a/sdf/ReportAnnotation.cc +++ b/sdf/ReportAnnotation.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdf/ReportAnnotation.hh b/sdf/ReportAnnotation.hh index 3ba54db2..815b0d3e 100644 --- a/sdf/ReportAnnotation.hh +++ b/sdf/ReportAnnotation.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdf/Sdf.i b/sdf/Sdf.i index aa44631c..d2fa8905 100644 --- a/sdf/Sdf.i +++ b/sdf/Sdf.i @@ -3,7 +3,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdf/Sdf.tcl b/sdf/Sdf.tcl index 324a2be9..c1c63653 100644 --- a/sdf/Sdf.tcl +++ b/sdf/Sdf.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -38,17 +38,14 @@ proc_redirect read_sdf { if [info exists keys(-cond_use)] { set cond_use $keys(-cond_use) if { $cond_use != "min" && $cond_use != "max" && $cond_use != "min_max" } { - sta_warn 612 "-cond_use must be min, max or min_max." + sta_warn 620 "-cond_use must be min, max or min_max." set cond_use "NULL" } if { $cond_use == "min_max" \ && { [operating_condition_analysis_type] == "single" }} { - sta_error 430 "-cond_use min_max cannot be used with analysis type single." + sta_error 621 "-cond_use min_max cannot be used with analysis type single." } } - if [info exists keys(-analysis_type)] { - sta_warn 617 "-analysis_type is deprecated. Use set_operating_conditions -analysis_type." - } set unescaped_dividers [info exists flags(-unescaped_dividers)] set incremental_only [info exists flags(-incremental_only)] @@ -154,7 +151,7 @@ proc_redirect write_sdf { if [info exists keys(-divider)] { set divider $keys(-divider) if { !($divider == "/" || $divider == ".") } { - sta_error 432 "SDF -divider must be / or ." + sta_error 623 "SDF -divider must be / or ." } } set digits 3 diff --git a/sdf/SdfLex.ll b/sdf/SdfLex.ll index 26c965bd..a414000b 100644 --- a/sdf/SdfLex.ll +++ b/sdf/SdfLex.ll @@ -1,7 +1,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdf/SdfParse.yy b/sdf/SdfParse.yy index 13d52a4b..9f9ae445 100644 --- a/sdf/SdfParse.yy +++ b/sdf/SdfParse.yy @@ -1,7 +1,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdf/SdfReader.cc b/sdf/SdfReader.cc index b5e24016..7dff5edd 100644 --- a/sdf/SdfReader.cc +++ b/sdf/SdfReader.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdf/SdfReader.hh b/sdf/SdfReader.hh index 3ab46b62..c270ca9e 100644 --- a/sdf/SdfReader.hh +++ b/sdf/SdfReader.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdf/SdfReaderPvt.hh b/sdf/SdfReaderPvt.hh index 00c2f560..c9aa5210 100644 --- a/sdf/SdfReaderPvt.hh +++ b/sdf/SdfReaderPvt.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdf/SdfWriter.cc b/sdf/SdfWriter.cc index 506a3a86..1fa32bab 100644 --- a/sdf/SdfWriter.cc +++ b/sdf/SdfWriter.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/sdf/SdfWriter.hh b/sdf/SdfWriter.hh index 0451c894..f3d23c08 100644 --- a/sdf/SdfWriter.hh +++ b/sdf/SdfWriter.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Bfs.cc b/search/Bfs.cc index d634cf2f..7971b975 100644 --- a/search/Bfs.cc +++ b/search/Bfs.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckCapacitanceLimits.cc b/search/CheckCapacitanceLimits.cc index 0acc5cec..c980e025 100644 --- a/search/CheckCapacitanceLimits.cc +++ b/search/CheckCapacitanceLimits.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckCapacitanceLimits.hh b/search/CheckCapacitanceLimits.hh index 8f0f5c7d..98f2382e 100644 --- a/search/CheckCapacitanceLimits.hh +++ b/search/CheckCapacitanceLimits.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckFanoutLimits.cc b/search/CheckFanoutLimits.cc index fe6ad0ae..e11843cd 100644 --- a/search/CheckFanoutLimits.cc +++ b/search/CheckFanoutLimits.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckFanoutLimits.hh b/search/CheckFanoutLimits.hh index 2d7a9715..8c3e6652 100644 --- a/search/CheckFanoutLimits.hh +++ b/search/CheckFanoutLimits.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckMaxSkews.cc b/search/CheckMaxSkews.cc index ced6bcd8..258738a4 100644 --- a/search/CheckMaxSkews.cc +++ b/search/CheckMaxSkews.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckMaxSkews.hh b/search/CheckMaxSkews.hh index 7a8902b0..c5f548d5 100644 --- a/search/CheckMaxSkews.hh +++ b/search/CheckMaxSkews.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckMinPeriods.cc b/search/CheckMinPeriods.cc index 93edbb5d..b7e8bcd4 100644 --- a/search/CheckMinPeriods.cc +++ b/search/CheckMinPeriods.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckMinPeriods.hh b/search/CheckMinPeriods.hh index 505c27c7..8da1c5c6 100644 --- a/search/CheckMinPeriods.hh +++ b/search/CheckMinPeriods.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckMinPulseWidths.cc b/search/CheckMinPulseWidths.cc index 830612ca..ece0222f 100644 --- a/search/CheckMinPulseWidths.cc +++ b/search/CheckMinPulseWidths.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckMinPulseWidths.hh b/search/CheckMinPulseWidths.hh index da5adaac..c2433b5b 100644 --- a/search/CheckMinPulseWidths.hh +++ b/search/CheckMinPulseWidths.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckSlewLimits.cc b/search/CheckSlewLimits.cc index f3e5e0cf..656b9a72 100644 --- a/search/CheckSlewLimits.cc +++ b/search/CheckSlewLimits.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckSlewLimits.hh b/search/CheckSlewLimits.hh index bb431e3e..9e70d69b 100644 --- a/search/CheckSlewLimits.hh +++ b/search/CheckSlewLimits.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckTiming.cc b/search/CheckTiming.cc index d18b60a7..c658f54a 100644 --- a/search/CheckTiming.cc +++ b/search/CheckTiming.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/CheckTiming.hh b/search/CheckTiming.hh index 6c7aa99a..6603e87d 100644 --- a/search/CheckTiming.hh +++ b/search/CheckTiming.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/ClkInfo.cc b/search/ClkInfo.cc index 6ab578ad..0bc2d728 100644 --- a/search/ClkInfo.cc +++ b/search/ClkInfo.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/ClkInfo.hh b/search/ClkInfo.hh index 3e3830e2..2e4c198e 100644 --- a/search/ClkInfo.hh +++ b/search/ClkInfo.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/ClkNetwork.cc b/search/ClkNetwork.cc index 080230c9..fee8131e 100644 --- a/search/ClkNetwork.cc +++ b/search/ClkNetwork.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/ClkSkew.cc b/search/ClkSkew.cc index 217b536c..971e1ea1 100644 --- a/search/ClkSkew.cc +++ b/search/ClkSkew.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/ClkSkew.hh b/search/ClkSkew.hh index b7c7a290..97497436 100644 --- a/search/ClkSkew.hh +++ b/search/ClkSkew.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Corner.cc b/search/Corner.cc index 072ec314..47902c7c 100644 --- a/search/Corner.cc +++ b/search/Corner.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -114,8 +114,9 @@ Corners::copy(Corners *corners) makeAnalysisPts(); for (ParasiticAnalysisPt *orig_ap : corners->parasitic_analysis_pts_) { - ParasiticAnalysisPt *ap = new ParasiticAnalysisPt(orig_ap->name(), orig_ap->index(), - orig_ap->minMax()); + ParasiticAnalysisPt *ap = new ParasiticAnalysisPt(orig_ap->name(), + orig_ap->index(), + orig_ap->indexMax()); parasitic_analysis_pts_.push_back(ap); } @@ -127,64 +128,46 @@ Corners::copy(Corners *corners) } void -Corners::makeParasiticAnalysisPts(bool per_corner, - bool per_min_max) +Corners::makeParasiticAnalysisPts(bool per_corner) { parasitic_analysis_pts_.deleteContentsClear(); - if (per_corner && per_min_max) { - // each corner has min/max parasitics + if (per_corner) { + // per corner, per min/max + parasitic_analysis_pts_.resize(corners_.size() * MinMax::index_count); for (Corner *corner : corners_) { corner->setParasiticAnalysisPtcount(MinMax::index_count); for (MinMax *min_max : MinMax::range()) { int mm_index = min_max->index(); int ap_index = corner->index() * MinMax::index_count + mm_index; + int ap_index_max = corner->index() * MinMax::index_count + + MinMax::max()->index(); string ap_name = corner->name(); ap_name += "_"; ap_name += min_max->asString(); ParasiticAnalysisPt *ap = new ParasiticAnalysisPt(ap_name.c_str(), - ap_index, - min_max); - parasitic_analysis_pts_.push_back(ap); + ap_index, ap_index_max); + parasitic_analysis_pts_[ap_index] = ap; corner->setParasiticAP(ap, mm_index); } } } - else if (per_corner && !per_min_max) { - // each corner has parasitics - for (Corner *corner : corners_) { - ParasiticAnalysisPt *ap = new ParasiticAnalysisPt(corner->name(), - corner->index(), - MinMax::max()); - parasitic_analysis_pts_.push_back(ap); - corner->setParasiticAnalysisPtcount(1); - corner->setParasiticAP(ap, 0); - } - } - else if (!per_corner && per_min_max) { - // min/max parasitics shared by all corners + else { + // shared corner, per min/max parasitic_analysis_pts_.resize(MinMax::index_count); + int ap_index_max = MinMax::max()->index(); for (MinMax *min_max : MinMax::range()) { int mm_index = min_max->index(); + int ap_index = mm_index; ParasiticAnalysisPt *ap = new ParasiticAnalysisPt(min_max->asString(), - mm_index, - min_max); - parasitic_analysis_pts_[mm_index] = ap; + ap_index, + ap_index_max); + parasitic_analysis_pts_[ap_index] = ap; for (Corner *corner : corners_) { corner->setParasiticAnalysisPtcount(MinMax::index_count); corner->setParasiticAP(ap, mm_index); } } } - else if (!per_corner && !per_min_max) { - // single parasitics shared by all corners - ParasiticAnalysisPt *ap = new ParasiticAnalysisPt("min_max", 0, - MinMax::max()); - parasitic_analysis_pts_.push_back(ap); - for (Corner *corner : corners_) { - corner->setParasiticAnalysisPtcount(1); - corner->setParasiticAP(ap, 0); - } - } } void @@ -404,9 +387,9 @@ Corner::setParasiticAnalysisPtcount(int ap_count) void Corner::setParasiticAP(ParasiticAnalysisPt *ap, - int index) + int mm_index) { - parasitic_analysis_pts_[index] = ap; + parasitic_analysis_pts_[mm_index] = ap; } void diff --git a/search/Crpr.cc b/search/Crpr.cc index effa5b1d..af1b14e8 100644 --- a/search/Crpr.cc +++ b/search/Crpr.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Crpr.hh b/search/Crpr.hh index d1afe46a..62999a33 100644 --- a/search/Crpr.hh +++ b/search/Crpr.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/FindRegister.cc b/search/FindRegister.cc index d5fd65d6..547474a4 100644 --- a/search/FindRegister.cc +++ b/search/FindRegister.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/FindRegister.hh b/search/FindRegister.hh index 90bd2673..48dc5474 100644 --- a/search/FindRegister.hh +++ b/search/FindRegister.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/GatedClk.cc b/search/GatedClk.cc index 27172167..6fbaac7a 100644 --- a/search/GatedClk.cc +++ b/search/GatedClk.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/GatedClk.hh b/search/GatedClk.hh index 487e725a..55767cac 100644 --- a/search/GatedClk.hh +++ b/search/GatedClk.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Genclks.cc b/search/Genclks.cc index e967c09e..c2a8a9a1 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -271,7 +271,7 @@ Genclks::checkMaster(Clock *gclk) { ensureMaster(gclk); if (gclk->masterClk() == nullptr) - report_->warn(10, "no master clock found for generated clock %s.", + report_->warn(1060, "no master clock found for generated clock %s.", gclk->name()); } @@ -329,7 +329,7 @@ Genclks::ensureMaster(Clock *gclk) } } if (master_clk_count > 1) - report_->warn(12, + report_->warn(1061, "generated clock %s pin %s is in the fanout of multiple clocks.", gclk->name(), network_->pathName(src_pin)); @@ -935,7 +935,7 @@ Genclks::recordSrcPaths(Clock *gclk) // Don't warn if the master clock is ideal. && gclk->masterClk() && gclk->masterClk()->isPropagated()) - report_->warn(13, "generated clock %s source pin %s missing paths from master clock %s.", + report_->warn(1062, "generated clock %s source pin %s missing paths from master clock %s.", gclk->name(), network_->pathName(gclk_pin), gclk->masterClk()->name()); diff --git a/search/Genclks.hh b/search/Genclks.hh index cd23cde9..2f9d6df0 100644 --- a/search/Genclks.hh +++ b/search/Genclks.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Latches.cc b/search/Latches.cc index 2f2fafb1..bf1a8260 100644 --- a/search/Latches.cc +++ b/search/Latches.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Latches.hh b/search/Latches.hh index a125cfe1..69dacaa9 100644 --- a/search/Latches.hh +++ b/search/Latches.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Levelize.cc b/search/Levelize.cc index 07988367..96536f67 100644 --- a/search/Levelize.cc +++ b/search/Levelize.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Levelize.hh b/search/Levelize.hh index b04702fa..03ae3b4c 100644 --- a/search/Levelize.hh +++ b/search/Levelize.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/MakeTimingModel.cc b/search/MakeTimingModel.cc index b45d116b..2f6eee93 100644 --- a/search/MakeTimingModel.cc +++ b/search/MakeTimingModel.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -203,7 +203,7 @@ MakeTimingModel::checkClock(Clock *clk) { for (const Pin *pin : clk->leafPins()) { if (!network_->isTopLevelPort(pin)) - report_->warn(810, "clock %s pin %s is inside model block.", + report_->warn(1355, "clock %s pin %s is inside model block.", clk->name(), network_->pathName(pin)); } @@ -446,8 +446,7 @@ MakeTimingModel::makeInputOutputTimingArcs(const Pin *input_pin, LibertyPort *output_port = modelPort(output_pin); LibertyPort *input_port = modelPort(input_pin); attrs->setTimingSense(output_delays.timingSense()); - lib_builder_->makeCombinationalArcs(cell_, input_port, - output_port, nullptr, + lib_builder_->makeCombinationalArcs(cell_, input_port, output_port, true, true, attrs); } } @@ -552,8 +551,7 @@ MakeTimingModel::findClkInsertionDelays() TimingRole *role = (min_max == MinMax::min()) ? TimingRole::clockTreePathMin() : TimingRole::clockTreePathMax(); - lib_builder_->makeClockTreePathArcs(cell_, lib_port, nullptr, - role, attrs); + lib_builder_->makeClockTreePathArcs(cell_, lib_port, role, attrs); } } } @@ -655,7 +653,7 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin, float output_load_cap = graph_delay_calc_->loadCap(output_pin, dcalc_ap); ArcDelay drvr_self_delay; Slew drvr_self_slew; - drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap, 0.0, false, + drvr_gate_model->gateDelay(pvt, in_slew1, output_load_cap, false, drvr_self_delay, drvr_self_slew); const TableModel *drvr_table = drvr_gate_model->delayModel(); @@ -670,7 +668,7 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin, // get slew from driver input pin ArcDelay gate_delay; Slew gate_slew; - drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, 0.0, false, + drvr_gate_model->gateDelay(pvt, in_slew1, load_cap, false, gate_delay, gate_slew); // Remove the self delay driving the output pin net load cap. load_values->push_back(delayAsFloat(delay + gate_delay diff --git a/search/MakeTimingModel.hh b/search/MakeTimingModel.hh index 1b6e6361..60b6662e 100644 --- a/search/MakeTimingModel.hh +++ b/search/MakeTimingModel.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/MakeTimingModelPvt.hh b/search/MakeTimingModelPvt.hh index bd0c4064..55689296 100644 --- a/search/MakeTimingModelPvt.hh +++ b/search/MakeTimingModelPvt.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Path.cc b/search/Path.cc index fa3756e6..c7a91fc9 100644 --- a/search/Path.cc +++ b/search/Path.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/PathAnalysisPt.cc b/search/PathAnalysisPt.cc index 3b25f68a..fdafdf84 100644 --- a/search/PathAnalysisPt.cc +++ b/search/PathAnalysisPt.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/PathEnd.cc b/search/PathEnd.cc index 29436928..2f7f9292 100644 --- a/search/PathEnd.cc +++ b/search/PathEnd.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/PathEnum.cc b/search/PathEnum.cc index 6b64f053..d9560f41 100644 --- a/search/PathEnum.cc +++ b/search/PathEnum.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -471,7 +471,7 @@ PathEnum::divSlack(Path *before_div, return div_arrival - arc_arrival; } else { - report()->error(619, "path diversion missing edge."); + report()->error(1370, "path diversion missing edge."); return 0.0; } } @@ -566,7 +566,7 @@ PathEnum::makeDivertedPath(Path *path, first = false; } if (!found_div) - criticalError(250, "diversion path not found"); + criticalError(280, "diversion path not found"); } void diff --git a/search/PathEnum.hh b/search/PathEnum.hh index cd8d4c3d..0c777260 100644 --- a/search/PathEnum.hh +++ b/search/PathEnum.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/PathEnumed.cc b/search/PathEnumed.cc index ef8a19ee..1283b15a 100644 --- a/search/PathEnumed.cc +++ b/search/PathEnumed.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -123,7 +123,7 @@ const Required & PathEnumed::required(const StaState *sta) const { // Required times are never needed for enumerated paths. - sta->report()->critical(251, "enumerated path required time"); + sta->report()->critical(1380, "enumerated path required time"); return delay_zero; } @@ -132,7 +132,7 @@ PathEnumed::setRequired(const Required &, const StaState *sta) { // Required times are never needed for enumerated paths. - sta->report()->critical(252, "enumerated path required time"); + sta->report()->critical(1381, "enumerated path required time"); } Path * diff --git a/search/PathEnumed.hh b/search/PathEnumed.hh index 7461ab99..1203bc28 100644 --- a/search/PathEnumed.hh +++ b/search/PathEnumed.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/PathExpanded.cc b/search/PathExpanded.cc index 790ea1db..972e3bfa 100644 --- a/search/PathExpanded.cc +++ b/search/PathExpanded.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/PathGroup.cc b/search/PathGroup.cc index d7b75041..8e08d9e4 100644 --- a/search/PathGroup.cc +++ b/search/PathGroup.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -396,7 +396,7 @@ PathGroups::pathGroup(const PathEnd *path_end) const else if (path_end->isUnconstrained()) return unconstrained_[mm_index]; else { - report_->critical(253, "unknown path end type"); + report_->critical(1390, "unknown path end type"); return nullptr; } } diff --git a/search/PathRef.cc b/search/PathRef.cc index bef16c09..386df1ed 100644 --- a/search/PathRef.cc +++ b/search/PathRef.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/PathVertex.cc b/search/PathVertex.cc index ef68d11d..85b0f186 100644 --- a/search/PathVertex.cc +++ b/search/PathVertex.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -233,7 +233,7 @@ PathVertex::arrival(const StaState *sta) const if (arrivals) return arrivals[arrival_index_]; else { - sta->report()->error(620, "missing arrivals."); + sta->report()->error(1400, "missing arrivals."); return 0.0; } } @@ -247,7 +247,7 @@ PathVertex::setArrival(Arrival arrival, if (arrivals) arrivals[arrival_index_] = arrival; else - sta->report()->error(621, "missing arrivals."); + sta->report()->error(1401, "missing arrivals."); } } @@ -276,7 +276,7 @@ PathVertex::setRequired(const Required &required, requireds = graph->makeRequireds(vertex_, arrival_count); } else - sta->report()->error(622, "missing requireds."); + sta->report()->error(1402, "missing requireds."); } requireds[arrival_index_] = required; } diff --git a/search/PathVertexRep.cc b/search/PathVertexRep.cc index 624372d0..18e4098d 100644 --- a/search/PathVertexRep.cc +++ b/search/PathVertexRep.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -142,15 +142,15 @@ PathVertexRep::arrival(const StaState *sta) const bool arrival_exists; tag_group->arrivalIndex(tag, arrival_index, arrival_exists); if (!arrival_exists) - sta->report()->critical(254, "tag group missing tag"); + sta->report()->critical(1420, "tag group missing tag"); Arrival *arrivals = graph->arrivals(vertex); if (arrivals) return arrivals[arrival_index]; else - sta->report()->critical(624, "missing arrivals"); + sta->report()->critical(1421, "missing arrivals"); } else - sta->report()->error(623, "missing arrivals."); + sta->report()->error(1422, "missing arrivals."); return 0.0; } diff --git a/search/Property.cc b/search/Property.cc index f67764a8..42b5ed87 100644 --- a/search/Property.cc +++ b/search/Property.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 693651c8..89b31d28 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -286,7 +286,7 @@ ReportPath::reportPathEndHeader() reportSlackOnlyHeader(); break; default: - report_->critical(255, "unsupported path type"); + report_->critical(1470, "unsupported path type"); break; } } @@ -307,7 +307,7 @@ ReportPath::reportPathEndFooter() reportBlankLine(); break; default: - report_->critical(256, "unsupported path type"); + report_->critical(1471, "unsupported path type"); break; } } @@ -346,7 +346,7 @@ ReportPath::reportPathEnd(PathEnd *end, reportSlackOnly(end); break; default: - report_->critical(257, "unsupported path type"); + report_->critical(1473, "unsupported path type"); break; } } @@ -2261,7 +2261,7 @@ ReportPath::reportPathLine(const Path *path, float cap = field_blank_; // Don't show capacitance field for input pins. if (is_driver && field_capacitance_->enabled()) - cap = loadCap(pin, rf, dcalc_ap); + cap = graph_delay_calc_->loadCap(pin, rf, dcalc_ap); reportLine(what.c_str(), cap, slew, field_blank_, incr, time, false, early_late, rf, line_case); } @@ -2375,7 +2375,7 @@ ReportPath::reportPath(const Path *path) case ReportPathFormat::summary: case ReportPathFormat::slack_only: default: - report_->critical(259, "unsupported path type"); + report_->critical(1474, "unsupported path type"); break; } } @@ -2653,7 +2653,7 @@ ReportPath::reportPath5(const Path *path, float fanout = field_blank_; // Don't show capacitance field for input pins. if (is_driver && field_capacitance_->enabled()) - cap = loadCap(pin, rf, dcalc_ap); + cap = graph_delay_calc_->loadCap(pin, rf, dcalc_ap); // Don't show fanout field for input pins. if (is_driver && field_fanout_->enabled()) fanout = drvrFanout(vertex, dcalc_ap->corner(), min_max); @@ -2837,18 +2837,6 @@ ReportPath::pathInputDelayRefPath(const Path *path, } } -float -ReportPath::loadCap(Pin *drvr_pin, - const RiseFall *rf, - DcalcAnalysisPt *dcalc_ap) -{ - Parasitic *parasitic = nullptr; - parasitic = arc_delay_calc_->findParasitic(drvr_pin, rf, dcalc_ap); - float load_cap = graph_delay_calc_->loadCap(drvr_pin, parasitic, rf, dcalc_ap); - arc_delay_calc_->finishDrvrPin(); - return load_cap; -} - //////////////////////////////////////////////////////////////// void diff --git a/search/ReportPath.hh b/search/ReportPath.hh index 389513ce..75778cc0 100644 --- a/search/ReportPath.hh +++ b/search/ReportPath.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -384,9 +384,6 @@ protected: bool hasExtInputDriver(const Pin *pin, const RiseFall *rf, const MinMax *min_max); - float loadCap(Pin *drvr_pin, - const RiseFall *rf, - DcalcAnalysisPt *dcalc_ap); float drvrFanout(Vertex *drvr, const Corner *corner, const MinMax *min_max); diff --git a/search/Search.cc b/search/Search.cc index 27135bb9..6dafbb39 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -2468,7 +2468,7 @@ Search::thruClkInfo(PathVertex *from_path, sdc_->clockLatency(from_clk, to_pin, clk_rf, min_max, latency, exists); if (exists) { - // Latency on pin has precidence over fanin or hierarchical + // Latency on pin has precedence over fanin or hierarchical // pin latency. to_latency = latency; to_clk_prop = false; @@ -2651,7 +2651,7 @@ Search::findTagGroup(TagGroupBldr *tag_bldr) tag_group_set_->reserve(new_capacity); } if (tag_group_next_ > tag_group_index_max) - report_->critical(260, "max tag group index exceeded"); + report_->critical(1510, "max tag group index exceeded"); } return tag_group; } @@ -2887,7 +2887,7 @@ Search::findTag(const RiseFall *rf, tag_set_->reserve(new_capacity); } if (tag_next_ == tag_index_max) - report_->critical(261, "max tag index exceeded"); + report_->critical(1511, "max tag index exceeded"); } if (own_states) delete states; @@ -3614,7 +3614,7 @@ Search::matchesFilter(Path *path, // -to return matchesFilterTo(path, to_clk_edge); else { - report_->critical(262, "unexpected filter path"); + report_->critical(1512, "unexpected filter path"); return false; } } @@ -3782,7 +3782,7 @@ Search::tnsIncr(Vertex *vertex, vertex->name(sdc_network_)); tns_[path_ap_index] += slack; if (tns_slacks_[path_ap_index].hasKey(vertex)) - report_->critical(263, "tns incr existing vertex"); + report_->critical(1513, "tns incr existing vertex"); tns_slacks_[path_ap_index][vertex] = slack; } } diff --git a/search/SearchPred.cc b/search/SearchPred.cc index dcfe00ce..8fcb8fac 100644 --- a/search/SearchPred.cc +++ b/search/SearchPred.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Sim.cc b/search/Sim.cc index 24c98e2b..30db0f0c 100644 --- a/search/Sim.cc +++ b/search/Sim.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -206,7 +206,7 @@ Sim::funcBdd(const FuncExpr *expr, result = Cudd_ReadLogicZero(cudd_mgr_); break; default: - report_->critical(596, "unknown function operator"); + report_->critical(1520, "unknown function operator"); } if (result) Cudd_Ref(result); @@ -861,7 +861,7 @@ Sim::setPinValue(const Pin *pin, if (exists && value != constraint_value) { if (value != LogicValue::unknown) - report_->warn(15, "propagated logic value %c differs from constraint value of %c on pin %s.", + report_->warn(1521, "propagated logic value %c differs from constraint value of %c on pin %s.", logicValueString(value), logicValueString(constraint_value), sdc_network_->pathName(pin)); diff --git a/search/Sim.hh b/search/Sim.hh index 4f0a6690..25a808f1 100644 --- a/search/Sim.hh +++ b/search/Sim.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Sta.cc b/search/Sta.cc index bb437451..e1246db9 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -271,9 +271,8 @@ Sta::Sta() : update_genclks_(false), equiv_cells_(nullptr), graph_sdc_annotated_(false), - // Default to same parasitics for each corner min/max. - parasitics_per_corner_(false), - parasitics_per_min_max_(false) + // Default to same parasitics for all corners. + parasitics_per_corner_(false) { } @@ -2026,10 +2025,10 @@ Sta::checkExceptionFromPins(ExceptionFrom *from, const Pin *pin = pin_iter.next(); if (exceptionFromInvalid(pin)) { if (line) - report_->fileWarn(267, file, line, "'%s' is not a valid start point.", + report_->fileWarn(1554, file, line, "'%s' is not a valid start point.", cmd_network_->pathName(pin)); else - report_->warn(18, "'%s' is not a valid start point.", + report_->warn(1550, "'%s' is not a valid start point.", cmd_network_->pathName(pin)); } } @@ -2102,10 +2101,10 @@ Sta::checkExceptionToPins(ExceptionTo *to, const Pin *pin = pin_iter.next(); if (sdc_->exceptionToInvalid(pin)) { if (line) - report_->fileWarn(266, file, line, "'%s' is not a valid endpoint.", + report_->fileWarn(1551, file, line, "'%s' is not a valid endpoint.", cmd_network_->pathName(pin)); else - report_->warn(17, "'%s' is not a valid endpoint.", + report_->warn(1552, "'%s' is not a valid endpoint.", cmd_network_->pathName(pin)); } } @@ -2428,7 +2427,7 @@ void Sta::makeCorners(StringSet *corner_names) { if (corner_names->size() > corner_count_max) - report_->error(374, "maximum corner count exceeded"); + report_->error(1553, "maximum corner count exceeded"); sdc_->makeCornersBefore(); parasitics_->deleteParasitics(); corners_->makeCorners(corner_names); @@ -2658,18 +2657,14 @@ Sta::ensureClkArrivals() //////////////////////////////////////////////////////////////// -void -Sta::visitStartpoints(VertexVisitor *visitor) +PinSet +Sta::startpointPins() { ensureGraph(); - search_->visitStartpoints(visitor); -} - -void -Sta::visitEndpoints(VertexVisitor *visitor) -{ - ensureGraph(); - search_->visitEndpoints(visitor); + PinSet pins(network_); + VertexPinCollector visitor(pins); + search_->visitStartpoints(&visitor); + return pins; } VertexSet * @@ -2679,6 +2674,16 @@ Sta::endpoints() return search_->endpoints(); } +PinSet +Sta::endpointPins() +{ + ensureGraph(); + PinSet pins(network_); + for (Vertex *vertex : *search_->endpoints()) + pins.insert(vertex->pin()); + return pins; +} + int Sta::endpointViolationCount(const MinMax *min_max) { @@ -3790,10 +3795,7 @@ Sta::connectedCap(const Pin *drvr_pin, float &wire_cap) const { const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); - Parasitic *parasitic = arc_delay_calc_->findParasitic(drvr_pin, rf, dcalc_ap); - graph_delay_calc_->loadCap(drvr_pin, parasitic, rf, dcalc_ap, - pin_cap, wire_cap); - arc_delay_calc_->finishDrvrPin(); + graph_delay_calc_->loadCap(drvr_pin, rf, dcalc_ap, pin_cap, wire_cap); } void @@ -3886,40 +3888,29 @@ Sta::readSpef(const char *filename, bool pin_cap_included, bool keep_coupling_caps, float coupling_cap_factor, - ReducedParasiticType reduce_to, - bool delete_after_reduce, - bool quiet) + bool reduce) { - setParasiticAnalysisPts(corner != nullptr, - min_max != MinMaxAll::all()); - if (corner == nullptr) - corner = cmd_corner_; - const MinMax *cnst_min_max = (min_max == MinMaxAll::all()) + setParasiticAnalysisPts(corner != nullptr); + const MinMax *ap_min_max = (min_max == MinMaxAll::all()) ? MinMax::max() : min_max->asMinMax(); - ParasiticAnalysisPt *ap = corner->findParasiticAnalysisPt(cnst_min_max); - const OperatingConditions *op_cond = - sdc_->operatingConditions(cnst_min_max); + const Corner *ap_corner = corner ? corner : corners_->corners()[0]; + ParasiticAnalysisPt *ap = ap_corner->findParasiticAnalysisPt(ap_min_max); bool success = readSpefFile(filename, instance, ap, pin_cap_included, keep_coupling_caps, - coupling_cap_factor, - reduce_to, delete_after_reduce, - op_cond, corner, cnst_min_max, quiet, - report_, network_, parasitics_); + coupling_cap_factor, reduce, + corner, min_max, this); graph_delay_calc_->delaysInvalid(); search_->arrivalsInvalid(); return success; } void -Sta::setParasiticAnalysisPts(bool per_corner, - bool per_min_max) +Sta::setParasiticAnalysisPts(bool per_corner) { - if (per_corner != parasitics_per_corner_ - || per_min_max != parasitics_per_min_max_) { + if (per_corner != parasitics_per_corner_) { deleteParasitics(); parasitics_per_corner_ = per_corner; - parasitics_per_min_max_ = per_min_max; makeParasiticAnalysisPts(); } } @@ -3927,8 +3918,7 @@ Sta::setParasiticAnalysisPts(bool per_corner, void Sta::makeParasiticAnalysisPts() { - corners_->makeParasiticAnalysisPts(parasitics_per_corner_, - parasitics_per_min_max_); + corners_->makeParasiticAnalysisPts(parasitics_per_corner_); } void @@ -3936,7 +3926,6 @@ Sta::reportParasiticAnnotation(bool report_unannotated, const Corner *corner) { ensureGraph(); - findDelays(); sta::reportParasiticAnnotation(report_unannotated, corner, this); } @@ -4225,7 +4214,7 @@ Sta::replaceEquivCellBefore(const Instance *inst, if (to_set) edge->setTimingArcSet(to_set); else - report_->critical(264, "corresponding timing arc set not found in equiv cells"); + report_->critical(1553, "corresponding timing arc set not found in equiv cells"); } } } @@ -4429,7 +4418,7 @@ Sta::connectLoadPinAfter(Vertex *vertex) void Sta::disconnectPinBefore(const Pin *pin) { - parasitics_->disconnectPinBefore(pin); + parasitics_->disconnectPinBefore(pin, network_); sdc_->disconnectPinBefore(pin); sim_->disconnectPinBefore(pin); if (graph_) { @@ -5154,67 +5143,38 @@ Sta::crossesHierarchy(Edge *edge) const //////////////////////////////////////////////////////////////// -class InstanceMaxSlewGreater +static Slew +instMaxSlew(const Instance *inst, + Sta *sta) { -public: - explicit InstanceMaxSlewGreater(const StaState *sta); - bool operator()(const Instance *inst1, - const Instance *inst2) const; - -protected: - Slew instMaxSlew(const Instance *inst) const; - const StaState *sta_; -}; - -InstanceMaxSlewGreater::InstanceMaxSlewGreater(const StaState *sta) : - sta_(sta) -{ -} - -bool -InstanceMaxSlewGreater::operator()(const Instance *inst1, - const Instance *inst2) const -{ - return delayGreater(instMaxSlew(inst1), instMaxSlew(inst2), sta_); -} - -Slew -InstanceMaxSlewGreater::instMaxSlew(const Instance *inst) const -{ - Network *network = sta_->network(); - Graph *graph = sta_->graph(); + Network *network = sta->network(); + Graph *graph = sta->graph(); Slew max_slew = 0.0; InstancePinIterator *pin_iter = network->pinIterator(inst); while (pin_iter->hasNext()) { Pin *pin = pin_iter->next(); if (network->isDriver(pin)) { Vertex *vertex = graph->pinDrvrVertex(pin); - for (RiseFall *rf : RiseFall::range()) { - for (DcalcAnalysisPt *dcalc_ap : sta_->corners()->dcalcAnalysisPts()) { - Slew slew = graph->slew(vertex, rf, dcalc_ap->index()); - if (delayGreater(slew, max_slew, sta_)) - max_slew = slew; - } - } + max_slew = max(max_slew, sta->vertexSlew(vertex, MinMax::max())); } } delete pin_iter; return max_slew; } -SlowDrvrIterator * -Sta::slowDrvrIterator() +InstanceSeq +Sta::slowDrivers(int count) { - InstanceSeq *insts = new InstanceSeq; - LeafInstanceIterator *leaf_iter = network_->leafInstanceIterator(); - while (leaf_iter->hasNext()) { - Instance *leaf = leaf_iter->next(); - insts->push_back(leaf); - } - delete leaf_iter; - - sort(insts, InstanceMaxSlewGreater(this)); - return new SlowDrvrIterator(insts); + findDelays(); + InstanceSeq insts = network_->leafInstances(); + sort(insts, [=] (const Instance *inst1, + const Instance *inst2) { + return delayGreater(instMaxSlew(inst1, this), + instMaxSlew(inst2, this), + this); + }); + insts.resize(count); + return insts; } //////////////////////////////////////////////////////////////// diff --git a/search/StaState.cc b/search/StaState.cc index dba67922..249d2bd9 100644 --- a/search/StaState.cc +++ b/search/StaState.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Tag.cc b/search/Tag.cc index a8ad24ab..b50837f4 100644 --- a/search/Tag.cc +++ b/search/Tag.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/Tag.hh b/search/Tag.hh index 28225c1c..55a27103 100644 --- a/search/Tag.hh +++ b/search/Tag.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/TagGroup.cc b/search/TagGroup.cc index 090515ac..e922d05c 100644 --- a/search/TagGroup.cc +++ b/search/TagGroup.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -294,7 +294,7 @@ TagGroupBldr::copyArrivals(TagGroup *tag_group, } } else - sta_->report()->critical(265, "tag group missing tag"); + sta_->report()->critical(1351, "tag group missing tag"); } } diff --git a/search/TagGroup.hh b/search/TagGroup.hh index 790e7129..ca923bfa 100644 --- a/search/TagGroup.hh +++ b/search/TagGroup.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/VertexVisitor.cc b/search/VertexVisitor.cc index ca68e977..fc201706 100644 --- a/search/VertexVisitor.cc +++ b/search/VertexVisitor.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/VisitPathEnds.cc b/search/VisitPathEnds.cc index b21aa364..d72d3972 100644 --- a/search/VisitPathEnds.cc +++ b/search/VisitPathEnds.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -97,7 +97,7 @@ VisitPathEnds::visitClkedPathEnds(const Pin *pin, // Ignore segment startpoint paths. && (!is_segment_start || !tag->isSegmentStart())) { - // set_output_delay to timing check has precidence. + // set_output_delay to timing check has precedence. if (sdc_->hasOutputDelay(pin)) visitOutputDelayEnd(pin, path, end_rf, path_ap, filtered, visitor, is_constrained); diff --git a/search/VisitPathGroupVertices.cc b/search/VisitPathGroupVertices.cc index f003690f..2b2ebdaa 100644 --- a/search/VisitPathGroupVertices.cc +++ b/search/VisitPathGroupVertices.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/VisitPathGroupVertices.hh b/search/VisitPathGroupVertices.hh index 0dc8c914..bf93cea4 100644 --- a/search/VisitPathGroupVertices.hh +++ b/search/VisitPathGroupVertices.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/WorstSlack.cc b/search/WorstSlack.cc index 2ab655a5..611096ac 100644 --- a/search/WorstSlack.cc +++ b/search/WorstSlack.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/WorstSlack.hh b/search/WorstSlack.hh index 1c257ed7..ebe5729c 100644 --- a/search/WorstSlack.hh +++ b/search/WorstSlack.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/search/WritePathSpice.cc b/search/WritePathSpice.cc index 55b763b1..608c32d9 100644 --- a/search/WritePathSpice.cc +++ b/search/WritePathSpice.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -72,6 +72,7 @@ public: StdStringSet *off_path_pin_names, const char *power_name, const char *gnd_name, + bool measure_stmts, const StaState *sta); ~WritePathSpice(); void writeSpice(); @@ -99,8 +100,7 @@ private: DcalcAPIndex dcalc_ap_index); void writeStageParasitics(Stage stage); void writeStageParasiticNetwork(Pin *drvr_pin, - Parasitic *parasitic, - ParasiticAnalysisPt *parasitic_ap); + Parasitic *parasitic); void writeStagePiElmore(Pin *drvr_pin, Parasitic *parasitic); void writeNullParasitics(Pin *drvr_pin); @@ -225,6 +225,7 @@ private: StdStringSet *off_path_pin_names_; const char *power_name_; const char *gnd_name_; + bool measure_stmts_; ofstream spice_stream_; PathExpanded path_expanded_; @@ -281,11 +282,15 @@ writePathSpice(Path *path, StdStringSet *off_path_pin_names, const char *power_name, const char *gnd_name, + bool measure_stmts, StaState *sta) { + if (sta->network()->defaultLibertyLibrary() == nullptr) + sta->report()->error(1600, "No liberty libraries found,"); WritePathSpice writer(path, spice_filename, subckt_filename, lib_subckt_filename, model_filename, - off_path_pin_names, power_name, gnd_name, sta); + off_path_pin_names, power_name, gnd_name, + measure_stmts, sta); writer.writeSpice(); } @@ -297,6 +302,7 @@ WritePathSpice::WritePathSpice(Path *path, StdStringSet *off_path_pin_names, const char *power_name, const char *gnd_name, + bool measure_stmts, const StaState *sta) : StaState(sta), path_(path), @@ -307,13 +313,14 @@ WritePathSpice::WritePathSpice(Path *path, off_path_pin_names_(off_path_pin_names), power_name_(power_name), gnd_name_(gnd_name), + measure_stmts_(measure_stmts), path_expanded_(sta), net_name_(nullptr), default_library_(network_->defaultLibertyLibrary()), short_ckt_resistance_(.0001), clk_cycle_count_(3) { - bool exists; + bool exists = false; default_library_->supplyVoltage(power_name_, power_voltage_, exists); if (!exists) { DcalcAnalysisPt *dcalc_ap = path_->dcalcAnalysisPt(this); @@ -344,7 +351,8 @@ WritePathSpice::writeSpice() writeHeader(); writePrintStmt(); writeStageInstances(); - writeMeasureStmts(); + if (measure_stmts_) + writeMeasureStmts(); writeInputSource(); writeStageSubckts(); streamPrint(spice_stream_, ".end\n"); @@ -379,8 +387,6 @@ WritePathSpice::writeHeader() start_path->transition(this)->asString(), network_->pathName(path_->pin(this)), path_->transition(this)->asString()); - float temp = pvt->temperature(); - streamPrint(spice_stream_, ".temp %.1f\n", temp); streamPrint(spice_stream_, ".include \"%s\"\n", model_filename_); string subckt_filename_stem = filenameStem(subckt_filename_); streamPrint(spice_stream_, ".include \"%s\"\n", subckt_filename_stem.c_str()); @@ -389,6 +395,7 @@ WritePathSpice::writeHeader() float time_step = 1e-13; streamPrint(spice_stream_, ".tran %.3g %.3g\n\n", time_step, max_time); + // Suppress printing model parameters. streamPrint(spice_stream_, ".options nomod\n"); } @@ -505,14 +512,14 @@ WritePathSpice::pgPortVoltage(LibertyPgPort *pg_port) else if (stringEqual(voltage_name, gnd_name_)) voltage = gnd_voltage_; else - report_->error(24, "pg_pin %s/%s voltage %s not found,", + report_->error(1601 , "pg_pin %s/%s voltage %s not found,", pg_port->cell()->name(), pg_port->name(), voltage_name); } } else - report_->error(25, "Liberty pg_port %s/%s missing voltage_name attribute,", + report_->error(1602, "Liberty pg_port %s/%s missing voltage_name attribute,", pg_port->cell()->name(), pg_port->name()); return voltage; @@ -1091,7 +1098,7 @@ WritePathSpice::writeVoltageSource(LibertyCell *cell, if (pg_port) voltage = pgPortVoltage(pg_port); else - report_->error(26, "%s pg_port %s not found,", + report_->error(1603, "%s pg_port %s not found,", cell->name(), pg_port_name); @@ -1146,7 +1153,7 @@ WritePathSpice::regPortValues(Stage stage, dcalc_ap_index = drvr_path->dcalcAnalysisPt(this)->index(); } else - report_->error(27, "no register/latch found for path from %s to %s,", + report_->error(1604, "no register/latch found for path from %s to %s,", stageGateInputPort(stage)->name(), stageDrvrPort(stage)->name()); } @@ -1290,54 +1297,6 @@ WritePathSpice::onePort(FuncExpr *expr) } } -// Sort predicate for ParasiticDevices. -class ParasiticDeviceLess -{ -public: - ParasiticDeviceLess(Parasitics *parasitics) : - parasitics_(parasitics) - { - } - bool operator()(const ParasiticDevice *device1, - const ParasiticDevice *device2) const - { - ParasiticNode *node1 = parasitics_->node1(device1); - ParasiticNode *node2 = parasitics_->node1(device2); - const char *name1 = parasitics_->name(node1); - const char *name2 = parasitics_->name(node2); - if (stringEq(name1, name2)) { - ParasiticNode *node12 = parasitics_->node2(device1); - ParasiticNode *node22 = parasitics_->node2(device2); - const char *name12 = parasitics_->name(node12); - const char *name22 = parasitics_->name(node22); - return stringLess(name12, name22); - } - else - return stringLess(name1, name2); - } -private: - Parasitics *parasitics_; -}; - -// Sort predicate for ParasiticDevices. -class ParasiticNodeLess -{ -public: - ParasiticNodeLess(Parasitics *parasitics) : - parasitics_(parasitics) - { - } - bool operator()(const ParasiticNode *node1, - const ParasiticNode *node2) const - { - const char *name1 = parasitics_->name(node1); - const char *name2 = parasitics_->name(node2); - return stringLess(name1, name2); - } -private: - Parasitics *parasitics_; -}; - void WritePathSpice::writeStageParasitics(Stage stage) { @@ -1353,7 +1312,7 @@ WritePathSpice::writeStageParasitics(Stage stage) ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); Parasitic *parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); if (parasitic) - writeStageParasiticNetwork(drvr_pin, parasitic, parasitic_ap); + writeStageParasiticNetwork(drvr_pin, parasitic); else { const RiseFall *drvr_rf = drvr_path->transition(this); parasitic = parasitics_->findPiElmore(drvr_pin, drvr_rf, parasitic_ap); @@ -1368,51 +1327,51 @@ WritePathSpice::writeStageParasitics(Stage stage) void WritePathSpice::writeStageParasiticNetwork(Pin *drvr_pin, - Parasitic *parasitic, - ParasiticAnalysisPt *parasitic_ap) + Parasitic *parasitic) { Set reachable_pins; int res_index = 1; int cap_index = 1; - // Sort devices for consistent regression results. - Vector devices; - ParasiticDeviceIterator *device_iter1 = parasitics_->deviceIterator(parasitic); - while (device_iter1->hasNext()) { - ParasiticDevice *device = device_iter1->next(); - devices.push_back(device); + // Sort resistors for consistent regression results. + ParasiticResistorSeq resistors = parasitics_->resistors(parasitic); + sort(resistors.begin(), resistors.end(), + [=] (const ParasiticResistor *r1, + const ParasiticResistor *r2) { + return parasitics_->id(r1) < parasitics_->id(r2); + }); + for (ParasiticResistor *resistor : resistors) { + float resistance = parasitics_->value(resistor); + ParasiticNode *node1 = parasitics_->node1(resistor); + ParasiticNode *node2 = parasitics_->node2(resistor); + streamPrint(spice_stream_, "R%d %s %s %.3e\n", + res_index, + nodeName(node1), + nodeName(node2), + resistance); + res_index++; + + const Pin *pin1 = parasitics_->pin(node1); + reachable_pins.insert(pin1); + const Pin *pin2 = parasitics_->pin(node2); + reachable_pins.insert(pin2); } - delete device_iter1; - sort(devices, ParasiticDeviceLess(parasitics_)); - - for (ParasiticDevice *device : devices) { - float resistance = parasitics_->value(device, parasitic_ap); - if (parasitics_->isResistor(device)) { - ParasiticNode *node1 = parasitics_->node1(device); - ParasiticNode *node2 = parasitics_->node2(device); - streamPrint(spice_stream_, "R%d %s %s %.3e\n", - res_index, - nodeName(node1), - nodeName(node2), - resistance); - res_index++; - - const Pin *pin1 = parasitics_->connectionPin(node1); - reachable_pins.insert(pin1); - const Pin *pin2 = parasitics_->connectionPin(node2); - reachable_pins.insert(pin2); - } - else if (parasitics_->isCouplingCap(device)) { - // Ground coupling caps for now. - ParasiticNode *node1 = parasitics_->node1(device); - float cap = parasitics_->value(device, parasitic_ap); - streamPrint(spice_stream_, "C%d %s 0 %.3e\n", - cap_index, - nodeName(node1), - cap); - cap_index++; - } + ParasiticCapacitorSeq capacitors = parasitics_->capacitors(parasitic); + sort(capacitors.begin(), capacitors.end(), + [=] (const ParasiticCapacitor *c1, + const ParasiticCapacitor *c2) { + return parasitics_->id(c1) < parasitics_->id(c2); + }); + for (ParasiticCapacitor *capacitor : capacitors) { + // Ground coupling caps for now. + ParasiticNode *node1 = parasitics_->node1(capacitor); + float cap = parasitics_->value(capacitor); + streamPrint(spice_stream_, "C%d %s 0 %.3e\n", + cap_index, + nodeName(node1), + cap); + cap_index++; } // Add resistors from drvr to load for missing parasitic connections. @@ -1434,17 +1393,17 @@ WritePathSpice::writeStageParasiticNetwork(Pin *drvr_pin, delete pin_iter; // Sort node capacitors for consistent regression results. - Vector nodes; - ParasiticNodeIterator *node_iter = parasitics_->nodeIterator(parasitic); - while (node_iter->hasNext()) { - ParasiticNode *node = node_iter->next(); - nodes.push_back(node); - } - - sort(nodes, ParasiticNodeLess(parasitics_)); + ParasiticNodeSeq nodes = parasitics_->nodes(parasitic); + sort(nodes.begin(), nodes.end(), + [=] (const ParasiticNode *node1, + const ParasiticNode *node2) { + const char *name1 = parasitics_->name(node1); + const char *name2 = parasitics_->name(node2); + return stringLess(name1, name2); + }); for (ParasiticNode *node : nodes) { - float cap = parasitics_->nodeGndCap(node, parasitic_ap); + float cap = parasitics_->nodeGndCap(node); // Spice has a cow over zero value caps. if (cap > 0.0) { streamPrint(spice_stream_, "C%d %s 0 %.3e\n", @@ -1454,7 +1413,6 @@ WritePathSpice::writeStageParasiticNetwork(Pin *drvr_pin, cap_index++; } } - delete node_iter; } void @@ -1548,7 +1506,7 @@ WritePathSpice::initNodeMap(const char *net_name) const char * WritePathSpice::nodeName(ParasiticNode *node) { - const Pin *pin = parasitics_->connectionPin(node); + const Pin *pin = parasitics_->pin(node); if (pin) return parasitics_->name(node); else { @@ -1612,7 +1570,7 @@ WritePathSpice::writeSubckts() missing_cells += "\n"; missing_cells += cell_name; } - report_->error(28, "The subkct file %s is missing definitions for %s", + report_->error(1605, "The subkct file %s is missing definitions for %s", lib_subckt_filename_, missing_cells.c_str()); } @@ -1710,7 +1668,7 @@ WritePathSpice::recordSpicePortNames(const char *cell_name, && pg_port == nullptr && !stringEqual(port_name, power_name_) && !stringEqual(port_name, gnd_name_)) - report_->error(29, "subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground.", + report_->error(1606, "subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground.", cell_name, port_name); spice_port_names->push_back(port_name); } diff --git a/tcl/CmdArgs.tcl b/tcl/CmdArgs.tcl index c19df5a1..a53562d5 100644 --- a/tcl/CmdArgs.tcl +++ b/tcl/CmdArgs.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -105,7 +105,7 @@ proc get_object_args { objects clks_var libcells_var libports_var \ && $object_type == "TimingArcSet" } { lappend timing_arc_sets $obj } else { - sta_error 467 "unsupported object type $object_type." + sta_error 100 "unsupported object type $object_type." } } elseif { $obj != {} } { # Check for implicit arg. @@ -163,7 +163,7 @@ proc get_object_args { objects clks_var libcells_var libports_var \ if { $matches != {} } { set nets [concat $nets $matches] } else { - sta_warn 305 "object '$obj' not found." + sta_warn 101 "object '$obj' not found." } } } @@ -392,6 +392,7 @@ proc get_ports_or_pins { pattern } { ################################################################ +# -corner keyword is optional. # If -corner keyword is missing: # one corner: return default # multiple corners: error @@ -402,19 +403,18 @@ proc parse_corner { keys_var } { set corner_name $keys(-corner) set corner [find_corner $corner_name] if { $corner == "NULL" } { - sta_error 468 "$corner_name is not the name of process corner." + sta_error 102 "$corner_name is not the name of process corner." } else { return $corner } } elseif { [multi_corner] } { - sta_error 469 "-corner keyword required with multi-corner analysis." + sta_error 103 "-corner keyword required with multi-corner analysis." } else { return [cmd_corner] } } # -corner keyword is required. -# Assumes caller checks for existence of -corner keyword arg. proc parse_corner_required { keys_var } { upvar 1 $keys_var keys @@ -422,12 +422,12 @@ proc parse_corner_required { keys_var } { set corner_name $keys(-corner) set corner [find_corner $corner_name] if { $corner == "NULL" } { - sta_error 470 "$corner_name is not the name of process corner." + sta_error 104 "$corner_name is not the name of process corner." } else { return $corner } } else { - sta_error 471 "missing -corner arg." + sta_error 105 "missing -corner arg." } } @@ -438,7 +438,7 @@ proc parse_corner_or_default { keys_var } { set corner_name $keys(-corner) set corner [find_corner $corner_name] if { $corner == "NULL" } { - sta_error 472 "$corner_name is not the name of process corner." + sta_error 106 "$corner_name is not the name of process corner." } else { return $corner } @@ -455,7 +455,7 @@ proc parse_corner_or_all { keys_var } { set corner_name $keys(-corner) set corner [find_corner $corner_name] if { $corner == "NULL" } { - sta_error 473 "$corner_name is not the name of process corner." + sta_error 107 "$corner_name is not the name of process corner." } else { return $corner } @@ -480,7 +480,7 @@ proc parse_rise_fall_flags { flags_var } { proc parse_min_max_flags { flags_var } { upvar 1 $flags_var flags if { [info exists flags(-min)] && [info exists flags(-max)] } { - sta_error 474 "both -min and -max specified." + sta_error 108 "both -min and -max specified." } elseif { [info exists flags(-min)] && ![info exists flags(-max)] } { return "min" } elseif { [info exists flags(-max)] && ![info exists flags(-min)] } { @@ -494,7 +494,7 @@ proc parse_min_max_flags { flags_var } { proc parse_min_max_all_flags { flags_var } { upvar 1 $flags_var flags if { [info exists flags(-min)] && [info exists flags(-max)] } { - sta_error 475 "both -min and -max specified." + sta_error 109 "both -min and -max specified." } elseif { [info exists flags(-min)] && ![info exists flags(-max)] } { return "min" } elseif { [info exists flags(-max)] && ![info exists flags(-min)] } { @@ -521,20 +521,20 @@ proc parse_min_max_all_check_flags { flags_var } { proc parse_early_late_flags { flags_var } { upvar 1 $flags_var flags if { [info exists flags(-early)] && [info exists flags(-late)] } { - sta_error 476 "only one of -early and -late can be specified." + sta_error 110 "only one of -early and -late can be specified." } elseif { [info exists flags(-early)] } { return "min" } elseif { [info exists flags(-late)] } { return "max" } else { - sta_error 477 "-early or -late must be specified." + sta_error 111 "-early or -late must be specified." } } proc parse_early_late_all_flags { flags_var } { upvar 1 $flags_var flags if { [info exists flags(-early)] && [info exists flags(-late)] } { - sta_error 478 "both -early and -late specified." + sta_error 112 "both -early and -late specified." } elseif { [info exists flags(-early)] && ![info exists flags(-late)] } { return "min" } elseif { [info exists flags(-late)] && ![info exists flags(-early)] } { @@ -549,18 +549,18 @@ proc parse_early_late_all_flags { flags_var } { proc get_liberty_error { arg_name arg } { set lib "NULL" if {[llength $arg] > 1} { - sta_error 479 "$arg_name must be a single library." + sta_error 113 "$arg_name must be a single library." } elseif { [is_object $arg] } { set object_type [object_type $arg] if { $object_type == "LibertyLibrary" } { set lib $arg } else { - sta_error 480 "$arg_name type '$object_type' is not a library." + sta_error 114 "$arg_name type '$object_type' is not a library." } } else { set lib [find_liberty $arg] if { $lib == "NULL" } { - sta_error 481 "library '$arg' not found." + sta_error 115 "library '$arg' not found." } } return $lib @@ -577,13 +577,13 @@ proc get_lib_cell_error { arg_name arg } { proc get_lib_cell_arg { arg_name arg error_proc } { set lib_cell "NULL" if { [llength $arg] > 1 } { - sta_error 482 "$arg_name must be a single lib cell." + sta_error 116 "$arg_name must be a single lib cell." } elseif { [is_object $arg] } { set object_type [object_type $arg] if { $object_type == "LibertyCell" } { set lib_cell $arg } else { - $error_proc 700 "$arg_name type '$object_type' is not a liberty cell." + $error_proc 116 "$arg_name type '$object_type' is not a liberty cell." } # Parse library_name/cell_name. } elseif {[regexp [cell_regexp] $arg ignore lib_name cell_name]} { @@ -591,15 +591,15 @@ proc get_lib_cell_arg { arg_name arg error_proc } { if { $library != "NULL" } { set lib_cell [$library find_liberty_cell $cell_name] if { $lib_cell == "NULL" } { - $error_proc 701 "liberty cell '$arg' not found." + $error_proc 117 "liberty cell '$arg' not found." } } else { - $error_proc 702 "library '$lib_name' not found." + $error_proc 118 "library '$lib_name' not found." } } else { set lib_cell [find_liberty_cell $arg] if { $lib_cell == "NULL" } { - $error_proc 703 "liberty cell '$arg' not found." + $error_proc 119 "liberty cell '$arg' not found." } } return $lib_cell @@ -619,7 +619,7 @@ proc get_lib_cells_arg { arg_name arglist error_proc } { if { $object_type == "LibertyCell" } { lappend lib_cells $arg } else { - $error_proc 306 "unsupported object type $object_type." + $error_proc 120 "unsupported object type $object_type." } } elseif { $arg != {} } { set arg_lib_cells [get_lib_cells1 $arg $error_proc] @@ -645,7 +645,7 @@ proc get_lib_cells1 { patterns error_proc } { # Allow wildcards in the library name (incompatible). set libs [get_libs -quiet $lib_name] if { $libs == {} } { - $error_proc 375 "library '$lib_name' not found." + $error_proc 121 "library '$lib_name' not found." } else { foreach lib $libs { set matches [$lib find_liberty_cells_matching $cell_pattern 0 0] @@ -654,7 +654,7 @@ proc get_lib_cells1 { patterns error_proc } { } } if { $cells == {} } { - $error_proc 376 "cell '$cell_pattern' not found." + $error_proc 122 "cell '$cell_pattern' not found." } } } @@ -664,18 +664,18 @@ proc get_lib_cells1 { patterns error_proc } { proc get_instance_error { arg_name arg } { set inst "NULL" if {[llength $arg] > 1} { - sta_error 483 "$arg_name must be a single instance." + sta_error 123 "$arg_name must be a single instance." } elseif { [is_object $arg] } { set object_type [object_type $arg] if { $object_type == "Instance" } { set inst $arg } else { - sta_error 484 "$arg_name type '$object_type' is not an instance." + sta_error 124 "$arg_name type '$object_type' is not an instance." } } else { set inst [find_instance $arg] if { $inst == "NULL" } { - sta_error 485 "instance '$arg' not found." + sta_error 125 "instance '$arg' not found." } } return $inst @@ -694,14 +694,14 @@ proc get_instances_error { arg_name arglist } { if { $object_type == "Instance" } { lappend insts $arg } else { - sta_error 486 "$arg_name type '$object_type' is not an instance." + sta_error 126 "$arg_name type '$object_type' is not an instance." } } elseif { $arg != {} } { set arg_insts [get_cells -quiet $arg] if { $arg_insts != {} } { set insts [concat $insts $arg_insts] } else { - sta_error 487 "instance '$arg' not found." + sta_error 127 "instance '$arg' not found." } } } @@ -719,7 +719,7 @@ proc get_port_pin_error { arg_name arg } { proc get_port_pin_arg { arg_name arg warn_error } { set pin "NULL" if {[llength $arg] > 1} { - sta_warn_error 307 $warn_error "$arg_name must be a single port or pin." + sta_warn_error 128 $warn_error "$arg_name must be a single port or pin." } elseif { [is_object $arg] } { set object_type [object_type $arg] if { $object_type == "Pin" } { @@ -728,7 +728,7 @@ proc get_port_pin_arg { arg_name arg warn_error } { # Explicit port arg - convert to pin. set pin [find_pin [get_name $arg]] } else { - sta_warn_error 308 $warn_error "$arg_name type '$object_type' is not a pin or port." + sta_warn_error 129 $warn_error "$arg_name type '$object_type' is not a pin or port." } } else { set top_instance [top_instance] @@ -740,7 +740,7 @@ proc get_port_pin_arg { arg_name arg warn_error } { set pin [$top_instance find_pin [get_name $port]] } if { $pin == "NULL" } { - sta_warn_error 309 $warn_error "pin $arg not found." + sta_warn_error 130 $warn_error "pin $arg not found." } } return $pin @@ -762,14 +762,14 @@ proc get_port_pins_error { arg_name arglist } { # Convert port to pin. lappend pins [find_pin [get_name $arg]] } else { - sta_error 488 "$arg_name type '$object_type' is not a pin or port." + sta_error 131 "$arg_name type '$object_type' is not a pin or port." } } elseif { $arg != {} } { set arg_pins [get_ports_or_pins $arg] if { $arg_pins != {} } { set pins [concat $pins $arg_pins] } else { - sta_error 489 "pin '$arg' not found." + sta_error 132 "pin '$arg' not found." } } } @@ -789,7 +789,7 @@ proc get_ports_error { arg_name arglist } { if { $object_type == "Port" } { lappend ports $arg } else { - sta_error 490 "$arg_name type '$object_type' is not a port." + sta_error 133 "$arg_name type '$object_type' is not a port." } } elseif { $arg != {} } { set arg_ports [get_ports $arg] @@ -812,18 +812,18 @@ proc get_pin_warn { arg_name arg } { proc get_pin_arg { arg_name arg warn_error } { set pin "NULL" if {[llength $arg] > 1} { - sta_warn_error 310 $warn_error "$arg_name must be a single pin." + sta_warn_error 134 $warn_error "$arg_name must be a single pin." } elseif { [is_object $arg] } { set object_type [object_type $arg] if { $object_type == "Pin" } { set pin $arg } else { - sta_warn_error 311 $warn_error "$arg_name type '$object_type' is not a pin." + sta_warn_error 135 $warn_error "$arg_name type '$object_type' is not a pin." } } else { set pin [find_pin $arg] if { $pin == "NULL" } { - sta_warn_error 312 $warn_error "$arg_name pin $arg not found." + sta_warn_error 136 $warn_error "$arg_name pin $arg not found." } } return $pin @@ -840,18 +840,18 @@ proc get_clock_error { arg_name arg } { proc get_clock_arg { arg_name arg error_proc } { set clk "NULL" if {[llength $arg] > 1} { - $error_proc 597 "$arg_name arg must be a single clock, not a list." + $error_proc 137 "$arg_name arg must be a single clock, not a list." } elseif { [is_object $arg] } { set object_type [object_type $arg] if { $object_type == "Clock" } { set clk $arg } else { - $error_proc 598 "$arg_name arg value is a $object_type, not a clock." + $error_proc 138 "$arg_name arg value is a $object_type, not a clock." } } elseif { $arg != {} } { set clk [find_clock $arg] if { $clk == "NULL" } { - $error_proc 599 "$arg_name arg '$arg' clock not found." + $error_proc 138 "$arg_name arg '$arg' clock not found." } } return $clk @@ -870,7 +870,7 @@ proc get_clocks_warn { arg_name arglist } { if { $object_type == "Clock" } { lappend clks $arg } else { - sta_warn 313 "unsupported object type $object_type." + sta_warn 139 "unsupported object type $object_type." } } elseif { $arg != {} } { set arg_clocks [get_clocks $arg] @@ -885,18 +885,18 @@ proc get_clocks_warn { arg_name arglist } { proc get_net_arg { arg_name arg } { set net "NULL" if {[llength $arg] > 1} { - sta_warn 314 "$arg_name must be a single net." + sta_warn 140 "$arg_name must be a single net." } elseif { [is_object $arg] } { set object_type [object_type $arg] if { $object_type == "Net" } { set net $arg } else { - sta_warn 315 "$arg_name '$object_type' is not a net." + sta_warn 141 "$arg_name '$object_type' is not a net." } } else { set net [find_net $arg] if { $net == "NULL" } { - sta_warn 316 "$arg_name '$arg' not found." + sta_warn 143 "$arg_name '$arg' not found." } } return $net @@ -915,7 +915,7 @@ proc get_nets_arg { arg_name arglist } { if { $object_type == "Net" } { lappend nets $arg } else { - sta_warn 317 "unsupported object type $object_type." + sta_warn 142 "unsupported object type $object_type." } } elseif { $arg != {} } { set arg_nets [get_nets $arg] diff --git a/tcl/CmdUtil.tcl b/tcl/CmdUtil.tcl index 8fe51a62..324b2ead 100644 --- a/tcl/CmdUtil.tcl +++ b/tcl/CmdUtil.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -41,7 +41,7 @@ proc_redirect help { show_cmd_args $cmd } } else { - sta_warn 300 "no commands match '$pattern'." + sta_warn 160 "no commands match '$pattern'." } } @@ -86,9 +86,9 @@ proc cmd_usage_error { cmd } { variable cmd_args if [info exists cmd_args($cmd)] { - sta_error 404 "Usage: $cmd $cmd_args($cmd)" + sta_error 161 "Usage: $cmd $cmd_args($cmd)" } else { - sta_error 405 "Usage: $cmd argument error" + sta_error 162 "Usage: $cmd argument error" } } @@ -158,7 +158,7 @@ proc set_unit_values { unit key unit_name key_var } { set scale [unit_prefix_scale $unit $prefix] set_cmd_unit_scale $unit $scale } else { - sta_error 515 "unknown $unit unit '$suffix'." + sta_error 163 "unknown $unit unit '$suffix'." } } if [info exists keys(-digits)] { @@ -206,7 +206,7 @@ proc delete_objects_from_list_cmd { list objects } { } elseif {$list_type == "LibertyPort"} { set obj [get_lib_pins $obj] } else { - sta_error 439 "unsupported object type $list_type." + sta_error 164 "unsupported object type $list_type." } } set index [lsearch $list $obj] @@ -223,7 +223,7 @@ proc set_cmd_namespace { namespc } { if { $namespc == "sdc" || $namespc == "sta" } { set_cmd_namespace_cmd $namespc } else { - sta_error 589 "unknown namespace $namespc." + sta_error 165 "unknown namespace $namespc." } } diff --git a/tcl/Exception.i b/tcl/Exception.i index de5d9d68..1f4cfdc3 100644 --- a/tcl/Exception.i +++ b/tcl/Exception.i @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/tcl/Graph.tcl b/tcl/Graph.tcl index 6b9e7dda..72c649c0 100644 --- a/tcl/Graph.tcl +++ b/tcl/Graph.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 diff --git a/tcl/Init.tcl b/tcl/Init.tcl index 9f9927ec..4c2df17c 100644 --- a/tcl/Init.tcl +++ b/tcl/Init.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 diff --git a/tcl/Liberty.tcl b/tcl/Liberty.tcl index 9c5ef0f7..6f48dcb1 100644 --- a/tcl/Liberty.tcl +++ b/tcl/Liberty.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -19,19 +19,16 @@ namespace eval sta { define_cmd_args "read_liberty" \ - {[-corner corner] [-min] [-max] [-no_latch_infer] filename} + {[-corner corner] [-min] [-max] [-infer_latches] filename} proc_redirect read_liberty { parse_key_args "read_liberty" args keys {-corner} \ - flags {-min -max -no_latch_infer -infer_latches} + flags {-min -max -infer_latches} check_argc_eq1 "read_liberty" $args set filename [file nativename [lindex $args 0]] set corner [parse_corner keys] set min_max [parse_min_max_all_flags flags] - if { [info exists flags(-no_latch_infer)] } { - sta_warn 625 "-no_latch_infer is deprecated." - } set infer_latches [info exists flags(-infer_latches)] read_liberty_cmd $filename $corner $min_max $infer_latches } diff --git a/tcl/Link.tcl b/tcl/Link.tcl index 05c87625..39912ddf 100644 --- a/tcl/Link.tcl +++ b/tcl/Link.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -31,7 +31,7 @@ proc_redirect link_design { } if { $top_cell_name == "" } { if { $current_design_name == "" } { - sta_error 593 "missing top_cell_name argument and no current_design." + sta_error 220 "missing top_cell_name argument and no current_design." return 0 } else { set top_cell_name $current_design_name diff --git a/tcl/Network.tcl b/tcl/Network.tcl index 83ece34e..b6f31337 100644 --- a/tcl/Network.tcl +++ b/tcl/Network.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -25,18 +25,22 @@ proc_redirect report_instance { parse_key_args "report_instance" args keys {} flags {-connections -verbose} check_argc_eq1 "report_instance" $args - set connections [info exists flags(-connections)] - set verbose [info exists flags(-verbose)] + if { [info exists flags(-connections)] } { + sta_warn 233 "report_instance -connections is deprecated." + } + if { [info exists flags(-verbose)] } { + sta_warn 234 "report_instance -verbose is deprecated." + } set instance_path [lindex $args 0] set instance [find_instance $instance_path] if { $instance != "NULL" } { - report_instance1 $instance $connections $verbose + report_instance1 $instance } else { - sta_error 590 "instance $instance_path not found." + sta_error 230 "instance $instance_path not found." } } -proc report_instance1 { instance connections verbose } { +proc report_instance1 { instance } { if { $instance == [top_instance] } { set inst_name "top" } else { @@ -47,24 +51,17 @@ proc report_instance1 { instance connections verbose } { report_line " Cell: [get_name $cell]" report_line " Library: [get_name [$cell library]]" report_line " Path cells: [instance_cell_path $instance]" - if { $connections } { - report_instance_pins $instance $verbose - } - if { $verbose } { - report_instance_children_ $instance - } + report_instance_pins $instance + report_instance_children_ $instance } -proc report_instance_pins { instance verbose } { - report_instance_pins1 $instance $verbose \ - " Input pins:" 0 {"input" "bidirect"} - report_instance_pins1 $instance $verbose \ - " Output pins:" 0 {"output" "bidirect" "tristate"} - report_instance_pins1 $instance $verbose \ - " Other pins:" 1 {"internal" "power" "ground" "unknown"} +proc report_instance_pins { instance } { + report_instance_pins1 $instance " Input pins:" 0 {"input" "bidirect"} + report_instance_pins1 $instance " Output pins:" 0 {"output" "bidirect" "tristate"} + report_instance_pins1 $instance " Other pins:" 1 {"internal" "power" "ground" "unknown"} } -proc report_instance_pins1 {instance verbose header header_optional dirs} { +proc report_instance_pins1 {instance header header_optional dirs} { set header_shown 0 if { !$header_optional } { report_line $header @@ -79,13 +76,13 @@ proc report_instance_pins1 {instance verbose header header_optional dirs} { report_line $header set header_shown 1 } - report_instance_pin $pin $verbose + report_instance_pin $pin } } $iter finish } -proc report_instance_pin { pin verbose } { +proc report_instance_pin { pin } { set net [$pin net] if { $net == "NULL" } { set net_name "(unconnected)" @@ -93,18 +90,6 @@ proc report_instance_pin { pin verbose } { set net_name [get_full_name [$net highest_connected_net]] } report_line " [$pin port_name] [pin_direction $pin] $net_name" - if { $verbose && $net != "NULL" } { - set pins [net_connected_pins_sorted $net] - foreach pin $pins { - if [$pin is_load] { - if [$pin is_top_level_port] { - report_line " [get_full_name $pin] [pin_direction $pin] port" - } else { - report_line " [get_full_name $pin] [pin_direction $pin]" - } - } - } - } } # Concatenate the cell names of the instance parents. @@ -186,9 +171,8 @@ proc report_lib_cell_ { cell corner } { ################################################################ -define_cmd_args "report_net" \ - {[-connections] [-verbose] [-corner corner] [-digits digits] [-hier_pins]\ - net_path [> filename] [>> filename]} +define_cmd_args "report_net" {[-corner corner] [-digits digits]\ + net_path [> filename] [>> filename]} # -hpins to show hierarchical pins proc_redirect report_net { @@ -198,49 +182,49 @@ proc_redirect report_net { flags {-connections -verbose -hier_pins} check_argc_eq1 "report_net" $args + if { [info exists flags(-connections)] } { + sta_warn 235 "report_net -connections is deprecated." + } + if { [info exists flags(-verbose)] } { + sta_warn 236 "report_net -verbose is deprecated." + } + if { [info exists flags(-hier_pins)] } { + sta_warn 237 "report_net -hier_pins is deprecated." + } + set corner [parse_corner_or_all keys] set digits $sta_report_default_digits if { [info exists keys(-digits)] } { set digits $keys(-digits) } - set connections [info exists flags(-connections)] - set verbose [info exists flags(-verbose)] - set hier_pins [info exists flags(-hier_pins)] set net_path [lindex $args 0] set net [find_net $net_path] if { $net != "NULL" } { - report_net1 $net $connections $verbose $hier_pins $corner $digits + report_net1 $net $corner $digits } else { set pin [find_pin $net_path] if { $pin != "NULL" } { set net [$pin net] if { $net != "NULL" } { - report_net1 $net $connections $verbose $hier_pins $corner $digits + report_net1 $net $corner $digits } else { - sta_error 591 "net $net_path not found." + sta_error 231 "net $net_path not found." } } else { - sta_error 592 "net $net_path not found." + sta_error 232 "net $net_path not found." } } } -proc report_net1 { net connections verbose hier_pins corner digits } { +proc report_net1 { net corner digits } { report_line "Net [get_full_name $net]" - if {$connections} { - set pins [net_connected_pins_sorted $net] - if {$verbose} { - report_net_caps $net $pins $corner $digits - } - report_net_pins $pins "Driver pins" "is_driver" $verbose $corner $digits - report_net_pins $pins "Load pins" "is_load" $verbose $corner $digits - if {$hier_pins} { - report_net_pins $pins "Hierarchical pins" "is_hierarchical" \ - $verbose $corner $digits - } - report_net_other_pins $pins $verbose $corner $digits - } + set pins [net_connected_pins_sorted $net] + report_net_caps $net $pins $corner $digits + report_net_pins $pins "Driver pins" "is_driver" $corner $digits + report_net_pins $pins "Load pins" "is_load" $corner $digits + report_net_pins $pins "Hierarchical pins" "is_hierarchical" $corner $digits + report_net_other_pins $pins $corner $digits } proc net_connected_pins_sorted { net } { @@ -286,7 +270,7 @@ proc report_net_cap { net caption cap_msg corner digits } { report_line " $caption capacitance: [capacitance_range_str $cap_min $cap_max $digits]" } -proc report_net_pins { pins header pin_pred verbose corner digits } { +proc report_net_pins { pins header pin_pred corner digits } { set found 0 foreach pin $pins { if {[$pin $pin_pred]} { @@ -294,7 +278,7 @@ proc report_net_pins { pins header pin_pred verbose corner digits } { report_line $header set found 1 } - report_net_pin $pin $verbose $corner $digits + report_net_pin $pin $corner $digits } } if { $found } { @@ -302,7 +286,7 @@ proc report_net_pins { pins header pin_pred verbose corner digits } { } } -proc report_net_other_pins { pins verbose corner digits } { +proc report_net_other_pins { pins corner digits } { set header 0 foreach pin $pins { if { !([$pin is_driver] || [$pin is_load] || [$pin is_hierarchical]) } { @@ -311,39 +295,36 @@ proc report_net_other_pins { pins verbose corner digits } { report_line "Other pins" set header 1 } - report_net_pin $pin $verbose $corner $digits + report_net_pin $pin $corner $digits } } } -proc report_net_pin { pin verbose corner digits } { +proc report_net_pin { pin corner digits } { if [$pin is_leaf] { set cell_name [get_name [[$pin instance] cell]] set cap "" - if { $verbose } { - set liberty_port [$pin liberty_port] - if { $liberty_port != "NULL" } { - set cap [port_capacitance_str $liberty_port $corner $digits] - } + set liberty_port [$pin liberty_port] + if { $liberty_port != "NULL" } { + set cap [port_capacitance_str $liberty_port $corner $digits] } report_line " [get_full_name $pin] [pin_direction $pin] ($cell_name)$cap[pin_location_str $pin]" } elseif [$pin is_top_level_port] { set wire_cap "" set pin_cap "" set corner [sta::cmd_corner] - if { $verbose } { - set port [$pin port] - set cap_min [port_ext_wire_cap $port $corner "min"] - set cap_max [port_ext_wire_cap $port $corner "max"] - if { $cap_min > 0 || $cap_max > 0 } { - set wire_cap " wire [capacitance_range_str $cap_min $cap_max $digits]" - } - set cap_min [port_ext_pin_cap $port $corner "min"] - set cap_max [port_ext_pin_cap $port $corner "max"] - if { $cap_min > 0 || $cap_max > 0} { - set pin_cap " pin [capacitance_range_str $cap_min $cap_max $digits]" - } + set port [$pin port] + set cap_min [port_ext_wire_cap $port $corner "min"] + set cap_max [port_ext_wire_cap $port $corner "max"] + if { $cap_min > 0 || $cap_max > 0 } { + set wire_cap " wire [capacitance_range_str $cap_min $cap_max $digits]" + } + + set cap_min [port_ext_pin_cap $port $corner "min"] + set cap_max [port_ext_pin_cap $port $corner "max"] + if { $cap_min > 0 || $cap_max > 0} { + set pin_cap " pin [capacitance_range_str $cap_min $cap_max $digits]" } report_line " [get_full_name $pin] [pin_direction $pin] port$wire_cap$pin_cap[pin_location_str $pin]" } elseif [$pin is_hierarchical] { diff --git a/tcl/NetworkEdit.i b/tcl/NetworkEdit.i index 0892ba71..1b3e6673 100644 --- a/tcl/NetworkEdit.i +++ b/tcl/NetworkEdit.i @@ -3,7 +3,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/tcl/NetworkEdit.tcl b/tcl/NetworkEdit.tcl index d3e48208..4256aaf9 100644 --- a/tcl/NetworkEdit.tcl +++ b/tcl/NetworkEdit.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -104,7 +104,7 @@ proc parse_connect_pin { arg } { set inst [$pin instance] set port [$pin port] } else { - sta_error 586 "unsupported object type $object_type." + sta_error 250 "unsupported object type $object_type." } } else { if {[regexp $path_regexp $arg ignore path_name port_name]} { @@ -134,7 +134,7 @@ proc parse_connect_pin { arg } { } proc connect_pins { net pins } { - sta_warn 372 "connect_pins is deprecated. Use connect_pin." + 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 } { @@ -203,7 +203,7 @@ proc delete_instance { instance } { if { $object_type == "Instance" } { set inst $instance } else { - sta_error 587 "unsupported object type $object_type." + sta_error 252 "unsupported object type $object_type." } } else { set inst [find_instance $instance] @@ -221,7 +221,7 @@ proc delete_net { net } { if { [is_object $net] } { set object_type [object_type $net] if { $object_type != "Net" } { - sta_error 588 "unsupported object type $object_type." + sta_error 253 "unsupported object type $object_type." } } else { set net [find_net $net] diff --git a/tcl/Property.tcl b/tcl/Property.tcl index a9e97ea5..68660784 100644 --- a/tcl/Property.tcl +++ b/tcl/Property.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -29,12 +29,12 @@ proc get_property_cmd { cmd type_key cmd_args } { check_argc_eq2 $cmd $cmd_args set object [lindex $cmd_args 0] if { $object == "" } { - sta_error 491 "$cmd object is null." + sta_error 320 "$cmd object is null." } elseif { ![is_object $object] } { if [info exists keys($type_key)] { set object_type $keys($type_key) } else { - sta_error 492 "$cmd $type_key must be specified with object name argument." + sta_error 321 "$cmd $type_key must be specified with object name argument." } set object [get_property_object_type $object_type $object $quiet] } @@ -74,10 +74,10 @@ proc get_object_property { object prop } { } elseif { $object_type == "TimingArcSet" } { return [timing_arc_set_property $object $prop] } else { - sta_error 606 "get_property unsupported object type $object_type." + sta_error 322 "get_property unsupported object type $object_type." } } else { - sta_error 493 "get_property $object is not an object." + sta_error 323 "get_property $object is not an object." } } @@ -104,10 +104,10 @@ proc get_property_object_type { object_type object_name quiet } { || $object_type == "lib"} { set object [get_libs -quiet $object_name] } else { - sta_error 494 "$object_type not supported." + sta_error 324 "$object_type not supported." } if { $object == "NULL" && !$quiet } { - sta_error 495 "$object_type '$object_name' not found." + sta_error 325 "$object_type '$object_name' not found." } return [lindex $object 0] } diff --git a/tcl/Sdc.tcl b/tcl/Sdc.tcl index c8b67729..25b4d142 100644 --- a/tcl/Sdc.tcl +++ b/tcl/Sdc.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -70,7 +70,7 @@ proc source_ { filename echo verbose } { variable sdc_file variable sdc_line if [catch {open $filename r} stream] { - sta_error 511 "cannot open '$filename'." + sta_error 340 "cannot open '$filename'." } else { if { [file extension $filename] == ".gz" } { zlib push gunzip $stream @@ -125,7 +125,7 @@ proc source_ { filename echo verbose } { } close $stream if { $cmd != {} } { - sta_error 512 "incomplete command at end of file." + sta_error 341 "incomplete command at end of file." } set error_sdc_file $sdc_file set error_sdc_line $sdc_line @@ -209,7 +209,7 @@ proc check_path_divider { divider } { set sdc_dividers "/@^#.|" if { !([string length $divider] == 1 && [string first $divider $sdc_dividers] != -1)} { - sta_error 513 "hierarchy separator must be one of '$sdc_dividers'." + sta_error 342 "hierarchy separator must be one of '$sdc_dividers'." } } @@ -256,7 +256,7 @@ proc check_unit { unit key unit_name key_var } { set scale [unit_prefix_scale $unit $prefix] check_unit_scale $unit $scale } else { - sta_error 514 "unknown unit $unit '$suffix'." + sta_error 343 "unknown unit $unit '$suffix'." } } } @@ -278,14 +278,14 @@ proc unit_prefix_scale { unit prefix } { } elseif { [string equal $prefix "f"] } { return 1E-15 } else { - sta_error 604 "unknown $unit prefix '$prefix'." + sta_error 344 "unknown $unit prefix '$prefix'." } } proc check_unit_scale { unit scale } { set unit_scale [unit_scale $unit] if { ![fuzzy_equal $scale $unit_scale] } { - sta_warn 319 "$unit scale [format %.0e $scale] does not match library scale [format %.0e $unit_scale]." + sta_warn 345 "$unit scale [format %.0e $scale] does not match library scale [format %.0e $unit_scale]." } } @@ -391,7 +391,7 @@ proc all_registers { args } { + [info exists flags(-clock_pins)] \ + [info exists flags(-async_pins)] \ + [info exists flags(-output_pins)]] > 1 } { - sta_error 807 "only one of -cells, -data_pins, -clock_pins, -async_pins, -output_pins are suppported." + sta_error 346 "only one of -cells, -data_pins, -clock_pins, -async_pins, -output_pins are suppported." } if [info exists flags(-cells)] { return [find_register_instances $clks $clk_rf \ @@ -434,7 +434,7 @@ proc current_design { {design ""} } { set current_design_name $design return $design } else { - sta_warn 320 "current_design for other than top cell not supported." + sta_warn 347 "current_design for other than top cell not supported." set current_design_name $design return $design } @@ -470,7 +470,7 @@ proc get_cells { args } { set insts {} if [info exists keys(-of_objects)] { if { $args != {} } { - sta_warn 321 "patterns argument not supported with -of_objects." + sta_warn 348 "patterns argument not supported with -of_objects." } parse_port_pin_net_arg $keys(-of_objects) pins nets foreach pin $pins { @@ -503,7 +503,7 @@ proc get_cells { args } { set matches [find_instances_matching $pattern $regexp $nocase] } if { $matches == {} && !$quiet} { - sta_warn 322 "instance '$pattern' not found." + sta_warn 349 "instance '$pattern' not found." } set insts [concat $insts $matches] } @@ -536,7 +536,7 @@ proc filter_insts1 { filter objects } { } elseif { [regexp $filter_regexp1 $filter ignore attr_name op arg] } { set filtered_objects [filter_insts $attr_name $op $arg $objects] } else { - sta_error 516 "unsupported instance -filter expression." + sta_error 350 "unsupported instance -filter expression." } return $filtered_objects } @@ -563,7 +563,7 @@ proc get_clocks { args } { set clocks [concat $clocks $matches] } else { if {![info exists flags(-quiet)]} { - sta_warn 323 "clock '$pattern' not found." + sta_warn 351 "clock '$pattern' not found." } } } @@ -589,7 +589,7 @@ proc get_lib_cells { args } { set cells {} if [info exists keys(-of_objects)] { if { $args != {} } { - sta_warn 324 "positional arguments not supported with -of_objects." + sta_warn 352 "positional arguments not supported with -of_objects." } set insts [get_instances_error "objects" $keys(-of_objects)] foreach inst $insts { @@ -616,7 +616,7 @@ proc get_lib_cells { args } { set libs [get_libs -quiet $lib_name] if { $libs == {} } { if {!$quiet} { - sta_warn 325 "library '$lib_name' not found." + sta_warn 353 "library '$lib_name' not found." } } else { foreach lib $libs { @@ -628,7 +628,7 @@ proc get_lib_cells { args } { } if { $cells == {} } { if {!$quiet} { - sta_warn 326 "cell '$cell_pattern' not found." + sta_warn 354 "cell '$cell_pattern' not found." } } } @@ -675,7 +675,7 @@ proc get_lib_pins { args } { set libs [get_libs *] } else { if { !$quiet } { - sta_warn 327 "library/cell/port '$pattern' not found." + sta_warn 355 "library/cell/port '$pattern' not found." } return {} } @@ -695,12 +695,12 @@ proc get_lib_pins { args } { } if { !$found_match } { if { !$quiet } { - sta_warn 328 "port '$port_pattern' not found." + sta_warn 356 "port '$port_pattern' not found." } } } else { if { !$quiet } { - sta_warn 329 "library '$lib_name' not found." + sta_warn 357 "library '$lib_name' not found." } } } @@ -710,7 +710,7 @@ proc get_lib_pins { args } { proc check_nocase_flag { flags_var } { upvar 1 $flags_var flags if { [info exists flags(-nocase)] && ![info exists flags(-regexp)] } { - sta_warn 330 "-nocase ignored without -regexp." + sta_warn 358 "-nocase ignored without -regexp." } } @@ -736,7 +736,7 @@ proc get_libs { args } { set libs [concat $libs $matches] } else { if {![info exists flags(-quiet)]} { - sta_warn 331 "library '$pattern' not found." + sta_warn 359 "library '$pattern' not found." } } } @@ -799,7 +799,7 @@ proc get_nets { args } { set nets {} if [info exists keys(-of_objects)] { if { $args != {} } { - sta_warn 332 "patterns argument not supported with -of_objects." + sta_warn 360 "patterns argument not supported with -of_objects." } parse_inst_pin_arg $keys(-of_objects) insts pins foreach inst $insts { @@ -823,7 +823,7 @@ proc get_nets { args } { } set nets [concat $nets $matches] if { $matches == {} && !$quiet } { - sta_warn 333 "net '$pattern' not found." + sta_warn 361 "net '$pattern' not found." } } } @@ -852,7 +852,7 @@ proc get_pins { args } { set pins {} if [info exists keys(-of_objects)] { if { $args != {} } { - sta_warn 334 "patterns argument not supported with -of_objects." + sta_warn 362 "patterns argument not supported with -of_objects." } parse_inst_net_arg $keys(-of_objects) insts nets foreach inst $insts { @@ -889,7 +889,7 @@ proc get_pins { args } { } set pins [concat $pins $matches] if { $matches == {} && !$quiet } { - sta_warn 335 "pin '$pattern' not found." + sta_warn 363 "pin '$pattern' not found." } } } @@ -921,7 +921,7 @@ proc filter_pins1 { filter objects } { } elseif { [regexp $filter_regexp1 $filter ignore attr_name op arg] } { set filtered_objects [filter_pins $attr_name $op $arg $objects] } else { - sta_error 517 "unsupported pin -filter expression." + sta_error 364 "unsupported pin -filter expression." } return $filtered_objects } @@ -946,7 +946,7 @@ proc get_ports { args } { set ports {} if [info exists keys(-of_objects)] { if { $args != {} } { - sta_warn 336 "patterns argument not supported with -of_objects." + sta_warn 365 "patterns argument not supported with -of_objects." } set nets [get_nets_arg "objects" $keys(-of_objects)] foreach net $nets { @@ -960,7 +960,7 @@ proc get_ports { args } { set ports [concat $ports $matches] } else { if {![info exists flags(-quiet)]} { - sta_warn 337 "port '$pattern' not found." + sta_warn 366 "port '$pattern' not found." } } } @@ -997,7 +997,7 @@ proc filter_ports1 { filter objects } { } elseif { [regexp $filter_regexp1 $filter ignore attr_name op arg] } { set filtered_objects [filter_ports $attr_name $op $arg $objects] } else { - sta_error 518 "unsupported port -filter expression." + sta_error 367 "unsupported port -filter expression." } return $filtered_objects } @@ -1030,12 +1030,12 @@ proc create_clock { args } { set name $keys(-name) } elseif { $pins != {} } { if { $add } { - sta_error 519 "-add requires -name." + sta_error 368 "-add requires -name." } # Default clock name is the first pin name. set name [get_full_name [lindex $pins 0]] } else { - sta_error 520 "-name or port_pin_list must be specified." + sta_error 369 "-name or port_pin_list must be specified." } if [info exists keys(-period)] { @@ -1043,13 +1043,13 @@ proc create_clock { args } { check_positive_float "period" $period set period [time_ui_sta $period] } else { - sta_error 521 "missing -period argument." + sta_error 370 "missing -period argument." } if [info exists keys(-waveform)] { set wave_arg $keys(-waveform) if { [expr [llength $wave_arg] % 2] != 0 } { - sta_error 522 "-waveform edge_list must have an even number of edge times." + sta_error 371 "-waveform edge_list must have an even number of edge times." } set first_edge 1 set prev_edge 0 @@ -1058,10 +1058,10 @@ proc create_clock { args } { check_float "-waveform edge" $edge set edge [time_ui_sta $edge] if { !$first_edge && $edge < $prev_edge } { - sta_error 338 "non-increasing clock -waveform edge times." + sta_error 372 "non-increasing clock -waveform edge times." } if { $edge > [expr $period * 2] } { - sta_error 339 "-waveform time greater than two periods." + sta_error 373 "-waveform time greater than two periods." } lappend waveform $edge set prev_edge $edge @@ -1119,7 +1119,7 @@ proc create_generated_clock { args } { } } if { $pins == {} } { - sta_error 523 "empty ports/pins/nets argument." + sta_error 374 "empty ports/pins/nets argument." } set add [info exists flags(-add)] @@ -1127,19 +1127,19 @@ proc create_generated_clock { args } { set name $keys(-name) } elseif { $pins != {} } { if { $add } { - sta_error 524 "-add requires -name." + sta_error 375 "-add requires -name." } # Default clock name is the first pin name. set name [get_full_name [lindex $pins 0]] } else { - sta_error 525 "name or port_pin_list must be specified." + sta_error 376 "name or port_pin_list must be specified." } if [info exists keys(-source)] { set source $keys(-source) set source_pin [get_port_pin_error "master_pin" $source] } else { - sta_error 526 "missing -source argument." + sta_error 377 "missing -source argument." } set master_clk "NULL" @@ -1154,44 +1154,44 @@ proc create_generated_clock { args } { if {[info exists keys(-master_clock)]} { set master_clk [get_clock_error "-master_clk" $keys(-master_clock)] if { $master_clk == "NULL" } { - sta_error 527 "-master_clock argument empty." + sta_error 378 "-master_clock argument empty." } } elseif { $add } { - sta_error 528 "-add requireds -master_clock." + sta_error 379 "-add requireds -master_clock." } if {[info exists keys(-divide_by)] && [info exists keys(-multiply_by)]} { - sta_error 529 "-multiply_by and -divide_by options are exclusive." + sta_error 380 "-multiply_by and -divide_by options are exclusive." } elseif {[info exists keys(-divide_by)]} { set divide_by $keys(-divide_by) if {![string is integer $divide_by] || $divide_by < 1} { - sta_error 530 "-divide_by is not an integer greater than one." + sta_error 381 "-divide_by is not an integer greater than one." } if {$combinational && $divide_by != 1} { - sta_error 531 "-combinational implies -divide_by 1." + sta_error 382 "-combinational implies -divide_by 1." } } elseif {[info exists keys(-multiply_by)]} { set multiply_by $keys(-multiply_by) if {![string is integer $multiply_by] || $multiply_by < 1} { - sta_error 532 "-multiply_by is not an integer greater than one." + sta_error 383 "-multiply_by is not an integer greater than one." } if {[info exists keys(-duty_cycle)]} { set duty_cycle $keys(-duty_cycle) if {![string is double $duty_cycle] \ || $duty_cycle < 0.0 || $duty_cycle > 100.0} { - sta_error 533 "-duty_cycle is not a float between 0 and 100." + sta_error 384 "-duty_cycle is not a float between 0 and 100." } } } elseif {[info exists keys(-edges)]} { set edges $keys(-edges) if { [llength $edges] != 3 } { - sta_error 534 "-edges only supported for three edges." + sta_error 385 "-edges only supported for three edges." } set prev_edge [expr [lindex $edges 0] - 1] foreach edge $edges { check_cardinal "-edges" $edge if { $edge <= $prev_edge } { - sta_error 535 "edges times are not monotonically increasing." + sta_error 386 "edges times are not monotonically increasing." } } if [info exists keys(-edge_shift)] { @@ -1200,13 +1200,13 @@ proc create_generated_clock { args } { lappend edge_shifts [time_ui_sta $shift] } if { [llength $edge_shifts] != [llength $edges] } { - sta_error 536 "-edge_shift length does not match -edges length." + sta_error 387 "-edge_shift length does not match -edges length." } } } elseif { $combinational } { set divide_by 1 } else { - sta_error 537 "missing -multiply_by, -divide_by, -combinational or -edges argument." + sta_error 388 "missing -multiply_by, -divide_by, -combinational or -edges argument." } set invert 0 @@ -1214,13 +1214,13 @@ proc create_generated_clock { args } { if {!([info exists keys(-divide_by)] \ || [info exists keys(-multiply_by)] \ || [info exists flags(-combinational)])} { - sta_error 538 "cannot specify -invert without -multiply_by, -divide_by or -combinational." + sta_error 389 "cannot specify -invert without -multiply_by, -divide_by or -combinational." } set invert 1 } if {[info exists keys(-duty_cycle)] && ![info exists keys(-multiply_by)]} { - sta_error 539 "-duty_cycle requires -multiply_by value." + sta_error 390 "-duty_cycle requires -multiply_by value." } set comment [parse_comment_key keys] @@ -1280,26 +1280,26 @@ proc group_path { args } { check_exception_pins $from $to if { $arg_error } { delete_from_thrus_to $from $thrus $to - sta_error 545 "group_path command failed." + sta_error 391 "group_path command failed." return 0 } check_for_key_args $cmd args if { $args != {} } { delete_from_thrus_to $from $thrus $to - sta_error 546 "positional arguments not supported." + sta_error 392 "positional arguments not supported." } if { ($from == "NULL" && $thrus == "" && $to == "NULL") } { delete_from_thrus_to $from $thrus $to - sta_error 547 "-from, -through or -to required." + sta_error 393 "-from, -through or -to required." } set default [info exists flags(-default)] set name_exists [info exists keys(-name)] if { $default && $name_exists } { - sta_error 548 "-name and -default are mutually exclusive." + sta_error 394 "-name and -default are mutually exclusive." } elseif { !$name_exists && !$default } { - sta_error 549 "-name or -default option is required." + sta_error 395 "-name or -default option is required." } elseif { $default } { set name "" } else { @@ -1340,7 +1340,7 @@ proc set_clock_gating_check { args } { set active_value "" if {[info exists flags(-high)] && [info exists flags(-low)]} { - sta_error 550 "cannot specify both -high and -low." + sta_error 396 "cannot specify both -high and -low." } elseif [info exists flags(-low)] { set active_value "0" } elseif [info exists flags(-high)] { @@ -1348,7 +1348,7 @@ proc set_clock_gating_check { args } { } if { !([info exists keys(-hold)] || [info exists keys(-setup)]) } { - sta_error 551 "missing -setup or -hold argument." + sta_error 397 "missing -setup or -hold argument." } if [info exists keys(-hold)] { set_clock_gating_check1 $args $tr "min" $keys(-hold) $active_value @@ -1362,14 +1362,14 @@ proc set_clock_gating_check1 { args tr setup_hold margin active_value } { set margin [time_ui_sta $margin] if { [llength $args] == 0 } { if { $active_value != "" } { - sta_error 552 "-high and -low only permitted for pins and instances." + sta_error 398 "-high and -low only permitted for pins and instances." } set_clock_gating_check_cmd $tr $setup_hold $margin } elseif { [llength $args] == 1 } { parse_clk_inst_port_pin_arg [lindex $args 0] clks insts pins if { $clks != {} && $active_value != "" } { - sta_error 553 "-high and -low only permitted for pins and instances." + 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 @@ -1412,10 +1412,10 @@ proc set_clock_groups { args } { set allow_paths [info exists flags(-allow_paths)] if { ($logically_exclusive+$physically_exclusive+$asynchronous) == 0 } { - sta_error 554 "one of -logically_exclusive, -physically_exclusive or -asynchronous is required." + sta_error 400 "one of -logically_exclusive, -physically_exclusive or -asynchronous is required." } if { ($logically_exclusive+$physically_exclusive+$asynchronous) > 1 } { - sta_error 555 "the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive." + sta_error 401 "the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive." } set comment [parse_comment_key keys] @@ -1434,9 +1434,9 @@ proc set_clock_groups { args } { set args [lrange $args 2 end] } else { if {[is_keyword_arg $arg]} { - sta_warn 349 "unknown keyword argument $arg." + sta_warn 402 "unknown keyword argument $arg." } else { - sta_warn 341 "extra positional argument $arg." + sta_warn 403 "extra positional argument $arg." } set args [lrange $args 1 end] } @@ -1465,10 +1465,10 @@ proc unset_clk_groups_cmd { cmd cmd_args } { } if { $all && $names != {} } { - sta_error 454 "the -all and -name options are mutually exclusive." + sta_error 404 "the -all and -name options are mutually exclusive." } if { !$all && $names == {} } { - sta_error 455 "either -all or -name options must be specified." + sta_error 405 "either -all or -name options must be specified." } set logically_exclusive [info exists flags(-logically_exclusive)] @@ -1476,10 +1476,10 @@ proc unset_clk_groups_cmd { cmd cmd_args } { set asynchronous [info exists flags(-asynchronous)] if { ($logically_exclusive+$physically_exclusive+$asynchronous) == 0 } { - sta_error 456 "one of -logically_exclusive, -physically_exclusive or -asynchronous is required." + sta_error 406 "one of -logically_exclusive, -physically_exclusive or -asynchronous is required." } if { ($logically_exclusive+$physically_exclusive+$asynchronous) > 1 } { - sta_error 457 "the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive." + sta_error 407 "the keywords -logically_exclusive, -physically_exclusive and -asynchronous are mutually exclusive." } if { $all } { @@ -1529,7 +1529,7 @@ proc set_clock_latency { args } { if { [info exists keys(-clock)] } { set pin_clk [get_clock_warn "clock" $keys(-clock)] if { $clks != {} } { - sta_warn 342 "-clock ignored for clock objects." + sta_warn 408 "-clock ignored for clock objects." } } @@ -1543,14 +1543,14 @@ proc set_clock_latency { args } { foreach pin $pins { # Source only allowed on clocks and clock pins. if { ![is_clock_src $pin] } { - sta_error 556 "-source '[get_full_name $pin]' is not a clock 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 } } else { # Latency. if {[info exists flags(-early)] || [info exists flags(-late)]} { - sta_error 557 "-early/-late is only allowed with -source." + sta_error 410 "-early/-late is only allowed with -source." } foreach clk $clks { @@ -1579,7 +1579,7 @@ proc unset_clk_latency_cmd { cmd cmd_args } { if { [info exists keys(-clock)] } { set pin_clk [get_clock_warn "clock" $keys(-clock)] if { $clks != {} } { - sta_warn 303 "-clock ignored for clock objects." + sta_warn 411 "-clock ignored for clock objects." } } @@ -1591,7 +1591,7 @@ proc unset_clk_latency_cmd { cmd cmd_args } { foreach pin $pins { # Source only allowed on clocks and clock pins. if { ![is_clock_pin $pin] } { - sta_error 458 "-source '[$pin path_name]' is not a clock pin." + sta_error 412 "-source '[$pin path_name]' is not a clock pin." } unset_clock_insertion_cmd $pin_clk $pin } @@ -1619,11 +1619,11 @@ proc set_sense { args } { if { [info exists keys(-type)] } { set type $keys(-type) if { $type == "data" } { - sta_warn 343 "set_sense -type data not supported." + sta_warn 413 "set_sense -type data not supported." } elseif { $type == "clock" } { set_clock_sense_cmd1 "set_sense" $args } else { - sta_error 558 "set_sense -type clock|data" + sta_error 414 "set_sense -type clock|data" } } } @@ -1634,7 +1634,7 @@ define_cmd_args "set_clock_sense" \ [-clock clocks] pins} proc set_clock_sense { args } { - sta_warn 344 "set_clock_sense is deprecated as of SDC 2.1. Use set_sense -type clock." + sta_warn 415 "set_clock_sense is deprecated as of SDC 2.1. Use set_sense -type clock." set_clock_sense_cmd1 "set_clock_sense" $args } @@ -1646,7 +1646,7 @@ proc set_clock_sense_cmd1 { cmd cmd_args } { set pulse [info exists keys(-pulse)] if { $pulse } { - sta_warn 345 "-pulse argument not supported." + sta_warn 416 "-pulse argument not supported." } set positive [info exists flags(-positive)] set negative [info exists flags(-negative)] @@ -1655,7 +1655,7 @@ proc set_clock_sense_cmd1 { cmd cmd_args } { || ($negative && ($positive || $stop_propagation || $pulse)) \ || ($stop_propagation && ($positive || $negative || $pulse)) || ($pulse && ($positive || $negative || $stop_propagation)) } { - sta_warn 346 "-positive, -negative, -stop_propagation and -pulse are mutually exclusive." + sta_warn 417 "-positive, -negative, -stop_propagation and -pulse are mutually exclusive." } set pins [get_port_pins_error "pins" [lindex $cmd_args 0]] @@ -1668,7 +1668,7 @@ proc set_clock_sense_cmd1 { cmd cmd_args } { } foreach pin $pins { if {[$pin is_hierarchical]} { - sta_warn 347 "hierarchical pin '[get_full_name $pin]' not supported." + sta_warn 418 "hierarchical pin '[get_full_name $pin]' not supported." } } set_clock_sense_cmd $pins $clks $positive $negative $stop_propagation @@ -1692,7 +1692,7 @@ proc set_clock_transition { args } { foreach clk $clks { if { [$clk is_virtual] } { - sta_warn 559 "transition time can not be specified for virtual clocks." + 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] } @@ -1725,7 +1725,7 @@ proc set_clock_uncertainty { args } { flags {-rise -fall -setup -hold} if { [llength $args] == 0 } { - sta_error 560 "missing uncertainty value." + sta_error 420 "missing uncertainty value." } set uncertainty [lindex $args 0] check_float "uncertainty" $uncertainty @@ -1773,7 +1773,7 @@ proc set_clock_uncertainty { args } { if { $from_key != "none" && $to_key == "none" \ || $from_key == "none" && $to_key != "none" } { - sta_error 561 "-from/-to must be used together." + sta_error 421 "-from/-to must be used together." } elseif { $from_key != "none" && $to_key != "none" } { # Inter-clock uncertainty. check_argc_eq1 "-from/-to" $args @@ -1793,7 +1793,7 @@ proc set_clock_uncertainty { args } { check_argc_eq2 "set_clock_uncertainty" $args if { [info exists flags(-rise)] \ || [info exists flags(-fall)] } { - sta_error 562 "-rise, -fall options not allowed for single clock uncertainty." + sta_error 422 "-rise, -fall options not allowed for single clock uncertainty." } set objects [lindex $args 1] parse_clk_port_pin_arg $objects clks pins @@ -1859,7 +1859,7 @@ proc unset_clk_uncertainty_cmd { cmd cmd_args } { if { $from_key != "none" && $to_key == "none" \ || $from_key == "none" && $to_key != "none" } { - sta_error 459 "-from/-to must be used together." + sta_error 423 "-from/-to must be used together." } elseif { $from_key != "none" && $to_key != "none" } { # Inter-clock uncertainty. check_argc_eq0 "unset_clock_uncertainty" $cmd_args @@ -1879,7 +1879,7 @@ proc unset_clk_uncertainty_cmd { cmd cmd_args } { check_argc_eq1 $cmd $cmd_args if { [info exists keys(-rise)] \ || [info exists keys(-fall)] } { - sta_error 460 "-rise, -fall options not allowed for single clock uncertainty." + sta_error 424 "-rise, -fall options not allowed for single clock uncertainty." } set objects [lindex $cmd_args 0] parse_clk_port_pin_arg $objects clks pins @@ -1920,7 +1920,7 @@ proc set_data_check { args } { set from [get_port_pin_error "from_pin" $keys(-fall_from)] set from_rf "fall" } else { - sta_error 563 "missing -from, -rise_from or -fall_from argument." + sta_error 425 "missing -from, -rise_from or -fall_from argument." } if [info exists keys(-to)] { @@ -1932,7 +1932,7 @@ proc set_data_check { args } { set to [get_port_pin_error "to_pin" $keys(-fall_to)] set to_rf "fall" } else { - sta_error 564 "missing -to, -rise_to or -fall_to argument." + sta_error 426 "missing -to, -rise_to or -fall_to argument." } if [info exists keys(-clock)] { @@ -1980,7 +1980,7 @@ proc unset_data_checks_cmd { cmd cmd_args } { set from [get_port_pin_error "from_pin" $keys(-fall_from)] set from_rf "fall" } else { - sta_error 461 "missing -from, -rise_from or -fall_from argument." + sta_error 427 "missing -from, -rise_from or -fall_from argument." } if [info exists keys(-to)] { @@ -1992,7 +1992,7 @@ proc unset_data_checks_cmd { cmd cmd_args } { set to [get_port_pin_error "to_pin" $keys(-fall_to)] set to_rf "fall" } else { - sta_error 462 "missing -to, -rise_to or -fall_to argument." + sta_error 428 "missing -to, -rise_to or -fall_to argument." } if [info exists keys(-clock)] { @@ -2034,7 +2034,7 @@ proc set_disable_timing { args } { if { ([info exists keys(-from)] || [info exists keys(-to)]) \ && ($libports != {} || $pins != {} || $ports != {}) } { - sta_warn 348 "-from/-to keywords ignored for lib_pin, port and pin arguments." + sta_warn 429 "-from/-to keywords ignored for lib_pin, port and pin arguments." } foreach libcell $libcells { @@ -2064,7 +2064,7 @@ proc set_disable_timing_instance { inst from to } { set from_ports [parse_disable_inst_ports $inst $from] set to_ports [parse_disable_inst_ports $inst $to] if { ![$inst is_leaf] } { - sta_error 565 "-from/-to hierarchical instance not supported." + sta_error 430 "-from/-to hierarchical instance not supported." } if { $from_ports == "NULL" && $to_ports == "NULL" } { disable_instance $inst "NULL" "NULL" @@ -2096,7 +2096,7 @@ proc parse_disable_inst_ports { inst port_name } { set cell [instance_property $inst cell] set port [$cell find_port $port_name] if { $port == "NULL" } { - sta_error 566 "pin '[get_full_name $inst]${hierarchy_separator}${port_name}' not found." + sta_error 431 "pin '[get_full_name $inst]${hierarchy_separator}${port_name}' not found." } else { set lib_port [get_property $port liberty_port] set ports [port_members $lib_port] @@ -2137,7 +2137,7 @@ proc parse_disable_cell_ports { cell port_name } { } else { set port [$cell find_liberty_port $port_name] if { $port == "NULL" } { - sta_error 567 "pin '[get_name $cell]${hierarchy_separator}${port_name}' not found." + sta_error 432 "pin '[get_name $cell]${hierarchy_separator}${port_name}' not found." } else { set ports [port_members $port] } @@ -2171,7 +2171,7 @@ proc unset_disable_cmd { cmd cmd_args } { if { ([info exists keys(-from)] || [info exists keys(-to)]) \ && ($libports != {} || $pins != {} || $ports != {}) } { - sta_warn 304 "-from/-to keywords ignored for lib_pin, port and pin arguments." + sta_warn 434 "-from/-to keywords ignored for lib_pin, port and pin arguments." } foreach libcell $libcells { @@ -2223,7 +2223,7 @@ proc unset_disable_timing_instance { inst from to } { set from_ports [parse_disable_inst_ports $inst $from] set to_ports [parse_disable_inst_ports $inst $to] if { ![$inst is_leaf] } { - sta_error 463 "-from/-to hierarchical instance not supported." + sta_error 435 "-from/-to hierarchical instance not supported." } if { $from_ports == "NULL" && $to_ports == "NULL" } { unset_disable_instance $inst "NULL" "NULL" @@ -2277,11 +2277,11 @@ proc set_false_path { args } { } else { check_for_key_args $cmd args if { $args != {} } { - sta_warn 600 "'$args' ignored." + sta_warn 436 "'$args' ignored." } if { ($from == "NULL" && $thrus == "" && $to == "NULL") } { delete_from_thrus_to $from $thrus $to - sta_warn 350 "-from, -through or -to required." + sta_warn 437 "-from, -through or -to required." } else { if [info exists flags(-reset_path)] { reset_path_cmd $from $thrus $to $min_max @@ -2360,10 +2360,10 @@ proc set_port_delay { cmd sta_cmd cmd_args port_dirs } { if [info exists keys(-reference_pin)] { set ref_pin [get_port_pin_error "ref_pin" $keys(-reference_pin)] if { [info exists flags(-source_latency_included)] } { - sta_warn 351 "-source_latency_included ignored with -reference_pin." + sta_warn 438 "-source_latency_included ignored with -reference_pin." } if { [info exists flags(-network_latency_included)] } { - sta_warn 352 "-network_latency_included ignored with -reference_pin." + sta_warn 439 "-network_latency_included ignored with -reference_pin." } } @@ -2382,9 +2382,9 @@ proc set_port_delay { cmd sta_cmd cmd_args port_dirs } { foreach pin $pins { if { [$pin is_top_level_port] \ && [lsearch $port_dirs [pin_direction $pin]] == -1 } { - sta_warn 353 "$cmd not allowed on [pin_direction $pin] port '[get_full_name $pin]'." + sta_warn 440 "$cmd not allowed on [pin_direction $pin] port '[get_full_name $pin]'." } elseif { $clk != "NULL" && [lsearch [$clk sources] $pin] != -1 } { - sta_warn 354 "$cmd relative to a clock defined on the same port/pin not allowed." + 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\ $source_latency_included $network_latency_included \ @@ -2432,13 +2432,13 @@ proc set_path_delay { cmd args min_max } { check_for_key_args $cmd args if { [llength $args] == 0 } { delete_from_thrus_to $from $thrus $to - sta_error 568 "missing delay argument." + sta_error 442 "missing delay argument." } elseif { [llength $args] == 1 } { set delay $args check_float "$cmd delay" $delay set delay [time_ui_sta $delay] } else { - sta_warn 355 "'$args' ignored." + sta_warn 443 "'$args' ignored." } set ignore_clk_latency [info exists flags(-ignore_clock_latency)] @@ -2563,19 +2563,19 @@ proc set_multicycle_path { args } { check_for_key_args $cmd args if { [llength $args] == 0 } { delete_from_thrus_to $from $thrus $to - sta_error 569 "missing path multiplier argument." + sta_error 444 "missing path multiplier argument." } elseif { [llength $args] == 1 } { set path_multiplier $args check_integer "path multiplier" $path_multiplier } else { - sta_warn 356 "'$args' ignored." + sta_warn 445 "'$args' ignored." } set start [info exists flags(-start)] set end [info exists flags(-end)] if { $start && $end } { delete_from_thrus_to $from $thrus $to - sta_error 570 "cannot use -start with -end." + sta_error 446 "cannot use -start with -end." } elseif { $start } { set use_end_clk 0 } elseif { $end } { @@ -2625,18 +2625,18 @@ proc unset_path_exceptions_cmd { cmd cmd_args } { set to [parse_to_arg keys flags arg_error] if { $arg_error } { delete_from_thrus_to $from $thrus $to - sta_error 464 "$cmd command failed." + sta_error 447 "$cmd command failed." return 0 } check_for_key_args $cmd cmd_args if { $cmd_args != {} } { delete_from_thrus_to $from $thrus $to - sta_error 465 "positional arguments not supported." + sta_error 448 "positional arguments not supported." } if { ($from == "NULL" && $thrus == "" && $to == "NULL") } { delete_from_thrus_to $from $thrus $to - sta_error 466 "-from, -through or -to required." + sta_error 449 "-from, -through or -to required." } reset_path_cmd $from $thrus $to $min_max @@ -2703,7 +2703,7 @@ proc set_propagated_clock { objects } { parse_clk_port_pin_arg $objects clks pins foreach clk $clks { if { [$clk is_virtual] } { - sta_warn 357 "virtual clock [get_name $clk] can not be propagated." + sta_warn 450 "virtual clock [get_name $clk] can not be propagated." } else { set_propagated_clock_cmd $clk } @@ -2745,7 +2745,7 @@ proc set_case_analysis { value pins } { || $value == "rising" \ || $value == "fall" \ || $value == "falling") } { - sta_error 571 "value must be 0, zero, 1, one, rise, rising, fall, or falling." + sta_error 451 "value must be 0, zero, 1, one, rise, rising, fall, or falling." } set pins1 [get_port_pins_error "pins" $pins] foreach pin $pins1 { @@ -2814,17 +2814,17 @@ proc set_driving_cell { args } { set library [get_liberty_error "library" $keys(-library)] set cell [$library find_liberty_cell $cell_name] if { $cell == "NULL" } { - sta_error 572 "cell '$lib_name:$cell_name' not found." + sta_error 452 "cell '$lib_name:$cell_name' not found." } } else { set library "NULL" set cell [find_liberty_cell $cell_name] if { $cell == "NULL" } { - sta_error 573 "'$cell_name' not found." + sta_error 453 "'$cell_name' not found." } } } else { - sta_error 574 "missing -lib_cell argument." + sta_error 454 "missing -lib_cell argument." } set to_port "NULL" @@ -2832,7 +2832,7 @@ proc set_driving_cell { args } { set to_port_name $keys(-pin) set to_port [$cell find_liberty_port $to_port_name] if { $to_port == "NULL" } { - sta_error 575 "port '$to_port_name' not found." + sta_error 455 "port '$to_port_name' not found." } } else { set port_iter [$cell liberty_port_iterator] @@ -2844,7 +2844,7 @@ proc set_driving_cell { args } { incr output_count if { $output_count > 1 } { $port_iter finish - sta_error 576 "-pin argument required for cells with multiple outputs." + sta_error 456 "-pin argument required for cells with multiple outputs." } set to_port $port # No break. Keep looking for output ports to make sure there @@ -2859,7 +2859,7 @@ proc set_driving_cell { args } { set from_port_name $keys(-from_pin) set from_port [$cell find_liberty_port $from_port_name] if { $from_port == "NULL" } { - sta_error 577 "port '$from_port_name' not found." + sta_error 457 "port '$from_port_name' not found." } } @@ -2877,13 +2877,13 @@ proc set_driving_cell { args } { } if [info exists keys(-multiply_by)] { - sta_warn 358 "-multiply_by ignored." + sta_warn 458 "-multiply_by ignored." } if [info exists flags(-dont_scale)] { - sta_warn 359 "-dont_scale ignored." + sta_warn 459 "-dont_scale ignored." } if [info exists flags(-no_design_rule)] { - sta_warn 360 "-no_design_rule ignored." + sta_warn 460 "-no_design_rule ignored." } check_argc_eq1 "set_driving_cell" $args @@ -2906,7 +2906,7 @@ proc port_direction_any_output { dir } { define_cmd_args "set_fanout_load" {fanout ports} proc set_fanout_load { fanout port_list } { - sta_warn 601 "set_fanout_load not supported." + sta_warn 461 "set_fanout_load not supported." } ################################################################ @@ -2930,10 +2930,10 @@ proc set_input_transition { args } { set ports [get_ports_error "ports" [lindex $args 1]] if [info exists keys(-clock)] { - sta_warn 361 "-clock not supported." + sta_warn 462 "-clock not supported." } if [info exists flags(-clock_fall)] { - sta_warn 362 "-clock_fall not supported." + sta_warn 463 "-clock_fall not supported." } foreach port $ports { @@ -2979,13 +2979,13 @@ proc set_load { args } { } if { $nets != {} } { if { $pin_load } { - sta_warn 363 "-pin_load not allowed for net objects." + sta_warn 464 "-pin_load not allowed for net objects." } if { $wire_load } { - sta_warn 364 "-wire_load not allowed for net objects." + sta_warn 465 "-wire_load not allowed for net objects." } if { $tr != "rise_fall" } { - sta_warn 365 "-rise/-fall not allowed for net objects." + sta_warn 466 "-rise/-fall not allowed for net objects." } foreach net $nets { set_net_wire_cap $net $subtract_pin_load $corner $min_max $cap @@ -3072,7 +3072,7 @@ proc set_fanout_limit { fanout min_max objects } { foreach port $ports { set dir [port_direction $port] if { !($dir == "input" || $dir == "bidirect") } { - sta_error 578 "port '[get_name $port]' is not an input." + sta_error 467 "port '[get_name $port]' is not an input." } set_port_fanout_limit $port $min_max $fanout } @@ -3118,7 +3118,7 @@ proc set_max_transition { args } { || [info exists flags(-data_path)] || [info exists flags(-rise)] || [info exists flags(-fall)]) } { - sta_warn 366 "-data_path, -clock_path, -rise, -fall ignored for ports and designs." + sta_warn 468 "-data_path, -clock_path, -rise, -fall ignored for ports and designs." } # -clock_path/-data_path and transition only apply to clock objects. @@ -3189,7 +3189,7 @@ proc set_timing_derate { args } { set derate [lindex $args 0] check_float "derate" $derate if { $derate > 2.0 } { - sta_warn 367 "derating factor greater than 2.0." + sta_warn 469 "derating factor greater than 2.0." } set tr [parse_rise_fall_flags flags] @@ -3226,7 +3226,7 @@ proc set_timing_derate { args } { if { $nets != {} } { if { [info exists flags(-cell_delay)] \ || [info exists flags(-cell_check)] } { - sta_warn 368 "-cell_delay and -cell_check flags ignored for net objects." + sta_warn 470 "-cell_delay and -cell_check flags ignored for net objects." } foreach net $nets { foreach path_type $path_types { @@ -3296,7 +3296,7 @@ proc parse_from_arg { keys_var arg_error_var } { if {$from_pins == {} && $from_insts == {} && $from_clks == {}} { upvar 1 $arg_error_var arg_error set arg_error 1 - sta_warn 369 "no valid objects specified for $key." + sta_warn 471 "no valid objects specified for $key." return "NULL" } return [make_exception_from $from_pins $from_clks $from_insts $tr] @@ -3329,7 +3329,7 @@ proc parse_thrus_arg { args_var arg_error_var } { if {$pins == {} && $insts == {} && $nets == {}} { upvar 1 $arg_error_var arg_error set arg_error 1 - sta_warn 370 "no valid objects specified for $key" + sta_warn 472 "no valid objects specified for $key" } else { lappend thrus [make_exception_thru $pins $nets $insts $tr] } @@ -3378,7 +3378,7 @@ proc parse_to_arg1 { keys_var end_rf arg_error_var } { if {$to_pins == {} && $to_insts == {} && $to_clks == {}} { upvar 1 $arg_error_var arg_error set arg_error 1 - sta_warn 602 "no valid objects specified for $key." + sta_warn 473 "no valid objects specified for $key." return "NULL" } return [make_exception_to $to_pins $to_clks $to_insts $to_rf $end_rf] @@ -3446,7 +3446,7 @@ proc parse_op_cond { op_cond_name lib_key min_max key_var } { set liberty [get_liberty_error $lib_key $keys($lib_key)] set op_cond [$liberty find_operating_conditions $op_cond_name] if { $op_cond == "NULL" } { - sta_error 579 "operating condition '$op_cond_name' not found." + sta_error 474 "operating condition '$op_cond_name' not found." } else { set_operating_conditions_cmd $op_cond $min_max } @@ -3464,7 +3464,7 @@ proc parse_op_cond { op_cond_name lib_key min_max key_var } { } $lib_iter finish if { !$found } { - sta_error 580 "operating condition '$op_cond_name' not found." + sta_error 475 "operating condition '$op_cond_name' not found." } } } @@ -3478,7 +3478,7 @@ proc parse_op_cond_analysis_type { key_var } { || $analysis_type == "on_chip_variation" } { set_analysis_type_cmd $analysis_type } else { - sta_error 581 "-analysis_type must be single, bc_wc or on_chip_variation." + sta_error 476 "-analysis_type must be single, bc_wc or on_chip_variation." } } elseif { [info exists keys(-min)] && [info exists keys(-max)] } { set_analysis_type_cmd "bc_wc" @@ -3490,7 +3490,7 @@ proc parse_op_cond_analysis_type { key_var } { define_cmd_args "set_wire_load_min_block_size" {block_size} proc set_wire_load_min_block_size { block_size } { - sta_warn 371 "set_wire_load_min_block_size not supported." + sta_warn 477 "set_wire_load_min_block_size not supported." } ################################################################ @@ -3503,7 +3503,7 @@ proc set_wire_load_mode { mode } { || $mode == "segmented" } { set_wire_load_mode_cmd $mode } else { - sta_error 582 "mode must be top, enclosed or segmented." + sta_error 478 "mode must be top, enclosed or segmented." } } @@ -3518,7 +3518,7 @@ proc set_wire_load_model { args } { check_argc_eq0or1 "set_wire_load_model" $args if { ![info exists keys(-name)] } { - sta_error 583 "no wire load model specified." + sta_error 479 "no wire load model specified." } set model_name $keys(-name) @@ -3540,7 +3540,7 @@ proc set_wire_load_model { args } { $lib_iter finish } if {$wireload == "NULL"} { - sta_error 605 "wire load model '$model_name' not found." + sta_error 480 "wire load model '$model_name' not found." } set objects $args set_wire_load_cmd $wireload $min_max @@ -3579,7 +3579,7 @@ proc set_wire_load_selection_group { args } { $lib_iter finish } if {$selection == "NULL"} { - sta_error 584 "wire load selection group '$selection_name' not found." + sta_error 481 "wire load selection group '$selection_name' not found." } set_wire_load_selection_group_cmd $selection $min_max } @@ -3667,7 +3667,7 @@ define_cmd_args "define_corners" { corner1 [corner2]... } proc define_corners { args } { if { [get_libs -quiet *] != {} } { - sta_error 373 "define_corners must be called before read_liberty." + sta_error 482 "define_corners must be called before read_liberty." } define_corners_cmd $args } @@ -3737,7 +3737,7 @@ proc default_operating_conditions {} { } $lib_iter finish if { !$found } { - sta_error 585 "no default operating conditions found." + sta_error 500 "no default operating conditions found." } return $op_cond } diff --git a/tcl/Search.tcl b/tcl/Search.tcl index 192ac052..da485fc1 100644 --- a/tcl/Search.tcl +++ b/tcl/Search.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -133,7 +133,7 @@ proc find_timing_paths_cmd { cmd args_var } { } elseif { $mm_key == "min" || $mm_key == "max" || $mm_key == "min_max" } { set min_max $mm_key } else { - sta_error 420 "$cmd -path_delay must be min, min_rise, min_fall, max, max_rise, max_fall or min_max." + sta_error 510 "$cmd -path_delay must be min, min_rise, min_fall, max, max_rise, max_fall or min_max." } } @@ -143,7 +143,7 @@ proc find_timing_paths_cmd { cmd args_var } { set to [parse_to_arg1 keys $end_rf arg_error] if { $arg_error } { delete_from_thrus_to $from $thrus $to - sta_error 421 "$cmd command failed." + sta_error 511 "$cmd command failed." } check_for_key_args $cmd args @@ -162,7 +162,7 @@ proc find_timing_paths_cmd { cmd args_var } { if [info exists keys(-endpoint_count)] { set endpoint_count $keys(-endpoint_count) if { $endpoint_count < 1 } { - sta_error 422 "-endpoint_count must be a positive integer." + sta_error 512 "-endpoint_count must be a positive integer." } } @@ -171,7 +171,7 @@ proc find_timing_paths_cmd { cmd args_var } { set group_count $keys(-group_count) check_positive_integer "-group_count" $group_count if { $group_count < 1 } { - sta_error 423 "-group_count must be >= 1." + sta_error 513 "-group_count must be >= 1." } } @@ -202,9 +202,9 @@ proc find_timing_paths_cmd { cmd args_var } { delete_from_thrus_to $from $thrus $to set arg [lindex $args 0] if { [is_keyword_arg $arg] } { - sta_error 424 "'$arg' is not a known keyword or flag." + sta_error 514 "'$arg' is not a known keyword or flag." } else { - sta_error 425 "positional arguments not supported." + sta_error 515 "positional arguments not supported." } } @@ -323,7 +323,7 @@ proc_redirect report_clock_skew { check_argc_eq0 "report_clock_skew" $args if { [info exists flags(-setup)] && [info exists flags(-hold)] } { - sta_error 419 "report_clock_skew -setup and -hold are mutually exclusive options." + sta_error 516 "report_clock_skew -setup and -hold are mutually exclusive options." } elseif { [info exists flags(-setup)] } { set setup_hold "setup" } elseif { [info exists flags(-hold)] } { @@ -404,14 +404,9 @@ proc_redirect report_check_types { variable path_options parse_key_args "report_check_types" args keys {-net -corner}\ - flags {-violators -all_violators -verbose -no_line_splits} 0 + flags {-violators -verbose -no_line_splits} 0 set violators [info exists flags(-violators)] - if { [info exists flags(-all_violators)] } { - sta_warn 609 "-all_violators is deprecated. Use -violators" - set violators 1 - } - set verbose [info exists flags(-verbose)] set nosplit [info exists flags(-no_line_splits)] @@ -477,8 +472,7 @@ proc_redirect report_check_types { -max_fanout -min_fanout \ -max_capacitance -min_capacitance \ -min_pulse_width \ - -min_period -max_skew \ - -max_transition -min_transition } 1 + -min_period -max_skew} 1 set setup [info exists flags(-max_delay)] set hold [info exists flags(-min_delay)] @@ -487,15 +481,7 @@ proc_redirect report_check_types { set clk_gating_setup [info exists flags(-clock_gating_setup)] set clk_gating_hold [info exists flags(-clock_gating_hold)] set max_slew [info exists flags(-max_slew)] - if { [info exists flags(-max_transition)] } { - sta_warn 610 "-max_transition deprecated. Use -max_slew." - set max_slew 1 - } set min_slew [info exists flags(-min_slew)] - if { [info exists flags(-min_transition)] } { - sta_warn 611 "-min_transition deprecated. Use -min_slew." - set min_slew 1 - } set max_fanout [info exists flags(-max_fanout)] set min_fanout [info exists flags(-min_fanout)] set max_capacitance [info exists flags(-max_capacitance)] @@ -507,12 +493,12 @@ proc_redirect report_check_types { && (($setup && $hold) \ || ($recovery && $removal) \ || ($clk_gating_setup && $clk_gating_hold)) } { - sta_error 426 "analysis type single is not consistent with doing both setup/max and hold/min checks." + sta_error 520 "analysis type single is not consistent with doing both setup/max and hold/min checks." } } if { $args != {} } { - sta_error 427 "positional arguments not supported." + sta_error 521 "positional arguments not supported." } set corner [parse_corner_or_all keys] @@ -775,7 +761,7 @@ proc_redirect report_path { flags {-max -min -all -tags} 0 if { [info exists flags(-min)] && [info exists flags(-max)] } { - sta_error 508 "-min and -max cannot both be specified." + sta_error 522 "-min and -max cannot both be specified." } elseif [info exists flags(-min)] { set min_max "min" } elseif [info exists flags(-max)] { @@ -795,7 +781,7 @@ proc_redirect report_path { set pin [get_port_pin_error "pin" $pin_arg] if { [$pin is_hierarchical] } { - sta_error 509 "pin '$pin_arg' is hierarchical." + sta_error 523 "pin '$pin_arg' is hierarchical." } else { foreach vertex [$pin vertices] { if { $vertex != "NULL" } { @@ -861,7 +847,7 @@ proc parse_report_path_options { cmd args_var default_format set formats {full full_clock full_clock_expanded short \ end slack_only summary json} if { [lsearch $formats $format] == -1 } { - sta_error 510 "-format $format not recognized." + sta_error 524 "-format $format not recognized." } } else { set path_options(-format) $default_format @@ -900,9 +886,6 @@ proc parse_report_path_options { cmd args_var default_format set report_net [expr [lsearch $fields "net*"] != -1] set report_slew [expr [lsearch $fields "slew*"] != -1] set report_fanout [expr [lsearch $fields "fanout*"] != -1] - if { [expr [lsearch $fields "trans*"] != -1] } { - sta_warn 1640 "The transition_time field is deprecated. Use slew instead." - } } else { set report_input_pin 0 set report_cap 0 @@ -1008,7 +991,7 @@ proc worst_clock_skew { args } { check_argc_eq0 "worst_clock_skew" $args if { ([info exists flags(-setup)] && [info exists flags(-hold)]) \ || (![info exists flags(-setup)] && ![info exists flags(-hold)]) } { - sta_error 616 "specify one of -setup and -hold." + sta_error 526 "specify one of -setup and -hold." } elseif { [info exists flags(-setup)] } { set setup_hold "setup" } elseif { [info exists flags(-hold)] } { @@ -1057,7 +1040,7 @@ proc parse_path_group_arg { group_names } { if { [is_path_group_name $name] } { lappend names $name } else { - sta_warn 318 "unknown path group '$name'." + sta_warn 527 "unknown path group '$name'." } } return $names diff --git a/tcl/Splash.tcl b/tcl/Splash.tcl index 398e25de..5f3f1b3f 100644 --- a/tcl/Splash.tcl +++ b/tcl/Splash.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -25,7 +25,7 @@ namespace eval sta { define_cmd_args show_splash {} proc show_splash {} { - report_line "OpenSTA [sta::version] [string range [sta::git_sha1] 0 9] Copyright (c) 2023, Parallax Software, Inc. + report_line "OpenSTA [sta::version] [string range [sta::git_sha1] 0 9] Copyright (c) 2024, Parallax Software, Inc. License GPLv3: GNU GPL version 3 This is free software, and you are free to change and redistribute it diff --git a/tcl/Sta.tcl b/tcl/Sta.tcl index 4b8ad0db..e377c259 100644 --- a/tcl/Sta.tcl +++ b/tcl/Sta.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -155,7 +155,7 @@ proc get_timing_edges_cmd { cmd cmd_args } { if { [info exists keys(-of_objects)] } { if { [info exists keys(-from)] \ || [info exists keys(-from)] } { - sta_error 440 "-from/-to arguments not supported with -of_objects." + sta_error 540 "-from/-to arguments not supported with -of_objects." } set arcs [get_timing_arcs_objects $keys(-of_objects)] } elseif { [info exists keys(-from)] \ @@ -283,7 +283,7 @@ proc filter_timing_arcs1 { filter objects } { } elseif { [regexp $filter_regexp1 $filter ignore attr_name op arg] } { set filtered_objects [filter_timing_arcs $attr_name $op $arg $objects] } else { - sta_error 441 "unsupported -filter expression." + sta_error 541 "unsupported -filter expression." } return $filtered_objects } diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index c2febea1..d6d3b692 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -3,7 +3,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -33,8 +33,6 @@ // //////////////////////////////////////////////////////////////// -#include - #include "Machine.hh" #include "StaConfig.hh" // STA_VERSION #include "Stats.hh" @@ -61,7 +59,6 @@ #include "ExceptionPath.hh" #include "Sdc.hh" #include "Graph.hh" -#include "Parasitics.hh" #include "DelayCalc.hh" #include "DcalcAnalysisPt.hh" #include "Corner.hh" @@ -90,13 +87,7 @@ namespace sta { // //////////////////////////////////////////////////////////////// -typedef Vector LibrarySeq; typedef MinPulseWidthCheckSeq::Iterator MinPulseWidthCheckSeqIterator; -typedef string TmpString; -typedef Set StringSet; -typedef MinMaxAll MinMaxAllNull; - -using std::vector; // Get the network for commands. Network * @@ -115,7 +106,7 @@ cmdLinkedNetwork() return network; else { Report *report = Sta::sta()->report(); - report->error(201, "no network has been linked."); + report->error(1570, "no network has been linked."); return nullptr; } } @@ -129,7 +120,7 @@ cmdEditNetwork() return dynamic_cast(network); else { Report *report = Sta::sta()->report(); - report->error(202, "network does not support edits."); + report->error(1571, "network does not support edits."); return nullptr; } } @@ -143,1356 +134,12 @@ cmdGraph() return Sta::sta()->ensureGraph(); } -template -Vector * -tclListSeq(Tcl_Obj *const source, - swig_type_info *swig_type, - Tcl_Interp *interp) -{ - int argc; - Tcl_Obj **argv; - - if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK - && argc > 0) { - Vector *seq = new Vector; - 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); - seq->push_back(reinterpret_cast(obj)); - } - return seq; - } - else - return nullptr; -} - -template -SET_TYPE * -tclListSet(Tcl_Obj *const source, - swig_type_info *swig_type, - Tcl_Interp *interp) -{ - int argc; - Tcl_Obj **argv; - if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK - && argc > 0) { - SET_TYPE *set = new SET_TYPE; - 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; - } - else - return nullptr; -} - -template -SET_TYPE * -tclListNetworkSet(Tcl_Obj *const source, - swig_type_info *swig_type, - Tcl_Interp *interp, - const Network *network) -{ - int argc; - Tcl_Obj **argv; - if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK - && argc > 0) { - SET_TYPE *set = new SET_TYPE(network); - 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; - } - else - return nullptr; -} - -StringSet * -tclListSetConstChar(Tcl_Obj *const source, - Tcl_Interp *interp) -{ - int argc; - Tcl_Obj **argv; - - if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { - StringSet *set = new StringSet; - for (int i = 0; i < argc; i++) { - int length; - const char *str = Tcl_GetStringFromObj(argv[i], &length); - set->insert(str); - } - return set; - } - else - return nullptr; -} - -StringSeq * -tclListSeqConstChar(Tcl_Obj *const source, - Tcl_Interp *interp) -{ - int argc; - Tcl_Obj **argv; - - if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { - StringSeq *seq = new StringSeq; - for (int i = 0; i < argc; i++) { - int length; - const char *str = Tcl_GetStringFromObj(argv[i], &length); - seq->push_back(str); - } - return seq; - } - else - return nullptr; -} - -StdStringSet * -tclListSetStdString(Tcl_Obj *const source, - Tcl_Interp *interp) -{ - int argc; - Tcl_Obj **argv; - - if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { - StdStringSet *set = new StdStringSet; - for (int i = 0; i < argc; i++) { - int length; - const char *str = Tcl_GetStringFromObj(argv[i], &length); - set->insert(str); - } - return set; - } - else - return nullptr; -} - -//////////////////////////////////////////////////////////////// - -// Sequence out to tcl list. -template -void -seqPtrTclList(SEQ_TYPE *seq, - swig_type_info *swig_type, - Tcl_Interp *interp) -{ - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - for (const OBJECT_TYPE *obj : *seq) { - Tcl_Obj *tcl_obj = SWIG_NewInstanceObj(const_cast(obj), - swig_type, false); - Tcl_ListObjAppendElement(interp, list, tcl_obj); - } - Tcl_SetObjResult(interp, list); -} - -template -void -seqTclList(SEQ_TYPE &seq, - swig_type_info *swig_type, - Tcl_Interp *interp) -{ - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - for (const OBJECT_TYPE *obj : seq) { - Tcl_Obj *tcl_obj = SWIG_NewInstanceObj(const_cast(obj), - swig_type, false); - Tcl_ListObjAppendElement(interp, list, tcl_obj); - } - Tcl_SetObjResult(interp, list); -} - -template -void -setTclList(SET_TYPE set, - swig_type_info *swig_type, - Tcl_Interp *interp) -{ - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - for (const OBJECT_TYPE *obj : set) { - Tcl_Obj *tcl_obj = SWIG_NewInstanceObj(const_cast(obj), - swig_type, false); - Tcl_ListObjAppendElement(interp, list, tcl_obj); - } - Tcl_SetObjResult(interp, list); -} - -template -void -setPtrTclList(SET_TYPE *set, - swig_type_info *swig_type, - Tcl_Interp *interp) -{ - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - for (const OBJECT_TYPE *obj : *set) { - Tcl_Obj *tcl_obj = SWIG_NewInstanceObj(const_cast(obj), - swig_type, false); - Tcl_ListObjAppendElement(interp, list, tcl_obj); - } - Tcl_SetObjResult(interp, list); -} - -//////////////////////////////////////////////////////////////// - -PinSet -findStartpoints() -{ - Network *network = cmdNetwork(); - PinSet pins(network); - VertexPinCollector visitor(pins); - Sta::sta()->visitStartpoints(&visitor); - return pins; -} - -PinSet -findEndpoints() -{ - Network *network = cmdNetwork(); - PinSet pins(network); - VertexPinCollector visitor(pins); - Sta::sta()->visitEndpoints(&visitor); - return pins; -} - -//////////////////////////////////////////////////////////////// - -void -tclArgError(Tcl_Interp *interp, - const char *msg, - const char *arg) -{ - // Swig does not add try/catch around arg parsing so this cannot use Report::error. - string error_msg = "Error: "; - error_msg += msg; - char *error = stringPrint(error_msg.c_str(), arg); - Tcl_SetResult(interp, error, TCL_VOLATILE); - stringDelete(error); -} - -void -objectListNext(const char *list, - const char *type, - // Return values. - bool &type_match, - const char *&next) -{ - // Default return values (failure). - type_match = false; - next = nullptr; - // _hexaddress_p_type - const char *s = list; - char ch = *s++; - if (ch == '_') { - while (*s && isxdigit(*s)) - s++; - if ((s - list - 1) == sizeof(void*) * 2 - && *s && *s++ == '_' - && *s && *s++ == 'p' - && *s && *s++ == '_') { - const char *t = type; - while (*s && *s != ' ') { - if (*s != *t) - return; - s++; - t++; - } - type_match = true; - if (*s) - next = s + 1; - else - next = nullptr; - } - } -} - } // namespace using namespace sta; %} -//////////////////////////////////////////////////////////////// -// -// SWIG type definitions. -// -//////////////////////////////////////////////////////////////// - -// String that is deleted after crossing over to tcland. -%typemap(out) string { - string &str = $1; - // String is volatile because it is deleted. - Tcl_SetResult(interp, const_cast(str.c_str()), TCL_VOLATILE); -} - -// String that is deleted after crossing over to tcland. -%typemap(out) TmpString* { - string *str = $1; - if (str) { - // String is volatile because it is deleted. - Tcl_SetResult(interp, const_cast(str->c_str()), TCL_VOLATILE); - delete str; - } - else - Tcl_SetResult(interp, nullptr, TCL_STATIC); -} - -%typemap(in) StringSeq* { - $1 = tclListSeqConstChar($input, interp); -} - -%typemap(in) StdStringSet* { - $1 = tclListSetStdString($input, interp); -} - -%typemap(out) StringSeq* { - StringSeq *strs = $1; - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - for (const char *str : *strs) { - Tcl_Obj *obj = Tcl_NewStringObj(str, strlen(str)); - Tcl_ListObjAppendElement(interp, list, obj); - } - Tcl_SetObjResult(interp, list); -} - -%typemap(out) StringSeq { - StringSeq &strs = $1; - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - for (const char *str : strs) { - Tcl_Obj *obj = Tcl_NewStringObj(str, strlen(str)); - Tcl_ListObjAppendElement(interp, list, obj); - } - Tcl_SetObjResult(interp, list); -} - -%typemap(out) Library* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) LibraryIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) LibertyLibraryIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) Cell* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(in) CellSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_Cell, interp); -} - -%typemap(out) CellSeq { - seqTclList($1, SWIGTYPE_p_Cell, interp); -} - -%typemap(out) LibertyCellSeq * { - seqPtrTclList($1, SWIGTYPE_p_LibertyCell, interp); -} - -%typemap(out) LibertyCellSeq { - seqTclList($1, SWIGTYPE_p_LibertyCell, interp); -} - -%typemap(out) LibertyPortSeq { - seqTclList($1, SWIGTYPE_p_LibertyPort, interp); -} - -%typemap(out) CellPortIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) LibertyCellPortIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) Port* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(in) PortSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_Port, interp); -} - -%typemap(out) PortSeq { - seqTclList($1, SWIGTYPE_p_Port, interp); -} - -%typemap(out) PortMemberIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) LibertyCell* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) LibertyPort* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) LibertyPortMemberIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, SWIGTYPE_p_LibertyPortMemberIterator, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) TimingArc* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) TimingArcSetSeq& { - seqPtrTclList($1, SWIGTYPE_p_TimingArcSet, interp); -} - -%typemap(out) TimingArcSeq& { - seqPtrTclList($1, SWIGTYPE_p_TimingArc, interp); -} - -%typemap(out) Wireload* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) WireloadSelection* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(in) Transition* { - int length; - const char *arg = Tcl_GetStringFromObj($input, &length); - Transition *tr = Transition::find(arg); - if (tr == nullptr) { - Tcl_SetResult(interp,const_cast("Error: transition not found."), - TCL_STATIC); - return TCL_ERROR; - } - else - $1 = tr; -} - -%typemap(out) Transition* { - Transition *tr = $1; - const char *str = ""; - if (tr) - str = tr->asString(); - Tcl_SetResult(interp, const_cast(str), TCL_STATIC); -} - -%typemap(in) RiseFall* { - int length; - const char *arg = Tcl_GetStringFromObj($input, &length); - RiseFall *rf = RiseFall::find(arg); - if (rf == nullptr) { - Tcl_SetResult(interp,const_cast("Error: unknown rise/fall edge."), - TCL_STATIC); - return TCL_ERROR; - } - $1 = rf; -} - -%typemap(out) RiseFall* { - const RiseFall *tr = $1; - const char *str = ""; - if (tr) - str = tr->asString(); - Tcl_SetResult(interp, const_cast(str), TCL_STATIC); -} - -%typemap(in) RiseFallBoth* { - int length; - const char *arg = Tcl_GetStringFromObj($input, &length); - RiseFallBoth *tr = RiseFallBoth::find(arg); - if (tr == nullptr) { - Tcl_SetResult(interp,const_cast("Error: unknown transition name."), - TCL_STATIC); - return TCL_ERROR; - } - $1 = tr; -} - -%typemap(out) RiseFallBoth* { - RiseFallBoth *tr = $1; - const char *str = ""; - if (tr) - str = tr->asString(); - Tcl_SetResult(interp, const_cast(str), TCL_STATIC); -} - -%typemap(in) TimingRole* { - int length; - const char *arg = Tcl_GetStringFromObj($input, &length); - TimingRole *role = TimingRole::find(arg); - if (role) - $1 = TimingRole::find(arg); - else { - Tcl_SetResult(interp,const_cast("Error: unknown timing role."), - TCL_STATIC); - return TCL_ERROR; - } -} - -%typemap(out) TimingRole* { - Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); -} - -%typemap(in) LogicValue { - int length; - const char *arg = Tcl_GetStringFromObj($input, &length); - if (stringEq(arg, "0") || stringEq(arg, "zero")) - $1 = LogicValue::zero; - else if (stringEq(arg, "1") || stringEq(arg, "one")) - $1 = LogicValue::one; - else if (stringEq(arg, "X")) - $1 = LogicValue::unknown; - else if (stringEq(arg, "rise") || stringEq(arg, "rising")) - $1 = LogicValue::rise; - else if (stringEq(arg, "fall") || stringEq(arg, "falling")) - $1 = LogicValue::fall; - else { - Tcl_SetResult(interp,const_cast("Error: unknown logic value."), - TCL_STATIC); - return TCL_ERROR; - } -} - -%typemap(in) AnalysisType { - int length; - const char *arg = Tcl_GetStringFromObj($input, &length); - if (stringEqual(arg, "single")) - $1 = AnalysisType::single; - else if (stringEqual(arg, "bc_wc")) - $1 = AnalysisType::bc_wc; - else if (stringEq(arg, "on_chip_variation")) - $1 = AnalysisType::ocv; - else { - Tcl_SetResult(interp,const_cast("Error: unknown analysis type."), - TCL_STATIC); - - return TCL_ERROR; - } -} - -%typemap(out) Instance* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(in) InstanceSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_Instance, interp); -} - -%typemap(out) InstanceSeq { - seqTclList($1, SWIGTYPE_p_Instance, interp); -} - -%typemap(out) InstanceChildIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) LeafInstanceIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) InstancePinIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) InstanceNetIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) Pin* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) PinSeq* { - seqPtrTclList($1, SWIGTYPE_p_Pin, interp); -} - - -%typemap(out) PinSeq { - seqTclList($1, SWIGTYPE_p_Pin, interp); -} - -%typemap(out) Net* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) NetSeq* { - seqPtrTclList($1, SWIGTYPE_p_Net, interp); -} - -%typemap(out) NetSeq { - seqTclList($1, SWIGTYPE_p_Net, interp); -} - -%typemap(out) NetPinIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) NetTermIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) NetConnectedPinIterator* { - Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) PinConnectedPinIterator* { - Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) Clock* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) ClockSeq* { - seqPtrTclList($1, SWIGTYPE_p_Clock, interp); -} - -%typemap(out) ClockSeq { - seqTclList($1, SWIGTYPE_p_Clock, interp); -} - -%typemap(out) ClockEdge* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1,$1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(in) PinSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_Pin, interp); -} - -%typemap(in) PinSet* { - Network *network = cmdNetwork(); - $1 = tclListNetworkSet($input, SWIGTYPE_p_Pin, interp, network); -} - -%typemap(out) PinSet* { - setPtrTclList($1, SWIGTYPE_p_Pin, interp); -} - -%typemap(out) PinSet { - setTclList($1, SWIGTYPE_p_Pin, interp); -} - -%typemap(out) const PinSet& { - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - // A swig bug sets the result to PinSet* rather than const PinSet&. - PinSet *pins = $1; - for (const Pin *pin : *pins) { - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(pin), SWIGTYPE_p_Pin, false); - Tcl_ListObjAppendElement(interp, list, obj); - } - Tcl_SetObjResult(interp, list); -} - -%typemap(in) ClockSet* { - $1 = tclListSet($input, SWIGTYPE_p_Clock, interp); -} - -%typemap(out) ClockSet* { - setPtrTclList($1, SWIGTYPE_p_Clock, interp); -} - -%typemap(in) InstanceSet* { - Network *network = cmdNetwork(); - $1 = tclListNetworkSet($input, SWIGTYPE_p_Instance, - interp, network); -} - -%typemap(out) InstanceSet { - setTclList($1, SWIGTYPE_p_Instance, interp); -} - -%typemap(in) NetSet* { - Network *network = cmdNetwork(); - $1 = tclListNetworkSet($input, SWIGTYPE_p_Net, interp, network); -} - -%typemap(in) FloatSeq* { - int argc; - Tcl_Obj **argv; - FloatSeq *floats = nullptr; - - if (Tcl_ListObjGetElements(interp, $input, &argc, &argv) == TCL_OK) { - if (argc) - floats = new FloatSeq; - for (int i = 0; i < argc; i++) { - char *arg = Tcl_GetString(argv[i]); - double value; - if (Tcl_GetDouble(interp, arg, &value) == TCL_OK) - floats->push_back(static_cast(value)); - else { - delete floats; - tclArgError(interp, "%s is not a floating point number.", arg); - return TCL_ERROR; - } - } - } - $1 = floats; -} - -%typemap(out) FloatSeq* { - FloatSeq *floats = $1; - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - if (floats) { - for (float f : *floats) { - Tcl_Obj *obj = Tcl_NewDoubleObj(f); - Tcl_ListObjAppendElement(interp, list, obj); - } - } - Tcl_SetObjResult(interp, list); -} - -%typemap(out) FloatSeq { - FloatSeq &floats = $1; - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - for (float f : floats) { - Tcl_Obj *obj = Tcl_NewDoubleObj(f); - Tcl_ListObjAppendElement(interp, list, obj); - } - Tcl_SetObjResult(interp, list); -} - -%typemap(in) IntSeq* { - int argc; - Tcl_Obj **argv; - IntSeq *ints = nullptr; - - if (Tcl_ListObjGetElements(interp, $input, &argc, &argv) == TCL_OK) { - if (argc) - ints = new IntSeq; - for (int i = 0; i < argc; i++) { - char *arg = Tcl_GetString(argv[i]); - int value; - if (Tcl_GetInt(interp, arg, &value) == TCL_OK) - ints->push_back(value); - else { - delete ints; - tclArgError(interp, "%s is not an integer.", arg); - return TCL_ERROR; - } - } - } - $1 = ints; -} - -%typemap(out) Table1 { - Table1 &table = $1; - if (table.axis1()) { - Tcl_Obj *list3 = Tcl_NewListObj(0, nullptr); - Tcl_Obj *list1 = Tcl_NewListObj(0, nullptr); - for (float f : *table.axis1()->values()) { - Tcl_Obj *obj = Tcl_NewDoubleObj(f); - Tcl_ListObjAppendElement(interp, list1, obj); - } - Tcl_Obj *list2 = Tcl_NewListObj(0, nullptr); - for (float f : *table.values()) { - Tcl_Obj *obj = Tcl_NewDoubleObj(f); - Tcl_ListObjAppendElement(interp, list2, obj); - } - Tcl_ListObjAppendElement(interp, list3, list1); - Tcl_ListObjAppendElement(interp, list3, list2); - Tcl_SetObjResult(interp, list3); - } -} - -%typemap(out) const Table1* { - const Table1 *table = $1; - Tcl_Obj *list3 = Tcl_NewListObj(0, nullptr); - if (table) { - Tcl_Obj *list1 = Tcl_NewListObj(0, nullptr); - for (float f : *table->axis1()->values()) { - Tcl_Obj *obj = Tcl_NewDoubleObj(f); - Tcl_ListObjAppendElement(interp, list1, obj); - } - Tcl_Obj *list2 = Tcl_NewListObj(0, nullptr); - for (float f : *table->values()) { - Tcl_Obj *obj = Tcl_NewDoubleObj(f); - Tcl_ListObjAppendElement(interp, list2, obj); - } - Tcl_ListObjAppendElement(interp, list3, list1); - Tcl_ListObjAppendElement(interp, list3, list2); - } - Tcl_SetObjResult(interp, list3); -} - -%typemap(in) MinMax* { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - MinMax *min_max = MinMax::find(arg); - if (min_max) - $1 = min_max; - else { - tclArgError(interp, "%s not min or max.", arg); - return TCL_ERROR; - } -} - -%typemap(out) MinMax* { - Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); -} - -%typemap(out) MinMax* { - Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); -} - -%typemap(in) MinMaxAll* { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - MinMaxAll *min_max = MinMaxAll::find(arg); - if (min_max) - $1 = min_max; - else { - tclArgError(interp, "%s not min, max or min_max.", arg); - return TCL_ERROR; - } -} - -%typemap(in) MinMaxAllNull* { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - if (stringEqual(arg, "NULL")) - $1 = nullptr; - else { - MinMaxAll *min_max = MinMaxAll::find(arg); - if (min_max) - $1 = min_max; - else { - tclArgError(interp, "%s not min, max or min_max.", arg); - return TCL_ERROR; - } - } -} - -%typemap(out) MinMaxAll* { - Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); -} - -// SetupHold is typedef'd to MinMax. -%typemap(in) SetupHold* { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - if (stringEqual(arg, "hold") - || stringEqual(arg, "min")) - $1 = MinMax::min(); - else if (stringEqual(arg, "setup") - || stringEqual(arg, "max")) - $1 = MinMax::max(); - else { - tclArgError(interp, "%s not setup, hold, min or max.", arg); - return TCL_ERROR; - } -} - -// SetupHoldAll is typedef'd to MinMaxAll. -%typemap(in) SetupHoldAll* { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - if (stringEqual(arg, "hold") - || stringEqual(arg, "min")) - $1 = SetupHoldAll::min(); - else if (stringEqual(arg, "setup") - || stringEqual(arg, "max")) - $1 = SetupHoldAll::max(); - else if (stringEqual(arg, "setup_hold") - || stringEqual(arg, "min_max")) - $1 = SetupHoldAll::all(); - else { - tclArgError(interp, "%s not setup, hold, setup_hold, min, max or min_max.", arg); - return TCL_ERROR; - } -} - -// EarlyLate is typedef'd to MinMax. -%typemap(in) EarlyLate* { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - EarlyLate *early_late = EarlyLate::find(arg); - if (early_late) - $1 = early_late; - else { - tclArgError(interp, "%s not early/min, late/max or early_late/min_max.", arg); - return TCL_ERROR; - } -} - -// EarlyLateAll is typedef'd to MinMaxAll. -%typemap(in) EarlyLateAll* { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - EarlyLateAll *early_late = EarlyLateAll::find(arg); - if (early_late) - $1 = early_late; - else { - tclArgError(interp, "%s not early/min, late/max or early_late/min_max.", arg); - return TCL_ERROR; - } -} - -%typemap(in) TimingDerateType { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - if (stringEq(arg, "net_delay")) - $1 = TimingDerateType::net_delay; - else if (stringEq(arg, "cell_delay")) - $1 = TimingDerateType::cell_delay; - else if (stringEq(arg, "cell_check")) - $1 = TimingDerateType::cell_check; - else { - tclArgError(interp, "%s not net_delay, cell_delay or cell_check.", arg); - return TCL_ERROR; - } -} - -%typemap(in) TimingDerateCellType { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - if (stringEq(arg, "cell_delay")) - $1 = TimingDerateCellType::cell_delay; - else if (stringEq(arg, "cell_check")) - $1 = TimingDerateCellType::cell_check; - else { - tclArgError(interp, "%s not cell_delay or cell_check.", arg); - return TCL_ERROR; - } -} - -%typemap(in) PathClkOrData { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - if (stringEq(arg, "clk")) - $1 = PathClkOrData::clk; - else if (stringEq(arg, "data")) - $1 = PathClkOrData::data; - else { - tclArgError(interp, "%s not clk or data.", arg); - return TCL_ERROR; - } -} - -%typemap(in) ReportSortBy { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - if (stringEq(arg, "group")) - $1 = sort_by_group; - else if (stringEq(arg, "slack")) - $1 = sort_by_slack; - else { - tclArgError(interp, "%s not group or slack.", arg); - return TCL_ERROR; - } -} - -%typemap(in) ReportPathFormat { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - if (stringEq(arg, "full")) - $1 = ReportPathFormat::full; - else if (stringEq(arg, "full_clock")) - $1 = ReportPathFormat::full_clock; - else if (stringEq(arg, "full_clock_expanded")) - $1 = ReportPathFormat::full_clock_expanded; - else if (stringEq(arg, "short")) - $1 = ReportPathFormat::shorter; - else if (stringEq(arg, "end")) - $1 = ReportPathFormat::endpoint; - else if (stringEq(arg, "summary")) - $1 = ReportPathFormat::summary; - else if (stringEq(arg, "slack_only")) - $1 = ReportPathFormat::slack_only; - else if (stringEq(arg, "json")) - $1 = ReportPathFormat::json; - else { - tclArgError(interp, "unknown path type %s.", arg); - return TCL_ERROR; - } -} - -%typemap(in) ExceptionThruSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_ExceptionThru, interp); -} - -%typemap(out) Vertex* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) Vertex** { - int i = 0; - Tcl_ResetResult(interp); - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - while ($1[i]) { - Tcl_Obj *obj = SWIG_NewInstanceObj($1[i], SWIGTYPE_p_Vertex,false); - Tcl_ListObjAppendElement(interp, list, obj); - i++; - } - Tcl_SetObjResult(interp, list); -} - -%typemap(out) Edge* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(in) EdgeSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_Edge, interp); -} - -%typemap(out) EdgeSeq { - seqTclList($1, SWIGTYPE_p_Edge, interp); -} - -%typemap(out) VertexIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) VertexInEdgeIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) VertexOutEdgeIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) CheckErrorSeq & { - Tcl_Obj *error_list = Tcl_NewListObj(0, nullptr); - CheckErrorSeq *check_errors = $1; - CheckErrorSeq::Iterator check_iter(check_errors); - while (check_iter.hasNext()) { - CheckError *error = check_iter.next(); - Tcl_Obj *string_list = Tcl_NewListObj(0, nullptr); - CheckError::Iterator string_iter(error); - while (string_iter.hasNext()) { - const char *str = string_iter.next(); - size_t str_len = strlen(str); - Tcl_Obj *obj = Tcl_NewStringObj(const_cast(str), - static_cast(str_len)); - Tcl_ListObjAppendElement(interp, string_list, obj); - } - Tcl_ListObjAppendElement(interp, error_list, string_list); - } - Tcl_SetObjResult(interp, error_list); -} - -%typemap(out) PathEnd* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) PathEndSeq* { - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - const PathEndSeq *path_ends = $1; - PathEndSeq::ConstIterator end_iter(path_ends); - while (end_iter.hasNext()) { - PathEnd *path_end = end_iter.next(); - Tcl_Obj *obj = SWIG_NewInstanceObj(path_end, SWIGTYPE_p_PathEnd, false); - Tcl_ListObjAppendElement(interp, list, obj); - } - // Delete the PathEndSeq, not the ends. - delete path_ends; - Tcl_SetObjResult(interp, list); -} - -%typemap(out) PathEndSeq { - seqTclList($1, SWIGTYPE_p_PathEnd, interp); -} - -%typemap(out) MinPulseWidthCheckSeqIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) PathRefSeq* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); - - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - PathRefSeq *paths = $1; - PathRefSeq::Iterator path_iter(paths); - while (path_iter.hasNext()) { - PathRef *path = &path_iter.next(); - PathRef *copy = new PathRef(path); - Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false); - Tcl_ListObjAppendElement(interp, list, obj); - } - Tcl_SetObjResult(interp, list); -} - -%typemap(out) MinPulseWidthCheck* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) MinPulseWidthCheckSeq & { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) MinPulseWidthCheckSeqIterator & { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) VertexPathIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) SlowDrvrIterator* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) ExceptionFrom* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) ExceptionTo* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) ExceptionThru* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) OperatingConditions* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(in) ReducedParasiticType { - int length; - char *arg = Tcl_GetStringFromObj($input, &length); - if (stringEq(arg, "pi_elmore")) - $1 = ReducedParasiticType::pi_elmore; - else if (stringEq(arg, "pi_pole_residue2")) - $1 = ReducedParasiticType::pi_pole_residue2; - else if (stringEq(arg, "none")) - $1 = ReducedParasiticType::none; - else { - tclArgError(interp, "%s pi_elmore, pi_pole_residue2, or none.", arg); - return TCL_ERROR; - } -} - -%typemap(out) Arrival { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); -} - -%typemap(out) Required { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); -} - -%typemap(out) Slack { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); -} - -%typemap(out) ArcDelay { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); -} - -%typemap(out) Slew { - Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); -} - -%typemap(in) PathGroupNameSet* { - $1 = tclListSetConstChar($input, interp); -} - -%typemap(in) StringSet* { - $1 = tclListSetConstChar($input, interp); -} - -%typemap(out) Corner* { - Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) Corners* { - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - Corners *corners = $1; - for (Corner *corner : *corners) { - Tcl_Obj *obj = SWIG_NewInstanceObj(corner, SWIGTYPE_p_Corner, false); - Tcl_ListObjAppendElement(interp, list, obj); - } - Tcl_SetObjResult(interp, list); -} - -%typemap(out) PropertyValue { - PropertyValue value = $1; - switch (value.type()) { - case PropertyValue::Type::type_none: - Tcl_SetResult(interp, const_cast(""), TCL_STATIC); - break; - case PropertyValue::Type::type_string: - Tcl_SetResult(interp, const_cast(value.stringValue()), TCL_VOLATILE); - break; - case PropertyValue::Type::type_float: { - const Unit *unit = value.unit(); - const char *float_string = unit->asString(value.floatValue(), 6); - Tcl_SetResult(interp, const_cast(float_string), TCL_VOLATILE); - } - break; - case PropertyValue::Type::type_bool: { - const char *bool_string = value.boolValue() ? "1" : "0"; - Tcl_SetResult(interp, const_cast(bool_string), TCL_STATIC); - } - break; - case PropertyValue::Type::type_library: { - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.library()), - SWIGTYPE_p_Library, false); - Tcl_SetObjResult(interp, obj); - } - break; - case PropertyValue::Type::type_cell: { - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.cell()), - SWIGTYPE_p_Cell, false); - Tcl_SetObjResult(interp, obj); - } - break; - case PropertyValue::Type::type_port: { - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.port()), - SWIGTYPE_p_Port, false); - Tcl_SetObjResult(interp, obj); - } - break; - case PropertyValue::Type::type_liberty_library: { - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.libertyLibrary()), - SWIGTYPE_p_LibertyLibrary, false); - Tcl_SetObjResult(interp, obj); - } - break; - case PropertyValue::Type::type_liberty_cell: { - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.libertyCell()), - SWIGTYPE_p_LibertyCell, false); - Tcl_SetObjResult(interp, obj); - } - break; - case PropertyValue::Type::type_liberty_port: { - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.libertyPort()), - SWIGTYPE_p_LibertyPort, false); - Tcl_SetObjResult(interp, obj); - } - break; - case PropertyValue::Type::type_instance: { - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.instance()), - SWIGTYPE_p_Instance, false); - Tcl_SetObjResult(interp, obj); - } - break; - case PropertyValue::Type::type_pin: { - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.pin()), - SWIGTYPE_p_Pin, false); - Tcl_SetObjResult(interp, obj); - } - break; - case PropertyValue::Type::type_pins: { - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - PinSeq *pins = value.pins(); - PinSeq::Iterator pin_iter(pins); - while (pin_iter.hasNext()) { - const Pin *pin = pin_iter.next(); - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(pin), SWIGTYPE_p_Pin, false); - Tcl_ListObjAppendElement(interp, list, obj); - } - Tcl_SetObjResult(interp, list); - } - break; - case PropertyValue::Type::type_net: { - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.net()), - SWIGTYPE_p_Net, false); - Tcl_SetObjResult(interp, obj); - } - break; - case PropertyValue::Type::type_clk: { - Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.clock()), - SWIGTYPE_p_Clock, false); - Tcl_SetObjResult(interp, obj); - } - break; - case PropertyValue::Type::type_clks: { - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - ClockSeq *clks = value.clocks(); - ClockSeq::Iterator clk_iter(clks); - while (clk_iter.hasNext()) { - Clock *clk = clk_iter.next(); - Tcl_Obj *obj = SWIG_NewInstanceObj(clk, SWIGTYPE_p_Clock, false); - Tcl_ListObjAppendElement(interp, list, obj); - } - Tcl_SetObjResult(interp, list); - } - break; - case PropertyValue::Type::type_path_refs: { - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - for (PathRef &path : *value.pathRefs()) { - PathRef *copy = new PathRef(path); - Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false); - Tcl_ListObjAppendElement(interp, list, obj); - } - Tcl_SetObjResult(interp, list); - } - break; - case PropertyValue::Type::type_pwr_activity: { - PwrActivity activity = value.pwrActivity(); - Tcl_Obj *list = Tcl_NewListObj(0, nullptr); - Tcl_Obj *obj; - const char *str; - - str = stringPrintTmp("%.5e", activity.activity()); - obj = Tcl_NewStringObj(str, strlen(str)); - Tcl_ListObjAppendElement(interp, list, obj); - - str = stringPrintTmp("%.3f", activity.duty()); - obj = Tcl_NewStringObj(str, strlen(str)); - Tcl_ListObjAppendElement(interp, list, obj); - - str = activity.originName(); - obj = Tcl_NewStringObj(str, strlen(str)); - Tcl_ListObjAppendElement(interp, list, obj); - - Tcl_SetObjResult(interp, list); - } - break; - } -} - //////////////////////////////////////////////////////////////// // // Empty class definitions to make swig happy. @@ -1794,13 +441,6 @@ private: ~VertexPathIterator(); }; -class SlowDrvrIterator -{ -private: - SlowDrvrIterator(); - ~SlowDrvrIterator(); -}; - class ExceptionFrom { private: @@ -2008,20 +648,6 @@ is_object_list(const char *list, return true; } -void -set_rise_fall_short_names(const char *rise_short_name, - const char *fall_short_name) -{ - RiseFall::rise()->setShortName(rise_short_name); - RiseFall::fall()->setShortName(fall_short_name); - - RiseFallBoth::rise()->setShortName(rise_short_name); - RiseFallBoth::fall()->setShortName(fall_short_name); - - Transition::rise()->setName(rise_short_name); - Transition::fall()->setName(fall_short_name); -} - const char * rise_short_name() { @@ -2357,14 +983,7 @@ find_instance(char *path_name) InstanceSeq network_leaf_instances() { - InstanceSeq insts; - LeafInstanceIterator *iter = cmdLinkedNetwork()->leafInstanceIterator(); - while (iter->hasNext()) { - const Instance *inst = iter->next(); - insts.push_back(inst); - } - delete iter; - return insts; + return cmdLinkedNetwork()->leafInstances(); } InstanceSeq @@ -4112,7 +2731,7 @@ set_crpr_mode(const char *mode) else if (stringEq(mode, "same_transition")) Sta::sta()->setCrprMode(CrprMode::same_transition); else - sta->report()->critical(272, "unknown common clk pessimism mode."); + sta->report()->critical(1573, "unknown common clk pessimism mode."); } bool @@ -4126,7 +2745,7 @@ set_pocv_enabled(bool enabled) { #if !SSTA if (enabled) - Sta::sta()->report()->error(204, "POCV support requires compilation with SSTA=1."); + Sta::sta()->report()->error(1574, "POCV support requires compilation with SSTA=1."); #endif return Sta::sta()->setPocvEnabled(enabled); } @@ -4364,7 +2983,7 @@ set_report_path_field_properties(const char *field_name, if (field) field->setProperties(title, width, left_justify); else - sta->report()->error(607, "unknown report path field %s", field_name); + sta->report()->error(1575, "unknown report path field %s", field_name); } void @@ -4376,7 +2995,7 @@ set_report_path_field_width(const char *field_name, if (field) field->setWidth(width); else - sta->report()->error(608, "unknown report path field %s", field_name); + sta->report()->error(1576, "unknown report path field %s", field_name); } void @@ -4436,13 +3055,19 @@ worst_clk_skew_cmd(const SetupHold *setup_hold) PinSet startpoints() { - return findStartpoints(); + return Sta::sta()->startpointPins(); } PinSet endpoints() { - return findEndpoints(); + return Sta::sta()->endpointPins(); +} + +size_t +endpoint_count() +{ + return Sta::sta()->endpointPins().size(); } PinSet @@ -4911,12 +3536,13 @@ write_path_spice_cmd(PathRef *path, const char *model_filename, StdStringSet *off_path_pins, const char *power_name, - const char *gnd_name) + const char *gnd_name, + bool measure_stmts) { Sta *sta = Sta::sta(); writePathSpice(path, spice_filename, subckt_filename, lib_subckt_filename, model_filename, off_path_pins, - power_name, gnd_name, sta); + power_name, gnd_name, measure_stmts, sta); delete off_path_pins; } @@ -4984,10 +3610,10 @@ pin_logic_value(const Pin *pin) return logicValueString(value); } -SlowDrvrIterator * -slow_driver_iterator() +InstanceSeq +slow_drivers(int count) { - return Sta::sta()->slowDrvrIterator(); + return Sta::sta()->slowDrivers(count); } bool @@ -5061,7 +3687,7 @@ set_clock_sense_cmd(PinSet *pins, else if (stop_propagation) sta->setClockSense(pins, clks, ClockSense::stop); else - sta->report()->critical(273, "unknown clock sense"); + sta->report()->critical(1577, "unknown clock sense"); } bool @@ -5438,12 +4064,6 @@ port_location(const Port *port) return pin_location(pin); } -int -endpoint_count() -{ - return Sta::sta()->endpoints()->size(); -} - int endpoint_violation_count(const MinMax *min_max) { @@ -5758,7 +4378,6 @@ voltage_current(float in_slew, if (gate_model) { OutputWaveforms *waveforms = gate_model->outputWaveforms(); if (waveforms) { - waveforms->setVdd(.7); float current = waveforms->voltageCurrent(in_slew, load_cap, voltage); return current; } @@ -6387,18 +5006,6 @@ next() void finish() { delete self; } } -%extend SlowDrvrIterator { -bool has_next() { return self->hasNext(); } -const Instance *next() { return self->next(); } -void -finish() -{ - delete self->container(); - delete self; -} - -} - %extend Corner { const char *name() { return self->name(); } } diff --git a/tcl/StaTclTypes.i b/tcl/StaTclTypes.i new file mode 100644 index 00000000..a2af7ecb --- /dev/null +++ b/tcl/StaTclTypes.i @@ -0,0 +1,1350 @@ + +%{ + +#include "Machine.hh" +#include "StringUtil.hh" +#include "StringSet.hh" +#include "StringSeq.hh" +#include "PatternMatch.hh" +#include "Vector.hh" +#include "Network.hh" +#include "Liberty.hh" +#include "FuncExpr.hh" +#include "TimingArc.hh" +#include "TableModel.hh" +#include "TimingRole.hh" +#include "Graph.hh" +#include "NetworkClass.hh" +#include "Clock.hh" +#include "Corner.hh" +#include "Search.hh" +#include "PathRef.hh" +#include "search/Tag.hh" +#include "PathEnd.hh" +#include "SearchClass.hh" +#include "Sta.hh" + +namespace sta { + +typedef MinPulseWidthCheckSeq::Iterator MinPulseWidthCheckSeqIterator; +typedef MinMaxAll MinMaxAllNull; + +Network * +cmdNetwork(); +Network * +cmdLinkedNetwork(); +Graph * +cmdGraph(); + +template +Vector * +tclListSeq(Tcl_Obj *const source, + swig_type_info *swig_type, + Tcl_Interp *interp) +{ + int argc; + Tcl_Obj **argv; + + if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK + && argc > 0) { + Vector *seq = new Vector; + 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); + seq->push_back(reinterpret_cast(obj)); + } + return seq; + } + else + return nullptr; +} + +template +SET_TYPE * +tclListSet(Tcl_Obj *const source, + swig_type_info *swig_type, + Tcl_Interp *interp) +{ + int argc; + Tcl_Obj **argv; + if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK + && argc > 0) { + SET_TYPE *set = new SET_TYPE; + 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; + } + else + return nullptr; +} + +template +SET_TYPE * +tclListNetworkSet(Tcl_Obj *const source, + swig_type_info *swig_type, + Tcl_Interp *interp, + const Network *network) +{ + int argc; + Tcl_Obj **argv; + if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK + && argc > 0) { + SET_TYPE *set = new SET_TYPE(network); + 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; + } + else + return nullptr; +} + +StringSet * +tclListSetConstChar(Tcl_Obj *const source, + Tcl_Interp *interp) +{ + int argc; + Tcl_Obj **argv; + + if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { + StringSet *set = new StringSet; + for (int i = 0; i < argc; i++) { + int length; + const char *str = Tcl_GetStringFromObj(argv[i], &length); + set->insert(str); + } + return set; + } + else + return nullptr; +} + +StringSeq * +tclListSeqConstChar(Tcl_Obj *const source, + Tcl_Interp *interp) +{ + int argc; + Tcl_Obj **argv; + + if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { + StringSeq *seq = new StringSeq; + for (int i = 0; i < argc; i++) { + int length; + const char *str = Tcl_GetStringFromObj(argv[i], &length); + seq->push_back(str); + } + return seq; + } + else + return nullptr; +} + +StdStringSet * +tclListSetStdString(Tcl_Obj *const source, + Tcl_Interp *interp) +{ + int argc; + Tcl_Obj **argv; + + if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK) { + StdStringSet *set = new StdStringSet; + for (int i = 0; i < argc; i++) { + int length; + const char *str = Tcl_GetStringFromObj(argv[i], &length); + set->insert(str); + } + return set; + } + else + return nullptr; +} + +//////////////////////////////////////////////////////////////// + +// Sequence out to tcl list. +template +void +seqPtrTclList(SEQ_TYPE *seq, + swig_type_info *swig_type, + Tcl_Interp *interp) +{ + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + for (const OBJECT_TYPE *obj : *seq) { + Tcl_Obj *tcl_obj = SWIG_NewInstanceObj(const_cast(obj), + swig_type, false); + Tcl_ListObjAppendElement(interp, list, tcl_obj); + } + Tcl_SetObjResult(interp, list); +} + +template +void +seqTclList(SEQ_TYPE &seq, + swig_type_info *swig_type, + Tcl_Interp *interp) +{ + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + for (const OBJECT_TYPE *obj : seq) { + Tcl_Obj *tcl_obj = SWIG_NewInstanceObj(const_cast(obj), + swig_type, false); + Tcl_ListObjAppendElement(interp, list, tcl_obj); + } + Tcl_SetObjResult(interp, list); +} + +template +void +setTclList(SET_TYPE set, + swig_type_info *swig_type, + Tcl_Interp *interp) +{ + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + for (const OBJECT_TYPE *obj : set) { + Tcl_Obj *tcl_obj = SWIG_NewInstanceObj(const_cast(obj), + swig_type, false); + Tcl_ListObjAppendElement(interp, list, tcl_obj); + } + Tcl_SetObjResult(interp, list); +} + +template +void +setPtrTclList(SET_TYPE *set, + swig_type_info *swig_type, + Tcl_Interp *interp) +{ + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + for (const OBJECT_TYPE *obj : *set) { + Tcl_Obj *tcl_obj = SWIG_NewInstanceObj(const_cast(obj), + swig_type, false); + Tcl_ListObjAppendElement(interp, list, tcl_obj); + } + Tcl_SetObjResult(interp, list); +} + +//////////////////////////////////////////////////////////////// + +void +tclArgError(Tcl_Interp *interp, + const char *msg, + const char *arg) +{ + // Swig does not add try/catch around arg parsing so this cannot use Report::error. + string error_msg = "Error: "; + error_msg += msg; + char *error = stringPrint(error_msg.c_str(), arg); + Tcl_SetResult(interp, error, TCL_VOLATILE); + stringDelete(error); +} + +void +objectListNext(const char *list, + const char *type, + // Return values. + bool &type_match, + const char *&next) +{ + // Default return values (failure). + type_match = false; + next = nullptr; + // _hexaddress_p_type + const char *s = list; + char ch = *s++; + if (ch == '_') { + while (*s && isxdigit(*s)) + s++; + if ((s - list - 1) == sizeof(void*) * 2 + && *s && *s++ == '_' + && *s && *s++ == 'p' + && *s && *s++ == '_') { + const char *t = type; + while (*s && *s != ' ') { + if (*s != *t) + return; + s++; + t++; + } + type_match = true; + if (*s) + next = s + 1; + else + next = nullptr; + } + } +} + +} // namespace + +using namespace sta; + +%} + +//////////////////////////////////////////////////////////////// +// +// SWIG type definitions. +// +//////////////////////////////////////////////////////////////// + +// String that is deleted after crossing over to tcland. +%typemap(out) string { + string &str = $1; + // String is volatile because it is deleted. + Tcl_SetResult(interp, const_cast(str.c_str()), TCL_VOLATILE); +} + +// String that is deleted after crossing over to tcland. +%typemap(out) TmpString* { + string *str = $1; + if (str) { + // String is volatile because it is deleted. + Tcl_SetResult(interp, const_cast(str->c_str()), TCL_VOLATILE); + delete str; + } + else + Tcl_SetResult(interp, nullptr, TCL_STATIC); +} + +%typemap(in) StringSeq* { + $1 = tclListSeqConstChar($input, interp); +} + +%typemap(in) StdStringSet* { + $1 = tclListSetStdString($input, interp); +} + +%typemap(out) StringSeq* { + StringSeq *strs = $1; + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + for (const char *str : *strs) { + Tcl_Obj *obj = Tcl_NewStringObj(str, strlen(str)); + Tcl_ListObjAppendElement(interp, list, obj); + } + Tcl_SetObjResult(interp, list); +} + +%typemap(out) StringSeq { + StringSeq &strs = $1; + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + for (const char *str : strs) { + Tcl_Obj *obj = Tcl_NewStringObj(str, strlen(str)); + Tcl_ListObjAppendElement(interp, list, obj); + } + Tcl_SetObjResult(interp, list); +} + +%typemap(out) Library* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) LibraryIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) LibertyLibraryIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) Cell* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(in) CellSeq* { + $1 = tclListSeq($input, SWIGTYPE_p_Cell, interp); +} + +%typemap(out) CellSeq { + seqTclList($1, SWIGTYPE_p_Cell, interp); +} + +%typemap(out) LibertyCellSeq * { + seqPtrTclList($1, SWIGTYPE_p_LibertyCell, interp); +} + +%typemap(out) LibertyCellSeq { + seqTclList($1, SWIGTYPE_p_LibertyCell, interp); +} + +%typemap(out) LibertyPortSeq { + seqTclList($1, SWIGTYPE_p_LibertyPort, interp); +} + +%typemap(out) CellPortIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) LibertyCellPortIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) Port* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(in) PortSeq* { + $1 = tclListSeq($input, SWIGTYPE_p_Port, interp); +} + +%typemap(out) PortSeq { + seqTclList($1, SWIGTYPE_p_Port, interp); +} + +%typemap(out) PortMemberIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) LibertyCell* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) LibertyPort* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) LibertyPortMemberIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, SWIGTYPE_p_LibertyPortMemberIterator, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) TimingArc* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) TimingArcSetSeq& { + seqPtrTclList($1, SWIGTYPE_p_TimingArcSet, interp); +} + +%typemap(out) TimingArcSeq& { + seqPtrTclList($1, SWIGTYPE_p_TimingArc, interp); +} + +%typemap(out) Wireload* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) WireloadSelection* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(in) Transition* { + int length; + const char *arg = Tcl_GetStringFromObj($input, &length); + Transition *tr = Transition::find(arg); + if (tr == nullptr) { + Tcl_SetResult(interp,const_cast("Error: transition not found."), + TCL_STATIC); + return TCL_ERROR; + } + else + $1 = tr; +} + +%typemap(out) Transition* { + Transition *tr = $1; + const char *str = ""; + if (tr) + str = tr->asString(); + Tcl_SetResult(interp, const_cast(str), TCL_STATIC); +} + +%typemap(in) RiseFall* { + int length; + const char *arg = Tcl_GetStringFromObj($input, &length); + RiseFall *rf = RiseFall::find(arg); + if (rf == nullptr) { + Tcl_SetResult(interp,const_cast("Error: unknown rise/fall edge."), + TCL_STATIC); + return TCL_ERROR; + } + $1 = rf; +} + +%typemap(out) RiseFall* { + const RiseFall *tr = $1; + const char *str = ""; + if (tr) + str = tr->asString(); + Tcl_SetResult(interp, const_cast(str), TCL_STATIC); +} + +%typemap(in) RiseFallBoth* { + int length; + const char *arg = Tcl_GetStringFromObj($input, &length); + RiseFallBoth *tr = RiseFallBoth::find(arg); + if (tr == nullptr) { + Tcl_SetResult(interp,const_cast("Error: unknown transition name."), + TCL_STATIC); + return TCL_ERROR; + } + $1 = tr; +} + +%typemap(out) RiseFallBoth* { + RiseFallBoth *tr = $1; + const char *str = ""; + if (tr) + str = tr->asString(); + Tcl_SetResult(interp, const_cast(str), TCL_STATIC); +} + +%typemap(in) TimingRole* { + int length; + const char *arg = Tcl_GetStringFromObj($input, &length); + TimingRole *role = TimingRole::find(arg); + if (role) + $1 = TimingRole::find(arg); + else { + Tcl_SetResult(interp,const_cast("Error: unknown timing role."), + TCL_STATIC); + return TCL_ERROR; + } +} + +%typemap(out) TimingRole* { + Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); +} + +%typemap(in) LogicValue { + int length; + const char *arg = Tcl_GetStringFromObj($input, &length); + if (stringEq(arg, "0") || stringEq(arg, "zero")) + $1 = LogicValue::zero; + else if (stringEq(arg, "1") || stringEq(arg, "one")) + $1 = LogicValue::one; + else if (stringEq(arg, "X")) + $1 = LogicValue::unknown; + else if (stringEq(arg, "rise") || stringEq(arg, "rising")) + $1 = LogicValue::rise; + else if (stringEq(arg, "fall") || stringEq(arg, "falling")) + $1 = LogicValue::fall; + else { + Tcl_SetResult(interp,const_cast("Error: unknown logic value."), + TCL_STATIC); + return TCL_ERROR; + } +} + +%typemap(in) AnalysisType { + int length; + const char *arg = Tcl_GetStringFromObj($input, &length); + if (stringEqual(arg, "single")) + $1 = AnalysisType::single; + else if (stringEqual(arg, "bc_wc")) + $1 = AnalysisType::bc_wc; + else if (stringEq(arg, "on_chip_variation")) + $1 = AnalysisType::ocv; + else { + Tcl_SetResult(interp,const_cast("Error: unknown analysis type."), + TCL_STATIC); + + return TCL_ERROR; + } +} + +%typemap(out) Instance* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(in) InstanceSeq* { + $1 = tclListSeq($input, SWIGTYPE_p_Instance, interp); +} + +%typemap(out) InstanceSeq { + seqTclList($1, SWIGTYPE_p_Instance, interp); +} + +%typemap(out) InstanceChildIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) LeafInstanceIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) InstancePinIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) InstanceNetIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) Pin* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) PinSeq* { + seqPtrTclList($1, SWIGTYPE_p_Pin, interp); +} + + +%typemap(out) PinSeq { + seqTclList($1, SWIGTYPE_p_Pin, interp); +} + +%typemap(out) Net* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) NetSeq* { + seqPtrTclList($1, SWIGTYPE_p_Net, interp); +} + +%typemap(out) NetSeq { + seqTclList($1, SWIGTYPE_p_Net, interp); +} + +%typemap(out) NetPinIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) NetTermIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) NetConnectedPinIterator* { + Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) PinConnectedPinIterator* { + Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) Clock* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) ClockSeq* { + seqPtrTclList($1, SWIGTYPE_p_Clock, interp); +} + +%typemap(out) ClockSeq { + seqTclList($1, SWIGTYPE_p_Clock, interp); +} + +%typemap(out) ClockEdge* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1,$1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(in) PinSeq* { + $1 = tclListSeq($input, SWIGTYPE_p_Pin, interp); +} + +%typemap(in) PinSet* { + Network *network = cmdNetwork(); + $1 = tclListNetworkSet($input, SWIGTYPE_p_Pin, interp, network); +} + +%typemap(out) PinSet* { + setPtrTclList($1, SWIGTYPE_p_Pin, interp); +} + +%typemap(out) PinSet { + setTclList($1, SWIGTYPE_p_Pin, interp); +} + +%typemap(out) const PinSet& { + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + // A swig bug sets the result to PinSet* rather than const PinSet&. + PinSet *pins = $1; + for (const Pin *pin : *pins) { + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(pin), SWIGTYPE_p_Pin, false); + Tcl_ListObjAppendElement(interp, list, obj); + } + Tcl_SetObjResult(interp, list); +} + +%typemap(in) ClockSet* { + $1 = tclListSet($input, SWIGTYPE_p_Clock, interp); +} + +%typemap(out) ClockSet* { + setPtrTclList($1, SWIGTYPE_p_Clock, interp); +} + +%typemap(in) InstanceSet* { + Network *network = cmdNetwork(); + $1 = tclListNetworkSet($input, SWIGTYPE_p_Instance, + interp, network); +} + +%typemap(out) InstanceSet { + setTclList($1, SWIGTYPE_p_Instance, interp); +} + +%typemap(in) NetSet* { + Network *network = cmdNetwork(); + $1 = tclListNetworkSet($input, SWIGTYPE_p_Net, interp, network); +} + +%typemap(in) FloatSeq* { + int argc; + Tcl_Obj **argv; + FloatSeq *floats = nullptr; + + if (Tcl_ListObjGetElements(interp, $input, &argc, &argv) == TCL_OK) { + if (argc) + floats = new FloatSeq; + for (int i = 0; i < argc; i++) { + char *arg = Tcl_GetString(argv[i]); + double value; + if (Tcl_GetDouble(interp, arg, &value) == TCL_OK) + floats->push_back(static_cast(value)); + else { + delete floats; + tclArgError(interp, "%s is not a floating point number.", arg); + return TCL_ERROR; + } + } + } + $1 = floats; +} + +%typemap(out) FloatSeq* { + FloatSeq *floats = $1; + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + if (floats) { + for (float f : *floats) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list, obj); + } + } + Tcl_SetObjResult(interp, list); +} + +%typemap(out) FloatSeq { + FloatSeq &floats = $1; + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + for (float f : floats) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list, obj); + } + Tcl_SetObjResult(interp, list); +} + +%typemap(in) IntSeq* { + int argc; + Tcl_Obj **argv; + IntSeq *ints = nullptr; + + if (Tcl_ListObjGetElements(interp, $input, &argc, &argv) == TCL_OK) { + if (argc) + ints = new IntSeq; + for (int i = 0; i < argc; i++) { + char *arg = Tcl_GetString(argv[i]); + int value; + if (Tcl_GetInt(interp, arg, &value) == TCL_OK) + ints->push_back(value); + else { + delete ints; + tclArgError(interp, "%s is not an integer.", arg); + return TCL_ERROR; + } + } + } + $1 = ints; +} + +%typemap(out) Table1 { + Table1 &table = $1; + if (table.axis1()) { + Tcl_Obj *list3 = Tcl_NewListObj(0, nullptr); + Tcl_Obj *list1 = Tcl_NewListObj(0, nullptr); + for (float f : *table.axis1()->values()) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list1, obj); + } + Tcl_Obj *list2 = Tcl_NewListObj(0, nullptr); + for (float f : *table.values()) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list2, obj); + } + Tcl_ListObjAppendElement(interp, list3, list1); + Tcl_ListObjAppendElement(interp, list3, list2); + Tcl_SetObjResult(interp, list3); + } +} + +%typemap(out) const Table1* { + const Table1 *table = $1; + Tcl_Obj *list3 = Tcl_NewListObj(0, nullptr); + if (table) { + Tcl_Obj *list1 = Tcl_NewListObj(0, nullptr); + for (float f : *table->axis1()->values()) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list1, obj); + } + Tcl_Obj *list2 = Tcl_NewListObj(0, nullptr); + for (float f : *table->values()) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list2, obj); + } + Tcl_ListObjAppendElement(interp, list3, list1); + Tcl_ListObjAppendElement(interp, list3, list2); + } + Tcl_SetObjResult(interp, list3); +} + +%typemap(in) MinMax* { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + MinMax *min_max = MinMax::find(arg); + if (min_max) + $1 = min_max; + else { + tclArgError(interp, "%s not min or max.", arg); + return TCL_ERROR; + } +} + +%typemap(out) MinMax* { + Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); +} + +%typemap(out) MinMax* { + Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); +} + +%typemap(in) MinMaxAll* { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + MinMaxAll *min_max = MinMaxAll::find(arg); + if (min_max) + $1 = min_max; + else { + tclArgError(interp, "%s not min, max or min_max.", arg); + return TCL_ERROR; + } +} + +%typemap(in) MinMaxAllNull* { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + if (stringEqual(arg, "NULL")) + $1 = nullptr; + else { + MinMaxAll *min_max = MinMaxAll::find(arg); + if (min_max) + $1 = min_max; + else { + tclArgError(interp, "%s not min, max or min_max.", arg); + return TCL_ERROR; + } + } +} + +%typemap(out) MinMaxAll* { + Tcl_SetResult(interp, const_cast($1->asString()), TCL_STATIC); +} + +// SetupHold is typedef'd to MinMax. +%typemap(in) SetupHold* { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + if (stringEqual(arg, "hold") + || stringEqual(arg, "min")) + $1 = MinMax::min(); + else if (stringEqual(arg, "setup") + || stringEqual(arg, "max")) + $1 = MinMax::max(); + else { + tclArgError(interp, "%s not setup, hold, min or max.", arg); + return TCL_ERROR; + } +} + +// SetupHoldAll is typedef'd to MinMaxAll. +%typemap(in) SetupHoldAll* { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + if (stringEqual(arg, "hold") + || stringEqual(arg, "min")) + $1 = SetupHoldAll::min(); + else if (stringEqual(arg, "setup") + || stringEqual(arg, "max")) + $1 = SetupHoldAll::max(); + else if (stringEqual(arg, "setup_hold") + || stringEqual(arg, "min_max")) + $1 = SetupHoldAll::all(); + else { + tclArgError(interp, "%s not setup, hold, setup_hold, min, max or min_max.", arg); + return TCL_ERROR; + } +} + +// EarlyLate is typedef'd to MinMax. +%typemap(in) EarlyLate* { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + EarlyLate *early_late = EarlyLate::find(arg); + if (early_late) + $1 = early_late; + else { + tclArgError(interp, "%s not early/min, late/max or early_late/min_max.", arg); + return TCL_ERROR; + } +} + +// EarlyLateAll is typedef'd to MinMaxAll. +%typemap(in) EarlyLateAll* { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + EarlyLateAll *early_late = EarlyLateAll::find(arg); + if (early_late) + $1 = early_late; + else { + tclArgError(interp, "%s not early/min, late/max or early_late/min_max.", arg); + return TCL_ERROR; + } +} + +%typemap(in) TimingDerateType { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + if (stringEq(arg, "net_delay")) + $1 = TimingDerateType::net_delay; + else if (stringEq(arg, "cell_delay")) + $1 = TimingDerateType::cell_delay; + else if (stringEq(arg, "cell_check")) + $1 = TimingDerateType::cell_check; + else { + tclArgError(interp, "%s not net_delay, cell_delay or cell_check.", arg); + return TCL_ERROR; + } +} + +%typemap(in) TimingDerateCellType { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + if (stringEq(arg, "cell_delay")) + $1 = TimingDerateCellType::cell_delay; + else if (stringEq(arg, "cell_check")) + $1 = TimingDerateCellType::cell_check; + else { + tclArgError(interp, "%s not cell_delay or cell_check.", arg); + return TCL_ERROR; + } +} + +%typemap(in) PathClkOrData { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + if (stringEq(arg, "clk")) + $1 = PathClkOrData::clk; + else if (stringEq(arg, "data")) + $1 = PathClkOrData::data; + else { + tclArgError(interp, "%s not clk or data.", arg); + return TCL_ERROR; + } +} + +%typemap(in) ReportSortBy { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + if (stringEq(arg, "group")) + $1 = sort_by_group; + else if (stringEq(arg, "slack")) + $1 = sort_by_slack; + else { + tclArgError(interp, "%s not group or slack.", arg); + return TCL_ERROR; + } +} + +%typemap(in) ReportPathFormat { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + if (stringEq(arg, "full")) + $1 = ReportPathFormat::full; + else if (stringEq(arg, "full_clock")) + $1 = ReportPathFormat::full_clock; + else if (stringEq(arg, "full_clock_expanded")) + $1 = ReportPathFormat::full_clock_expanded; + else if (stringEq(arg, "short")) + $1 = ReportPathFormat::shorter; + else if (stringEq(arg, "end")) + $1 = ReportPathFormat::endpoint; + else if (stringEq(arg, "summary")) + $1 = ReportPathFormat::summary; + else if (stringEq(arg, "slack_only")) + $1 = ReportPathFormat::slack_only; + else if (stringEq(arg, "json")) + $1 = ReportPathFormat::json; + else { + tclArgError(interp, "unknown path type %s.", arg); + return TCL_ERROR; + } +} + +%typemap(in) ExceptionThruSeq* { + $1 = tclListSeq($input, SWIGTYPE_p_ExceptionThru, interp); +} + +%typemap(out) Vertex* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) Vertex** { + int i = 0; + Tcl_ResetResult(interp); + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + while ($1[i]) { + Tcl_Obj *obj = SWIG_NewInstanceObj($1[i], SWIGTYPE_p_Vertex,false); + Tcl_ListObjAppendElement(interp, list, obj); + i++; + } + Tcl_SetObjResult(interp, list); +} + +%typemap(out) Edge* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(in) EdgeSeq* { + $1 = tclListSeq($input, SWIGTYPE_p_Edge, interp); +} + +%typemap(out) EdgeSeq { + seqTclList($1, SWIGTYPE_p_Edge, interp); +} + +%typemap(out) VertexIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) VertexInEdgeIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) VertexOutEdgeIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) CheckErrorSeq & { + Tcl_Obj *error_list = Tcl_NewListObj(0, nullptr); + CheckErrorSeq *check_errors = $1; + CheckErrorSeq::Iterator check_iter(check_errors); + while (check_iter.hasNext()) { + CheckError *error = check_iter.next(); + Tcl_Obj *string_list = Tcl_NewListObj(0, nullptr); + CheckError::Iterator string_iter(error); + while (string_iter.hasNext()) { + const char *str = string_iter.next(); + size_t str_len = strlen(str); + Tcl_Obj *obj = Tcl_NewStringObj(const_cast(str), + static_cast(str_len)); + Tcl_ListObjAppendElement(interp, string_list, obj); + } + Tcl_ListObjAppendElement(interp, error_list, string_list); + } + Tcl_SetObjResult(interp, error_list); +} + +%typemap(out) PathEnd* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) PathEndSeq* { + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + const PathEndSeq *path_ends = $1; + PathEndSeq::ConstIterator end_iter(path_ends); + while (end_iter.hasNext()) { + PathEnd *path_end = end_iter.next(); + Tcl_Obj *obj = SWIG_NewInstanceObj(path_end, SWIGTYPE_p_PathEnd, false); + Tcl_ListObjAppendElement(interp, list, obj); + } + // Delete the PathEndSeq, not the ends. + delete path_ends; + Tcl_SetObjResult(interp, list); +} + +%typemap(out) PathEndSeq { + seqTclList($1, SWIGTYPE_p_PathEnd, interp); +} + +%typemap(out) MinPulseWidthCheckSeqIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) PathRefSeq* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); + + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + PathRefSeq *paths = $1; + PathRefSeq::Iterator path_iter(paths); + while (path_iter.hasNext()) { + PathRef *path = &path_iter.next(); + PathRef *copy = new PathRef(path); + Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false); + Tcl_ListObjAppendElement(interp, list, obj); + } + Tcl_SetObjResult(interp, list); +} + +%typemap(out) MinPulseWidthCheck* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) MinPulseWidthCheckSeq & { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) MinPulseWidthCheckSeqIterator & { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) VertexPathIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) SlowDrvrIterator* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) ExceptionFrom* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) ExceptionTo* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) ExceptionThru* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) OperatingConditions* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) Arrival { + Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); +} + +%typemap(out) Required { + Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); +} + +%typemap(out) Slack { + Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); +} + +%typemap(out) ArcDelay { + Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); +} + +%typemap(out) Slew { + Tcl_SetObjResult(interp,Tcl_NewDoubleObj(delayAsFloat($1))); +} + +%typemap(in) PathGroupNameSet* { + $1 = tclListSetConstChar($input, interp); +} + +%typemap(in) StringSet* { + $1 = tclListSetConstChar($input, interp); +} + +%typemap(out) Corner* { + Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false); + Tcl_SetObjResult(interp, obj); +} + +%typemap(out) Corners* { + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + Corners *corners = $1; + for (Corner *corner : *corners) { + Tcl_Obj *obj = SWIG_NewInstanceObj(corner, SWIGTYPE_p_Corner, false); + Tcl_ListObjAppendElement(interp, list, obj); + } + Tcl_SetObjResult(interp, list); +} + +%typemap(out) PropertyValue { + PropertyValue value = $1; + switch (value.type()) { + case PropertyValue::Type::type_none: + Tcl_SetResult(interp, const_cast(""), TCL_STATIC); + break; + case PropertyValue::Type::type_string: + Tcl_SetResult(interp, const_cast(value.stringValue()), TCL_VOLATILE); + break; + case PropertyValue::Type::type_float: { + const Unit *unit = value.unit(); + const char *float_string = unit->asString(value.floatValue(), 6); + Tcl_SetResult(interp, const_cast(float_string), TCL_VOLATILE); + } + break; + case PropertyValue::Type::type_bool: { + const char *bool_string = value.boolValue() ? "1" : "0"; + Tcl_SetResult(interp, const_cast(bool_string), TCL_STATIC); + } + break; + case PropertyValue::Type::type_library: { + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.library()), + SWIGTYPE_p_Library, false); + Tcl_SetObjResult(interp, obj); + } + break; + case PropertyValue::Type::type_cell: { + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.cell()), + SWIGTYPE_p_Cell, false); + Tcl_SetObjResult(interp, obj); + } + break; + case PropertyValue::Type::type_port: { + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.port()), + SWIGTYPE_p_Port, false); + Tcl_SetObjResult(interp, obj); + } + break; + case PropertyValue::Type::type_liberty_library: { + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.libertyLibrary()), + SWIGTYPE_p_LibertyLibrary, false); + Tcl_SetObjResult(interp, obj); + } + break; + case PropertyValue::Type::type_liberty_cell: { + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.libertyCell()), + SWIGTYPE_p_LibertyCell, false); + Tcl_SetObjResult(interp, obj); + } + break; + case PropertyValue::Type::type_liberty_port: { + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.libertyPort()), + SWIGTYPE_p_LibertyPort, false); + Tcl_SetObjResult(interp, obj); + } + break; + case PropertyValue::Type::type_instance: { + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.instance()), + SWIGTYPE_p_Instance, false); + Tcl_SetObjResult(interp, obj); + } + break; + case PropertyValue::Type::type_pin: { + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.pin()), + SWIGTYPE_p_Pin, false); + Tcl_SetObjResult(interp, obj); + } + break; + case PropertyValue::Type::type_pins: { + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + PinSeq *pins = value.pins(); + PinSeq::Iterator pin_iter(pins); + while (pin_iter.hasNext()) { + const Pin *pin = pin_iter.next(); + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(pin), SWIGTYPE_p_Pin, false); + Tcl_ListObjAppendElement(interp, list, obj); + } + Tcl_SetObjResult(interp, list); + } + break; + case PropertyValue::Type::type_net: { + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.net()), + SWIGTYPE_p_Net, false); + Tcl_SetObjResult(interp, obj); + } + break; + case PropertyValue::Type::type_clk: { + Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast(value.clock()), + SWIGTYPE_p_Clock, false); + Tcl_SetObjResult(interp, obj); + } + break; + case PropertyValue::Type::type_clks: { + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + ClockSeq *clks = value.clocks(); + ClockSeq::Iterator clk_iter(clks); + while (clk_iter.hasNext()) { + Clock *clk = clk_iter.next(); + Tcl_Obj *obj = SWIG_NewInstanceObj(clk, SWIGTYPE_p_Clock, false); + Tcl_ListObjAppendElement(interp, list, obj); + } + Tcl_SetObjResult(interp, list); + } + break; + case PropertyValue::Type::type_path_refs: { + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + for (PathRef &path : *value.pathRefs()) { + PathRef *copy = new PathRef(path); + Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false); + Tcl_ListObjAppendElement(interp, list, obj); + } + Tcl_SetObjResult(interp, list); + } + break; + case PropertyValue::Type::type_pwr_activity: { + PwrActivity activity = value.pwrActivity(); + Tcl_Obj *list = Tcl_NewListObj(0, nullptr); + Tcl_Obj *obj; + const char *str; + + str = stringPrintTmp("%.5e", activity.activity()); + obj = Tcl_NewStringObj(str, strlen(str)); + Tcl_ListObjAppendElement(interp, list, obj); + + str = stringPrintTmp("%.3f", activity.duty()); + obj = Tcl_NewStringObj(str, strlen(str)); + Tcl_ListObjAppendElement(interp, list, obj); + + str = activity.originName(); + obj = Tcl_NewStringObj(str, strlen(str)); + Tcl_ListObjAppendElement(interp, list, obj); + + Tcl_SetObjResult(interp, list); + } + break; + } +} diff --git a/tcl/Util.tcl b/tcl/Util.tcl index 41c53e0f..23b3ba00 100644 --- a/tcl/Util.tcl +++ b/tcl/Util.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -41,7 +41,7 @@ proc parse_key_args { cmd arg_var key_var keys {flag_var ""} {flags {}} \ if { $key_index >= 0 } { set key $arg if { [llength $args] == 1 } { - sta_error 400 "$cmd $key missing value." + sta_error 560 "$cmd $key missing value." } set key_value($key) [lindex $args 1] set args [lrange $args 1 end] @@ -58,7 +58,7 @@ proc parse_key_args { cmd arg_var key_var keys {flag_var ""} {flags {}} \ if { $key_index >= 0 } { set key [lindex $keys $key_index] if { [llength $args] == 1 } { - sta_error 401 "$cmd $key missing value." + sta_error 561 "$cmd $key missing value." } set key_value($key) [lindex $args 1] set args [lrange $args 1 end] @@ -68,7 +68,7 @@ proc parse_key_args { cmd arg_var key_var keys {flag_var ""} {flags {}} \ set flag [lindex $flags $flag_index] set flag_present($flag) 1 } elseif { $unknown_key_is_error } { - sta_error 402 "$cmd $arg is not a known keyword or flag." + sta_error 562 "$cmd $arg is not a known keyword or flag." } else { lappend args_rtn $arg } @@ -90,7 +90,7 @@ proc check_for_key_args { cmd arg_var } { while { $args != "" } { set arg [lindex $args 0] if { [is_keyword_arg $arg] } { - sta_error 403 "$cmd $arg is not a known keyword or flag." + sta_error 563 "$cmd $arg is not a known keyword or flag." } else { lappend args_rtn $arg } @@ -238,45 +238,45 @@ define_cmd_args "log_end" {} proc check_argc_eq0 { cmd arglist } { if { $arglist != {} } { - sta_error 406 "$cmd positional arguments not supported." + sta_error 564 "$cmd positional arguments not supported." } } proc check_argc_eq1 { cmd arglist } { if { [llength $arglist] != 1 } { - sta_error 407 "$cmd requires one positional argument." + sta_error 565 "$cmd requires one positional argument." } } proc check_argc_eq0or1 { cmd arglist } { set argc [llength $arglist] if { $argc != 0 && $argc != 1 } { - sta_error 408 "$cmd requires zero or one positional arguments." + sta_error 566 "$cmd requires zero or one positional arguments." } } proc check_argc_eq2 { cmd arglist } { if { [llength $arglist] != 2 } { - sta_error 409 "$cmd requires two positional arguments." + sta_error 567 "$cmd requires two positional arguments." } } proc check_argc_eq1or2 { cmd arglist } { set argc [llength $arglist] if { $argc != 1 && $argc != 2 } { - sta_error 410 "$cmd requires one or two positional arguments." + sta_error 568 "$cmd requires one or two positional arguments." } } proc check_argc_eq3 { cmd arglist } { if { [llength $arglist] != 3 } { - sta_error 411 "$cmd requires three positional arguments." + sta_error 569 "$cmd requires three positional arguments." } } proc check_argc_eq4 { cmd arglist } { if { [llength $arglist] != 4 } { - sta_error 412 "$cmd requires four positional arguments." + sta_error 570 "$cmd requires four positional arguments." } } @@ -284,37 +284,37 @@ proc check_argc_eq4 { cmd arglist } { proc check_float { cmd_arg arg } { if {![string is double $arg]} { - sta_error 413 "$cmd_arg '$arg' is not a float." + sta_error 571 "$cmd_arg '$arg' is not a float." } } proc check_positive_float { cmd_arg arg } { if {!([string is double $arg] && $arg >= 0.0)} { - sta_error 414 "$cmd_arg '$arg' is not a positive float." + sta_error 572 "$cmd_arg '$arg' is not a positive float." } } proc check_integer { cmd_arg arg } { if {!([string is integer $arg])} { - sta_error 415 "$cmd_arg '$arg' is not an integer." + sta_error 573 "$cmd_arg '$arg' is not an integer." } } proc check_positive_integer { cmd_arg arg } { if {!([string is integer $arg] && $arg >= 0)} { - sta_error 416 "$cmd_arg '$arg' is not a positive integer." + sta_error 574 "$cmd_arg '$arg' is not a positive integer." } } proc check_cardinal { cmd_arg arg } { if {!([string is integer $arg] && $arg >= 1)} { - sta_error 417 "$cmd_arg '$arg' is not an integer greater than or equal to one." + sta_error 575 "$cmd_arg '$arg' is not an integer greater than or equal to one." } } proc check_percent { cmd_arg arg } { if {!([string is double $arg] && $arg >= 0.0 && $arg <= 100.0)} { - sta_error 418 "$cmd_arg '$arg' is not between 0 and 100." + sta_error 576 "$cmd_arg '$arg' is not between 0 and 100." } } diff --git a/tcl/Variables.tcl b/tcl/Variables.tcl index 5460d3dc..0d054dbf 100644 --- a/tcl/Variables.tcl +++ b/tcl/Variables.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -42,7 +42,7 @@ proc trace_report_default_digits { name1 name2 op } { if { $op == "w" } { if { !([string is integer $sta_report_default_digits] \ && $sta_report_default_digits >= 0) } { - sta_error 436 "sta_report_default_digits must be a positive integer." + sta_error 590 "sta_report_default_digits must be a positive integer." } } } @@ -67,7 +67,7 @@ proc trace_crpr_mode { name1 name2 op } { if { $sta_crpr_mode == "same_pin" || $sta_crpr_mode == "same_transition" } { set_crpr_mode $sta_crpr_mode } else { - sta_error 437 "sta_crpr_mode must be pin or transition." + sta_error 591 "sta_crpr_mode must be pin or transition." } } } @@ -184,7 +184,7 @@ proc trace_boolean_var { op var_name get_proc set_proc } { } elseif { $var == 1 } { $set_proc 1 } else { - sta_error 438 "$var_name value must be 0 or 1." + sta_error 592 "$var_name value must be 0 or 1." } } } diff --git a/tcl/WritePathSpice.tcl b/tcl/WritePathSpice.tcl index 0ba7da65..8604471d 100644 --- a/tcl/WritePathSpice.tcl +++ b/tcl/WritePathSpice.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 @@ -21,66 +21,69 @@ define_cmd_args "write_path_spice" { -path_args path_args\ -lib_subckt_file lib_subckts_file\ -model_file model_file\ -power power\ - -ground ground} + -ground ground\ + [-measure_stmts]} proc write_path_spice { args } { parse_key_args "write_path_spice" args \ keys {-spice_directory -lib_subckt_file -model_file \ -power -ground -path_args} \ - flags {} + flags {-measure_stmts} if { [info exists keys(-spice_directory)] } { set spice_dir [file nativename $keys(-spice_directory)] if { ![file exists $spice_dir] } { - sta_error 496 "Directory $spice_dir not found." + sta_error 600 "Directory $spice_dir not found." } if { ![file isdirectory $spice_dir] } { - sta_error 497 "$spice_dir is not a directory." + sta_error 601 "$spice_dir is not a directory." } if { ![file writable $spice_dir] } { - sta_error 498 "Cannot write in $spice_dir." + sta_error 602 "Cannot write in $spice_dir." } } else { - sta_error 499 "No -spice_directory specified." + 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 500 "-lib_subckt_file $lib_subckt_file is not readable." + sta_error 604 "-lib_subckt_file $lib_subckt_file is not readable." } } else { - sta_error 501 "No -lib_subckt_file specified." + 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 502 "-model_file $model_file is not readable." + sta_error 606 "-model_file $model_file is not readable." } } else { - sta_error 503 "No -model_file specified." + sta_error 607 "No -model_file specified." } if { [info exists keys(-power)] } { set power $keys(-power) } else { - sta_error 504 "No -power specified." + sta_error 608 "No -power specified." } if { [info exists keys(-ground)] } { set ground $keys(-ground) } else { - sta_error 505 "No -ground specified." + sta_error 609 "No -ground specified." } + set measure_stmts [info exists keys(-measure_stmts)] + if { ![info exists keys(-path_args)] } { - sta_error 506 "No -path_args specified." + 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 507 "No paths found for -path_args $path_args." + sta_error 611 "No paths found for -path_args $path_args." } else { set path_index 1 foreach path_end $path_ends { @@ -89,7 +92,7 @@ proc write_path_spice { args } { 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 + $lib_subckt_file $model_file {} $power $ground $measure_stmts incr path_index } } diff --git a/test/power.ok b/test/power.ok index 20b60589..6d3c0eea 100644 --- a/test/power.ok +++ b/test/power.ok @@ -2,11 +2,11 @@ Warning: gcd_sky130hd.v line 527, module sky130_fd_sc_hd__tapvpwrvgnd_1 not foun Group Internal Switching Leakage Total Power Power Power Power (Watts) ---------------------------------------------------------------- -Sequential 3.27e-04 7.87e-05 2.96e-10 4.06e-04 36.4% -Combinational 2.34e-04 3.10e-04 6.95e-10 5.43e-04 48.7% -Clock 4.68e-05 1.20e-04 2.30e-11 1.67e-04 15.0% +Sequential 3.32e-04 8.62e-05 2.96e-10 4.19e-04 35.1% +Combinational 2.61e-04 3.46e-04 6.95e-10 6.07e-04 50.9% +Clock 4.68e-05 1.20e-04 2.30e-11 1.67e-04 14.0% Macro 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% Pad 0.00e+00 0.00e+00 0.00e+00 0.00e+00 0.0% ---------------------------------------------------------------- -Total 6.07e-04 5.09e-04 1.01e-09 1.12e-03 100.0% - 54.4% 45.6% 0.0% +Total 6.41e-04 5.53e-04 1.01e-09 1.19e-03 100.0% + 53.7% 46.3% 0.0% diff --git a/test/power_vcd.ok b/test/power_vcd.ok index 5744deeb..549c868f 100644 --- a/test/power_vcd.ok +++ b/test/power_vcd.ok @@ -1,5 +1,5 @@ Warning: gcd_sky130hd.v line 527, module sky130_fd_sc_hd__tapvpwrvgnd_1 not found. Creating black box for TAP_11. -Annotated 936 pin activities. +Annotated 937 pin activities. Group Internal Switching Leakage Total Power Power Power Power (Watts) ---------------------------------------------------------------- diff --git a/test/regression b/test/regression index 0f5aa924..f7731a61 100755 --- a/test/regression +++ b/test/regression @@ -3,7 +3,7 @@ exec tclsh $0 ${1+"$@"} # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 diff --git a/test/regression.tcl b/test/regression.tcl index 72ad544a..3814801f 100755 --- a/test/regression.tcl +++ b/test/regression.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 diff --git a/test/regression_vars.tcl b/test/regression_vars.tcl index 23a9b812..99d6f545 100644 --- a/test/regression_vars.tcl +++ b/test/regression_vars.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 diff --git a/test/save_ok b/test/save_ok index 7f2946c0..19af6802 100755 --- a/test/save_ok +++ b/test/save_ok @@ -3,7 +3,7 @@ exec tclsh $0 ${1+"$@"} # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 diff --git a/util/Debug.cc b/util/Debug.cc index 35c01d02..656d6972 100644 --- a/util/Debug.cc +++ b/util/Debug.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/Error.cc b/util/Error.cc index 2e8b37f1..f1738904 100644 --- a/util/Error.cc +++ b/util/Error.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/Fuzzy.cc b/util/Fuzzy.cc index a28409b3..1a5f3a13 100644 --- a/util/Fuzzy.cc +++ b/util/Fuzzy.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/Hash.cc b/util/Hash.cc index 820316c9..45bb58d8 100644 --- a/util/Hash.cc +++ b/util/Hash.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/Machine.cc b/util/Machine.cc index 1e3a5074..785d6900 100644 --- a/util/Machine.cc +++ b/util/Machine.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/MachineApple.cc b/util/MachineApple.cc index fb629310..d06145ff 100644 --- a/util/MachineApple.cc +++ b/util/MachineApple.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/MachineLinux.cc b/util/MachineLinux.cc index 87944102..26fc6d12 100644 --- a/util/MachineLinux.cc +++ b/util/MachineLinux.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/MachineUnknown.cc b/util/MachineUnknown.cc index 7f8bcded..4b8f1415 100644 --- a/util/MachineUnknown.cc +++ b/util/MachineUnknown.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/MachineWin32.cc b/util/MachineWin32.cc index a2ff5fc4..ee90f3ae 100644 --- a/util/MachineWin32.cc +++ b/util/MachineWin32.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/MinMax.cc b/util/MinMax.cc index ade8aa94..7631cf9c 100644 --- a/util/MinMax.cc +++ b/util/MinMax.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/PatternMatch.cc b/util/PatternMatch.cc index 1d077cfd..b8faf6c4 100644 --- a/util/PatternMatch.cc +++ b/util/PatternMatch.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/Report.cc b/util/Report.cc index 3e040c91..3b203ad6 100644 --- a/util/Report.cc +++ b/util/Report.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/ReportStd.cc b/util/ReportStd.cc index e5d5fa51..f929249a 100644 --- a/util/ReportStd.cc +++ b/util/ReportStd.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/ReportTcl.cc b/util/ReportTcl.cc index ba1cec19..83173070 100644 --- a/util/ReportTcl.cc +++ b/util/ReportTcl.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/RiseFallMinMax.cc b/util/RiseFallMinMax.cc index 3f26be80..22081616 100644 --- a/util/RiseFallMinMax.cc +++ b/util/RiseFallMinMax.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -157,7 +157,9 @@ RiseFallMinMax::setValues(RiseFallMinMax *values) void RiseFallMinMax::value(const RiseFall *rf, const MinMax *min_max, - float &value, bool &exists) const + // Return values. + float &value, + bool &exists) const { exists = exists_[rf->index()][min_max->index()]; if (exists) diff --git a/util/RiseFallValues.cc b/util/RiseFallValues.cc index 00de08fd..8f15462c 100644 --- a/util/RiseFallValues.cc +++ b/util/RiseFallValues.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/Stats.cc b/util/Stats.cc index 87d96afe..94e2dd54 100644 --- a/util/Stats.cc +++ b/util/Stats.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/StringSeq.cc b/util/StringSeq.cc index 6b006941..f9f167c0 100644 --- a/util/StringSeq.cc +++ b/util/StringSeq.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/StringSet.cc b/util/StringSet.cc index 134ef9b3..57d09bfe 100644 --- a/util/StringSet.cc +++ b/util/StringSet.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/StringUtil.cc b/util/StringUtil.cc index 6f70b2f8..bafd9420 100644 --- a/util/StringUtil.cc +++ b/util/StringUtil.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/TokenParser.cc b/util/TokenParser.cc index cb089431..bb659553 100644 --- a/util/TokenParser.cc +++ b/util/TokenParser.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/util/Transition.cc b/util/Transition.cc index b77b46ae..289aac02 100644 --- a/util/Transition.cc +++ b/util/Transition.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/verilog/Verilog.i b/verilog/Verilog.i index 4992444f..ac077dba 100644 --- a/verilog/Verilog.i +++ b/verilog/Verilog.i @@ -3,7 +3,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/verilog/Verilog.tcl b/verilog/Verilog.tcl index 775c5192..6a9031e4 100644 --- a/verilog/Verilog.tcl +++ b/verilog/Verilog.tcl @@ -1,5 +1,5 @@ # OpenSTA, Static Timing Analyzer -# Copyright (c) 2023, Parallax Software, Inc. +# 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 diff --git a/verilog/VerilogLex.ll b/verilog/VerilogLex.ll index 8548bdf6..42880540 100644 --- a/verilog/VerilogLex.ll +++ b/verilog/VerilogLex.ll @@ -1,7 +1,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/verilog/VerilogParse.yy b/verilog/VerilogParse.yy index f135f826..b12f3cef 100644 --- a/verilog/VerilogParse.yy +++ b/verilog/VerilogParse.yy @@ -1,7 +1,7 @@ %{ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/verilog/VerilogReader.cc b/verilog/VerilogReader.cc index 4ede7837..fdfa1288 100644 --- a/verilog/VerilogReader.cc +++ b/verilog/VerilogReader.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 @@ -883,7 +883,7 @@ VerilogModule::parseDcl(VerilogDcl *dcl, dcl_map_[net_name] = dcl; else if (!dcl->direction()->isInternal()) { string net_vname = reader->netVerilogName(net_name); - reader->warn(18, filename_, dcl->line(), + reader->warn(1395, filename_, dcl->line(), "signal %s previously declared on line %d.", net_vname.c_str(), existing_dcl->line()); @@ -912,7 +912,7 @@ VerilogModule::checkInstanceName(VerilogInst *inst, replacement_name = stringPrint("%s_%d", inst_name, i); } while (inst_names.findKey(replacement_name)); string inst_vname = reader->instanceVerilogName(inst_name); - reader->warn(19, filename_, inst->line(), + reader->warn(1396, filename_, inst->line(), "instance name %s duplicated - renamed to %s.", inst_vname.c_str(), replacement_name); @@ -1538,7 +1538,7 @@ VerilogNetConstant::parseConstant10(const char *constant_str, if (length > max_length || (length == max_length && strcmp(tmp, reader->constant10Max()) > 0)) - reader->warn(20, reader->filename(), reader->line(), + reader->warn(1397, reader->filename(), reader->line(), "base 10 constant greater than %s not supported.", reader->constant10Max()); else { @@ -1779,12 +1779,12 @@ VerilogReader::linkNetwork(const char *top_cell_name, return top_instance; } else { - report->error(274, "%s is not a verilog module.", top_cell_name); + report->error(1398, "%s is not a verilog module.", top_cell_name); return nullptr; } } else { - report->error(275, "%s is not a verilog module.", top_cell_name); + report->error(1399, "%s is not a verilog module.", top_cell_name); return nullptr; } } diff --git a/verilog/VerilogReaderPvt.hh b/verilog/VerilogReaderPvt.hh index d5fc4423..eb6afa09 100644 --- a/verilog/VerilogReaderPvt.hh +++ b/verilog/VerilogReaderPvt.hh @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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 diff --git a/verilog/VerilogWriter.cc b/verilog/VerilogWriter.cc index 1e969d51..e3362da3 100644 --- a/verilog/VerilogWriter.cc +++ b/verilog/VerilogWriter.cc @@ -1,5 +1,5 @@ // OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. +// 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