From 6c969fd8c604a00c23ff1702aafda1a3c6842e86 Mon Sep 17 00:00:00 2001 From: Matt Liberty Date: Fri, 1 Mar 2024 17:12:34 -0800 Subject: [PATCH] Update from upstream Signed-off-by: Matt Liberty --- CMakeLists.txt | 150 +-- dcalc/ArcDelayCalc.cc | 74 +- dcalc/ArnoldiReduce.cc | 3 +- dcalc/CcsCeffDelayCalc.cc | 678 ++++++++++++++ dcalc/CcsCeffDelayCalc.hh | 157 ++++ dcalc/DelayCalc.cc | 2 + dcalc/DelayCalc.tcl | 7 + dcalc/GraphDelayCalc.cc | 4 +- doc/OpenSTA.odt | Bin 105281 -> 105659 bytes doc/OpenSTA.pdf | Bin 251507 -> 251739 bytes graph/Graph.cc | 31 + include/sta/ArcDelayCalc.hh | 27 +- include/sta/Bdd.hh | 57 ++ include/sta/CircuitSim.hh | 23 + include/sta/FuncExpr.hh | 4 +- include/sta/Graph.hh | 10 +- include/sta/GraphDelayCalc.hh | 16 +- include/sta/Liberty.hh | 16 +- include/sta/NetworkClass.hh | 1 + include/sta/Parasitics.hh | 14 +- include/sta/PowerClass.hh | 2 + include/sta/SdcClass.hh | 2 + include/sta/SearchClass.hh | 2 +- include/sta/Sta.hh | 12 +- include/sta/TableModel.hh | 1 + include/sta/WritePathSpice.hh | 11 +- liberty/FuncExpr.cc | 4 +- liberty/Liberty.cc | 114 ++- liberty/LibertyBuilder.cc | 12 +- liberty/LibertyBuilder.hh | 2 + liberty/LibertyReader.cc | 2 +- liberty/LibertyWriter.cc | 2 +- liberty/TableModel.cc | 7 + parasitics/ConcreteParasitics.cc | 80 +- parasitics/ConcreteParasitics.hh | 10 +- parasitics/ConcreteParasiticsPvt.hh | 22 +- parasitics/Parasitics.cc | 7 + parasitics/ReduceParasitics.cc | 9 +- parasitics/SpefReader.cc | 58 +- power/Power.cc | 141 +-- power/Power.hh | 13 +- search/Bdd.cc | 179 ++++ search/ClkDelays.hh | 70 ++ search/ClkLatency.cc | 299 ++++++ search/ClkLatency.hh | 52 ++ search/ClkSkew.cc | 220 +++-- search/ClkSkew.hh | 32 +- search/MakeTimingModel.cc | 34 +- search/MakeTimingModelPvt.hh | 1 + search/Sim.cc | 162 +--- search/Sim.hh | 28 +- search/Sta.cc | 32 +- search/WritePathSpice.cc | 1308 ++------------------------- search/WriteSpice.cc | 1267 ++++++++++++++++++++++++++ search/WriteSpice.hh | 191 ++++ tcl/CmdArgs.tcl | 10 + tcl/Sdc.tcl | 12 +- tcl/Search.tcl | 57 +- tcl/StaTcl.i | 20 +- tcl/StaTclTypes.i | 106 ++- tcl/WritePathSpice.tcl | 26 +- 61 files changed, 3985 insertions(+), 1908 deletions(-) create mode 100644 dcalc/CcsCeffDelayCalc.cc create mode 100644 dcalc/CcsCeffDelayCalc.hh create mode 100644 include/sta/Bdd.hh create mode 100644 include/sta/CircuitSim.hh create mode 100644 search/Bdd.cc create mode 100644 search/ClkDelays.hh create mode 100644 search/ClkLatency.cc create mode 100644 search/ClkLatency.hh create mode 100644 search/WriteSpice.cc create mode 100644 search/WriteSpice.hh diff --git a/CMakeLists.txt b/CMakeLists.txt index eaa3c353..5fe12ab8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ project(STA VERSION 2.5.0 option(USE_CUDD "Use CUDD BDD package") option(CUDD_DIR "CUDD BDD package directory") +# Turn on to debug compiler args. set(CMAKE_VERBOSE_MAKEFILE OFF) set(STA_HOME ${PROJECT_SOURCE_DIR}) @@ -65,6 +66,7 @@ set(STA_SOURCE dcalc/ArcDcalcWaveforms.cc dcalc/ArnoldiDelayCalc.cc dcalc/ArnoldiReduce.cc + dcalc/CcsCeffDelayCalc.cc dcalc/DcalcAnalysisPt.cc dcalc/DelayCalc.cc dcalc/DelayCalcBase.cc @@ -145,6 +147,7 @@ set(STA_SOURCE sdf/SdfReader.cc sdf/SdfWriter.cc + search/Bdd.cc search/Bfs.cc search/CheckMaxSkews.cc search/CheckMinPeriods.cc @@ -154,6 +157,7 @@ set(STA_SOURCE search/CheckSlewLimits.cc search/CheckTiming.cc search/ClkInfo.cc + search/ClkLatency.cc search/ClkNetwork.cc search/ClkSkew.cc search/Corner.cc @@ -188,6 +192,7 @@ set(STA_SOURCE search/VisitPathGroupVertices.cc search/WorstSlack.cc search/WritePathSpice.cc + search/WriteSpice.cc power/Power.cc power/ReadVcdActivities.cc @@ -300,77 +305,6 @@ bison_target(SdfParser ${STA_HOME}/sdf/SdfParse.yy ${CMAKE_CURRENT_BINARY_DIR}/S add_flex_bison_dependency(SdfLex SdfParser) -################################################################ - -find_package(SWIG 3.0 REQUIRED) -include(UseSWIG) - -set(STA_SWIG_FILE app/StaApp.i) - -set_property(SOURCE ${STA_SWIG_FILE} - PROPERTY CPLUSPLUS ON -) -# Ubuntu 18.04 cmake version 3.10.2 does not support the -# COMPILE_OPTIONS and INCLUDE_DIRECTORIES properties, so cram -# them into SWIG_FLAGS for the time being. -set_property(SOURCE ${STA_SWIG_FILE} - PROPERTY SWIG_FLAGS - -module sta - -namespace -prefix sta - -I${STA_HOME}/tcl - -I${STA_HOME}/sdf - -I${STA_HOME}/dcalc - -I${STA_HOME}/parasitics - -I${STA_HOME}/power - -I${STA_HOME}/verilog -) - -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 - LANGUAGE tcl - TYPE STATIC - SOURCES ${STA_SWIG_FILE} -) - -get_target_property(STA_SWIG_CXX_FILE sta_swig SOURCES) - -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" - ) - -target_link_libraries(sta_swig - PUBLIC - OpenSTA -) - -# result build/CMakeFiles/sta_swig.dir/StaAppTCL_wrap.cxx -target_include_directories(sta_swig - PUBLIC - include/sta - - PRIVATE - ${STA_HOME} - ${TCL_INCLUDE_PATH} -) - ################################################################ set(STA_TCL_INIT ${CMAKE_CURRENT_BINARY_DIR}/StaTclInitVar.cc) @@ -469,6 +403,80 @@ configure_file(${STA_HOME}/util/StaConfig.hh.cmake ${STA_HOME}/include/sta/StaConfig.hh ) +########################################################### +# Swig +########################################################### + +find_package(SWIG 3.0 REQUIRED) +include(UseSWIG) + +set(STA_SWIG_FILE app/StaApp.i) + +set_property(SOURCE ${STA_SWIG_FILE} + PROPERTY CPLUSPLUS ON +) +# Ubuntu 18.04 cmake version 3.10.2 does not support the +# COMPILE_OPTIONS and INCLUDE_DIRECTORIES properties, so cram +# them into SWIG_FLAGS for the time being. +set_property(SOURCE ${STA_SWIG_FILE} + PROPERTY SWIG_FLAGS + -module sta + -namespace -prefix sta + -I${STA_HOME}/tcl + -I${STA_HOME}/sdf + -I${STA_HOME}/dcalc + -I${STA_HOME}/parasitics + -I${STA_HOME}/power + -I${STA_HOME}/verilog +) + +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 + LANGUAGE tcl + TYPE STATIC + SOURCES ${STA_SWIG_FILE} +) + +get_target_property(STA_SWIG_CXX_FILE sta_swig SOURCES) + +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" + INCLUDE_DIRECTORIES "${CUDD_INCLUDE}" + ) + +target_link_libraries(sta_swig + PUBLIC + OpenSTA +) + +# result build/CMakeFiles/sta_swig.dir/StaAppTCL_wrap.cxx +target_include_directories(sta_swig + PUBLIC + include/sta + + PRIVATE + ${STA_HOME} + ${TCL_INCLUDE_PATH} +) + ########################################################### # Library ########################################################### diff --git a/dcalc/ArcDelayCalc.cc b/dcalc/ArcDelayCalc.cc index 4b5a3cb7..bb7ea5c1 100644 --- a/dcalc/ArcDelayCalc.cc +++ b/dcalc/ArcDelayCalc.cc @@ -16,6 +16,10 @@ #include "ArcDelayCalc.hh" +#include "Liberty.hh" +#include "TimingArc.hh" +#include "Network.hh" + namespace sta { ArcDelayCalc::ArcDelayCalc(StaState *sta): @@ -53,19 +57,85 @@ ArcDcalcArg::ArcDcalcArg() : { } -ArcDcalcArg::ArcDcalcArg(const Pin *drvr_pin, +ArcDcalcArg::ArcDcalcArg(const Pin *in_pin, + const Pin *drvr_pin, Edge *edge, const TimingArc *arc, const Slew in_slew, const Parasitic *parasitic) : + in_pin_(in_pin), drvr_pin_(drvr_pin), edge_(edge), arc_(arc), in_slew_(in_slew), - parasitic_(parasitic) + parasitic_(parasitic), + input_delay_(0.0) { } +ArcDcalcArg::ArcDcalcArg(const Pin *in_pin, + const Pin *drvr_pin, + Edge *edge, + const TimingArc *arc, + float input_delay) : + in_pin_(in_pin), + drvr_pin_(drvr_pin), + edge_(edge), + arc_(arc), + in_slew_(0.0), + parasitic_(nullptr), + input_delay_(input_delay) +{ +} + +ArcDcalcArg::ArcDcalcArg(const ArcDcalcArg &arg) : + in_pin_(arg.in_pin_), + drvr_pin_(arg.drvr_pin_), + edge_(arg.edge_), + arc_(arg.arc_), + in_slew_(arg.in_slew_), + parasitic_(arg.parasitic_), + input_delay_(arg.input_delay_) +{ +} + +const RiseFall * +ArcDcalcArg::inEdge() const +{ + return arc_->fromEdge()->asRiseFall(); +} + +LibertyCell * +ArcDcalcArg::drvrCell() const +{ + + return arc_->to()->libertyCell(); +} + +const LibertyLibrary * +ArcDcalcArg::drvrLibrary() const +{ + return arc_->to()->libertyLibrary(); +} + +const RiseFall * +ArcDcalcArg::drvrEdge() const +{ + return arc_->toEdge()->asRiseFall(); +} + +const Net * +ArcDcalcArg::drvrNet(const Network *network) const +{ + return network->net(drvr_pin_); +} + +void +ArcDcalcArg::setInSlew(Slew in_slew) +{ + in_slew_ = in_slew; +} + void ArcDcalcArg::setParasitic(const Parasitic *parasitic) { diff --git a/dcalc/ArnoldiReduce.cc b/dcalc/ArnoldiReduce.cc index 5c80c382..91a36412 100644 --- a/dcalc/ArnoldiReduce.cc +++ b/dcalc/ArnoldiReduce.cc @@ -314,7 +314,8 @@ ArnoldiReduce::findPt(ParasiticNode *node) rcmodel * ArnoldiReduce::makeRcmodelDrv() { - ParasiticNode *drv_node = parasitics_->findNode(parasitic_network_, drvr_pin_); + ParasiticNode *drv_node = + parasitics_->findParasiticNode(parasitic_network_, drvr_pin_); ts_point *pdrv = findPt(drv_node); makeRcmodelDfs(pdrv); getRC(); diff --git a/dcalc/CcsCeffDelayCalc.cc b/dcalc/CcsCeffDelayCalc.cc new file mode 100644 index 00000000..7c11eec7 --- /dev/null +++ b/dcalc/CcsCeffDelayCalc.cc @@ -0,0 +1,678 @@ +// 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 "CcsCeffDelayCalc.hh" + +#include "Debug.hh" +#include "Units.hh" +#include "Liberty.hh" +#include "TimingArc.hh" +#include "Network.hh" +#include "Graph.hh" +#include "Corner.hh" +#include "DcalcAnalysisPt.hh" +#include "Parasitics.hh" +#include "GraphDelayCalc.hh" +#include "DmpDelayCalc.hh" +#include "FindRoot.hh" + +namespace sta { + +// Implementaion based on: +// "Gate Delay Estimation with Library Compatible Current Source Models +// and Effective Capacitance", D. Garyfallou et al, +// IEEE Transactions on Very Large Scale Integration (VLSI) Systems, March 2021 + +using std::abs; +using std::exp; +using std::make_shared; + +ArcDelayCalc * +makeCcsCeffDelayCalc(StaState *sta) +{ + return new CcsCeffDelayCalc(sta); +} + +CcsCeffDelayCalc::CcsCeffDelayCalc(StaState *sta) : + LumpedCapDelayCalc(sta), + output_waveforms_(nullptr), + // Includes the Vh:Vdd region. + region_count_(0), + vl_fail_(false), + capacitance_unit_(units_->capacitanceUnit()), + table_dcalc_(makeDmpCeffElmoreDelayCalc(sta)) +{ +} + +CcsCeffDelayCalc::~CcsCeffDelayCalc() +{ + delete table_dcalc_; +} + +ArcDelayCalc * +CcsCeffDelayCalc::copy() +{ + return new CcsCeffDelayCalc(this); +} + +ArcDcalcResult +CcsCeffDelayCalc::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) +{ + bool vdd_exists; + LibertyCell *drvr_cell = arc->to()->libertyCell(); + const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary(); + const RiseFall *rf = arc->toEdge()->asRiseFall(); + drvr_library->supplyVoltage("VDD", vdd_, vdd_exists); + if (!vdd_exists) + report_->error(1700, "VDD not defined in library %s", drvr_library->name()); + vth_ = drvr_library->outputThreshold(rf) * vdd_; + vl_ = drvr_library->slewLowerThreshold(rf) * vdd_; + vh_ = drvr_library->slewUpperThreshold(rf) * vdd_; + in_slew_ = in_slew; + load_cap_ = load_cap; + parasitic_ = parasitic; + drvr_cell->ensureVoltageWaveforms(); + output_waveforms_ = nullptr; + + GateTableModel *table_model = gateTableModel(arc, dcalc_ap); + if (table_model && parasitic) { + OutputWaveforms *output_waveforms = table_model->outputWaveforms(); + parasitics_->piModel(parasitic, c2_, rpi_, c1_); + if (output_waveforms + && rpi_ > 0.0 && c1_ > 0.0 + // Bounds check because extrapolating waveforms does not work for shit. + && output_waveforms->slewAxis()->inBounds(in_slew_) + && output_waveforms->capAxis()->inBounds(c2_) + && output_waveforms->capAxis()->inBounds(load_cap_)) { + in_slew_ = delayAsFloat(in_slew); + output_waveforms_ = output_waveforms; + ref_time_ = output_waveforms_->referenceTime(in_slew_); + debugPrint(debug_, "ccs_dcalc", 1, "%s %s", + drvr_cell->name(), + rf->asString()); + ArcDelay gate_delay; + Slew drvr_slew; + gateDelaySlew(drvr_library, rf, gate_delay, drvr_slew); + return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map); + } + } + return table_dcalc_->gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, + load_pin_index_map, dcalc_ap); +} + +void +CcsCeffDelayCalc::gateDelaySlew(const LibertyLibrary *drvr_library, + const RiseFall *rf, + // Return values. + ArcDelay &gate_delay, + Slew &drvr_slew) +{ + initRegions(drvr_library, rf); + findCsmWaveform(); + ref_time_ = output_waveforms_->referenceTime(in_slew_); + gate_delay = region_times_[region_vth_idx_] - ref_time_; + drvr_slew = abs(region_times_[region_vh_idx_] - region_times_[region_vl_idx_]); + debugPrint(debug_, "ccs_dcalc", 2, + "gate_delay %s drvr_slew %s (initial)", + delayAsString(gate_delay, this), + delayAsString(drvr_slew, this)); + float prev_drvr_slew = delayAsFloat(drvr_slew); + constexpr int max_iterations = 5; + for (int iter = 0; iter < max_iterations; iter++) { + debugPrint(debug_, "ccs_dcalc", 2, "iteration %d", iter); + // Init drvr ramp model for vl. + for (size_t i = 0; i <= region_count_; i++) { + region_ramp_times_[i] = region_times_[i]; + if (i < region_count_) + region_ramp_slopes_[i] = (region_volts_[i + 1] - region_volts_[i]) + / (region_times_[i + 1] - region_times_[i]); + } + + for (size_t i = 0; i < region_count_; i++) { + double v1 = region_volts_[i]; + double v2 = region_volts_[i + 1]; + double t1 = region_times_[i]; + double t2 = region_times_[i + 1]; + + // Receiver cap Cp(l) assumed constant and included in c1. + // Note that eqn 8 in the ref'd paper does not properly account + // for the charge on c1 from previous segments so it does not + // work well. + double c1_v1, c1_v2, ignore; + vl(t1, rpi_ * c1_, c1_v1, ignore); + vl(t2, rpi_ * c1_, c1_v2, ignore); + double q1 = v1 * c2_ + c1_v1 * c1_; + double q2 = v2 * c2_ + c1_v2 * c1_; + double ceff = (q2 - q1) / (v2 - v1); + + debugPrint(debug_, "ccs_dcalc", 2, "ceff %s", + capacitance_unit_->asString(ceff)); + region_ceff_[i] = ceff; + } + findCsmWaveform(); + gate_delay = region_times_[region_vth_idx_] - ref_time_; + drvr_slew = abs(region_times_[region_vh_idx_] - region_times_[region_vl_idx_]); + debugPrint(debug_, "ccs_dcalc", 2, + "gate_delay %s drvr_slew %s", + delayAsString(gate_delay, this), + delayAsString(drvr_slew, this)); + if (abs(delayAsFloat(drvr_slew) - prev_drvr_slew) < .01 * prev_drvr_slew) + break; + prev_drvr_slew = delayAsFloat(drvr_slew); + } +} + +void +CcsCeffDelayCalc::initRegions(const LibertyLibrary *drvr_library, + const RiseFall *rf) +{ + // Falling waveforms are treated as rising to simplify the conditionals. + if (rf == RiseFall::fall()) { + vl_ = (1.0 - drvr_library->slewUpperThreshold(rf)) * vdd_; + vh_ = (1.0 - drvr_library->slewLowerThreshold(rf)) * vdd_; + } + + // Includes the Vh:Vdd region. + region_count_ = 7; + region_volts_.resize(region_count_ + 1); + region_ceff_.resize(region_count_ + 1); + region_times_.resize(region_count_ + 1); + region_begin_times_.resize(region_count_ + 1); + region_end_times_.resize(region_count_ + 1); + region_time_offsets_.resize(region_count_ + 1); + region_ramp_times_.resize(region_count_ + 1); + region_ramp_slopes_.resize(region_count_ + 1); + + region_vl_idx_ = 1; + region_vh_idx_ = region_count_ - 1; + + double vth_vh = (vh_ - vth_); + switch (region_count_) { + case 4: + region_vth_idx_ = 2; + region_volts_ = {0.0, vl_, vth_, vh_, vdd_}; + break; + case 5: { + region_vth_idx_ = 2; + double v1 = vth_ + .7 * vth_vh; + region_volts_ = {0.0, vl_, vth_, v1, vh_, vdd_}; + break; + } + case 6: { + region_vth_idx_ = 2; + double v1 = vth_ + .3 * vth_vh; + double v2 = vth_ + .6 * vth_vh; + region_volts_ = {0.0, vl_, vth_, v1, v2, vh_, vdd_}; + break; + } + case 7: { + region_vth_idx_ = 2; + region_vh_idx_ = 5; + double v1 = vth_ + .3 * vth_vh; + double v2 = vth_ + .6 * vth_vh; + double v3 = vh_ + .5 * (vdd_ - vh_); + region_volts_ = {0.0, vl_, vth_, v1, v2, vh_, v3, vdd_}; + break; + } + case 8: { + region_vth_idx_ = 2; + region_vh_idx_ = 6; + double v1 = vth_ + .25 * vth_vh; + double v2 = vth_ + .50 * vth_vh; + double v3 = vth_ + .75 * vth_vh; + double v4 = vh_ + .5 * (vdd_ - vh_); + region_volts_ = {0.0, vl_, vth_, v1, v2, v3, vh_, v4, vdd_}; + break; + } + case 9: { + region_vth_idx_ = 2; + region_vh_idx_ = 7; + double v1 = vth_ + .2 * vth_vh; + double v2 = vth_ + .4 * vth_vh; + double v3 = vth_ + .6 * vth_vh; + double v4 = vth_ + .8 * vth_vh; + double v5 = vh_ + .5 * (vdd_ - vh_); + region_volts_ = {0.0, vl_, vth_, v1, v2, v3, v4, vh_, v5, vdd_}; + break; + } + case 10: { + region_vth_idx_ = 2; + region_vh_idx_ = 7; + double v1 = vth_ + .2 * vth_vh; + double v2 = vth_ + .4 * vth_vh; + double v3 = vth_ + .6 * vth_vh; + double v4 = vth_ + .8 * vth_vh; + double v5 = vh_ + .3 * (vdd_ - vh_); + double v6 = vh_ + .6 * (vdd_ - vh_); + region_volts_ = {0.0, vl_, vth_, v1, v2, v3, v4, vh_, v5, v6, vdd_}; + break; + } + default: + report_->error(1701, "unsupported ccs region count."); + break; + } + fill(region_ceff_.begin(), region_ceff_.end(), c2_ + c1_); +} + +void +CcsCeffDelayCalc::findCsmWaveform() +{ + for (size_t i = 0; i < region_count_; i++) { + double t1 = output_waveforms_->voltageTime(in_slew_, region_ceff_[i], + region_volts_[i]); + double t2 = output_waveforms_->voltageTime(in_slew_, region_ceff_[i], + region_volts_[i + 1]); + region_begin_times_[i] = t1; + region_end_times_[i] = t2; + double time_offset = (i == 0) + ? 0.0 + : t1 - (region_end_times_[i - 1] - region_time_offsets_[i - 1]); + region_time_offsets_[i] = time_offset; + + if (i == 0) + region_times_[i] = t1 - time_offset; + region_times_[i + 1] = t2 - time_offset; + } +} + +//////////////////////////////////////////////////////////////// + +ArcDcalcResult +CcsCeffDelayCalc::makeResult(const LibertyLibrary *drvr_library, + const RiseFall *rf, + ArcDelay &gate_delay, + Slew &drvr_slew, + const LoadPinIndexMap &load_pin_index_map) +{ + ArcDcalcResult dcalc_result(load_pin_index_map.size()); + debugPrint(debug_, "ccs_dcalc", 2, + "gate_delay %s drvr_slew %s", + delayAsString(gate_delay, this), + delayAsString(drvr_slew, this)); + 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_library, rf, drvr_slew, wire_delay, load_slew); + dcalc_result.setWireDelay(load_idx, wire_delay); + dcalc_result.setLoadSlew(load_idx, load_slew); + } + return dcalc_result; +} + +void +CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin, + const LibertyLibrary *drvr_library, + const RiseFall *rf, + Slew &drvr_slew, + // Return values. + 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 (parasitic_ + && parasitics_->isPiElmore(parasitic_)) + parasitics_->findElmore(parasitic_, load_pin, elmore, elmore_exists); + + if (elmore_exists && + (elmore == 0.0 + // Elmore delay is small compared to driver slew. + || elmore < delayAsFloat(drvr_slew) * 1e-3)) { + wire_delay1 = elmore; + load_slew1 = drvr_slew; + } + else + loadDelaySlew(load_pin, drvr_slew, elmore, wire_delay1, load_slew1); + + thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew); + wire_delay = wire_delay1; + load_slew = load_slew1; +} + +void +CcsCeffDelayCalc::loadDelaySlew(const Pin *load_pin, + Slew &drvr_slew, + float elmore, + // Return values. + ArcDelay &delay, + Slew &slew) +{ + for (size_t i = 0; i <= region_count_; i++) { + region_ramp_times_[i] = region_times_[i]; + if (i < region_count_) + region_ramp_slopes_[i] = (region_volts_[i + 1] - region_volts_[i]) + / (region_times_[i + 1] - region_times_[i]); + } + + vl_fail_ = false; + double t_vl = findVlTime(vl_, elmore); + double t_vth = findVlTime(vth_, elmore); + double t_vh = findVlTime(vh_, elmore); + if (!vl_fail_) { + delay = t_vth - region_times_[region_vth_idx_]; + slew = t_vh - t_vl; + } + else { + delay = elmore; + slew = drvr_slew; + fail("load delay threshold crossing"); + } + debugPrint(debug_, "ccs_dcalc", 2, + "load %s delay %s slew %s", + network_->pathName(load_pin), + delayAsString(delay, this), + delayAsString(slew, this)); +} + +// Elmore (one pole) response to ramp with slope slew. +static void +rampElmoreV(double t, + double slew, + double elmore, + // Return values. + double &v, + double &dv_dt) +{ + double exp_t = 1.0 - exp2(-t / elmore); + v = slew * (t - elmore * exp_t); + // First derivative of loadVl dv/dt. + dv_dt = slew * exp_t; +} + +// Elmore (one pole) response to 2 segment ramps [0, vth] slew1, [vth, vdd] slew2. +void +CcsCeffDelayCalc::vl(double t, + double elmore, + // Return values. + double &vl, + double &dvl_dt) +{ + vl = 0.0; + dvl_dt = 0.0; + for (size_t i = 0; i < region_count_; i++) { + double t_begin = region_ramp_times_[i]; + double t_end = region_ramp_times_[i + 1]; + double ramp_slope = region_ramp_slopes_[i]; + if (t >= t_begin) { + double v, dv_dt; + rampElmoreV(t - t_begin, ramp_slope, elmore, v, dv_dt); + vl += v; + dvl_dt += dv_dt; + } + if (t > t_end) { + double v, dv_dt; + rampElmoreV(t - t_end, ramp_slope, elmore, v, dv_dt); + vl -= v; + dvl_dt -= dv_dt; + } + } +} + +// for debugging +double +CcsCeffDelayCalc::vl(double t, + double elmore) +{ + double vl1, dvl_dt; + vl(t, elmore, vl1, dvl_dt); + return vl1; +} + +double +CcsCeffDelayCalc::findVlTime(double v, + double elmore) +{ + double t_init = region_ramp_times_[0]; + double t_final = region_ramp_times_[region_count_]; + bool root_fail = false; + double time = findRoot([=] (double t, + double &y, + double &dy) { + vl(t, elmore, y, dy); + y -= v; + }, t_init, t_final + elmore * 3.0, .001, 20, root_fail); + vl_fail_ |= root_fail; + return time; +} + +//////////////////////////////////////////////////////////////// + +// Waveform accessors for swig/tcl. + +Table1 +CcsCeffDelayCalc::drvrWaveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Corner *corner, + const MinMax *min_max) +{ + bool dcalc_success = makeWaveformPreamble(in_pin, in_rf, drvr_pin, + drvr_rf, corner, min_max); + if (dcalc_success) + return drvrWaveform(in_slew_, drvr_rf); + else + return Table1(); +} + +Table1 +CcsCeffDelayCalc::drvrWaveform(const Slew &in_slew, + const RiseFall *drvr_rf) +{ + // Stitch together the ccs waveforms for each region. + FloatSeq *drvr_times = new FloatSeq; + FloatSeq *drvr_volts = new FloatSeq; + for (size_t i = 0; i < region_count_; i++) { + double t1 = region_begin_times_[i]; + double t2 = region_end_times_[i]; + size_t time_steps = 10; + double time_step = (t2 - t1) / time_steps; + double time_offset = region_time_offsets_[i]; + for (size_t s = 0; s <= time_steps; s++) { + double t = t1 + s * time_step; + drvr_times->push_back(t - time_offset); + double v = output_waveforms_->timeVoltage(delayAsFloat(in_slew), + region_ceff_[i], t); + if (drvr_rf == RiseFall::fall()) + v = vdd_ - v; + drvr_volts->push_back(v); + } + } + TableAxisPtr drvr_time_axis = make_shared(TableAxisVariable::time, + drvr_times); + Table1 drvr_table(drvr_volts, drvr_time_axis); + return drvr_table; +} + +// For debugging +Table1 +CcsCeffDelayCalc::loadWaveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Pin *load_pin, + const Corner *corner, + const MinMax *min_max) +{ + bool elmore_exists = false; + float elmore = 0.0; + if (parasitic_) { + parasitics_->findElmore(parasitic_, load_pin, elmore, elmore_exists); + bool dcalc_success = makeWaveformPreamble(in_pin, in_rf, drvr_pin, + drvr_rf, corner, min_max); + if (dcalc_success + && elmore_exists) { + FloatSeq *load_times = new FloatSeq; + FloatSeq *load_volts = new FloatSeq; + double t_vh = findVlTime(vh_, elmore); + double dt = t_vh / 20.0; + double v_final = vh_ + (vdd_ - vh_) * .8; + double v = 0.0; + for (double t = 0; v < v_final; t += dt) { + load_times->push_back(t); + + double ignore; + vl(t, elmore, v, ignore); + double v1 = (drvr_rf == RiseFall::rise()) ? v : vdd_ - v; + load_volts->push_back(v1); + } + TableAxisPtr load_time_axis = make_shared(TableAxisVariable::time, + load_times); + Table1 load_table(load_volts, load_time_axis); + return load_table; + } + } + return Table1(); +} + +Table1 +CcsCeffDelayCalc::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) +{ + bool elmore_exists = false; + float elmore = 0.0; + if (parasitic_) { + parasitics_->findElmore(parasitic_, load_pin, elmore, elmore_exists); + bool dcalc_success = makeWaveformPreamble(in_pin, in_rf, drvr_pin, + drvr_rf, corner, min_max); + if (dcalc_success + && elmore_exists) { + FloatSeq *load_times = new FloatSeq; + FloatSeq *load_volts = new FloatSeq; + for (size_t j = 0; j <= region_count_; j++) { + double t = region_ramp_times_[j]; + load_times->push_back(t); + double v = 0.0; + for (size_t i = 0; i < region_count_; i++) { + double t_begin = region_ramp_times_[i]; + double t_end = region_ramp_times_[i + 1]; + double ramp_slope = region_ramp_slopes_[i]; + if (t >= t_begin) + v += (t - t_begin) * ramp_slope; + if (t > t_end) + v -= (t - t_end) * ramp_slope; + } + double v1 = (drvr_rf == RiseFall::rise()) ? v : vdd_ - v; + load_volts->push_back(v1); + } + TableAxisPtr load_time_axis = make_shared(TableAxisVariable::time, + load_times); + Table1 load_table(load_volts, load_time_axis); + return load_table; + } + } + return Table1(); +} + +bool +CcsCeffDelayCalc::makeWaveformPreamble(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Corner *corner, + const MinMax *min_max) +{ + Vertex *in_vertex = graph_->pinLoadVertex(in_pin); + Vertex *drvr_vertex = graph_->pinDrvrVertex(drvr_pin); + Edge *edge = nullptr; + VertexInEdgeIterator edge_iter(drvr_vertex, graph_); + while (edge_iter.hasNext()) { + edge = edge_iter.next(); + Vertex *from_vertex = edge->from(graph_); + const Pin *from_pin = from_vertex->pin(); + if (from_pin == in_pin) + break; + } + if (edge) { + TimingArc *arc = nullptr; + for (TimingArc *arc1 : edge->timingArcSet()->arcs()) { + if (arc1->fromEdge()->asRiseFall() == in_rf + && arc1->toEdge()->asRiseFall() == drvr_rf) { + arc = arc1; + break; + } + } + if (arc) { + DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); + const Slew &in_slew = graph_->slew(in_vertex, in_rf, dcalc_ap->index()); + parasitic_ = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf, dcalc_ap); + if (parasitic_) { + parasitics_->piModel(parasitic_, c2_, rpi_, c1_); + LoadPinIndexMap load_pin_index_map = + graph_delay_calc_->makeLoadPinIndexMap(drvr_vertex); + gateDelay(drvr_pin, arc, in_slew, load_cap_, parasitic_, + load_pin_index_map, dcalc_ap); + return true; + } + } + } + return false; +} + +//////////////////////////////////////////////////////////////// + +string +CcsCeffDelayCalc::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) +{ + Parasitic *pi_elmore = nullptr; + const RiseFall *rf = arc->toEdge()->asRiseFall(); + if (parasitic && !parasitics_->isPiElmore(parasitic)) { + const ParasiticAnalysisPt *ap = dcalc_ap->parasiticAnalysisPt(); + pi_elmore = parasitics_->reduceToPiElmore(parasitic, drvr_pin_, rf, + dcalc_ap->corner(), + dcalc_ap->constraintMinMax(), ap); + } + string report = table_dcalc_->reportGateDelay(drvr_pin, arc, in_slew, load_cap, + pi_elmore, load_pin_index_map, + dcalc_ap, digits); + parasitics_->deleteDrvrReducedParasitics(drvr_pin); + return report; +} + +void +CcsCeffDelayCalc::fail(const char *reason) +{ + // Report failures with a unique debug flag. + if (debug_->check("ccs_dcalc", 1) || debug_->check("dcalc_error", 1)) + report_->reportLine("delay_calc: CCS failed - %s", reason); +} + +} // namespace diff --git a/dcalc/CcsCeffDelayCalc.hh b/dcalc/CcsCeffDelayCalc.hh new file mode 100644 index 00000000..35094007 --- /dev/null +++ b/dcalc/CcsCeffDelayCalc.hh @@ -0,0 +1,157 @@ +// 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 "LumpedCapDelayCalc.hh" +#include "ArcDcalcWaveforms.hh" + +namespace sta { + +using std::vector; + +ArcDelayCalc * +makeCcsCeffDelayCalc(StaState *sta); + +class CcsCeffDelayCalc : public LumpedCapDelayCalc, public ArcDcalcWaveforms +{ +public: + CcsCeffDelayCalc(StaState *sta); + virtual ~CcsCeffDelayCalc(); + ArcDelayCalc *copy() 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 *parasitic, + const LoadPinIndexMap &load_pin_index_map, + const DcalcAnalysisPt *dcalc_ap, + int digits) override; + + Table1 drvrWaveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Corner *corner, + const MinMax *min_max) override; + Table1 loadWaveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Pin *load_pin, + const Corner *corner, + const MinMax *min_max) override; + Table1 drvrRampWaveform(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Pin *load_pin, + const Corner *corner, + const MinMax *min_max) override; + +protected: + typedef vector Region; + + void gateDelaySlew(const LibertyLibrary *drvr_library, + const RiseFall *rf, + // Return values. + ArcDelay &gate_delay, + Slew &drvr_slew); + void initRegions(const LibertyLibrary *drvr_library, + const RiseFall *rf); + void findCsmWaveform(); + ArcDcalcResult makeResult(const LibertyLibrary *drvr_library, + const RiseFall *rf, + ArcDelay &gate_delay, + Slew &drvr_slew, + const LoadPinIndexMap &load_pin_index_map); + void loadDelaySlew(const Pin *load_pin, + const LibertyLibrary *drvr_library, + const RiseFall *rf, + Slew &drvr_slew, + // Return values. + ArcDelay &wire_delay, + Slew &load_slew); + void loadDelaySlew(const Pin *load_pin, + Slew &drvr_slew, + float elmore, + // Return values. + ArcDelay &delay, + Slew &slew); + bool makeWaveformPreamble(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Corner *corner, + const MinMax *min_max); + double findVlTime(double v, + double elmore); + void vl(double t, + double elmore, + // Return values. + double &vl, + double &dvl_dt); + double vl(double t, + double elmore); + Table1 drvrWaveform(const Slew &in_slew, + const RiseFall *drvr_rf); + void fail(const char *reason); + + const Pin *drvr_pin_; + double in_slew_; + double load_cap_; + const Parasitic *parasitic_; + + OutputWaveforms *output_waveforms_; + double ref_time_; + float vdd_; + float vth_; + float vl_; + float vh_; + + float c2_; + float rpi_; + float c1_; + + size_t region_count_; + size_t region_vl_idx_; + size_t region_vth_idx_; + size_t region_vh_idx_; + + Region region_volts_; + Region region_ceff_; + Region region_times_; + Region region_begin_times_; + Region region_end_times_; + Region region_time_offsets_; + Region region_ramp_times_; + Region region_ramp_slopes_; + bool vl_fail_; + + const Unit *capacitance_unit_; + // Delay calculator to use when ccs waveforms are missing from liberty. + ArcDelayCalc *table_dcalc_; +}; + +} // namespace diff --git a/dcalc/DelayCalc.cc b/dcalc/DelayCalc.cc index ab032824..2fe5dcd5 100644 --- a/dcalc/DelayCalc.cc +++ b/dcalc/DelayCalc.cc @@ -22,6 +22,7 @@ #include "LumpedCapDelayCalc.hh" #include "DmpDelayCalc.hh" #include "ArnoldiDelayCalc.hh" +#include "CcsCeffDelayCalc.hh" namespace sta { @@ -37,6 +38,7 @@ registerDelayCalcs() registerDelayCalc("dmp_ceff_elmore", makeDmpCeffElmoreDelayCalc); registerDelayCalc("dmp_ceff_two_pole", makeDmpCeffTwoPoleDelayCalc); registerDelayCalc("arnoldi", makeArnoldiDelayCalc); + registerDelayCalc("ccs_ceff", makeCcsCeffDelayCalc); } void diff --git a/dcalc/DelayCalc.tcl b/dcalc/DelayCalc.tcl index 7af909e5..c93684db 100644 --- a/dcalc/DelayCalc.tcl +++ b/dcalc/DelayCalc.tcl @@ -16,6 +16,13 @@ namespace eval sta { +define_cmd_args "report_dcalc" \ + {[-from from_pin] [-to to_pin] [-corner corner] [-min] [-max] [-digits digits]} + +proc_redirect report_dcalc { + report_dcalc_cmd "report_dcalc" $args "-digits" +} + # Allow any combination of -from/-to pins. proc report_dcalc_cmd { cmd cmd_args digits_key } { global sta_report_default_digits diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index da3b40d0..87ccc66d 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -954,14 +954,14 @@ GraphDelayCalc::makeArcDcalcArgs(Vertex *drvr_vertex, // Shockingly one fpga vendor connects outputs with no timing arcs together. if (edge1) { Vertex *from_vertex = edge1->from(graph_); + const Pin *from_pin = from_vertex->pin(); 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)); + dcalc_args.emplace_back(from_pin, drvr_pin1, edge1, arc1, in_slew, parasitic); } } return dcalc_args; diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt index 30afc942bfb3925e7e5bdbad91fe93567e9f1fce..2682fccf734bdb5effd1926c615791fa27c44906 100644 GIT binary patch delta 75389 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%0Agt52d(r!!8WQZ_Nqi0$HEJ9YD zefXSz?KXZ9Ur^NU_W@Ou`3qH>&fmuoFSMI%Vc_IdHCjy0{bJg0AzCo~O*q_}k36ZV zZ$Ti)rF!n4gy5bGb!*VC@rO|yzu>*q2<+FM+zb;vAn;ikd7Yz&2`z%QDAZ_$3K%43qJ|WT%E7Zs-vR~y?CB@Tbw92A`qv8Kh_0E5t#b5XL&$*F;icL1MorU>)~vbp8T8lcv@B@o%#Cb} zcxpZDMvmO{>xwRPW`1yd>lCd@v|3#v0T}+wHg|v@F|q_l{bhS4hd|aIwp% zRuPGk+sfELGXIWQiQ3{_&T&v6Q9Ulg29(9Mh+*ARi66Ljna2W*}B< z;072Moq4z#r~8PjW4^#Q<@a$U4GB|vI9XL|$?mMR&O&KG4cIN!4@>Iu@brNVO)wd% z7a~ocZ<*X(Eey*MO`M8&7U|7Eoohpiw03}hHq-T~{`{KEs2WN*k?NtdI{TYiTab(B zzwLtiFE^gMd% zXi?T1-6w^C3B+?hWA(I2arlOM3hGr=pzFk(nUpLiqJqSMIi3CB2QPAo76qztbs@ z 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 z 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 P$YBv;Dk{d-CSv~wi~^Xz diff --git a/graph/Graph.cc b/graph/Graph.cc index 2007e610..c24d69ca 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -498,6 +498,37 @@ Graph::deleteOutEdge(Vertex *vertex, Graph::edge(next)->vertex_out_prev_ = prev; } +void +Graph::gateEdgeArc(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + // Return values. + Edge *&edge, + const TimingArc *&arc) const +{ + Vertex *in_vertex = pinLoadVertex(in_pin); + Vertex *drvr_vertex = pinDrvrVertex(drvr_pin); + // Iterate over load drivers to avoid driver fanout^2. + VertexInEdgeIterator edge_iter(drvr_vertex, this); + while (edge_iter.hasNext()) { + Edge *edge1 = edge_iter.next(); + if (edge1->from(this) == in_vertex) { + TimingArcSet *arc_set = edge1->timingArcSet(); + for (TimingArc *arc1 : arc_set->arcs()) { + if (arc1->fromEdge()->asRiseFall() == in_rf + && arc1->toEdge()->asRiseFall() == drvr_rf) { + edge = edge1; + arc = arc1; + return; + } + } + } + } + edge = nullptr; + arc = nullptr; +} + //////////////////////////////////////////////////////////////// Arrival * diff --git a/include/sta/ArcDelayCalc.hh b/include/sta/ArcDelayCalc.hh index 64f81069..eb56da6f 100644 --- a/include/sta/ArcDelayCalc.hh +++ b/include/sta/ArcDelayCalc.hh @@ -50,24 +50,41 @@ class ArcDcalcArg { public: ArcDcalcArg(); - ArcDcalcArg(const Pin *drvr_pin, - Edge *edge, - const TimingArc *arc, - const Slew in_slew, - const Parasitic *parasitic); + ArcDcalcArg(const ArcDcalcArg &arg); + ArcDcalcArg(const Pin *in_pin, + const Pin *drvr_pin, + Edge *edge, + const TimingArc *arc, + const Slew in_slew, + const Parasitic *parasitic); + ArcDcalcArg(const Pin *in_pin, + const Pin *drvr_pin, + Edge *edge, + const TimingArc *arc, + float in_delay); + const Pin *inPin() const { return in_pin_; } + const RiseFall *inEdge() const; const Pin *drvrPin() const { return drvr_pin_; } + LibertyCell *drvrCell() const; + const LibertyLibrary *drvrLibrary() const; + const RiseFall *drvrEdge() const; + const Net *drvrNet(const Network *network) const; Edge *edge() const { return edge_; } const TimingArc *arc() const { return arc_; } Slew inSlew() const { return in_slew_; } + void setInSlew(Slew in_slew); const Parasitic *parasitic() { return parasitic_; } void setParasitic(const Parasitic *parasitic); + float inputDelay() const { return input_delay_; } protected: + const Pin *in_pin_; const Pin *drvr_pin_; Edge *edge_; const TimingArc *arc_; Slew in_slew_; const Parasitic *parasitic_; + float input_delay_; }; // Arc delay calc result. diff --git a/include/sta/Bdd.hh b/include/sta/Bdd.hh new file mode 100644 index 00000000..bc95283d --- /dev/null +++ b/include/sta/Bdd.hh @@ -0,0 +1,57 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2024, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include + +#include "StaState.hh" +#include "LibertyClass.hh" + +#if CUDD +#include "cudd.h" +#else +struct DdNode; +struct DdManager; +#endif + +namespace sta { + +typedef std::map BddPortVarMap; +typedef std::map BddVarIdxPortMap; + +class Bdd : public StaState +{ +public: + Bdd(const StaState *sta); + ~Bdd(); + DdNode *funcBdd(const FuncExpr *expr); + DdNode *findNode(const LibertyPort *port); + const LibertyPort *nodePort(DdNode *node); + DdNode *ensureNode(const LibertyPort *port); + const LibertyPort *varIndexPort(int var_index); + BddPortVarMap &portVarMap() { return bdd_port_var_map_; } + + void clearVarMap(); + DdManager *cuddMgr() const { return cudd_mgr_; } + +private: + DdManager *cudd_mgr_; + BddPortVarMap bdd_port_var_map_; + BddVarIdxPortMap bdd_var_idx_port_map_; +}; + +} // namespace diff --git a/include/sta/CircuitSim.hh b/include/sta/CircuitSim.hh new file mode 100644 index 00000000..e0bf24d3 --- /dev/null +++ b/include/sta/CircuitSim.hh @@ -0,0 +1,23 @@ +// 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 + +namespace sta { + +enum class CircuitSim { hspice, ngspice, xyce }; + +} // namespace diff --git a/include/sta/FuncExpr.hh b/include/sta/FuncExpr.hh index 586c241a..0d4f725d 100644 --- a/include/sta/FuncExpr.hh +++ b/include/sta/FuncExpr.hh @@ -93,12 +93,12 @@ funcExprNot(FuncExpr *expr); class FuncExprPortIterator : public Iterator { public: - explicit FuncExprPortIterator(FuncExpr *expr); + explicit FuncExprPortIterator(const FuncExpr *expr); virtual bool hasNext() { return iter_.hasNext(); } virtual LibertyPort *next() { return iter_.next(); } private: - void findPorts(FuncExpr *expr); + void findPorts(const FuncExpr *expr); LibertyPortSet ports_; LibertyPortSet::ConstIterator iter_; diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index 00fec1f2..eb53b2e7 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -115,7 +115,6 @@ public: uint32_t count); PathVertexRep *prevPaths(Vertex *vertex) const; void clearPrevPaths(); - // Slews are reported slews in seconds. // Reported slew are the same as those in the liberty tables. // reported_slews = measured_slews / slew_derate_from_library // Measured slews are between slew_lower_threshold and slew_upper_threshold. @@ -141,6 +140,15 @@ public: void makeWireEdgesThruPin(const Pin *hpin); virtual void makeWireEdgesFromPin(const Pin *drvr_pin); virtual void deleteEdge(Edge *edge); + // Find the edge and timing arc on a gate between in_pin and drvr_pin. + void gateEdgeArc(const Pin *in_pin, + const RiseFall *in_rf, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + // Return values. + Edge *&edge, + const TimingArc *&arc) const; + virtual ArcDelay arcDelay(const Edge *edge, const TimingArc *arc, DcalcAPIndex ap_index) const; diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh index a93dd890..bf69f979 100644 --- a/include/sta/GraphDelayCalc.hh +++ b/include/sta/GraphDelayCalc.hh @@ -92,6 +92,14 @@ public: float &wire_cap, float &fanout, bool &has_set_load) 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; LoadPinIndexMap makeLoadPinIndexMap(Vertex *drvr_vertex); void findDriverArcDelays(Vertex *drvr_vertex, Edge *edge, @@ -231,14 +239,6 @@ protected: 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, diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index eef1af46..30d3a02e 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -319,7 +319,6 @@ 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, @@ -371,7 +370,6 @@ 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; @@ -533,6 +531,7 @@ public: // Check all liberty cells to make sure they exist // for all the defined corners. static void checkLibertyCorners(); + void ensureVoltageWaveforms(); protected: void addPort(ConcretePort *port); @@ -608,6 +607,7 @@ protected: bool leakage_power_exists_; LibertyPgPortMap pg_port_map_; bool has_internal_ports_; + bool have_voltage_waveforms_; private: friend class LibertyLibrary; @@ -795,7 +795,15 @@ public: DriverWaveform *driverWaveform(const RiseFall *rf) const; void setDriverWaveform(DriverWaveform *driver_waveform, const RiseFall *rf); - RiseFallMinMax clockTreePathDelays(); + void setClkTreeDelay(const TableModel *model, + const RiseFall *rf, + const MinMax *min_max); + float clkTreeDelay(float in_slew, + const RiseFall *rf, + const MinMax *min_max) const; + // Assumes input slew of 0.0. + RiseFallMinMax clkTreeDelays() const; + RiseFallMinMax clockTreePathDelays() const; // __attribute__ ((deprecated)) static bool equiv(const LibertyPort *port1, const LibertyPort *port2); @@ -837,6 +845,8 @@ protected: Vector corner_ports_; ReceiverModelPtr receiver_model_; DriverWaveform *driver_waveform_[RiseFall::index_count]; + // Redundant with clock_tree_path_delay timing arcs but faster to access. + const TableModel *clk_tree_delay_[RiseFall::index_count][MinMax::index_count]; unsigned int min_pulse_width_exists_:RiseFall::index_count; bool min_period_exists_:1; diff --git a/include/sta/NetworkClass.hh b/include/sta/NetworkClass.hh index 97fc0a39..bcda1ba5 100644 --- a/include/sta/NetworkClass.hh +++ b/include/sta/NetworkClass.hh @@ -50,6 +50,7 @@ typedef Iterator PortMemberIterator; typedef Vector PinSeq; typedef Vector InstanceSeq; typedef Vector NetSeq; +typedef std::vector ConstNetSeq; typedef Iterator InstanceChildIterator; typedef Iterator InstancePinIterator; typedef Iterator InstanceNetIterator; diff --git a/include/sta/Parasitics.hh b/include/sta/Parasitics.hh index a55143c9..23e589a7 100644 --- a/include/sta/Parasitics.hh +++ b/include/sta/Parasitics.hh @@ -163,11 +163,20 @@ public: // True if the parasitic network caps include pin capacitances. virtual bool includesPinCaps(const Parasitic *parasitic) const = 0; // Parasitic network component builders. + virtual ParasiticNode *findParasiticNode(Parasitic *parasitic, + const Net *net, + int id, + const Network *network) const = 0; // Make a subnode of the parasitic network net. virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, const Net *net, int id, const Network *network) = 0; + // Find the parasitic node connected to pin. + virtual ParasiticNode *findParasiticNode(const Parasitic *parasitic, + const Pin *pin) const = 0; + virtual ParasiticNode *findNode(const Parasitic *parasitic, + const Pin *pin) const __attribute__ ((deprecated)); // Make a subnode of the parasitic network net connected to pin. virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, const Pin *pin, @@ -175,14 +184,11 @@ public: // Increment the grounded capacitance on node. virtual void incrCap(ParasiticNode *node, float cap) = 0; - virtual const char *name(const ParasiticNode *node) = 0; + virtual const char *name(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 = 0; diff --git a/include/sta/PowerClass.hh b/include/sta/PowerClass.hh index 63665609..8a8e28b3 100644 --- a/include/sta/PowerClass.hh +++ b/include/sta/PowerClass.hh @@ -18,6 +18,8 @@ namespace sta { +class Power; + enum class PwrActivityOrigin { global, diff --git a/include/sta/SdcClass.hh b/include/sta/SdcClass.hh index c8a9460a..7ef169a7 100644 --- a/include/sta/SdcClass.hh +++ b/include/sta/SdcClass.hh @@ -75,7 +75,9 @@ public: typedef Vector FloatSeq; typedef Vector IntSeq; typedef Vector ClockSeq; +typedef std::vector ConstClockSeq; typedef Set ClockSet; +typedef std::set ConstClockSet; typedef ClockSet ClockGroup; typedef Vector PinSetSeq; typedef MinMax SetupHold; diff --git a/include/sta/SearchClass.hh b/include/sta/SearchClass.hh index 66e82e7d..88096f0f 100644 --- a/include/sta/SearchClass.hh +++ b/include/sta/SearchClass.hh @@ -61,6 +61,7 @@ class MaxSkewCheck; class CharPtrLess; class SearchPred; class BfsFwdIterator; +class ClkDelays; // Tag compare using tag matching (tagMatch) critera. class TagMatchLess @@ -116,7 +117,6 @@ typedef Vector PathVertexSeq; typedef Vector SlackSeq; typedef Delay Crpr; typedef Vector PathRefSeq; -typedef MinMaxValues ClkDelays[RiseFall::index_count][RiseFall::index_count]; enum class ReportPathFormat { full, full_clock, diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 34fd2375..be5433d8 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -57,8 +57,6 @@ class SearchPred; class Corner; class ClkSkews; class ReportField; -class Power; -class PowerResult; class EquivCells; typedef InstanceSeq::Iterator SlowDrvrIterator; @@ -913,15 +911,17 @@ public: void reportPath(Path *path); // Report clk skews for clks. - void reportClkSkew(ClockSet *clks, + void reportClkSkew(ConstClockSeq clks, const Corner *corner, const SetupHold *setup_hold, int digits); float findWorstClkSkew(const SetupHold *setup_hold); + + void reportClkLatency(ConstClockSeq clks, + const Corner *corner, + int digits); // Find min/max/rise/fall delays for clk. - void findClkDelays(const Clock *clk, - // Return values. - ClkDelays &delays); + ClkDelays findClkDelays(const Clock *clk); // Update arrival times for all pins. // If necessary updateTiming propagates arrivals around latch diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index ceb475bb..dafad465 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -318,6 +318,7 @@ public: TableAxisPtr axis1); virtual ~Table1(); Table1(Table1 &&table); + Table1(const Table1 &table); Table1 &operator= (Table1 &&table); int order() const override { return 1; } const TableAxis *axis1() const override { return axis1_.get(); } diff --git a/include/sta/WritePathSpice.hh b/include/sta/WritePathSpice.hh index ce43c42e..826e12ce 100644 --- a/include/sta/WritePathSpice.hh +++ b/include/sta/WritePathSpice.hh @@ -16,16 +16,11 @@ #pragma once -#include -#include - #include "StringSet.hh" +#include "CircuitSim.hh" namespace sta { -using std::string; -using std::set; - class Path; class StaState; @@ -41,11 +36,9 @@ writePathSpice(Path *path, const char *lib_subckt_filename, // Device model file included in spice file. const char *model_filename, - // Nets off of path to include in the spice run. - StdStringSet *off_path_pin_names, const char *power_name, const char *gnd_name, - bool measure_stmts, + CircuitSim ckt_sim, StaState *sta); } // namespace diff --git a/liberty/FuncExpr.cc b/liberty/FuncExpr.cc index 894ad09f..1de36ac3 100644 --- a/liberty/FuncExpr.cc +++ b/liberty/FuncExpr.cc @@ -345,14 +345,14 @@ funcExprNot(FuncExpr *expr) //////////////////////////////////////////////////////////////// -FuncExprPortIterator::FuncExprPortIterator(FuncExpr *expr) +FuncExprPortIterator::FuncExprPortIterator(const FuncExpr *expr) { findPorts(expr); iter_.init(ports_); } void -FuncExprPortIterator::findPorts(FuncExpr *expr) +FuncExprPortIterator::findPorts(const FuncExpr *expr) { if (expr) { if (expr->op() == FuncExpr::op_port) diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index af4dcdc7..7e52064e 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -84,8 +84,7 @@ LibertyLibrary::LibertyLibrary(const char *name, default_ocv_derate_(nullptr), buffers_(nullptr), inverters_(nullptr), - driver_waveform_default_(nullptr), - have_voltage_waveforms_(false) + driver_waveform_default_(nullptr) { // Scalar templates are builtin. for (int i = 0; i != table_template_type_count; i++) { @@ -895,33 +894,6 @@ LibertyLibrary::addDriverWaveform(DriverWaveform *driver_waveform) } } -void -LibertyLibrary::ensureVoltageWaveforms() -{ - if (!have_voltage_waveforms_) { - float vdd = 0.0f; - 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) : @@ -969,7 +941,8 @@ LibertyCell::LibertyCell(LibertyLibrary *library, is_disabled_constraint_(false), leakage_power_(0.0), leakage_power_exists_(false), - has_internal_ports_(false) + has_internal_ports_(false), + have_voltage_waveforms_(false) { liberty_cell_ = this; } @@ -1101,13 +1074,13 @@ LibertyCell::setIsMemory(bool is_memory) } void -LibertyCell::LibertyCell::setIsPad(bool is_pad) +LibertyCell::setIsPad(bool is_pad) { is_pad_ = is_pad; } void -LibertyCell::LibertyCell::setIsClockCell(bool is_clock_cell) +LibertyCell::setIsClockCell(bool is_clock_cell) { is_clock_cell_ = is_clock_cell; } @@ -1919,6 +1892,29 @@ LibertyCell::latchCheckEnableEdge(TimingArcSet *check_set) return nullptr; } +void +LibertyCell::ensureVoltageWaveforms() +{ + if (!have_voltage_waveforms_) { + float vdd = 0.0; + bool vdd_exists; + liberty_library_->supplyVoltage("VDD", vdd, vdd_exists); + if (!vdd_exists || vdd == 0.0) + criticalError(1120, "library missing vdd"); + for (TimingArcSet *arc_set : timingArcSets()) { + 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; + } +} + //////////////////////////////////////////////////////////////// LibertyCellPortIterator::LibertyCellPortIterator(const LibertyCell *cell) : @@ -2005,6 +2001,10 @@ LibertyPort::LibertyPort(LibertyCell *cell, liberty_port_ = this; min_pulse_width_[RiseFall::riseIndex()] = 0.0; min_pulse_width_[RiseFall::fallIndex()] = 0.0; + for (auto rf_index : RiseFall::rangeIndex()) { + for (auto mm_index : MinMax::rangeIndex()) + clk_tree_delay_[rf_index][mm_index] = nullptr; + } } LibertyPort::~LibertyPort() @@ -2598,31 +2598,47 @@ LibertyPort::setDriverWaveform(DriverWaveform *driver_waveform, } RiseFallMinMax -LibertyPort::clockTreePathDelays() +LibertyPort::clockTreePathDelays() const +{ + return clkTreeDelays(); +} + +RiseFallMinMax +LibertyPort::clkTreeDelays() const { RiseFallMinMax delays; - const TimingArcSetSeq &arc_sets = liberty_cell_->timingArcSets(nullptr, this); - for (TimingArcSet *arc_set : arc_sets) { - TimingRole *role = arc_set->role(); - if (role == TimingRole::clockTreePathMin() - || role == TimingRole::clockTreePathMax()) { - for (TimingArc *arc : arc_set->arcs()) { - TimingModel *model = arc->model(); - GateTimingModel *gate_model = dynamic_cast(model); - ArcDelay delay; - Slew 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() - : MinMax::max(); - delays.setValue(rf, min_max, delayAsFloat(delay)); + for (const RiseFall *rf : RiseFall::range()) { + for (const MinMax *min_max : MinMax::range()) { + const TableModel *model = clk_tree_delay_[rf->index()][min_max->index()]; + if (model) { + float delay = model->findValue(0.0, 0.0, 0.0); + delays.setValue(rf, min_max, delay); } } } return delays; } +float +LibertyPort::clkTreeDelay(float in_slew, + const RiseFall *rf, + const MinMax *min_max) const +{ + const TableModel *model = clk_tree_delay_[rf->index()][min_max->index()]; + if (model) + return model->findValue(in_slew, 0.0, 0.0); + else + return 0.0; +} + +void +LibertyPort::setClkTreeDelay(const TableModel *model, + const RiseFall *rf, + const MinMax *min_max) +{ + clk_tree_delay_[rf->index()][min_max->index()] = model; +} + //////////////////////////////////////////////////////////////// LibertyPortSeq diff --git a/liberty/LibertyBuilder.cc b/liberty/LibertyBuilder.cc index 89a82662..dac8d59b 100644 --- a/liberty/LibertyBuilder.cc +++ b/liberty/LibertyBuilder.cc @@ -20,6 +20,8 @@ #include "TimingRole.hh" #include "FuncExpr.hh" #include "TimingArc.hh" +#include "TimingModel.hh" +#include "TableModel.hh" #include "InternalPower.hh" #include "LeakagePower.hh" #include "Sequential.hh" @@ -269,10 +271,10 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, attrs); case TimingType::min_clock_tree_path: return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMin(), - attrs); + MinMax::min(), attrs); case TimingType::max_clock_tree_path: return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMax(), - attrs); + MinMax::max(), attrs); case TimingType::min_pulse_width: case TimingType::minimum_period: case TimingType::nochange_high_high: @@ -633,13 +635,17 @@ TimingArcSet * LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell, LibertyPort *to_port, TimingRole *role, + const MinMax *min_max, TimingArcAttrsPtr 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) + if (model) { makeTimingArc(arc_set, nullptr, to_rf->asTransition(), model); + const GateTableModel *gate_model = dynamic_cast(model); + to_port->setClkTreeDelay(gate_model->delayModel(), to_rf, min_max); + } } return arc_set; } diff --git a/liberty/LibertyBuilder.hh b/liberty/LibertyBuilder.hh index 3b4896e4..820112c0 100644 --- a/liberty/LibertyBuilder.hh +++ b/liberty/LibertyBuilder.hh @@ -16,6 +16,7 @@ #pragma once +#include "MinMax.hh" #include "Vector.hh" #include "Transition.hh" #include "LibertyClass.hh" @@ -81,6 +82,7 @@ public: TimingArcSet *makeClockTreePathArcs(LibertyCell *cell, LibertyPort *to_port, TimingRole *role, + const MinMax *min_max, TimingArcAttrsPtr attrs); protected: diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index f26d7076..5d394ea4 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -295,7 +295,7 @@ LibertyReader::defineVisitors() &LibertyReader::visitClockGatingIntegratedCell); defineAttrVisitor("area", &LibertyReader::visitArea); defineAttrVisitor("dont_use", &LibertyReader::visitDontUse); - defineAttrVisitor("is_macro", &LibertyReader::visitIsMacro); + defineAttrVisitor("is_macro_cell", &LibertyReader::visitIsMacro); defineAttrVisitor("is_memory", &LibertyReader::visitIsMemory); defineAttrVisitor("is_pad", &LibertyReader::visitIsPad); defineAttrVisitor("is_clock_cell", &LibertyReader::visitIsClockCell); diff --git a/liberty/LibertyWriter.cc b/liberty/LibertyWriter.cc index 5a94f482..2a53babf 100644 --- a/liberty/LibertyWriter.cc +++ b/liberty/LibertyWriter.cc @@ -272,7 +272,7 @@ LibertyWriter::writeCell(const LibertyCell *cell) if (area > 0.0) fprintf(stream_, " area : %.3f \n", area); if (cell->isMacro()) - fprintf(stream_, " is_macro : true;\n"); + fprintf(stream_, " is_macro_cell : true;\n"); if (cell->interfaceTiming()) fprintf(stream_, " interface_timing : true;\n"); diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 5604b7fb..39ce51ee 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -819,6 +819,13 @@ Table1::Table1(Table1 &&table) : table.axis1_ = nullptr; } +Table1::Table1(const Table1 &table) : + Table(), + values_(new FloatSeq(*table.values_)), + axis1_(table.axis1_) +{ +} + Table1::~Table1() { delete values_; diff --git a/parasitics/ConcreteParasitics.cc b/parasitics/ConcreteParasitics.cc index 97a5f7e9..3bcd71b4 100644 --- a/parasitics/ConcreteParasitics.cc +++ b/parasitics/ConcreteParasitics.cc @@ -487,8 +487,11 @@ ConcreteParasiticCapacitor::ConcreteParasiticCapacitor(size_t id, //////////////////////////////////////////////////////////////// ConcreteParasiticNetwork::ConcreteParasiticNetwork(const Net *net, - bool includes_pin_caps) : + bool includes_pin_caps, + const Network *network) : net_(net), + sub_nodes_(network), + pin_nodes_(network), max_node_id_(0), includes_pin_caps_(includes_pin_caps) { @@ -580,6 +583,29 @@ ConcreteParasiticNetwork::capacitance() const return cap; } +ConcreteParasiticNode * +ConcreteParasiticNetwork::findParasiticNode(const Net *net, + int id, + const Network *) const +{ + NetIdPair net_id(net, id); + auto id_node = sub_nodes_.find(net_id); + if (id_node == sub_nodes_.end()) + return nullptr; + else + return id_node->second; +} + +ConcreteParasiticNode * +ConcreteParasiticNetwork::findParasiticNode(const Pin *pin) const +{ + auto pin_node = pin_nodes_.find(pin); + if (pin_node == pin_nodes_.end()) + return nullptr; + else + return pin_node->second; +} + ConcreteParasiticNode * ConcreteParasiticNetwork::ensureParasiticNode(const Net *net, int id, @@ -623,22 +649,12 @@ ConcreteParasiticNetwork::ensureParasiticNode(const Pin *pin, return node; } -ConcreteParasiticNode * -ConcreteParasiticNetwork::findNode(const Pin *pin) const -{ - 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); + ParasiticNode *drvr_node = findParasiticNode(drvr_pin); if (drvr_node) { ParasiticNodeResistorMap resistor_map = parasitics->parasiticNodeResistorMap(this); @@ -713,6 +729,11 @@ ConcreteParasiticNetwork::disconnectPin(const Pin *pin, } } +NetIdPairLess::NetIdPairLess(const Network *network) : + net_less_(network) +{ +} + bool NetIdPairLess::operator()(const NetIdPair &net_id1, const NetIdPair &net_id2) const @@ -721,7 +742,7 @@ NetIdPairLess::operator()(const NetIdPair &net_id1, const Net *net2 = net_id2.first; int id1 = net_id1.second; int id2 = net_id2.second; - return net1 < net2 + return net_less_(net1, net2) || (net1 == net2 && id1 < id2); } @@ -1229,7 +1250,7 @@ ConcreteParasitics::makeParasiticNetwork(const Net *net, for (const Pin *drvr_pin : *network_->drivers(net)) deleteParasitics(drvr_pin, ap); } - parasitic = new ConcreteParasiticNetwork(net, includes_pin_caps); + parasitic = new ConcreteParasiticNetwork(net, includes_pin_caps, network_); parasitics[ap_index] = parasitic; return parasitic; } @@ -1286,6 +1307,17 @@ ConcreteParasitics::includesPinCaps(const Parasitic *parasitic) const return cparasitic->includesPinCaps(); } +ParasiticNode * +ConcreteParasitics::findParasiticNode(Parasitic *parasitic, + const Net *net, + int id, + const Network *network) const +{ + const ConcreteParasiticNetwork *cparasitic = + static_cast(parasitic); + return cparasitic->findParasiticNode(net, id, network); +} + ParasiticNode * ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic, const Net *net, @@ -1297,6 +1329,15 @@ ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic, return cparasitic->ensureParasiticNode(net, id, network); } +ParasiticNode * +ConcreteParasitics::findParasiticNode(const Parasitic *parasitic, + const Pin *pin) const +{ + const ConcreteParasiticNetwork *cparasitic = + static_cast(parasitic); + return cparasitic->findParasiticNode(pin); +} + ParasiticNode * ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic, const Pin *pin, @@ -1373,7 +1414,7 @@ ConcreteParasitics::capacitors(const Parasitic *parasitic) const const char * -ConcreteParasitics::name(const ParasiticNode *node) +ConcreteParasitics::name(const ParasiticNode *node) const { const ConcreteParasiticNode *cnode = static_cast(node); @@ -1413,15 +1454,6 @@ ConcreteParasitics::isExternal(const ParasiticNode *node) const return cnode->isExternal(); } -ParasiticNode * -ConcreteParasitics::findNode(const Parasitic *parasitic, - const Pin *pin) const -{ - const ConcreteParasiticNetwork *cparasitic = - static_cast(parasitic); - return cparasitic->findNode(pin); -} - //////////////////////////////////////////////////////////////// size_t diff --git a/parasitics/ConcreteParasitics.hh b/parasitics/ConcreteParasitics.hh index 842b3046..04014fda 100644 --- a/parasitics/ConcreteParasitics.hh +++ b/parasitics/ConcreteParasitics.hh @@ -113,19 +113,23 @@ public: const ParasiticAnalysisPt *ap) override; void deleteParasiticNetworks(const Net *net) override; bool includesPinCaps(const Parasitic *parasitic) const override; + ParasiticNode *findParasiticNode(Parasitic *parasitic, + const Net *net, + int id, + const Network *network) const override; ParasiticNode *ensureParasiticNode(Parasitic *parasitic, const Net *net, int id, const Network *network) override; + ParasiticNode *findParasiticNode(const Parasitic *parasitic, + const Pin *pin) const 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 char *name(const ParasiticNode *node) const override; const Pin *pin(const ParasiticNode *node) const override; const Net *net(const ParasiticNode *node, const Network *network) const override; diff --git a/parasitics/ConcreteParasiticsPvt.hh b/parasitics/ConcreteParasiticsPvt.hh index c4bcc346..4979d63f 100644 --- a/parasitics/ConcreteParasiticsPvt.hh +++ b/parasitics/ConcreteParasiticsPvt.hh @@ -27,17 +27,23 @@ class ConcretePoleResidue; class ConcreteParasiticDevice; class ConcreteParasiticNode; -typedef std::map ConcreteElmoreLoadMap; -typedef std::map ConcretePoleResidueMap; typedef std::pair NetIdPair; -struct NetIdPairLess +class NetIdPairLess { +public: + NetIdPairLess(const Network *network); bool operator()(const NetIdPair &net_id1, const NetIdPair &net_id2) const; + +private: + const NetIdLess net_less_; }; + +typedef std::map ConcreteElmoreLoadMap; +typedef std::map ConcretePoleResidueMap; typedef std::map ConcreteParasiticSubNodeMap; -typedef std::map ConcreteParasiticPinNodeMap; +typedef std::map ConcreteParasiticPinNodeMap; typedef std::set ParasiticNodeSet; typedef std::set ParasiticResistorSet; typedef std::vector ParasiticResistorSeq; @@ -197,17 +203,21 @@ class ConcreteParasiticNetwork : public ParasiticNetwork, { public: ConcreteParasiticNetwork(const Net *net, - bool includes_pin_caps); + bool includes_pin_caps, + const Network *network); virtual ~ConcreteParasiticNetwork(); virtual bool isParasiticNetwork() const { return true; } const Net *net() { return net_; } bool includesPinCaps() const { return includes_pin_caps_; } + ConcreteParasiticNode *findParasiticNode(const Net *net, + int id, + const Network *network) const; ConcreteParasiticNode *ensureParasiticNode(const Net *net, int id, const Network *network); + ConcreteParasiticNode *findParasiticNode(const Pin *pin) const; ConcreteParasiticNode *ensureParasiticNode(const Pin *pin, const Network *network); - ConcreteParasiticNode *findNode(const Pin *pin) const; virtual float capacitance() const; ParasiticNodeSeq nodes() const; void disconnectPin(const Pin *pin, diff --git a/parasitics/Parasitics.cc b/parasitics/Parasitics.cc index 605ab87e..5d8a10c5 100644 --- a/parasitics/Parasitics.cc +++ b/parasitics/Parasitics.cc @@ -53,6 +53,13 @@ Parasitics::findParasiticNet(const Pin *pin) const return nullptr; } +ParasiticNode * +Parasitics::findNode(const Parasitic *parasitic, + const Pin *pin) const +{ + return findParasiticNode(parasitic, pin); +} + PinSet Parasitics::loads(const Pin *drvr_pin) const { diff --git a/parasitics/ReduceParasitics.cc b/parasitics/ReduceParasitics.cc index f6a692d1..4d8f3f75 100644 --- a/parasitics/ReduceParasitics.cc +++ b/parasitics/ReduceParasitics.cc @@ -306,7 +306,8 @@ reduceToPiElmore(const Parasitic *parasitic_network, StaState *sta) { Parasitics *parasitics = sta->parasitics(); - ParasiticNode *drvr_node = parasitics->findNode(parasitic_network, drvr_pin); + ParasiticNode *drvr_node = + parasitics->findParasiticNode(parasitic_network, drvr_pin); if (drvr_node) { debugPrint(sta->debug(), "parasitic_reduce", 1, "Reduce driver %s %s %s", sta->network()->pathName(drvr_pin), @@ -456,7 +457,8 @@ reduceToPiPoleResidue2(const Parasitic *parasitic_network, StaState *sta) { Parasitics *parasitics = sta->parasitics(); - ParasiticNode *drvr_node = parasitics->findNode(parasitic_network, drvr_pin); + ParasiticNode *drvr_node = + parasitics->findParasiticNode(parasitic_network, drvr_pin); if (drvr_node) { debugPrint(sta->debug(), "parasitic_reduce", 1, "Reduce driver %s", sta->network()->pathName(drvr_pin)); @@ -508,7 +510,8 @@ ReduceToPiPoleResidue2::findPolesResidues(const Parasitic *parasitic_network, while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); if (network_->isLoad(pin)) { - ParasiticNode *load_node = parasitics_->findNode(parasitic_network, pin); + ParasiticNode *load_node = + parasitics_->findParasiticNode(parasitic_network, pin); if (load_node) { findPolesResidues(pi_pole_residue, drvr_pin, pin, load_node); } diff --git a/parasitics/SpefReader.cc b/parasitics/SpefReader.cc index d0efbd27..8767986a 100644 --- a/parasitics/SpefReader.cc +++ b/parasitics/SpefReader.cc @@ -468,38 +468,40 @@ SpefReader::findParasiticNode(char *name, *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_); + if (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 { - // Replace delimiter for error message. + Net *net = findNet(name); + // Replace delimiter for error messages. *delim = delimiter_; - warn(1652, "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 (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_); + 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 - warn(1654, "node %s not a pin or net:number", name); } } } diff --git a/power/Power.cc b/power/Power.cc index f46b3f2a..112af13d 100644 --- a/power/Power.cc +++ b/power/Power.cc @@ -47,13 +47,6 @@ #include "Bfs.hh" #include "ClkNetwork.hh" -#if CUDD -#include "cudd.h" -#else -#define Cudd_Init(ignore1, ignore2, ignore3, ignore4, ignore5) nullptr -#define Cudd_Quit(ignore1) -#endif - // Related liberty not supported: // library // default_cell_leakage_power : 0; @@ -95,15 +88,10 @@ Power::Power(StaState *sta) : input_activity_{0.1, 0.5, PwrActivityOrigin::input}, seq_activity_map_(100, SeqPinHash(network_), SeqPinEqual()), activities_valid_(false), - cudd_mgr_(Cudd_Init(0, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0)) + bdd_(sta) { } -Power::~Power() -{ - Cudd_Quit(cudd_mgr_); -} - void Power::setGlobalActivity(float activity, float duty) @@ -524,12 +512,12 @@ Power::evalActivity(FuncExpr *expr, if (func_port && func_port->direction()->isInternal()) return findSeqActivity(inst, func_port); else { - DdNode *bdd = funcBdd(expr); + DdNode *bdd = bdd_.funcBdd(expr); float duty = evalBddDuty(bdd, inst); float activity = evalBddActivity(bdd, inst); - Cudd_RecursiveDeref(cudd_mgr_, bdd); - clearVarMap(); + Cudd_RecursiveDeref(bdd_.cuddMgr(), bdd); + bdd_.clearVarMap(); return PwrActivity(activity, duty, PwrActivityOrigin::propagated); } } @@ -540,110 +528,19 @@ Power::evalDiffDuty(FuncExpr *expr, LibertyPort *from_port, const Instance *inst) { - DdNode *bdd = funcBdd(expr); - DdNode *var_node = bdd_port_var_map_[from_port]; + DdNode *bdd = bdd_.funcBdd(expr); + DdNode *var_node = bdd_.findNode(from_port); unsigned var_index = Cudd_NodeReadIndex(var_node); - DdNode *diff = Cudd_bddBooleanDiff(cudd_mgr_, bdd, var_index); + DdNode *diff = Cudd_bddBooleanDiff(bdd_.cuddMgr(), bdd, var_index); Cudd_Ref(diff); float duty = evalBddDuty(diff, inst); - Cudd_RecursiveDeref(cudd_mgr_, diff); - Cudd_RecursiveDeref(cudd_mgr_, bdd); - clearVarMap(); + Cudd_RecursiveDeref(bdd_.cuddMgr(), diff); + Cudd_RecursiveDeref(bdd_.cuddMgr(), bdd); + bdd_.clearVarMap(); return duty; } -DdNode * -Power::funcBdd(const FuncExpr *expr) -{ - DdNode *left = nullptr; - DdNode *right = nullptr; - DdNode *result = nullptr; - switch (expr->op()) { - case FuncExpr::op_port: { - LibertyPort *port = expr->port(); - result = ensureNode(port); - break; - } - case FuncExpr::op_not: - left = funcBdd(expr->left()); - if (left) - result = Cudd_Not(left); - break; - case FuncExpr::op_or: - left = funcBdd(expr->left()); - right = funcBdd(expr->right()); - if (left && right) - result = Cudd_bddOr(cudd_mgr_, left, right); - else if (left) - result = left; - else if (right) - result = right; - break; - case FuncExpr::op_and: - left = funcBdd(expr->left()); - right = funcBdd(expr->right()); - if (left && right) - result = Cudd_bddAnd(cudd_mgr_, left, right); - else if (left) - result = left; - else if (right) - result = right; - break; - case FuncExpr::op_xor: - left = funcBdd(expr->left()); - right = funcBdd(expr->right()); - if (left && right) - result = Cudd_bddXor(cudd_mgr_, left, right); - else if (left) - result = left; - else if (right) - result = right; - break; - case FuncExpr::op_one: - result = Cudd_ReadOne(cudd_mgr_); - break; - case FuncExpr::op_zero: - result = Cudd_ReadLogicZero(cudd_mgr_); - break; - default: - report_->critical(1440, "unknown function operator"); - } - if (result) - Cudd_Ref(result); - if (left) - Cudd_RecursiveDeref(cudd_mgr_, left); - if (right) - Cudd_RecursiveDeref(cudd_mgr_, right); - return result; -} - -DdNode * -Power::ensureNode(LibertyPort *port) -{ - DdNode *bdd = bdd_port_var_map_.findKey(port); - if (bdd == nullptr) { - bdd = Cudd_bddNewVar(cudd_mgr_); - bdd_port_var_map_[port] = bdd; - unsigned var_index = Cudd_NodeReadIndex(bdd); - bdd_var_idx_port_map_[var_index] = port; - Cudd_Ref(bdd); - debugPrint(debug_, "power_activity", 2, "%s var %d", port->name(), var_index); - } - return bdd; -} - -void -Power::clearVarMap() -{ - for (auto port_node : bdd_port_var_map_) { - DdNode *var_node = port_node.second; - Cudd_RecursiveDeref(cudd_mgr_, var_node); - } - bdd_port_var_map_.clear(); - bdd_var_idx_port_map_.clear(); -} - // As suggested by // https://stackoverflow.com/questions/63326728/cudd-printminterm-accessing-the-individual-minterms-in-the-sum-of-products float @@ -651,9 +548,9 @@ Power::evalBddDuty(DdNode *bdd, const Instance *inst) { if (Cudd_IsConstant(bdd)) { - if (bdd == Cudd_ReadOne(cudd_mgr_)) + if (bdd == Cudd_ReadOne(bdd_.cuddMgr())) return 1.0; - else if (bdd == Cudd_ReadLogicZero(cudd_mgr_)) + else if (bdd == Cudd_ReadLogicZero(bdd_.cuddMgr())) return 0.0; else criticalError(1100, "unknown cudd constant"); @@ -662,10 +559,10 @@ Power::evalBddDuty(DdNode *bdd, float duty0 = evalBddDuty(Cudd_E(bdd), inst); float duty1 = evalBddDuty(Cudd_T(bdd), inst); unsigned int index = Cudd_NodeReadIndex(bdd); - int var_index = Cudd_ReadPerm(cudd_mgr_, index); - LibertyPort *port = bdd_var_idx_port_map_[var_index]; + int var_index = Cudd_ReadPerm(bdd_.cuddMgr(), index); + const LibertyPort *port = bdd_.varIndexPort(var_index); if (port->direction()->isInternal()) - return findSeqActivity(inst, port).duty(); + return findSeqActivity(inst, const_cast(port)).duty(); else { const Pin *pin = findLinkPin(inst, port); if (pin) { @@ -689,17 +586,17 @@ Power::evalBddActivity(DdNode *bdd, const Instance *inst) { float activity = 0.0; - for (auto port_var : bdd_port_var_map_) { - LibertyPort *port = port_var.first; + for (auto port_var : bdd_.portVarMap()) { + const LibertyPort *port = port_var.first; const Pin *pin = findLinkPin(inst, port); if (pin) { PwrActivity var_activity = findActivity(pin); DdNode *var_node = port_var.second; unsigned int var_index = Cudd_NodeReadIndex(var_node); - DdNode *diff = Cudd_bddBooleanDiff(cudd_mgr_, bdd, var_index); + DdNode *diff = Cudd_bddBooleanDiff(bdd_.cuddMgr(), bdd, var_index); Cudd_Ref(diff); float diff_duty = evalBddDuty(diff, inst); - Cudd_RecursiveDeref(cudd_mgr_, diff); + Cudd_RecursiveDeref(bdd_.cuddMgr(), diff); float var_act = var_activity.activity() * diff_duty; activity += var_act; const Clock *clk = findClk(pin); diff --git a/power/Power.hh b/power/Power.hh index 81c13de1..d638b25d 100644 --- a/power/Power.hh +++ b/power/Power.hh @@ -24,6 +24,7 @@ #include "SdcClass.hh" #include "PowerClass.hh" #include "StaState.hh" +#include "Bdd.hh" struct DdNode; struct DdManager; @@ -38,8 +39,6 @@ class BfsFwdIterator; class Vertex; typedef std::pair SeqPin; -typedef Map BddPortVarMap; -typedef Map BddVarIdxPortMap; class SeqPinHash { @@ -68,7 +67,6 @@ class Power : public StaState { public: Power(StaState *sta); - ~Power(); void power(const Corner *corner, // Return values. PowerResult &total, @@ -196,10 +194,6 @@ protected: const Pin *&enable, const Pin *&clk, const Pin *&gclk) const; - - DdNode *funcBdd(const FuncExpr *expr); - DdNode *ensureNode(LibertyPort *port); - void clearVarMap(); float evalBddActivity(DdNode *bdd, const Instance *inst); float evalBddDuty(DdNode *bdd, @@ -217,10 +211,7 @@ private: PwrActivityMap activity_map_; PwrSeqActivityMap seq_activity_map_; bool activities_valid_; - - DdManager *cudd_mgr_; - BddPortVarMap bdd_port_var_map_; - BddVarIdxPortMap bdd_var_idx_port_map_; + Bdd bdd_; static constexpr int max_activity_passes_ = 100; diff --git a/search/Bdd.cc b/search/Bdd.cc new file mode 100644 index 00000000..88eda5a6 --- /dev/null +++ b/search/Bdd.cc @@ -0,0 +1,179 @@ +// 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 "Bdd.hh" + +#include "StaConfig.hh" +#include "Report.hh" +#include "FuncExpr.hh" + +#if CUDD +#include "cudd.h" +#else +#include +#define CUDD_UNIQUE_SLOTS 0 +#define CUDD_CACHE_SLOTS 0 +DdManager *Cudd_Init(int, int, int, int, int) { return nullptr; } +void Cudd_Quit(void *) {} +DdNode *Cudd_Not(void *) { return nullptr; } +DdNode *Cudd_bddOr(void *, void *, void *) { return nullptr; } +DdNode *Cudd_bddAnd(void *, void *, void *) { return nullptr; } +DdNode *Cudd_bddXor(void *, void *, void *) { return nullptr; } +DdNode *Cudd_ReadOne(void *) { return nullptr; } +DdNode *Cudd_ReadLogicZero(void *) { return nullptr; } +DdNode *Cudd_bddNewVar(void *) { return nullptr; } +int Cudd_NodeReadIndex(void *) { return 0;} +void Cudd_Ref(void *) {} +void Cudd_RecursiveDeref(void *, void *) {} +#endif + +namespace sta { + +Bdd::Bdd(const StaState *sta) : + StaState(sta), + cudd_mgr_(Cudd_Init(0, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0)) +{ +} + +Bdd::~Bdd() +{ + Cudd_Quit(cudd_mgr_); +} + +DdNode * +Bdd::funcBdd(const FuncExpr *expr) +{ + DdNode *left = nullptr; + DdNode *right = nullptr; + DdNode *result = nullptr; + switch (expr->op()) { + case FuncExpr::op_port: { + LibertyPort *port = expr->port(); + result = ensureNode(port); + break; + } + case FuncExpr::op_not: + left = funcBdd(expr->left()); + if (left) + result = Cudd_Not(left); + break; + case FuncExpr::op_or: + left = funcBdd(expr->left()); + right = funcBdd(expr->right()); + if (left && right) + result = Cudd_bddOr(cudd_mgr_, left, right); + else if (left) + result = left; + else if (right) + result = right; + break; + case FuncExpr::op_and: + left = funcBdd(expr->left()); + right = funcBdd(expr->right()); + if (left && right) + result = Cudd_bddAnd(cudd_mgr_, left, right); + else if (left) + result = left; + else if (right) + result = right; + break; + case FuncExpr::op_xor: + left = funcBdd(expr->left()); + right = funcBdd(expr->right()); + if (left && right) + result = Cudd_bddXor(cudd_mgr_, left, right); + else if (left) + result = left; + else if (right) + result = right; + break; + case FuncExpr::op_one: + result = Cudd_ReadOne(cudd_mgr_); + break; + case FuncExpr::op_zero: + result = Cudd_ReadLogicZero(cudd_mgr_); + break; + default: + report_->critical(1440, "unknown function operator"); + } + if (result) + Cudd_Ref(result); + if (left) + Cudd_RecursiveDeref(cudd_mgr_, left); + if (right) + Cudd_RecursiveDeref(cudd_mgr_, right); + return result; +} + +DdNode * +Bdd::findNode(const LibertyPort *port) +{ + auto port_var = bdd_port_var_map_.find(port); + if (port_var == bdd_port_var_map_.end()) + return nullptr; + else + return port_var->second; +} + +DdNode * +Bdd::ensureNode(const LibertyPort *port) +{ + auto port_var = bdd_port_var_map_.find(port); + DdNode *node = nullptr; + if (port_var == bdd_port_var_map_.end()) { + node = Cudd_bddNewVar(cudd_mgr_); + bdd_port_var_map_[port] = node; + unsigned var_index = Cudd_NodeReadIndex(node); + bdd_var_idx_port_map_[var_index] = port; + Cudd_Ref(node); + } + else + node = port_var->second; + return node; +} + +const LibertyPort * +Bdd::nodePort(DdNode *node) +{ + auto port_index = bdd_var_idx_port_map_.find(Cudd_NodeReadIndex(node)); + if (port_index == bdd_var_idx_port_map_.end()) + return nullptr; + else + return port_index->second; +} + +const LibertyPort * +Bdd::varIndexPort(int var_index) +{ + auto index_port = bdd_var_idx_port_map_.find(var_index); + if (index_port == bdd_var_idx_port_map_.end()) + return nullptr; + else + return index_port->second; +} + +void +Bdd::clearVarMap() +{ + for (auto port_node : bdd_port_var_map_) { + DdNode *var_node = port_node.second; + Cudd_RecursiveDeref(cudd_mgr_, var_node); + } + bdd_port_var_map_.clear(); + bdd_var_idx_port_map_.clear(); +} + +} // namespace diff --git a/search/ClkDelays.hh b/search/ClkDelays.hh new file mode 100644 index 00000000..3aadfa88 --- /dev/null +++ b/search/ClkDelays.hh @@ -0,0 +1,70 @@ +// 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 "StaState.hh" +#include "Transition.hh" +#include "PathVertex.hh" + +namespace sta { + +class ClkDelays +{ +public: + ClkDelays(); + void delay(const RiseFall *src_rf, + const RiseFall *end_rf, + const MinMax *min_max, + // Return values. + float &insertion, + float &delay, + float &lib_clk_delay, + float &latency, + PathVertex &path, + bool &exists); + void latency(const RiseFall *src_rf, + const RiseFall *end_rf, + const MinMax *min_max, + // Return values. + float &delay, + bool &exists); + static float latency(PathVertex *clk_path, + StaState *sta); + void setLatency(const RiseFall *src_rf, + const RiseFall *end_rf, + const MinMax *min_max, + PathVertex *path, + StaState *sta); + +private: + static float insertionDelay(PathVertex *clk_path, + StaState *sta); + static float delay(PathVertex *clk_path, + StaState *sta); + static float clkTreeDelay(PathVertex *clk_path, + StaState *sta); + + float insertion_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count]; + float delay_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count]; + float lib_clk_delay_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count]; + float latency_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count]; + PathVertex path_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count]; + bool exists_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count]; +}; + +} // namespace diff --git a/search/ClkLatency.cc b/search/ClkLatency.cc new file mode 100644 index 00000000..9e2e91a4 --- /dev/null +++ b/search/ClkLatency.cc @@ -0,0 +1,299 @@ +// 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 "ClkLatency.hh" + +#include + +#include "Report.hh" +#include "Debug.hh" +#include "Units.hh" +#include "Liberty.hh" +#include "Network.hh" +#include "Clock.hh" +#include "Graph.hh" +#include "PathVertex.hh" +#include "StaState.hh" +#include "Search.hh" +#include "PathAnalysisPt.hh" +#include "ClkInfo.hh" + +namespace sta { + +ClkLatency::ClkLatency(StaState *sta) : + StaState(sta) +{ +} + +ClkDelays +ClkLatency::findClkDelays(const Clock *clk, + const Corner *corner) +{ + ConstClockSeq clks; + clks.push_back(clk); + ClkDelayMap clk_delay_map = findClkDelays(clks, corner); + return clk_delay_map[clk]; +} + +void +ClkLatency::reportClkLatency(ConstClockSeq clks, + const Corner *corner, + int digits) +{ + ClkDelayMap clk_delay_map = findClkDelays(clks, corner); + + // Sort the clocks to report in a stable order. + ConstClockSeq sorted_clks; + for (const Clock *clk : clks) + sorted_clks.push_back(clk); + std::sort(sorted_clks.begin(), sorted_clks.end(), ClkNameLess()); + + for (const Clock *clk : sorted_clks) { + ClkDelays clk_delays = clk_delay_map[clk]; + reportClkLatency(clk, clk_delays, digits); + report_->reportBlankLine(); + } +} + +void +ClkLatency::reportClkLatency(const Clock *clk, + ClkDelays &clk_delays, + int digits) +{ + Unit *time_unit = units_->timeUnit(); + report_->reportLine("Clock %s", clk->name()); + for (const RiseFall *src_rf : RiseFall::range()) { + for (const RiseFall *end_rf : RiseFall::range()) { + PathVertex path_min; + float insertion_min; + float delay_min; + float lib_clk_delay_min; + float latency_min; + bool exists_min; + clk_delays.delay(src_rf, end_rf, MinMax::min(), insertion_min, + delay_min, lib_clk_delay_min, latency_min, + path_min, exists_min); + PathVertex path_max; + float insertion_max; + float delay_max; + float lib_clk_delay_max; + float latency_max; + bool exists_max; + clk_delays.delay(src_rf, end_rf, MinMax::max(), insertion_max, + delay_max, lib_clk_delay_max, latency_max, + path_max, exists_max); + if (exists_min & exists_max) { + report_->reportLine("%s -> %s", + src_rf->name(), + end_rf->name()); + report_->reportLine(" min max"); + + report_->reportLine("%7s %7s source latency", + time_unit->asString(insertion_min, digits), + time_unit->asString(insertion_max, digits)); + report_->reportLine("%7s %7s network latency %s", + time_unit->asString(delay_min, digits), + "", + sdc_network_->pathName(path_min.pin(this))); + report_->reportLine("%7s %7s network latency %s", + "", + time_unit->asString(delay_max, digits), + sdc_network_->pathName(path_max.pin(this))); + if (lib_clk_delay_min != 0.0 + || lib_clk_delay_max != 0.0) + report_->reportLine("%7s %7s liberty clock tree delay", + time_unit->asString(lib_clk_delay_min, digits), + time_unit->asString(lib_clk_delay_max, digits)); + report_->reportLine("---------------"); + report_->reportLine("%7s %7s latency", + time_unit->asString(latency_min, digits), + time_unit->asString(latency_max, digits)); + float skew = latency_max - latency_min; + report_->reportLine(" %7s skew", + time_unit->asString(skew, digits)); + report_->reportBlankLine(); + } + } + } +} + +ClkDelayMap +ClkLatency::findClkDelays(ConstClockSeq clks, + const Corner *corner) +{ + ClkDelayMap clk_delay_map; + // Make entries for the relevant clocks to filter path clocks. + for (const Clock *clk : clks) + clk_delay_map[clk]; + for (Vertex *clk_vertex : *graph_->regClkVertices()) { + VertexPathIterator path_iter(clk_vertex, this); + while (path_iter.hasNext()) { + PathVertex *path = path_iter.next(); + const ClockEdge *path_clk_edge = path->clkEdge(this); + const PathAnalysisPt *path_ap = path->pathAnalysisPt(this); + if (path_clk_edge + && (corner == nullptr + || path_ap->corner() == corner)) { + const Clock *path_clk = path_clk_edge->clock(); + auto delays_itr = clk_delay_map.find(path_clk); + if (delays_itr != clk_delay_map.end()) { + ClkDelays &clk_delays = delays_itr->second; + const RiseFall *clk_rf = path_clk_edge->transition(); + const MinMax *min_max = path->minMax(this); + const RiseFall *end_rf = path->transition(this); + float latency = ClkDelays::latency(path, this); + float clk_latency; + bool exists; + clk_delays.latency(clk_rf, end_rf, min_max, clk_latency, exists); + if (!exists || min_max->compare(latency, clk_latency)) + clk_delays.setLatency(clk_rf, end_rf, min_max, path, this); + } + } + } + } + return clk_delay_map; +} + +//////////////////////////////////////////////////////////////// + +ClkDelays::ClkDelays() +{ + for (auto src_rf_index : RiseFall::rangeIndex()) { + for (auto end_rf_index : RiseFall::rangeIndex()) { + for (auto mm_index : MinMax::rangeIndex()) { + insertion_[src_rf_index][end_rf_index][mm_index] = 0.0; + delay_[src_rf_index][end_rf_index][mm_index] = 0.0; + lib_clk_delay_[src_rf_index][end_rf_index][mm_index] = 0.0; + latency_[src_rf_index][end_rf_index][mm_index] = 0.0; + exists_[src_rf_index][end_rf_index][mm_index] = false; + } + } + } +} + +void +ClkDelays::delay(const RiseFall *src_rf, + const RiseFall *end_rf, + const MinMax *min_max, + // Return values. + float &insertion, + float &delay, + float &lib_clk_delay, + float &latency, + PathVertex &path, + bool &exists) +{ + int src_rf_index = src_rf->index(); + int end_rf_index = end_rf->index(); + int mm_index = min_max->index(); + path = path_[src_rf_index][end_rf_index][mm_index]; + insertion = insertion_[src_rf_index][end_rf_index][mm_index]; + delay = delay_[src_rf_index][end_rf_index][mm_index]; + lib_clk_delay = lib_clk_delay_[src_rf_index][end_rf_index][mm_index]; + latency = latency_[src_rf_index][end_rf_index][mm_index]; + exists = exists_[src_rf_index][end_rf_index][mm_index]; +} + +void +ClkDelays::latency(const RiseFall *src_rf, + const RiseFall *end_rf, + const MinMax *min_max, + // Return values. + float &latency, + bool &exists) +{ + int src_rf_index = src_rf->index(); + int end_rf_index = end_rf->index(); + int mm_index = min_max->index(); + latency = latency_[src_rf_index][end_rf_index][mm_index]; + exists = exists_[src_rf_index][end_rf_index][mm_index]; +} + +void +ClkDelays::setLatency(const RiseFall *src_rf, + const RiseFall *end_rf, + const MinMax *min_max, + PathVertex *path, + StaState *sta) +{ + int src_rf_index = src_rf->index(); + int end_rf_index = end_rf->index(); + int mm_index = min_max->index(); + + float insertion = insertionDelay(path, sta); + insertion_[src_rf_index][end_rf_index][mm_index] = insertion; + + float delay1 = delay(path, sta); + delay_[src_rf_index][end_rf_index][mm_index] = delay1; + + float lib_clk_delay = clkTreeDelay(path, sta); + lib_clk_delay_[src_rf_index][end_rf_index][mm_index] = lib_clk_delay; + + float latency = insertion + delay1 + lib_clk_delay; + latency_[src_rf_index][end_rf_index][mm_index] = latency; + + path_[src_rf_index][end_rf_index][mm_index] = *path; + exists_[src_rf_index][end_rf_index][mm_index] = true; +} + +float +ClkDelays::latency(PathVertex *clk_path, + StaState *sta) +{ + + float insertion = insertionDelay(clk_path, sta); + float delay1 = delay(clk_path, sta); + float lib_clk_delay = clkTreeDelay(clk_path, sta); + return insertion + delay1 + lib_clk_delay; +} + +float +ClkDelays::delay(PathVertex *clk_path, + StaState *sta) +{ + Arrival arrival = clk_path->arrival(sta); + const ClockEdge *path_clk_edge = clk_path->clkEdge(sta); + return delayAsFloat(arrival) - path_clk_edge->time(); +} + +float +ClkDelays::insertionDelay(PathVertex *clk_path, + StaState *sta) +{ + const ClockEdge *clk_edge = clk_path->clkEdge(sta); + const Clock *clk = clk_edge->clock(); + const RiseFall *clk_rf = clk_edge->transition(); + ClkInfo *clk_info = clk_path->clkInfo(sta); + const Pin *src_pin = clk_info->clkSrc(); + const PathAnalysisPt *path_ap = clk_path->pathAnalysisPt(sta); + const MinMax *min_max = clk_path->minMax(sta); + return sta->search()->clockInsertion(clk, src_pin, clk_rf, min_max, min_max, path_ap); +} + +float +ClkDelays::clkTreeDelay(PathVertex *clk_path, + StaState *sta) +{ + const Vertex *vertex = clk_path->vertex(sta); + const Pin *pin = vertex->pin(); + const LibertyPort *port = sta->network()->libertyPort(pin); + const MinMax *min_max = clk_path->minMax(sta); + const RiseFall *rf = clk_path->transition(sta); + Slew slew = clk_path->slew(sta); + return port->clkTreeDelay(slew, rf, min_max); +} + +} // namespace diff --git a/search/ClkLatency.hh b/search/ClkLatency.hh new file mode 100644 index 00000000..4bbe5fab --- /dev/null +++ b/search/ClkLatency.hh @@ -0,0 +1,52 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2024, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include + +#include "SdcClass.hh" +#include "StaState.hh" +#include "Transition.hh" +#include "SearchClass.hh" +#include "PathVertex.hh" +#include "ClkDelays.hh" + +namespace sta { + +typedef std::map ClkDelayMap; + +// Find and report clock skews between source/target registers. +class ClkLatency : public StaState +{ +public: + ClkLatency(StaState *sta); + // Report clk latency for clks. + void reportClkLatency(ConstClockSeq clks, + const Corner *corner, + int digits); + ClkDelays findClkDelays(const Clock *clk, + const Corner *corner); + +protected: + ClkDelayMap findClkDelays(ConstClockSeq clks, + const Corner *corner); + void reportClkLatency(const Clock *clk, + ClkDelays &clk_delays, + int digits); +}; + +} // namespace diff --git a/search/ClkSkew.cc b/search/ClkSkew.cc index 971e1ea1..b3fd5160 100644 --- a/search/ClkSkew.cc +++ b/search/ClkSkew.cc @@ -17,12 +17,13 @@ #include "ClkSkew.hh" #include // abs +#include #include "Report.hh" #include "Debug.hh" -#include "Fuzzy.hh" #include "Units.hh" #include "TimingArc.hh" +#include "Liberty.hh" #include "Network.hh" #include "Graph.hh" #include "Sdc.hh" @@ -52,10 +53,15 @@ public: PathVertex *tgtPath() { return &tgt_path_; } float srcLatency(StaState *sta); float tgtLatency(StaState *sta); + float srcClkTreeDelay(StaState *sta); + float tgtClkTreeDelay(StaState *sta); Crpr crpr(StaState *sta); float skew() const { return skew_; } private: + float clkTreeDelay(PathVertex &clk_path, + StaState *sta); + PathVertex src_path_; PathVertex tgt_path_; float skew_; @@ -94,14 +100,41 @@ float ClkSkew::srcLatency(StaState *sta) { Arrival src_arrival = src_path_.arrival(sta); - return delayAsFloat(src_arrival) - src_path_.clkEdge(sta)->time(); + return delayAsFloat(src_arrival) - src_path_.clkEdge(sta)->time() + + clkTreeDelay(src_path_, sta); +} + +float +ClkSkew::srcClkTreeDelay(StaState *sta) +{ + return clkTreeDelay(src_path_, sta); } float ClkSkew::tgtLatency(StaState *sta) { Arrival tgt_arrival = tgt_path_.arrival(sta); - return delayAsFloat(tgt_arrival) - tgt_path_.clkEdge(sta)->time(); + return delayAsFloat(tgt_arrival) - tgt_path_.clkEdge(sta)->time() + + clkTreeDelay(tgt_path_, sta); +} + +float +ClkSkew::tgtClkTreeDelay(StaState *sta) +{ + return clkTreeDelay(tgt_path_, sta); +} + +float +ClkSkew::clkTreeDelay(PathVertex &clk_path, + StaState *sta) +{ + const Vertex *vertex = clk_path.vertex(sta); + const Pin *pin = vertex->pin(); + const LibertyPort *port = sta->network()->libertyPort(pin); + const MinMax *min_max = clk_path.minMax(sta); + const RiseFall *rf = clk_path.transition(sta); + Slew slew = clk_path.slew(sta); + return port->clkTreeDelay(slew, rf, min_max); } Crpr @@ -119,106 +152,129 @@ ClkSkews::ClkSkews(StaState *sta) : } void -ClkSkews::reportClkSkew(ClockSet *clks, +ClkSkews::reportClkSkew(ConstClockSeq clks, const Corner *corner, const SetupHold *setup_hold, int digits) { - ClkSkewMap skews; - findClkSkew(clks, corner, setup_hold, skews); + ClkSkewMap skews = findClkSkew(clks, corner, setup_hold); // Sort the clocks to report in a stable order. - ClockSeq sorted_clks; - for (Clock *clk : *clks) + ConstClockSeq sorted_clks; + for (const Clock *clk : clks) sorted_clks.push_back(clk); - sort(sorted_clks, ClkNameLess()); + std::sort(sorted_clks.begin(), sorted_clks.end(), ClkNameLess()); - Unit *time_unit = units_->timeUnit(); - ClockSeq::Iterator clk_iter2(sorted_clks); - while (clk_iter2.hasNext()) { - Clock *clk = clk_iter2.next(); + for (const Clock *clk : sorted_clks) { report_->reportLine("Clock %s", clk->name()); - ClkSkew *clk_skew = skews.findKey(clk); - if (clk_skew) { - report_->reportLine("Latency CRPR Skew"); - PathVertex *src_path = clk_skew->srcPath(); - PathVertex *tgt_path = clk_skew->tgtPath(); - report_->reportLine("%s %s", - sdc_network_->pathName(src_path->pin(this)), - src_path->transition(this)->asString()); - report_->reportLine("%7s", - time_unit->asString(clk_skew->srcLatency(this), digits)); - report_->reportLine("%s %s", - sdc_network_->pathName(tgt_path->pin(this)), - tgt_path->transition(this)->asString()); - report_->reportLine("%7s %7s %7s", - time_unit->asString(clk_skew->tgtLatency(this), digits), - time_unit->asString(delayAsFloat(-clk_skew->crpr(this)), - digits), - time_unit->asString(clk_skew->skew(), digits)); - } + auto skew_itr = skews.find(clk); + if (skew_itr != skews.end()) + reportClkSkew(skew_itr->second, digits); else report_->reportLine("No launch/capture paths found."); report_->reportBlankLine(); } +} - skews.deleteContents(); +void +ClkSkews::reportClkSkew(ClkSkew &clk_skew, + int digits) +{ + Unit *time_unit = units_->timeUnit(); + PathVertex *src_path = clk_skew.srcPath(); + PathVertex *tgt_path = clk_skew.tgtPath(); + float src_latency = clk_skew.srcLatency(this); + float tgt_latency = clk_skew.tgtLatency(this); + float src_clk_tree_delay = clk_skew.srcClkTreeDelay(this); + float tgt_clk_tree_delay = clk_skew.tgtClkTreeDelay(this); + + if (src_clk_tree_delay != 0.0) + src_latency -= src_clk_tree_delay; + report_->reportLine("%7s source latency %s %s", + time_unit->asString(src_latency, digits), + sdc_network_->pathName(src_path->pin(this)), + src_path->transition(this)->asString()); + if (src_clk_tree_delay != 0.0) + report_->reportLine("%7s source clock tree delay", + time_unit->asString(src_clk_tree_delay, digits)); + + if (tgt_clk_tree_delay != 0.0) + tgt_latency -= tgt_clk_tree_delay; + report_->reportLine("%7s target latency %s %s", + time_unit->asString(-tgt_latency, digits), + sdc_network_->pathName(tgt_path->pin(this)), + tgt_path->transition(this)->asString()); + if (tgt_clk_tree_delay != 0.0) + report_->reportLine("%7s target clock tree delay", + time_unit->asString(-tgt_clk_tree_delay, digits)); + + report_->reportLine("%7s CRPR", + time_unit->asString(delayAsFloat(-clk_skew.crpr(this)), + digits)); + report_->reportLine("--------------"); + report_->reportLine("%7s %s skew", + time_unit->asString(clk_skew.skew(), digits), + src_path->minMax(this) == MinMax::max() ? "setup" : "hold"); } float ClkSkews::findWorstClkSkew(const Corner *corner, const SetupHold *setup_hold) { - ClockSet clks; - for (Clock *clk : *sdc_->clocks()) - clks.insert(clk); - ClkSkewMap skews; - findClkSkew(&clks, corner, setup_hold, skews); + ConstClockSeq clks; + for (const Clock *clk : *sdc_->clocks()) + clks.push_back(clk); + ClkSkewMap skews = findClkSkew(clks, corner, setup_hold); float worst_skew = 0.0; for (auto clk_skew_itr : skews) { - ClkSkew *clk_skew = clk_skew_itr.second; - float skew = clk_skew->skew(); + ClkSkew &clk_skew = clk_skew_itr.second; + float skew = clk_skew.skew(); if (abs(skew) > abs(worst_skew)) worst_skew = skew; } - skews.deleteContents(); return worst_skew; } -void -ClkSkews::findClkSkew(ClockSet *clks, +ClkSkewMap +ClkSkews::findClkSkew(ConstClockSeq &clks, const Corner *corner, - const SetupHold *setup_hold, - ClkSkewMap &skews) + const SetupHold *setup_hold) { + ClkSkewMap skews; + + ConstClockSet clk_set; + for (const Clock *clk : clks) + clk_set.insert(clk); + for (Vertex *src_vertex : *graph_->regClkVertices()) { - if (hasClkPaths(src_vertex, clks)) { + if (hasClkPaths(src_vertex, clk_set)) { VertexOutEdgeIterator edge_iter(src_vertex, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); if (edge->role()->genericRole() == TimingRole::regClkToQ()) { Vertex *q_vertex = edge->to(graph_); - RiseFall *rf = edge->timingArcSet()->isRisingFallingEdge(); - RiseFallBoth *src_rf = rf + const RiseFall *rf = edge->timingArcSet()->isRisingFallingEdge(); + const RiseFallBoth *src_rf = rf ? rf->asRiseFallBoth() : RiseFallBoth::riseFall(); - findClkSkewFrom(src_vertex, q_vertex, src_rf, clks, + findClkSkewFrom(src_vertex, q_vertex, src_rf, clk_set, corner, setup_hold, skews); } } } } + return skews; } bool ClkSkews::hasClkPaths(Vertex *vertex, - ClockSet *clks) + ConstClockSet &clks) { VertexPathIterator path_iter(vertex, this); while (path_iter.hasNext()) { PathVertex *path = path_iter.next(); const Clock *path_clk = path->clock(this); - if (clks->hasKey(const_cast(path_clk))) + if (clks.find(path_clk) != clks.end()) return true; } return false; @@ -227,16 +283,14 @@ ClkSkews::hasClkPaths(Vertex *vertex, void ClkSkews::findClkSkewFrom(Vertex *src_vertex, Vertex *q_vertex, - RiseFallBoth *src_rf, - ClockSet *clks, + const RiseFallBoth *src_rf, + ConstClockSet &clk_set, const Corner *corner, const SetupHold *setup_hold, ClkSkewMap &skews) { VertexSet endpoints = findFanout(q_vertex); - VertexSet::Iterator end_iter(endpoints); - while (end_iter.hasNext()) { - Vertex *end = end_iter.next(); + for (Vertex *end : endpoints) { VertexInEdgeIterator edge_iter(end, graph_); while (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); @@ -247,12 +301,12 @@ ClkSkews::findClkSkewFrom(Vertex *src_vertex, || ((setup_hold == SetupHold::min() && role->genericRole() == TimingRole::hold())))) { Vertex *tgt_vertex = edge->from(graph_); - RiseFall *tgt_rf1 = edge->timingArcSet()->isRisingFallingEdge(); - RiseFallBoth *tgt_rf = tgt_rf1 + const RiseFall *tgt_rf1 = edge->timingArcSet()->isRisingFallingEdge(); + const RiseFallBoth *tgt_rf = tgt_rf1 ? tgt_rf1->asRiseFallBoth() : RiseFallBoth::riseFall(); findClkSkew(src_vertex, src_rf, tgt_vertex, tgt_rf, - clks, corner, setup_hold, skews); + clk_set, corner, setup_hold, skews); } } } @@ -260,13 +314,13 @@ ClkSkews::findClkSkewFrom(Vertex *src_vertex, void ClkSkews::findClkSkew(Vertex *src_vertex, - RiseFallBoth *src_rf, + const RiseFallBoth *src_rf, Vertex *tgt_vertex, - RiseFallBoth *tgt_rf, - ClockSet *clks, + const RiseFallBoth *tgt_rf, + ConstClockSet &clk_set, const Corner *corner, const SetupHold *setup_hold, - ClkSkewMap &skews) + ClkSkewMap &skews) { Unit *time_unit = units_->timeUnit(); const SetupHold *tgt_min_max = setup_hold->opposite(); @@ -276,7 +330,7 @@ ClkSkews::findClkSkew(Vertex *src_vertex, const Clock *src_clk = src_path->clock(this); if (src_rf->matches(src_path->transition(this)) && src_path->minMax(this) == setup_hold - && clks->hasKey(const_cast(src_clk))) { + && clk_set.find(src_clk) != clk_set.end()) { Corner *src_corner = src_path->pathAnalysisPt(this)->corner(); if (corner == nullptr || src_corner == corner) { @@ -290,7 +344,7 @@ ClkSkews::findClkSkew(Vertex *src_vertex, && tgt_path->minMax(this) == tgt_min_max && tgt_path->pathAnalysisPt(this)->corner() == src_corner) { ClkSkew probe(src_path, tgt_path, this); - ClkSkew *clk_skew = skews.findKey(const_cast(src_clk)); + ClkSkew &clk_skew = skews[src_clk]; debugPrint(debug_, "clk_skew", 2, "%s %s %s -> %s %s %s crpr = %s skew = %s", network_->pathName(src_path->pin(this)), @@ -301,12 +355,9 @@ ClkSkews::findClkSkew(Vertex *src_vertex, time_unit->asString(probe.tgtLatency(this)), delayAsString(probe.crpr(this), this), time_unit->asString(probe.skew())); - if (clk_skew == nullptr) { - clk_skew = new ClkSkew(probe); - skews[src_clk] = clk_skew; - } - else if (abs(probe.skew()) > abs(clk_skew->skew())) - *clk_skew = probe; + if (clk_skew.srcPath()->isNull() + || abs(probe.skew()) > abs(clk_skew.skew())) + clk_skew = probe; } } } @@ -358,31 +409,4 @@ ClkSkews::findFanout(Vertex *from) return endpoints; } -//////////////////////////////////////////////////////////////// - -void -ClkSkews::findClkDelays(const Clock *clk, - // Return values. - ClkDelays &delays) -{ - for (Vertex *clk_vertex : *graph_->regClkVertices()) { - VertexPathIterator path_iter(clk_vertex, this); - while (path_iter.hasNext()) { - PathVertex *path = path_iter.next(); - const ClockEdge *path_clk_edge = path->clkEdge(this); - if (path_clk_edge) { - const RiseFall *clk_rf = path_clk_edge->transition(); - const Clock *path_clk = path_clk_edge->clock(); - if (path_clk == clk) { - Arrival arrival = path->arrival(this); - Delay clk_delay = delayAsFloat(arrival) - path_clk_edge->time(); - const MinMax *min_max = path->minMax(this); - const RiseFall *rf = path->transition(this); - delays[clk_rf->index()][rf->index()].setValue(min_max, clk_delay); - } - } - } - } -} - } // namespace diff --git a/search/ClkSkew.hh b/search/ClkSkew.hh index 97497436..ca2491b3 100644 --- a/search/ClkSkew.hh +++ b/search/ClkSkew.hh @@ -16,17 +16,19 @@ #pragma once -#include "Map.hh" +#include + #include "SdcClass.hh" #include "StaState.hh" #include "Transition.hh" #include "SearchClass.hh" +#include "PathVertex.hh" namespace sta { class ClkSkew; -typedef Map ClkSkewMap; +typedef std::map ClkSkewMap; // Find and report clock skews between source/target registers. class ClkSkews : public StaState @@ -34,40 +36,38 @@ class ClkSkews : public StaState public: ClkSkews(StaState *sta); // Report clk skews for clks. - void reportClkSkew(ClockSet *clks, + void reportClkSkew(ConstClockSeq clks, const Corner *corner, const SetupHold *setup_hold, int digits); // Find worst clock skew between src/target registers. float findWorstClkSkew(const Corner *corner, const SetupHold *setup_hold); - void findClkDelays(const Clock *clk, - // Return values. - ClkDelays &delays); protected: - void findClkSkew(ClockSet *clks, - const Corner *corner, - const SetupHold *setup_hold, - ClkSkewMap &skews); + ClkSkewMap findClkSkew(ConstClockSeq &clks, + const Corner *corner, + const SetupHold *setup_hold); bool hasClkPaths(Vertex *vertex, - ClockSet *clks); + ConstClockSet &clks); void findClkSkewFrom(Vertex *src_vertex, Vertex *q_vertex, - RiseFallBoth *src_rf, - ClockSet *clks, + const RiseFallBoth *src_rf, + ConstClockSet &clk_set, const Corner *corner, const SetupHold *setup_hold, ClkSkewMap &skews); void findClkSkew(Vertex *src_vertex, - RiseFallBoth *src_rf, + const RiseFallBoth *src_rf, Vertex *tgt_vertex, - RiseFallBoth *tgt_rf, - ClockSet *clks, + const RiseFallBoth *tgt_rf, + ConstClockSet &clk_set, const Corner *corner, const SetupHold *setup_hold, ClkSkewMap &skews); VertexSet findFanout(Vertex *from); + void reportClkSkew(ClkSkew &clk_skew, + int digits); }; } // namespace diff --git a/search/MakeTimingModel.cc b/search/MakeTimingModel.cc index 2f6eee93..ff9a861f 100644 --- a/search/MakeTimingModel.cc +++ b/search/MakeTimingModel.cc @@ -40,7 +40,7 @@ #include "Sta.hh" #include "VisitPathEnds.hh" #include "ArcDelayCalc.hh" -#include "ClkSkew.hh" +#include "ClkLatency.hh" namespace sta { @@ -156,7 +156,22 @@ void MakeTimingModel::makeCell() { cell_ = lib_builder_->makeCell(library_, cell_name_, filename_); - cell_->setInterfaceTiming(true); + cell_->setIsMacro(true); + cell_->setArea(findArea()); +} + +float +MakeTimingModel::findArea() +{ + float area = 0.0; + LeafInstanceIterator *leaf_iter = network_->leafInstanceIterator(); + while (leaf_iter->hasNext()) { + const Instance *inst = leaf_iter->next(); + const LibertyCell *cell = network_->libertyCell(inst); + area += cell->area(); + } + delete leaf_iter; + return area; } void @@ -527,17 +542,17 @@ MakeTimingModel::findClkInsertionDelays() size_t clk_count = clks->size(); if (clk_count == 1) { for (const Clock *clk : *clks) { - ClkDelays delays; - sta_->findClkDelays(clk, delays); + ClkDelays delays = sta_->findClkDelays(clk); for (const MinMax *min_max : MinMax::range()) { TimingArcAttrsPtr attrs = nullptr; for (const RiseFall *clk_rf : RiseFall::range()) { - int clk_rf_index = clk_rf->index(); float delay = min_max->initValue(); - for (const int end_rf_index : RiseFall::rangeIndex()) { - Delay delay1; + for (const RiseFall *end_rf : RiseFall::range()) { + PathVertex clk_path; + float insertion, delay1, lib_clk_delay, latency; bool exists; - delays[clk_rf_index][end_rf_index].value(min_max, delay1, exists); + delays.delay(clk_rf, end_rf, min_max, insertion, delay1, + lib_clk_delay, latency, clk_path, exists); if (exists) delay = min_max->minMax(delay, delayAsFloat(delay1)); } @@ -551,7 +566,8 @@ MakeTimingModel::findClkInsertionDelays() TimingRole *role = (min_max == MinMax::min()) ? TimingRole::clockTreePathMin() : TimingRole::clockTreePathMax(); - lib_builder_->makeClockTreePathArcs(cell_, lib_port, role, attrs); + lib_builder_->makeClockTreePathArcs(cell_, lib_port, role, + min_max, attrs); } } } diff --git a/search/MakeTimingModelPvt.hh b/search/MakeTimingModelPvt.hh index 55689296..da5f15b8 100644 --- a/search/MakeTimingModelPvt.hh +++ b/search/MakeTimingModelPvt.hh @@ -57,6 +57,7 @@ public: private: void makeLibrary(); void makeCell(); + float findArea(); void makePorts(); void checkClock(Clock *clk); void findTimingFromInputs(); diff --git a/search/Sim.cc b/search/Sim.cc index 30db0f0c..2e37b334 100644 --- a/search/Sim.cc +++ b/search/Sim.cc @@ -60,14 +60,13 @@ Sim::Sim(StaState *sta) : invalid_load_pins_(network_), instances_with_const_pins_(network_), instances_to_annotate_(network_), - cudd_mgr_(Cudd_Init(0, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0)) + bdd_(sta) { } Sim::~Sim() { delete observer_; - Cudd_Quit(cudd_mgr_); } #if CUDD @@ -82,17 +81,18 @@ Sim::functionSense(const FuncExpr *expr, expr->asString()); bool increasing, decreasing; { - UniqueLock lock(cudd_lock_); - DdNode *bdd = funcBdd(expr, inst); + UniqueLock lock(bdd_lock_); + DdNode *bdd = funcBddSim(expr, inst); + DdManager *cudd_mgr = bdd_.cuddMgr(); LibertyPort *input_port = network_->libertyPort(input_pin); - DdNode *input_node = ensureNode(input_port); + DdNode *input_node = bdd_.ensureNode(input_port); unsigned int input_index = Cudd_NodeReadIndex(input_node); - increasing = (Cudd_Increasing(cudd_mgr_, bdd, input_index) - == Cudd_ReadOne(cudd_mgr_)); - decreasing = (Cudd_Decreasing(cudd_mgr_, bdd, input_index) - == Cudd_ReadOne(cudd_mgr_)); - Cudd_RecursiveDeref(cudd_mgr_, bdd); - clearSymtab(); + increasing = (Cudd_Increasing(cudd_mgr, bdd, input_index) + == Cudd_ReadOne(cudd_mgr)); + decreasing = (Cudd_Decreasing(cudd_mgr, bdd, input_index) + == Cudd_ReadOne(cudd_mgr)); + Cudd_RecursiveDeref(cudd_mgr, bdd); + bdd_.clearVarMap(); } TimingSense sense; if (increasing && decreasing) @@ -107,127 +107,57 @@ Sim::functionSense(const FuncExpr *expr, return sense; } -void -Sim::clearSymtab() const -{ - for (auto name_node : symtab_) { - DdNode *sym_node = name_node.second; - Cudd_RecursiveDeref(cudd_mgr_, sym_node); - } - symtab_.clear(); -} - LogicValue Sim::evalExpr(const FuncExpr *expr, - const Instance *inst) const + const Instance *inst) { - UniqueLock lock(cudd_lock_); - DdNode *bdd = funcBdd(expr, inst); + UniqueLock lock(bdd_lock_); + DdNode *bdd = funcBddSim(expr, inst); LogicValue value = LogicValue::unknown; - if (bdd == Cudd_ReadLogicZero(cudd_mgr_)) + DdManager *cudd_mgr = bdd_.cuddMgr(); + if (bdd == Cudd_ReadLogicZero(cudd_mgr)) value = LogicValue::zero; - else if (bdd == Cudd_ReadOne(cudd_mgr_)) + else if (bdd == Cudd_ReadOne(cudd_mgr)) value = LogicValue::one; + if (bdd) { - Cudd_RecursiveDeref(cudd_mgr_, bdd); - clearSymtab(); + Cudd_RecursiveDeref(bdd_.cuddMgr(), bdd); + bdd_.clearVarMap(); } return value; } -// Returns nullptr if the expression simply references an internal port. +// BDD with instance pin values substituted. DdNode * -Sim::funcBdd(const FuncExpr *expr, - const Instance *inst) const +Sim::funcBddSim(const FuncExpr *expr, + const Instance *inst) { - DdNode *left = nullptr; - DdNode *right = nullptr; - DdNode *result = nullptr; - switch (expr->op()) { - case FuncExpr::op_port: { - LibertyPort *port = expr->port(); - Pin *pin = network_->findPin(inst, port); - // Internal ports don't have instance pins. - if (pin) { + DdNode *bdd = bdd_.funcBdd(expr); + DdManager *cudd_mgr = bdd_.cuddMgr(); + InstancePinIterator *pin_iter = network_->pinIterator(inst); + while (pin_iter->hasNext()) { + const Pin *pin = pin_iter->next(); + const LibertyPort *port = network_->libertyPort(pin); + DdNode *port_node = bdd_.findNode(port); + if (port_node) { LogicValue value = logicValue(pin); + int var_index = Cudd_NodeReadIndex(port_node); + //printf("%s %d %c\n", port->name(), var_index, logicValueString(value)); switch (value) { case LogicValue::zero: - result = Cudd_ReadLogicZero(cudd_mgr_); - break; + bdd = Cudd_bddCompose(cudd_mgr, bdd, Cudd_ReadLogicZero(cudd_mgr), var_index); + Cudd_Ref(bdd); + break; case LogicValue::one: - result = Cudd_ReadOne(cudd_mgr_); - break; + bdd = Cudd_bddCompose(cudd_mgr, bdd, Cudd_ReadOne(cudd_mgr), var_index); + Cudd_Ref(bdd); + break; default: - result = ensureNode(port); - break; + break; } } - break; } - case FuncExpr::op_not: - left = funcBdd(expr->left(), inst); - if (left) - result = Cudd_Not(left); - break; - case FuncExpr::op_or: - left = funcBdd(expr->left(), inst); - right = funcBdd(expr->right(), inst); - if (left && right) - result = Cudd_bddOr(cudd_mgr_, left, right); - else if (left) - result = left; - else if (right) - result = right; - break; - case FuncExpr::op_and: - left = funcBdd(expr->left(), inst); - right = funcBdd(expr->right(), inst); - if (left && right) - result = Cudd_bddAnd(cudd_mgr_, left, right); - else if (left) - result = left; - else if (right) - result = right; - break; - case FuncExpr::op_xor: - left = funcBdd(expr->left(), inst); - right = funcBdd(expr->right(), inst); - if (left && right) - result = Cudd_bddXor(cudd_mgr_, left, right); - else if (left) - result = left; - else if (right) - result = right; - break; - case FuncExpr::op_one: - result = Cudd_ReadOne(cudd_mgr_); - break; - case FuncExpr::op_zero: - result = Cudd_ReadLogicZero(cudd_mgr_); - break; - default: - report_->critical(1520, "unknown function operator"); - } - if (result) - Cudd_Ref(result); - if (left) - Cudd_RecursiveDeref(cudd_mgr_, left); - if (right) - Cudd_RecursiveDeref(cudd_mgr_, right); - return result; -} - -DdNode * -Sim::ensureNode(LibertyPort *port) const -{ - const char *port_name = port->name(); - DdNode *node = symtab_.findKey(port_name); - if (node == nullptr) { - node = Cudd_bddNewVar(cudd_mgr_); - symtab_[port_name] = node; - Cudd_Ref(node); - } - return node; + return bdd; } #else @@ -468,7 +398,7 @@ Sim::functionSense(const FuncExpr *expr, LogicValue Sim::evalExpr(const FuncExpr *expr, - const Instance *inst) const + const Instance *inst) { switch (expr->op()) { case FuncExpr::op_port: { @@ -1199,7 +1129,7 @@ isCondDisabled(Edge *edge, const Pin *from_pin, const Pin *to_pin, const Network *network, - const Sim *sim) + Sim *sim) { bool is_disabled; FuncExpr *disable_cond; @@ -1214,7 +1144,7 @@ isCondDisabled(Edge *edge, const Pin *from_pin, const Pin *to_pin, const Network *network, - const Sim *sim, + Sim *sim, bool &is_disabled, FuncExpr *&disable_cond) { @@ -1248,7 +1178,7 @@ bool isModeDisabled(Edge *edge, const Instance *inst, const Network *network, - const Sim *sim) + Sim *sim) { bool is_disabled; FuncExpr *disable_cond; @@ -1261,7 +1191,7 @@ void isModeDisabled(Edge *edge, const Instance *inst, const Network *network, - const Sim *sim, + Sim *sim, bool &is_disabled, FuncExpr *&disable_cond) { diff --git a/search/Sim.hh b/search/Sim.hh index 25a808f1..eeca92a4 100644 --- a/search/Sim.hh +++ b/search/Sim.hh @@ -25,9 +25,7 @@ #include "GraphClass.hh" #include "SdcClass.hh" #include "StaState.hh" - -struct DdNode; -struct DdManager; +#include "Bdd.hh" namespace sta { @@ -35,7 +33,6 @@ class SimObserver; typedef Map PinValueMap; typedef std::queue EvalQueue; -typedef Map BddSymbolTable; // Propagate constants from constraints and netlist tie high/low // connections thru gates. @@ -50,7 +47,7 @@ public: void ensureConstantsPropagated(); void constantsInvalid(); LogicValue evalExpr(const FuncExpr *expr, - const Instance *inst) const; + const Instance *inst); LogicValue logicValue(const Pin *pin) const; bool logicZeroOne(const Pin *pin) const; bool logicZeroOne(const Vertex *vertex) const; @@ -110,6 +107,8 @@ protected: const Pin *load_pin); void setSimValue(Vertex *vertex, LogicValue value); + DdNode *funcBddSim(const FuncExpr *expr, + const Instance *inst); SimObserver *observer_; bool valid_; @@ -128,15 +127,8 @@ protected: // Instances with constant pin values for annotateVertexEdges. InstanceSet instances_with_const_pins_; InstanceSet instances_to_annotate_; - - DdNode *funcBdd(const FuncExpr *expr, - const Instance *inst) const; - DdNode *ensureNode(LibertyPort *port) const; - void clearSymtab() const; - - DdManager *cudd_mgr_; - mutable BddSymbolTable symtab_; - mutable std::mutex cudd_lock_; + Bdd bdd_; + mutable std::mutex bdd_lock_; }; // Abstract base class for Sim value change observer. @@ -160,7 +152,7 @@ isCondDisabled(Edge *edge, const Pin *from_pin, const Pin *to_pin, const Network *network, - const Sim *sim); + Sim *sim); // isCondDisabled but also return the cond expression that causes // the disable. This can differ from the edge cond expression @@ -172,7 +164,7 @@ isCondDisabled(Edge *edge, const Pin *from_pin, const Pin *to_pin, const Network *network, - const Sim *sim, + Sim *sim, bool &is_disabled, FuncExpr *&disable_cond); @@ -182,12 +174,12 @@ bool isModeDisabled(Edge *edge, const Instance *inst, const Network *network, - const Sim *sim); + Sim *sim); void isModeDisabled(Edge *edge, const Instance *inst, const Network *network, - const Sim *sim, + Sim *sim, bool &is_disabled, FuncExpr *&disable_cond); diff --git a/search/Sta.cc b/search/Sta.cc index e1246db9..f6012128 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -63,6 +63,7 @@ #include "CheckMinPeriods.hh" #include "CheckMaxSkews.hh" #include "ClkSkew.hh" +#include "ClkLatency.hh" #include "FindRegister.hh" #include "ReportPath.hh" #include "VisitPathGroupVertices.hh" @@ -2600,7 +2601,7 @@ Sta::updateTiming(bool full) //////////////////////////////////////////////////////////////// void -Sta::reportClkSkew(ClockSet *clks, +Sta::reportClkSkew(ConstClockSeq clks, const Corner *corner, const SetupHold *setup_hold, int digits) @@ -2616,15 +2617,6 @@ Sta::findWorstClkSkew(const SetupHold *setup_hold) return clk_skews_->findWorstClkSkew(cmd_corner_, setup_hold); } -void -Sta::findClkDelays(const Clock *clk, - // Return values. - ClkDelays &delays) -{ - clkSkewPreamble(); - clk_skews_->findClkDelays(clk, delays); -} - void Sta::clkSkewPreamble() { @@ -2635,6 +2627,26 @@ Sta::clkSkewPreamble() //////////////////////////////////////////////////////////////// +void +Sta::reportClkLatency(ConstClockSeq clks, + const Corner *corner, + int digits) +{ + ensureClkArrivals(); + ClkLatency clk_latency(this); + clk_latency.reportClkLatency(clks, corner, digits); +} + +ClkDelays +Sta::findClkDelays(const Clock *clk) +{ + ensureClkArrivals(); + ClkLatency clk_latency(this); + return clk_latency.findClkDelays(clk, nullptr); +} + +//////////////////////////////////////////////////////////////// + void Sta::delaysInvalid() { diff --git a/search/WritePathSpice.cc b/search/WritePathSpice.cc index 608c32d9..93b0970e 100644 --- a/search/WritePathSpice.cc +++ b/search/WritePathSpice.cc @@ -17,7 +17,6 @@ #include "WritePathSpice.hh" #include -#include #include #include "Debug.hh" @@ -27,9 +26,9 @@ #include "FuncExpr.hh" #include "Units.hh" #include "Sequential.hh" -#include "TableModel.hh" #include "Liberty.hh" #include "TimingArc.hh" +#include "TableModel.hh" #include "PortDirection.hh" #include "Network.hh" #include "Graph.hh" @@ -42,6 +41,7 @@ #include "PathExpanded.hh" #include "StaState.hh" #include "Sim.hh" +#include "WriteSpice.hh" namespace sta { @@ -49,135 +49,47 @@ using std::ofstream; using std::ifstream; using std::max; -typedef Map CellSpicePortNames; typedef int Stage; -typedef Map ParasiticNodeMap; -typedef Map LibertyPortLogicValues; - -void -streamPrint(ofstream &stream, - const char *fmt, - ...) __attribute__((format (printf, 2, 3))); //////////////////////////////////////////////////////////////// -class WritePathSpice : public StaState +class WritePathSpice : public WriteSpice { public: WritePathSpice(Path *path, const char *spice_filename, - const char *subckt_filename, + const char *subckt_filename, const char *lib_subckt_filename, const char *model_filename, - StdStringSet *off_path_pin_names, const char *power_name, const char *gnd_name, - bool measure_stmts, + CircuitSim ckt_sim, const StaState *sta); - ~WritePathSpice(); void writeSpice(); private: void writeHeader(); + void writePrintStmt(); void writeStageInstances(); void writeInputSource(); - void writeRampVoltSource(const Pin *pin, - const RiseFall *rf, - float slew, - float time, - int &volt_index); void writeStageSubckts(); void writeInputStage(Stage stage); void writeMeasureStmts(); void writeMeasureStmt(const Pin *pin); void writeGateStage(Stage stage); - void writeSubcktInst(const Pin *input_pin); - void writeSubcktInstVoltSrcs(Stage stage, - const Pin *input_pin, - int &volt_index, - LibertyPortLogicValues &port_values, - const Clock *clk, - DcalcAPIndex dcalc_ap_index); void writeStageParasitics(Stage stage); - void writeStageParasiticNetwork(Pin *drvr_pin, - Parasitic *parasitic); - void writeStagePiElmore(Pin *drvr_pin, - Parasitic *parasitic); - void writeNullParasitics(Pin *drvr_pin); void writeSubckts(); - StdStringSet findPathCellnames(); + StdStringSet findPathCellNames(); void findPathCellSubckts(StdStringSet &path_cell_names); - void recordSpicePortNames(const char *cell_name, - StringVector &tokens); float maxTime(); float pathMaxTime(); - const char *nodeName(ParasiticNode *node); - void initNodeMap(const char *net_name); - const char *spiceTrans(const RiseFall *rf); void writeMeasureDelayStmt(Stage stage, Path *from_path, Path *to_path); void writeMeasureSlewStmt(Stage stage, Path *path); - void gatePortValues(Stage stage, - // Return values. - LibertyPortLogicValues &port_values, - const Clock *&clk, - DcalcAPIndex &dcalc_ap_index); - void regPortValues(Stage stage, - // Return values. - LibertyPortLogicValues &port_values, - const Clock *&clk, - DcalcAPIndex &dcalc_ap_index); - void gatePortValues(const Instance *inst, - FuncExpr *expr, - LibertyPort *input_port, - // Return values. - LibertyPortLogicValues &port_values); - void seqPortValues(Sequential *seq, - const RiseFall *rf, - // Return values. - LibertyPortLogicValues &port_values); void writeInputWaveform(); void writeClkWaveform(); - void writeWaveformEdge(const RiseFall *rf, - float time, - float slew); - void writeWaveformVoltSource(const Pin *pin, - DriverWaveform *drvr_waveform, - const RiseFall *rf, - float slew, - int &volt_index); - void writeClkedStepSource(const Pin *pin, - const RiseFall *rf, - const Clock *clk, - DcalcAPIndex dcalc_ap_index, - int &volt_index); - float clkWaveformTImeOffset(const Clock *clk); - float findSlew(Path *path); - float findSlew(Path *path, - const RiseFall *rf, - TimingArc *next_arc); - float findSlew(Vertex *vertex, - const RiseFall *rf, - TimingArc *next_arc, - DcalcAPIndex dcalc_ap_index); - LibertyPort *onePort(FuncExpr *expr); - void writeVoltageSource(const char *inst_name, - const char *port_name, - float voltage, - int &volt_index); - void writeVoltageSource(LibertyCell *cell, - const char *inst_name, - const char *subckt_port_name, - const char *pg_port_name, - float voltage, - int &volt_index); - float slewAxisMinValue(TimingArc *arc); - float pgPortVoltage(LibertyPgPort *pg_port); - void writePrintStmt(); - float railToRailSlew(float slew, - const RiseFall *rf); // Stage "accessors". // @@ -215,129 +127,62 @@ private: const char *stageLoadPinName(Stage stage); LibertyCell *stageLibertyCell(Stage stage); Instance *stageInstance(Stage stage); - StdStringSet stageOffPathPinNames(Stage stage); + float findSlew(Path *path); + float findSlew(Path *path, + const RiseFall *rf, + TimingArc *next_arc); Path *path_; - const char *spice_filename_; - const char *subckt_filename_; - const char *lib_subckt_filename_; - const char *model_filename_; - StdStringSet *off_path_pin_names_; - const char *power_name_; - const char *gnd_name_; - bool measure_stmts_; - - ofstream spice_stream_; PathExpanded path_expanded_; - CellSpicePortNames cell_spice_port_names_; - ParasiticNodeMap node_map_; - int next_node_index_; - const char *net_name_; - float power_voltage_; - float gnd_voltage_; - LibertyLibrary *default_library_; - // Resistance to use to simulate a short circuit between spice nodes. - float short_ckt_resistance_; // Input clock waveform cycles. int clk_cycle_count_; + + using WriteSpice::writeHeader; + using WriteSpice::writePrintStmt; + using WriteSpice::writeSubckts; + using WriteSpice::writeVoltageSource; + using WriteSpice::writeMeasureDelayStmt; + using WriteSpice::writeMeasureSlewStmt; + using WriteSpice::findSlew; }; //////////////////////////////////////////////////////////////// -class SubcktEndsMissing : public Exception -{ -public: - SubcktEndsMissing(const char *cell_name, - const char *subckt_filename); - const char *what() const noexcept; - -protected: - string what_; -}; - -SubcktEndsMissing::SubcktEndsMissing(const char *cell_name, - const char *subckt_filename) : - Exception() -{ - what_ = "spice subckt for cell "; - what_ += cell_name; - what_ += " missing .ends in "; - what_ += subckt_filename; -} - -const char * -SubcktEndsMissing::what() const noexcept -{ - return what_.c_str(); -} - -//////////////////////////////////////////////////////////////// - void writePathSpice(Path *path, const char *spice_filename, const char *subckt_filename, const char *lib_subckt_filename, const char *model_filename, - StdStringSet *off_path_pin_names, const char *power_name, const char *gnd_name, - bool measure_stmts, + CircuitSim ckt_sim, 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, - measure_stmts, sta); + lib_subckt_filename, model_filename, + power_name, gnd_name, ckt_sim, sta); writer.writeSpice(); } WritePathSpice::WritePathSpice(Path *path, - const char *spice_filename, + const char *spice_filename, const char *subckt_filename, const char *lib_subckt_filename, const char *model_filename, - StdStringSet *off_path_pin_names, const char *power_name, const char *gnd_name, - bool measure_stmts, + CircuitSim ckt_sim, const StaState *sta) : - StaState(sta), + WriteSpice(spice_filename, subckt_filename, lib_subckt_filename, + model_filename, power_name, gnd_name, ckt_sim, sta), path_(path), - spice_filename_(spice_filename), - subckt_filename_(subckt_filename), - lib_subckt_filename_(lib_subckt_filename), - model_filename_(model_filename), - 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 = false; - default_library_->supplyVoltage(power_name_, power_voltage_, exists); - if (!exists) { - DcalcAnalysisPt *dcalc_ap = path_->dcalcAnalysisPt(this); - const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); - if (op_cond == nullptr) - op_cond = network_->defaultLibertyLibrary()->defaultOperatingConditions(); - power_voltage_ = op_cond->voltage(); - } - default_library_->supplyVoltage(gnd_name_, gnd_voltage_, exists); - if (!exists) - gnd_voltage_ = 0.0; -} - -WritePathSpice::~WritePathSpice() -{ - stringDelete(net_name_); - cell_spice_port_names_.deleteContents(); + initPowerGnd( path_->dcalcAnalysisPt(this)); } void @@ -350,10 +195,10 @@ WritePathSpice::writeSpice() writeSubckts(); writeHeader(); writePrintStmt(); - writeStageInstances(); - if (measure_stmts_) + if (ckt_sim_ == CircuitSim::hspice) writeMeasureStmts(); writeInputSource(); + writeStageInstances(); writeStageSubckts(); streamPrint(spice_stream_, ".end\n"); spice_stream_.close(); @@ -362,55 +207,29 @@ WritePathSpice::writeSpice() throw FileNotWritable(spice_filename_); } -// Use c++17 fs::path(filename).stem() -static string -filenameStem(const char *filename) -{ - string filename1 = filename; - const size_t last_slash_idx = filename1.find_last_of("\\/"); - if (last_slash_idx != std::string::npos) - return filename1.substr(last_slash_idx + 1); - else - return filename1; -} - void WritePathSpice::writeHeader() { - const MinMax *min_max = path_->minMax(this); - Pvt *pvt = sdc_->operatingConditions(min_max); - if (pvt == nullptr) - pvt = default_library_->defaultOperatingConditions(); Path *start_path = path_expanded_.startPath(); - streamPrint(spice_stream_, "* Path from %s %s to %s %s\n", - network_->pathName(start_path->pin(this)), - start_path->transition(this)->asString(), - network_->pathName(path_->pin(this)), - path_->transition(this)->asString()); - 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()); - + string title = stdstrPrint("Path from %s %s to %s %s", + network_->pathName(start_path->pin(this)), + start_path->transition(this)->asString(), + network_->pathName(path_->pin(this)), + path_->transition(this)->asString()); float max_time = maxTime(); 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"); + writeHeader(title, max_time, time_step); } void WritePathSpice::writePrintStmt() { - streamPrint(spice_stream_, ".print tran"); + StdStringSeq node_names; for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { - streamPrint(spice_stream_, " v(%s)", stageDrvrPinName(stage)); - streamPrint(spice_stream_, " v(%s)", stageLoadPinName(stage)); - StdStringSet off_path_names = stageOffPathPinNames(stage); - for (const string &off_path_name : off_path_names) - streamPrint(spice_stream_, " v(%s)", off_path_name.c_str()); + node_names.push_back(stageDrvrPinName(stage)); + node_names.push_back(stageLoadPinName(stage)); } - streamPrint(spice_stream_, "\n\n"); + writePrintStmt(node_names); } float @@ -457,15 +276,6 @@ WritePathSpice::pathMaxTime() return max_time; } -float -WritePathSpice::railToRailSlew(float slew, - const RiseFall *rf) -{ - float lower = default_library_->slewLowerThreshold(rf); - float upper = default_library_->slewUpperThreshold(rf); - return slew / (upper - lower); -} - void WritePathSpice::writeStageInstances() { @@ -483,48 +293,17 @@ WritePathSpice::writeStageInstances() stageLoadPinName(stage), stage_cname); else { - streamPrint(spice_stream_, "x%s %s %s %s", + streamPrint(spice_stream_, "x%s %s %s %s %s\n", stage_cname, stageGateInputPinName(stage), stageDrvrPinName(stage), - stageLoadPinName(stage)); - StdStringSet off_path_names = stageOffPathPinNames(stage); - for (const string &off_path_name : off_path_names) - streamPrint(spice_stream_, " %s", off_path_name.c_str()); - streamPrint(spice_stream_, " %s\n", stage_cname); + stageLoadPinName(stage), + stage_cname); } } streamPrint(spice_stream_, "\n"); } -float -WritePathSpice::pgPortVoltage(LibertyPgPort *pg_port) -{ - LibertyLibrary *liberty = pg_port->cell()->libertyLibrary(); - float voltage = 0.0; - bool exists; - const char *voltage_name = pg_port->voltageName(); - if (voltage_name) { - liberty->supplyVoltage(voltage_name, voltage, exists); - if (!exists) { - if (stringEqual(voltage_name, power_name_)) - voltage = power_voltage_; - else if (stringEqual(voltage_name, gnd_name_)) - voltage = gnd_voltage_; - else - report_->error(1601 , "pg_pin %s/%s voltage %s not found,", - pg_port->cell()->name(), - pg_port->name(), - voltage_name); - } - } - else - report_->error(1602, "Liberty pg_port %s/%s missing voltage_name attribute,", - pg_port->cell()->name(), - pg_port->name()); - return voltage; -} - void WritePathSpice::writeInputSource() { @@ -554,7 +333,6 @@ WritePathSpice::writeInputWaveform() float dt = railToRailSlew(slew0, rf); float time0 = dt * threshold; - int volt_index = 1; const Pin *drvr_pin = stageDrvrPin(input_stage); const Pin *load_pin = stageLoadPin(input_stage); const LibertyPort *load_port = network_->libertyPort(load_pin); @@ -562,71 +340,9 @@ WritePathSpice::writeInputWaveform() if (load_port) drvr_waveform = load_port->driverWaveform(rf); if (drvr_waveform) - writeWaveformVoltSource(drvr_pin, drvr_waveform, - rf, slew0, volt_index); + writeWaveformVoltSource(drvr_pin, drvr_waveform, rf, 0.0, slew0); else - writeRampVoltSource(drvr_pin, rf, slew0, time0, volt_index); -} - -void -WritePathSpice::writeWaveformVoltSource(const Pin *pin, - DriverWaveform *drvr_waveform, - const RiseFall *rf, - float slew, - int &volt_index) -{ - float volt0, volt1, volt_factor; - if (rf == RiseFall::rise()) { - volt0 = gnd_voltage_; - volt1 = power_voltage_; - volt_factor = power_voltage_; - } - else { - volt0 = power_voltage_; - volt1 = gnd_voltage_; - volt_factor = -power_voltage_; - } - streamPrint(spice_stream_, "v%d %s 0 pwl(\n", - volt_index, - network_->pathName(pin)); - streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0); - Table1 waveform = drvr_waveform->waveform(slew); - const TableAxis *time_axis = waveform.axis1(); - for (size_t time_index = 0; time_index < time_axis->size(); time_index++) { - float time = time_axis->axisValue(time_index); - float wave_volt = waveform.value(time_index); - float volt = volt0 + wave_volt * volt_factor; - streamPrint(spice_stream_, "+%.3e %.3e\n", time, volt); - } - streamPrint(spice_stream_, "+%.3e %.3e\n", maxTime(), volt1); - streamPrint(spice_stream_, "+)\n"); - volt_index++; -} - -void -WritePathSpice::writeRampVoltSource(const Pin *pin, - const RiseFall *rf, - float slew, - float time, - int &volt_index) -{ - float volt0, volt1; - if (rf == RiseFall::rise()) { - volt0 = gnd_voltage_; - volt1 = power_voltage_; - } - else { - volt0 = power_voltage_; - volt1 = gnd_voltage_; - } - streamPrint(spice_stream_, "v%d %s 0 pwl(\n", - volt_index, - network_->pathName(pin)); - streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0); - writeWaveformEdge(rf, time, slew); - streamPrint(spice_stream_, "+%.3e %.3e\n", maxTime(), volt1); - streamPrint(spice_stream_, "+)\n"); - volt_index++; + writeRampVoltSource(drvr_pin, rf, time0, slew0); } void @@ -636,9 +352,10 @@ WritePathSpice::writeClkWaveform() PathRef *input_path = stageDrvrPath(input_stage); TimingArc *next_arc = stageGateArc(input_stage + 1); const ClockEdge *clk_edge = input_path->clkEdge(this); + const Clock *clk = clk_edge->clock(); float period = clk->period(); - float time_offset = clkWaveformTImeOffset(clk); + float time_offset = clkWaveformTimeOffset(clk); RiseFall *rf0, *rf1; float volt0; if (clk_edge->time() < period) { @@ -662,16 +379,10 @@ WritePathSpice::writeClkWaveform() writeWaveformEdge(rf0, time0, slew0); writeWaveformEdge(rf1, time1, slew1); } - streamPrint(spice_stream_, "+%.3e %.3e\n", maxTime(), volt0); + streamPrint(spice_stream_, "+%.3e %.3e\n", max_time_, volt0); streamPrint(spice_stream_, "+)\n"); } -float -WritePathSpice::clkWaveformTImeOffset(const Clock *clk) -{ - return clk->period() / 10; -} - float WritePathSpice::findSlew(Path *path) { @@ -683,80 +394,14 @@ WritePathSpice::findSlew(Path *path) float WritePathSpice::findSlew(Path *path, - const RiseFall *rf, - TimingArc *next_arc) + const RiseFall *rf, + TimingArc *next_arc) { Vertex *vertex = path->vertex(this); DcalcAPIndex dcalc_ap_index = path->dcalcAnalysisPt(this)->index(); return findSlew(vertex, rf, next_arc, dcalc_ap_index); } -float -WritePathSpice::findSlew(Vertex *vertex, - const RiseFall *rf, - TimingArc *next_arc, - DcalcAPIndex dcalc_ap_index) -{ - float slew = delayAsFloat(graph_->slew(vertex, rf, dcalc_ap_index)); - if (slew == 0.0 && next_arc) - slew = slewAxisMinValue(next_arc); - if (slew == 0.0) - slew = units_->timeUnit()->scale(); - return slew; -} - -// Look up the smallest slew axis value in the timing arc delay table. -float -WritePathSpice::slewAxisMinValue(TimingArc *arc) -{ - GateTableModel *gate_model = dynamic_cast(arc->model()); - if (gate_model) { - const TableModel *model = gate_model->delayModel(); - const TableAxis *axis1 = model->axis1(); - TableAxisVariable var1 = axis1->variable(); - if (var1 == TableAxisVariable::input_transition_time - || var1 == TableAxisVariable::input_net_transition) - return axis1->axisValue(0); - - const TableAxis *axis2 = model->axis2(); - TableAxisVariable var2 = axis2->variable(); - if (var2 == TableAxisVariable::input_transition_time - || var2 == TableAxisVariable::input_net_transition) - return axis2->axisValue(0); - - const TableAxis *axis3 = model->axis3(); - TableAxisVariable var3 = axis3->variable(); - if (var3 == TableAxisVariable::input_transition_time - || var3 == TableAxisVariable::input_net_transition) - return axis3->axisValue(0); - } - return 0.0; -} - -// Write PWL rise/fall edge that crosses threshold at time. -void -WritePathSpice::writeWaveformEdge(const RiseFall *rf, - float time, - float slew) -{ - float volt0, volt1; - if (rf == RiseFall::rise()) { - volt0 = gnd_voltage_; - volt1 = power_voltage_; - } - else { - volt0 = power_voltage_; - volt1 = gnd_voltage_; - } - float threshold = default_library_->inputThreshold(rf); - float dt = railToRailSlew(slew, rf); - float time0 = time - dt * threshold; - float time1 = time0 + dt; - if (time0 > 0.0) - streamPrint(spice_stream_, "+%.3e %.3e\n", time0, volt0); - streamPrint(spice_stream_, "+%.3e %.3e\n", time1, volt1); -} - //////////////////////////////////////////////////////////////// void @@ -789,73 +434,19 @@ WritePathSpice::writeMeasureDelayStmt(Stage stage, Path *from_path, Path *to_path) { - const char *from_pin_name = network_->pathName(from_path->pin(this)); - const RiseFall *from_rf = from_path->transition(this); - float from_threshold = power_voltage_ * default_library_->inputThreshold(from_rf); - - const char *to_pin_name = network_->pathName(to_path->pin(this)); - const RiseFall *to_rf = to_path->transition(this); - float to_threshold = power_voltage_ * default_library_->inputThreshold(to_rf); - string stage_name = stageName(stage); - streamPrint(spice_stream_, - ".measure tran %s_%s_delay_%s\n", - stage_name.c_str(), - from_pin_name, - to_pin_name); - streamPrint(spice_stream_, - "+trig v(%s) val=%.3f %s=last\n", - from_pin_name, - from_threshold, - spiceTrans(from_rf)); - streamPrint(spice_stream_, - "+targ v(%s) val=%.3f %s=last\n", - to_pin_name, - to_threshold, - spiceTrans(to_rf)); + writeMeasureDelayStmt(from_path->pin(this), from_path->transition(this), + to_path->pin(this), to_path->transition(this), + stageName(stage)); } void WritePathSpice::writeMeasureSlewStmt(Stage stage, Path *path) { - const char *pin_name = network_->pathName(path->pin(this)); + const Pin *pin = path->pin(this); const RiseFall *rf = path->transition(this); - const char *spice_rf = spiceTrans(rf); - float lower = power_voltage_ * default_library_->slewLowerThreshold(rf); - float upper = power_voltage_ * default_library_->slewUpperThreshold(rf); - float threshold1, threshold2; - if (rf == RiseFall::rise()) { - threshold1 = lower; - threshold2 = upper; - } - else { - threshold1 = upper; - threshold2 = lower; - } - string stage_name = stageName(stage); - streamPrint(spice_stream_, - ".measure tran %s_%s_slew\n", - stage_name.c_str(), - pin_name); - streamPrint(spice_stream_, - "+trig v(%s) val=%.3f %s=last\n", - pin_name, - threshold1, - spice_rf); - streamPrint(spice_stream_, - "+targ v(%s) val=%.3f %s=last\n", - pin_name, - threshold2, - spice_rf); -} - -const char * -WritePathSpice::spiceTrans(const RiseFall *rf) -{ - if (rf == RiseFall::rise()) - return "RISE"; - else - return "FALL"; + string prefix = stageName(stage); + writeMeasureSlewStmt(pin, rf, prefix); } void @@ -866,6 +457,9 @@ WritePathSpice::writeStageSubckts() streamPrint(spice_stream_, "***************\n\n"); for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { + cap_index_ = 1; + res_index_ = 1; + volt_index_ = 1; if (stage == stageFirst()) writeInputStage(stage); else @@ -881,9 +475,9 @@ WritePathSpice::writeInputStage(Stage stage) // External driver not handled. const char *drvr_pin_name = stageDrvrPinName(stage); const char *load_pin_name = stageLoadPinName(stage); - string stage_name = stageName(stage); + string prefix = stageName(stage); streamPrint(spice_stream_, ".subckt %s %s %s\n", - stage_name.c_str(), + prefix.c_str(), drvr_pin_name, load_pin_name); writeStageParasitics(stage); @@ -900,625 +494,53 @@ WritePathSpice::writeGateStage(Stage stage) const char *drvr_pin_name = stageDrvrPinName(stage); const Pin *load_pin = stageLoadPin(stage); const char *load_pin_name = stageLoadPinName(stage); - streamPrint(spice_stream_, ".subckt stage%d %s %s %s", - stage, - input_pin_name, - drvr_pin_name, - load_pin_name); - StdStringSet off_path_names = stageOffPathPinNames(stage); - for (const string &off_path_name : off_path_names) - streamPrint(spice_stream_, " %s", off_path_name.c_str()); - streamPrint(spice_stream_, "\n"); + string subckt_name = "stage" + std::to_string(stage); - // Driver subckt call. Instance *inst = stageInstance(stage); LibertyPort *input_port = stageGateInputPort(stage); LibertyPort *drvr_port = stageDrvrPort(stage); + + streamPrint(spice_stream_, ".subckt %s %s %s %s\n", + subckt_name.c_str(), + input_pin_name, + drvr_pin_name, + load_pin_name); + + // Driver subckt call. streamPrint(spice_stream_, "* Gate %s %s -> %s\n", network_->pathName(inst), input_port->name(), drvr_port->name()); writeSubcktInst(input_pin); + + PathRef *drvr_path = stageDrvrPath(stage); + DcalcAPIndex dcalc_ap_index = drvr_path->dcalcAnalysisPt(this)->index(); + const RiseFall *drvr_rf = drvr_path->transition(this); + Edge *gate_edge = stageGateEdge(stage); + LibertyPortLogicValues port_values; - DcalcAPIndex dcalc_ap_index; - const Clock *clk; - int volt_index = 1; - gatePortValues(stage, port_values, clk, dcalc_ap_index); - writeSubcktInstVoltSrcs(stage, input_pin, volt_index, - port_values, clk, dcalc_ap_index); + bool is_clked; + gatePortValues(input_pin, drvr_pin, drvr_rf, gate_edge, + port_values, is_clked); + + const Clock *clk = (is_clked) ? stageDrvrPath(stage)->clock(this) : nullptr; + writeSubcktInstVoltSrcs(input_pin, port_values, clk, dcalc_ap_index); streamPrint(spice_stream_, "\n"); - port_values.clear(); - auto pin_iter = network_->connectedPinIterator(drvr_pin); - while (pin_iter->hasNext()) { - const Pin *pin = pin_iter->next(); - if (pin != drvr_pin - && pin != load_pin - && network_->direction(pin)->isAnyInput() - && !network_->isHierarchical(pin) - && !network_->isTopLevelPort(pin)) { - streamPrint(spice_stream_, "* Side load %s\n", network_->pathName(pin)); - writeSubcktInst(pin); - writeSubcktInstVoltSrcs(stage, pin, volt_index, port_values, nullptr, 0); - streamPrint(spice_stream_, "\n"); - } - } - delete pin_iter; - + writeSubcktInstLoads(drvr_pin, load_pin); writeStageParasitics(stage); streamPrint(spice_stream_, ".ends\n\n"); } -void -WritePathSpice::writeSubcktInst(const Pin *input_pin) -{ - const Instance *inst = network_->instance(input_pin); - const char *inst_name = network_->pathName(inst); - LibertyCell *cell = network_->libertyCell(inst); - const char *cell_name = cell->name(); - StringVector *spice_port_names = cell_spice_port_names_[cell_name]; - streamPrint(spice_stream_, "x%s", inst_name); - for (string subckt_port_name : *spice_port_names) { - const char *subckt_port_cname = subckt_port_name.c_str(); - Pin *pin = network_->findPin(inst, subckt_port_cname); - LibertyPgPort *pg_port = cell->findPgPort(subckt_port_cname); - const char *pin_name; - if (pin) { - pin_name = network_->pathName(pin); - streamPrint(spice_stream_, " %s", pin_name); - } - else if (pg_port) - streamPrint(spice_stream_, " %s/%s", inst_name, subckt_port_cname); - else if (stringEq(subckt_port_cname, power_name_) - || stringEq(subckt_port_cname, gnd_name_)) - streamPrint(spice_stream_, " %s/%s", inst_name, subckt_port_cname); - } - streamPrint(spice_stream_, " %s\n", cell_name); -} - -// Power/ground and input voltage sources. -void -WritePathSpice::writeSubcktInstVoltSrcs(Stage stage, - const Pin *input_pin, - int &volt_index, - LibertyPortLogicValues &port_values, - const Clock *clk, - DcalcAPIndex dcalc_ap_index) - -{ - const Instance *inst = network_->instance(input_pin); - LibertyCell *cell = network_->libertyCell(inst); - const char *cell_name = cell->name(); - StringVector *spice_port_names = cell_spice_port_names_[cell_name]; - - const Pin *drvr_pin = stageDrvrPin(stage); - const LibertyPort *input_port = network_->libertyPort(input_pin); - const LibertyPort *drvr_port = network_->libertyPort(drvr_pin); - const char *input_port_name = input_port->name(); - const char *drvr_port_name = drvr_port->name(); - const char *inst_name = network_->pathName(inst); - - debugPrint(debug_, "write_spice", 2, "subckt %s", cell->name()); - for (string subckt_port_sname : *spice_port_names) { - const char *subckt_port_name = subckt_port_sname.c_str(); - LibertyPgPort *pg_port = cell->findPgPort(subckt_port_name); - debugPrint(debug_, "write_spice", 2, " port %s%s", - subckt_port_name, - pg_port ? " pwr/gnd" : ""); - if (pg_port) - writeVoltageSource(inst_name, subckt_port_name, - pgPortVoltage(pg_port), volt_index); - else if (stringEq(subckt_port_name, power_name_)) - writeVoltageSource(inst_name, subckt_port_name, - power_voltage_, volt_index); - else if (stringEq(subckt_port_name, gnd_name_)) - writeVoltageSource(inst_name, subckt_port_name, - gnd_voltage_, volt_index); - else if (!(stringEq(subckt_port_name, input_port_name) - || stringEq(subckt_port_name, drvr_port_name))) { - // Input voltage to sensitize path from gate input to output. - LibertyPort *port = cell->findLibertyPort(subckt_port_name); - if (port - && port->direction()->isAnyInput()) { - const Pin *pin = network_->findPin(inst, port); - // Look for tie high/low or propagated constant values. - LogicValue port_value = sim_->logicValue(pin); - if (port_value == LogicValue::unknown) { - bool has_value; - LogicValue value; - port_values.findKey(port, value, has_value); - if (has_value) - port_value = value; - } - switch (port_value) { - case LogicValue::zero: - case LogicValue::unknown: - writeVoltageSource(cell, inst_name, subckt_port_name, - port->relatedGroundPin(), - gnd_voltage_, - volt_index); - break; - case LogicValue::one: - writeVoltageSource(cell, inst_name, subckt_port_name, - port->relatedPowerPin(), - power_voltage_, - volt_index); - break; - case LogicValue::rise: - writeClkedStepSource(pin, RiseFall::rise(), clk, - dcalc_ap_index, volt_index); - break; - case LogicValue::fall: - writeClkedStepSource(pin, RiseFall::fall(), clk, - dcalc_ap_index, volt_index); - break; - } - } - } - } -} - -// PWL voltage source that rises half way into the first clock cycle. -void -WritePathSpice::writeClkedStepSource(const Pin *pin, - const RiseFall *rf, - const Clock *clk, - DcalcAPIndex dcalc_ap_index, - int &volt_index) -{ - Vertex *vertex = graph_->pinLoadVertex(pin); - float slew = findSlew(vertex, rf, nullptr, dcalc_ap_index); - float time = clkWaveformTImeOffset(clk) + clk->period() / 2.0; - writeRampVoltSource(pin, rf, slew, time, volt_index); -} - -void -WritePathSpice::writeVoltageSource(const char *inst_name, - const char *port_name, - float voltage, - int &volt_index) -{ - streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n", - volt_index, - inst_name, port_name, - voltage); - volt_index++; -} - -void -WritePathSpice::writeVoltageSource(LibertyCell *cell, - const char *inst_name, - const char *subckt_port_name, - const char *pg_port_name, - float voltage, - int &volt_index) -{ - if (pg_port_name) { - LibertyPgPort *pg_port = cell->findPgPort(pg_port_name); - if (pg_port) - voltage = pgPortVoltage(pg_port); - else - report_->error(1603, "%s pg_port %s not found,", - cell->name(), - pg_port_name); - - } - writeVoltageSource(inst_name, subckt_port_name, voltage, volt_index); -} - -void -WritePathSpice::gatePortValues(Stage stage, - // Return values. - LibertyPortLogicValues &port_values, - const Clock *&clk, - DcalcAPIndex &dcalc_ap_index) -{ - clk = nullptr; - dcalc_ap_index = 0; - - Edge *gate_edge = stageGateEdge(stage); - LibertyPort *drvr_port = stageDrvrPort(stage); - if (gate_edge - && gate_edge->role()->genericRole() == TimingRole::regClkToQ()) - regPortValues(stage, port_values, clk, dcalc_ap_index); - else if (drvr_port->function()) { - Pin *input_pin = stageGateInputPin(stage); - LibertyPort *input_port = network_->libertyPort(input_pin); - Instance *inst = network_->instance(input_pin); - gatePortValues(inst, drvr_port->function(), input_port, port_values); - } -} - -void -WritePathSpice::regPortValues(Stage stage, - // Return values. - LibertyPortLogicValues &port_values, - const Clock *&clk, - DcalcAPIndex &dcalc_ap_index) -{ - LibertyPort *drvr_port = stageDrvrPort(stage); - FuncExpr *drvr_expr = drvr_port->function(); - if (drvr_expr) { - LibertyPort *q_port = drvr_expr->port(); - if (q_port) { - // Drvr (register/latch output) function should be a reference - // to an internal port like IQ or IQN. - LibertyCell *cell = stageLibertyCell(stage); - Sequential *seq = cell->outputPortSequential(q_port); - if (seq) { - PathRef *drvr_path = stageDrvrPath(stage); - const RiseFall *drvr_rf = drvr_path->transition(this); - seqPortValues(seq, drvr_rf, port_values); - clk = drvr_path->clock(this); - dcalc_ap_index = drvr_path->dcalcAnalysisPt(this)->index(); - } - else - report_->error(1604, "no register/latch found for path from %s to %s,", - stageGateInputPort(stage)->name(), - stageDrvrPort(stage)->name()); - } - } -} - -// Find the logic values for expression inputs to enable paths input_port. -void -WritePathSpice::gatePortValues(const Instance *inst, - FuncExpr *expr, - LibertyPort *input_port, - // Return values. - LibertyPortLogicValues &port_values) -{ - FuncExpr *left = expr->left(); - FuncExpr *right = expr->right(); - switch (expr->op()) { - case FuncExpr::op_port: - break; - case FuncExpr::op_not: - gatePortValues(inst, left, input_port, port_values); - break; - case FuncExpr::op_or: - if (left->hasPort(input_port) - && right->op() == FuncExpr::op_port) - port_values[right->port()] = LogicValue::zero; - else if (left->hasPort(input_port) - && right->op() == FuncExpr::op_not - && right->left()->op() == FuncExpr::op_port) - // input_port + !right_port - port_values[right->left()->port()] = LogicValue::one; - else if (right->hasPort(input_port) - && left->op() == FuncExpr::op_port) - port_values[left->port()] = LogicValue::zero; - else if (right->hasPort(input_port) - && left->op() == FuncExpr::op_not - && left->left()->op() == FuncExpr::op_port) - // input_port + !left_port - port_values[left->left()->port()] = LogicValue::one; - else { - gatePortValues(inst, left, input_port, port_values); - gatePortValues(inst, right, input_port, port_values); - } - break; - case FuncExpr::op_and: - if (left->hasPort(input_port) - && right->op() == FuncExpr::op_port) - port_values[right->port()] = LogicValue::one; - else if (left->hasPort(input_port) - && right->op() == FuncExpr::op_not - && right->left()->op() == FuncExpr::op_port) - // input_port * !right_port - port_values[right->left()->port()] = LogicValue::zero; - else if (right->hasPort(input_port) - && left->op() == FuncExpr::op_port) - port_values[left->port()] = LogicValue::one; - else if (right->hasPort(input_port) - && left->op() == FuncExpr::op_not - && left->left()->op() == FuncExpr::op_port) - // input_port * !left_port - port_values[left->left()->port()] = LogicValue::zero; - else { - gatePortValues(inst, left, input_port, port_values); - gatePortValues(inst, right, input_port, port_values); - } - break; - case FuncExpr::op_xor: - // Need to know timing arc sense to get this right. - if (left->port() == input_port - && right->op() == FuncExpr::op_port) - port_values[right->port()] = LogicValue::zero; - else if (right->port() == input_port - && left->op() == FuncExpr::op_port) - port_values[left->port()] = LogicValue::zero; - else { - gatePortValues(inst, left, input_port, port_values); - gatePortValues(inst, right, input_port, port_values); - } - break; - case FuncExpr::op_one: - case FuncExpr::op_zero: - break; - } -} - -void -WritePathSpice::seqPortValues(Sequential *seq, - const RiseFall *rf, - // Return values. - LibertyPortLogicValues &port_values) -{ - FuncExpr *data = seq->data(); - LibertyPort *port = onePort(data); - if (port) { - TimingSense sense = data->portTimingSense(port); - switch (sense) { - case TimingSense::positive_unate: - if (rf == RiseFall::rise()) - port_values[port] = LogicValue::rise; - else - port_values[port] = LogicValue::fall; - break; - case TimingSense::negative_unate: - if (rf == RiseFall::rise()) - port_values[port] = LogicValue::fall; - else - port_values[port] = LogicValue::rise; - break; - case TimingSense::non_unate: - case TimingSense::none: - case TimingSense::unknown: - default: - break; - } - } -} - -// Pick a port, any port... -LibertyPort * -WritePathSpice::onePort(FuncExpr *expr) -{ - FuncExpr *left = expr->left(); - FuncExpr *right = expr->right(); - LibertyPort *port; - switch (expr->op()) { - case FuncExpr::op_port: - return expr->port(); - case FuncExpr::op_not: - return onePort(left); - case FuncExpr::op_or: - case FuncExpr::op_and: - case FuncExpr::op_xor: - port = onePort(left); - if (port == nullptr) - port = onePort(right); - return port; - case FuncExpr::op_one: - case FuncExpr::op_zero: - default: - return nullptr; - } -} - void WritePathSpice::writeStageParasitics(Stage stage) { PathRef *drvr_path = stageDrvrPath(stage); - Pin *drvr_pin = stageDrvrPin(stage); - - Net *net = network_->net(drvr_pin); - const char *net_name = net ? network_->pathName(net) : network_->pathName(drvr_pin); - initNodeMap(net_name); - streamPrint(spice_stream_, "* Net %s\n", net_name); - DcalcAnalysisPt *dcalc_ap = drvr_path->dcalcAnalysisPt(this); ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt(); - Parasitic *parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); - if (parasitic) - writeStageParasiticNetwork(drvr_pin, parasitic); - else { - const RiseFall *drvr_rf = drvr_path->transition(this); - parasitic = parasitics_->findPiElmore(drvr_pin, drvr_rf, parasitic_ap); - if (parasitic) - writeStagePiElmore(drvr_pin, parasitic); - else { - streamPrint(spice_stream_, "* No parasitics found for this net.\n"); - writeNullParasitics(drvr_pin); - } - } -} - -void -WritePathSpice::writeStageParasiticNetwork(Pin *drvr_pin, - Parasitic *parasitic) -{ - Set reachable_pins; - int res_index = 1; - int cap_index = 1; - - // 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); - } - - 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. - auto pin_iter = network_->connectedPinIterator(drvr_pin); - while (pin_iter->hasNext()) { - const Pin *pin = pin_iter->next(); - if (pin != drvr_pin - && network_->isLoad(pin) - && !network_->isHierarchical(pin) - && !reachable_pins.hasKey(pin)) { - streamPrint(spice_stream_, "R%d %s %s %.3e\n", - res_index, - network_->pathName(drvr_pin), - network_->pathName(pin), - short_ckt_resistance_); - res_index++; - } - } - delete pin_iter; - - // Sort node capacitors for consistent regression results. - 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); - // Spice has a cow over zero value caps. - if (cap > 0.0) { - streamPrint(spice_stream_, "C%d %s 0 %.3e\n", - cap_index, - nodeName(node), - cap); - cap_index++; - } - } -} - -void -WritePathSpice::writeStagePiElmore(Pin *drvr_pin, - Parasitic *parasitic) -{ - float c2, rpi, c1; - parasitics_->piModel(parasitic, c2, rpi, c1); - const char *c1_node = "n1"; - streamPrint(spice_stream_, "RPI %s %s %.3e\n", - network_->pathName(drvr_pin), - c1_node, - rpi); - if (c2 > 0.0) - streamPrint(spice_stream_, "C2 %s 0 %.3e\n", - network_->pathName(drvr_pin), - c2); - if (c1 > 0.0) - streamPrint(spice_stream_, "C1 %s 0 %.3e\n", - c1_node, - c1); - - int load_index = 3; - auto pin_iter = network_->connectedPinIterator(drvr_pin); - while (pin_iter->hasNext()) { - const Pin *load_pin = pin_iter->next(); - if (load_pin != drvr_pin - && network_->isLoad(load_pin) - && !network_->isHierarchical(load_pin)) { - float elmore; - bool exists; - parasitics_->findElmore(parasitic, load_pin, elmore, exists); - if (exists) { - streamPrint(spice_stream_, "E%d el%d 0 %s 0 1.0\n", - load_index, - load_index, - network_->pathName(drvr_pin)); - streamPrint(spice_stream_, "R%d el%d %s 1.0\n", - load_index, - load_index, - network_->pathName(load_pin)); - streamPrint(spice_stream_, "C%d %s 0 %.3e\n", - load_index, - network_->pathName(load_pin), - elmore); - } - else - // Add resistor from drvr to load for missing elmore. - streamPrint(spice_stream_, "R%d %s %s %.3e\n", - load_index, - network_->pathName(drvr_pin), - network_->pathName(load_pin), - short_ckt_resistance_); - load_index++; - } - } - delete pin_iter; -} - -void -WritePathSpice::writeNullParasitics(Pin *drvr_pin) -{ - int res_index = 1; - // Add resistors from drvr to load for missing parasitic connections. - auto pin_iter = network_->connectedPinIterator(drvr_pin); - while (pin_iter->hasNext()) { - const Pin *load_pin = pin_iter->next(); - if (load_pin != drvr_pin - && network_->isLoad(load_pin) - && !network_->isHierarchical(load_pin)) { - streamPrint(spice_stream_, "R%d %s %s %.3e\n", - res_index, - network_->pathName(drvr_pin), - network_->pathName(load_pin), - short_ckt_resistance_); - res_index++; - } - } - delete pin_iter; -} - -void -WritePathSpice::initNodeMap(const char *net_name) -{ - stringDelete(net_name_); - node_map_.clear(); - next_node_index_ = 1; - net_name_ = stringCopy(net_name); -} - -const char * -WritePathSpice::nodeName(ParasiticNode *node) -{ - const Pin *pin = parasitics_->pin(node); - if (pin) - return parasitics_->name(node); - else { - int node_index; - bool node_index_exists; - node_map_.findKey(node, node_index, node_index_exists); - if (!node_index_exists) { - node_index = next_node_index_++; - node_map_[node] = node_index; - } - return stringPrintTmp("%s/%d", net_name_, node_index); - } + NetSet coupling_nets; + writeDrvrParasitics(stageDrvrPin(stage), drvr_path->transition(this), + coupling_nets, parasitic_ap); } //////////////////////////////////////////////////////////////// @@ -1528,64 +550,12 @@ WritePathSpice::nodeName(ParasiticNode *node) void WritePathSpice::writeSubckts() { - StdStringSet path_cell_names = findPathCellnames(); - findPathCellSubckts(path_cell_names); - - ifstream lib_subckts_stream(lib_subckt_filename_); - if (lib_subckts_stream.is_open()) { - ofstream subckts_stream(subckt_filename_); - if (subckts_stream.is_open()) { - string line; - while (getline(lib_subckts_stream, line)) { - // .subckt [args..] - StringVector tokens; - split(line, " \t", tokens); - if (tokens.size() >= 2 - && stringEqual(tokens[0].c_str(), ".subckt")) { - const char *cell_name = tokens[1].c_str(); - if (path_cell_names.find(cell_name) != path_cell_names.end()) { - subckts_stream << line << "\n"; - bool found_ends = false; - while (getline(lib_subckts_stream, line)) { - subckts_stream << line << "\n"; - if (stringBeginEqual(line.c_str(), ".ends")) { - subckts_stream << "\n"; - found_ends = true; - break; - } - } - if (!found_ends) - throw SubcktEndsMissing(cell_name, lib_subckt_filename_); - path_cell_names.erase(cell_name); - } - recordSpicePortNames(cell_name, tokens); - } - } - subckts_stream.close(); - lib_subckts_stream.close(); - - if (!path_cell_names.empty()) { - string missing_cells; - for (const string &cell_name : path_cell_names) { - missing_cells += "\n"; - missing_cells += cell_name; - } - report_->error(1605, "The subkct file %s is missing definitions for %s", - lib_subckt_filename_, - missing_cells.c_str()); - } - } - else { - lib_subckts_stream.close(); - throw FileNotWritable(subckt_filename_); - } - } - else - throw FileNotReadable(lib_subckt_filename_); + StdStringSet cell_names = findPathCellNames(); + writeSubckts(cell_names); } StdStringSet -WritePathSpice::findPathCellnames() +WritePathSpice::findPathCellNames() { StdStringSet path_cell_names; for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { @@ -1613,69 +583,6 @@ WritePathSpice::findPathCellnames() return path_cell_names; } -// Subckts can call subckts (asap7). -void -WritePathSpice::findPathCellSubckts(StdStringSet &path_cell_names) -{ - ifstream lib_subckts_stream(lib_subckt_filename_); - if (lib_subckts_stream.is_open()) { - string line; - while (getline(lib_subckts_stream, line)) { - // .subckt [args..] - StringVector tokens; - split(line, " \t", tokens); - if (tokens.size() >= 2 - && stringEqual(tokens[0].c_str(), ".subckt")) { - const char *cell_name = tokens[1].c_str(); - if (path_cell_names.find(cell_name) != path_cell_names.end()) { - // Scan the subckt definition for subckt calls. - string stmt; - while (getline(lib_subckts_stream, line)) { - if (line[0] == '+') - stmt += line.substr(1); - else { - // Process previous statement. - if (tolower(stmt[0]) == 'x') { - split(stmt, " \t", tokens); - string &subckt_cell = tokens[tokens.size() - 1]; - path_cell_names.insert(subckt_cell); - } - stmt = line; - } - if (stringBeginEqual(line.c_str(), ".ends")) - break; - } - } - } - } - } - else - throw FileNotReadable(lib_subckt_filename_); -} - -void -WritePathSpice::recordSpicePortNames(const char *cell_name, - StringVector &tokens) -{ - LibertyCell *cell = network_->findLibertyCell(cell_name); - if (cell) { - StringVector *spice_port_names = new StringVector; - for (size_t i = 2; i < tokens.size(); i++) { - const char *port_name = tokens[i].c_str(); - LibertyPort *port = cell->findLibertyPort(port_name); - LibertyPgPort *pg_port = cell->findPgPort(port_name); - if (port == nullptr - && pg_port == nullptr - && !stringEqual(port_name, power_name_) - && !stringEqual(port_name, gnd_name_)) - report_->error(1606, "subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground.", - cell_name, port_name); - spice_port_names->push_back(port_name); - } - cell_spice_port_names_[cell_name] = spice_port_names; - } -} - //////////////////////////////////////////////////////////////// Stage @@ -1826,26 +733,6 @@ WritePathSpice::stageLoadPinName(Stage stage) return network_->pathName(pin); } -StdStringSet -WritePathSpice::stageOffPathPinNames(Stage stage) -{ - StdStringSet pin_names; - if (off_path_pin_names_) { - const PathRef *path = stageDrvrPath(stage); - Vertex *drvr = path->vertex(this); - VertexOutEdgeIterator edge_iter(drvr, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - Vertex *load = edge->to(graph_); - const Pin *load_pin = load->pin(); - string load_pin_name = network_->pathName(load_pin); - if (off_path_pin_names_->find(load_pin_name) != off_path_pin_names_->end()) - pin_names.insert(load_pin_name); - } - } - return pin_names; -} - Instance * WritePathSpice::stageInstance(Stage stage) { @@ -1860,23 +747,4 @@ WritePathSpice::stageLibertyCell(Stage stage) return network_->libertyPort(pin)->libertyCell(); } -//////////////////////////////////////////////////////////////// - -// fprintf for c++ streams. -// Yes, I hate formatted output to ostream THAT much. -void -streamPrint(ofstream &stream, - const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - char *result = nullptr; - if (vasprintf(&result, fmt, args) == -1) - criticalError(267, "out of memory"); - stream << result; - free(result); - va_end(args); -} - } // namespace diff --git a/search/WriteSpice.cc b/search/WriteSpice.cc new file mode 100644 index 00000000..1f6539da --- /dev/null +++ b/search/WriteSpice.cc @@ -0,0 +1,1267 @@ +// 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 "WriteSpice.hh" + +#include "Debug.hh" +#include "Units.hh" +#include "TableModel.hh" +#include "TimingRole.hh" +#include "FuncExpr.hh" +#include "Sequential.hh" +#include "PortDirection.hh" +#include "TimingArc.hh" +#include "Liberty.hh" +#include "Network.hh" +#include "Graph.hh" +#include "Sim.hh" +#include "Clock.hh" +#include "PathVertex.hh" +#include "DcalcAnalysisPt.hh" +#include "Bdd.hh" + +namespace sta { + +using std::ifstream; + +Net * +pinNet(const Pin *pin, + const Network *network); + +class SubcktEndsMissing : public Exception +{ +public: + SubcktEndsMissing(const char *cell_name, + const char *subckt_filename); + const char *what() const noexcept; + +protected: + string what_; +}; + +SubcktEndsMissing::SubcktEndsMissing(const char *cell_name, + const char *subckt_filename) : + Exception() +{ + what_ = "spice subckt for cell "; + what_ += cell_name; + what_ += " missing .ends in "; + what_ += subckt_filename; +} + +const char * +SubcktEndsMissing::what() const noexcept +{ + return what_.c_str(); +} + +//////////////////////////////////////////////////////////////// + +WriteSpice::WriteSpice(const char *spice_filename, + const char *subckt_filename, + const char *lib_subckt_filename, + const char *model_filename, + const char *power_name, + const char *gnd_name, + CircuitSim ckt_sim, + const StaState *sta) : + StaState(sta), + spice_filename_(spice_filename), + subckt_filename_(subckt_filename), + lib_subckt_filename_(lib_subckt_filename), + model_filename_(model_filename), + power_name_(power_name), + gnd_name_(gnd_name), + ckt_sim_(ckt_sim), + default_library_(network_->defaultLibertyLibrary()), + short_ckt_resistance_(.0001), + cap_index_(1), + res_index_(1), + volt_index_(1), + next_node_index_(1), + bdd_(sta) +{ +} + +void +WriteSpice::initPowerGnd(const DcalcAnalysisPt *dcalc_ap) +{ + bool exists = false; + default_library_->supplyVoltage(power_name_, power_voltage_, exists); + if (!exists) { + const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); + if (op_cond == nullptr) + op_cond = network_->defaultLibertyLibrary()->defaultOperatingConditions(); + power_voltage_ = op_cond->voltage(); + } + default_library_->supplyVoltage(gnd_name_, gnd_voltage_, exists); + if (!exists) + gnd_voltage_ = 0.0; +} + +// Use c++17 fs::path(filename).stem() +static string +filenameStem(const char *filename) +{ + string filename1 = filename; + const size_t last_slash_idx = filename1.find_last_of("\\/"); + if (last_slash_idx != std::string::npos) + return filename1.substr(last_slash_idx + 1); + else + return filename1; +} + +void +WriteSpice::writeHeader(string &title, + float max_time, + float time_step) +{ + streamPrint(spice_stream_, "* %s\n", title.c_str()); + 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()); + + streamPrint(spice_stream_, ".tran %.3g %.3g\n", time_step, max_time); + // Suppress printing model parameters. + if (ckt_sim_ == CircuitSim::hspice) + streamPrint(spice_stream_, ".options nomod\n"); + streamPrint(spice_stream_, "\n"); + max_time_ = max_time; +} + +void +WriteSpice::writePrintStmt(StdStringSeq &node_names) +{ + streamPrint(spice_stream_, ".print tran"); + if (ckt_sim_ == CircuitSim::xyce) { + string csv_filename = replaceFileExt(spice_filename_, "csv"); + streamPrint(spice_stream_, " format=csv file=%s", csv_filename.c_str()); + writeGnuplotFile(node_names); + } + for (string &name : node_names) + streamPrint(spice_stream_, " v(%s)", name.c_str()); + streamPrint(spice_stream_, "\n\n"); +} + +string +WriteSpice::replaceFileExt(string filename, + const char *ext) +{ + size_t dot = filename.rfind('.'); + string ext_filename = filename.substr(0, dot + 1); + ext_filename += ext; + return ext_filename; +} + +// Write gnuplot command file for use with xyce csv file. +void +WriteSpice::writeGnuplotFile(StdStringSeq &node_nanes) +{ + string gnuplot_filename = replaceFileExt(spice_filename_, "gnuplot"); + string csv_filename = replaceFileExt(spice_filename_, "csv"); + ofstream gnuplot_stream; + gnuplot_stream.open(gnuplot_filename); + if (gnuplot_stream.is_open()) { + streamPrint(gnuplot_stream, "set datafile separator ','\n"); + streamPrint(gnuplot_stream, "set key autotitle columnhead\n"); + streamPrint(gnuplot_stream, "plot\\\n"); + streamPrint(gnuplot_stream, "\"%s\" using 1:2 with lines", + csv_filename.c_str()); + for (size_t i = 3; i <= node_nanes.size() + 1; i++) { + streamPrint(gnuplot_stream, ",\\\n"); + streamPrint(gnuplot_stream, "'' using 1:%lu with lines", i); + } + streamPrint(gnuplot_stream, "\n"); + streamPrint(gnuplot_stream, "pause mouse close\n"); + gnuplot_stream.close(); + } +} + +void +WriteSpice::writeSubckts(StdStringSet &cell_names) +{ + findCellSubckts(cell_names); + ifstream lib_subckts_stream(lib_subckt_filename_); + if (lib_subckts_stream.is_open()) { + ofstream subckts_stream(subckt_filename_); + if (subckts_stream.is_open()) { + string line; + while (getline(lib_subckts_stream, line)) { + // .subckt [args..] + StringVector tokens; + split(line, " \t", tokens); + if (tokens.size() >= 2 + && stringEqual(tokens[0].c_str(), ".subckt")) { + const char *cell_name = tokens[1].c_str(); + if (cell_names.find(cell_name) != cell_names.end()) { + subckts_stream << line << "\n"; + bool found_ends = false; + while (getline(lib_subckts_stream, line)) { + subckts_stream << line << "\n"; + if (stringBeginEqual(line.c_str(), ".ends")) { + subckts_stream << "\n"; + found_ends = true; + break; + } + } + if (!found_ends) + throw SubcktEndsMissing(cell_name, lib_subckt_filename_); + cell_names.erase(cell_name); + } + recordSpicePortNames(cell_name, tokens); + } + } + subckts_stream.close(); + lib_subckts_stream.close(); + + if (!cell_names.empty()) { + string missing_cells; + for (const string &cell_name : cell_names) { + missing_cells += "\n"; + missing_cells += cell_name; + } + report_->error(1605, "The subkct file %s is missing definitions for %s", + lib_subckt_filename_, + missing_cells.c_str()); + } + } + else { + lib_subckts_stream.close(); + throw FileNotWritable(subckt_filename_); + } + } + else + throw FileNotReadable(lib_subckt_filename_); +} + +void +WriteSpice::recordSpicePortNames(const char *cell_name, + StringVector &tokens) +{ + LibertyCell *cell = network_->findLibertyCell(cell_name); + if (cell) { + StringVector &spice_port_names = cell_spice_port_names_[cell_name]; + for (size_t i = 2; i < tokens.size(); i++) { + const char *port_name = tokens[i].c_str(); + LibertyPort *port = cell->findLibertyPort(port_name); + LibertyPgPort *pg_port = cell->findPgPort(port_name); + if (port == nullptr + && pg_port == nullptr + && !stringEqual(port_name, power_name_) + && !stringEqual(port_name, gnd_name_)) + report_->error(1606, "subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground.", + cell_name, port_name); + spice_port_names.push_back(port_name); + } + } +} + +// Subckts can call subckts (asap7). +void +WriteSpice::findCellSubckts(StdStringSet &cell_names) +{ + ifstream lib_subckts_stream(lib_subckt_filename_); + if (lib_subckts_stream.is_open()) { + string line; + while (getline(lib_subckts_stream, line)) { + // .subckt [args..] + StringVector tokens; + split(line, " \t", tokens); + if (tokens.size() >= 2 + && stringEqual(tokens[0].c_str(), ".subckt")) { + const char *cell_name = tokens[1].c_str(); + if (cell_names.find(cell_name) != cell_names.end()) { + // Scan the subckt definition for subckt calls. + string stmt; + while (getline(lib_subckts_stream, line)) { + if (line[0] == '+') + stmt += line.substr(1); + else { + // Process previous statement. + if (tolower(stmt[0]) == 'x') { + split(stmt, " \t", tokens); + string &subckt_cell = tokens[tokens.size() - 1]; + cell_names.insert(subckt_cell); + } + stmt = line; + } + if (stringBeginEqual(line.c_str(), ".ends")) + break; + } + } + } + } + } + else + throw FileNotReadable(lib_subckt_filename_); +} + +//////////////////////////////////////////////////////////////// + +void +WriteSpice::writeSubcktInst(const Pin *input_pin) +{ + const Instance *inst = network_->instance(input_pin); + const char *inst_name = network_->pathName(inst); + LibertyCell *cell = network_->libertyCell(inst); + const char *cell_name = cell->name(); + StringVector &spice_port_names = cell_spice_port_names_[cell_name]; + streamPrint(spice_stream_, "x%s", inst_name); + for (string subckt_port_name : spice_port_names) { + const char *subckt_port_cname = subckt_port_name.c_str(); + Pin *pin = network_->findPin(inst, subckt_port_cname); + LibertyPgPort *pg_port = cell->findPgPort(subckt_port_cname); + const char *pin_name; + if (pin) { + pin_name = network_->pathName(pin); + streamPrint(spice_stream_, " %s", pin_name); + } + else if (pg_port) + streamPrint(spice_stream_, " %s/%s", inst_name, subckt_port_cname); + else if (stringEq(subckt_port_cname, power_name_) + || stringEq(subckt_port_cname, gnd_name_)) + streamPrint(spice_stream_, " %s/%s", inst_name, subckt_port_cname); + } + streamPrint(spice_stream_, " %s\n", cell_name); +} + +// Power/ground and input voltage sources. +void +WriteSpice::writeSubcktInstVoltSrcs(const Pin *input_pin, + LibertyPortLogicValues &port_values, + const Clock *clk, + DcalcAPIndex dcalc_ap_index) +{ + const Instance *inst = network_->instance(input_pin); + LibertyCell *cell = network_->libertyCell(inst); + const char *cell_name = cell->name(); + StringVector &spice_port_names = cell_spice_port_names_[cell_name]; + + const LibertyPort *input_port = network_->libertyPort(input_pin); + const char *inst_name = network_->pathName(inst); + + debugPrint(debug_, "write_spice", 2, "subckt %s", cell->name()); + for (string subckt_port_sname : spice_port_names) { + const char *subckt_port_name = subckt_port_sname.c_str(); + LibertyPort *port = cell->findLibertyPort(subckt_port_name); + LibertyPgPort *pg_port = cell->findPgPort(subckt_port_name); + debugPrint(debug_, "write_spice", 2, " port %s%s", + subckt_port_name, + pg_port ? " pwr/gnd" : ""); + if (pg_port) + writeVoltageSource(inst_name, subckt_port_name, + pgPortVoltage(pg_port)); + else if (stringEq(subckt_port_name, power_name_)) + writeVoltageSource(inst_name, subckt_port_name, power_voltage_); + else if (stringEq(subckt_port_name, gnd_name_)) + writeVoltageSource(inst_name, subckt_port_name, gnd_voltage_); + else if (port + && port != input_port + && port->direction()->isAnyInput()) { + // Input voltage to sensitize path from gate input to output. + const Pin *pin = network_->findPin(inst, port); + // Look for tie high/low or propagated constant values. + LogicValue port_value = sim_->logicValue(pin); + if (port_value == LogicValue::unknown) { + bool has_value; + LogicValue value; + port_values.findKey(port, value, has_value); + if (has_value) + port_value = value; + } + switch (port_value) { + case LogicValue::zero: + case LogicValue::unknown: + writeVoltageSource(cell, inst_name, subckt_port_name, + port->relatedGroundPin(), + gnd_voltage_); + break; + case LogicValue::one: + writeVoltageSource(cell, inst_name, subckt_port_name, + port->relatedPowerPin(), + power_voltage_); + break; + case LogicValue::rise: + writeClkedStepSource(pin, RiseFall::rise(), clk, dcalc_ap_index); + + break; + case LogicValue::fall: + writeClkedStepSource(pin, RiseFall::fall(), clk, dcalc_ap_index); + break; + } + } + } +} + +void +WriteSpice::writeVoltageSource(const char *inst_name, + const char *port_name, + float voltage) +{ + string node_name = inst_name; + node_name += '/'; + node_name += port_name; + writeVoltageSource(node_name.c_str(), voltage); +} + +void +WriteSpice::writeVoltageSource(LibertyCell *cell, + const char *inst_name, + const char *subckt_port_name, + const char *pg_port_name, + float voltage) +{ + if (pg_port_name) { + LibertyPgPort *pg_port = cell->findPgPort(pg_port_name); + if (pg_port) + voltage = pgPortVoltage(pg_port); + else + report_->error(1603, "%s pg_port %s not found,", + cell->name(), + pg_port_name); + + } + writeVoltageSource(inst_name, subckt_port_name, voltage); +} + +float +WriteSpice::pgPortVoltage(LibertyPgPort *pg_port) +{ + LibertyLibrary *liberty = pg_port->cell()->libertyLibrary(); + float voltage = 0.0; + bool exists; + const char *voltage_name = pg_port->voltageName(); + if (voltage_name) { + liberty->supplyVoltage(voltage_name, voltage, exists); + if (!exists) { + if (stringEqual(voltage_name, power_name_)) + voltage = power_voltage_; + else if (stringEqual(voltage_name, gnd_name_)) + voltage = gnd_voltage_; + else + report_->error(1601 , "pg_pin %s/%s voltage %s not found,", + pg_port->cell()->name(), + pg_port->name(), + voltage_name); + } + } + else + report_->error(1602, "Liberty pg_port %s/%s missing voltage_name attribute,", + pg_port->cell()->name(), + pg_port->name()); + return voltage; +} + +// PWL voltage source that rises half way into the first clock cycle. +void +WriteSpice::writeClkedStepSource(const Pin *pin, + const RiseFall *rf, + const Clock *clk, + DcalcAPIndex dcalc_ap_index) +{ + Vertex *vertex = graph_->pinLoadVertex(pin); + float slew = findSlew(vertex, rf, nullptr, dcalc_ap_index); + float time = clkWaveformTimeOffset(clk) + clk->period() / 2.0; + writeRampVoltSource(pin, rf, time, slew); +} + +float +WriteSpice::clkWaveformTimeOffset(const Clock *clk) +{ + return clk->period() / 10; +} + +//////////////////////////////////////////////////////////////// + +float +WriteSpice::findSlew(Vertex *vertex, + const RiseFall *rf, + TimingArc *next_arc, + DcalcAPIndex dcalc_ap_index) +{ + float slew = delayAsFloat(graph_->slew(vertex, rf, dcalc_ap_index)); + if (slew == 0.0 && next_arc) + slew = slewAxisMinValue(next_arc); + if (slew == 0.0) + slew = units_->timeUnit()->scale(); + return slew; +} + +// Look up the smallest slew axis value in the timing arc delay table. +float +WriteSpice::slewAxisMinValue(TimingArc *arc) +{ + GateTableModel *gate_model = dynamic_cast(arc->model()); + if (gate_model) { + const TableModel *model = gate_model->delayModel(); + const TableAxis *axis1 = model->axis1(); + TableAxisVariable var1 = axis1->variable(); + if (var1 == TableAxisVariable::input_transition_time + || var1 == TableAxisVariable::input_net_transition) + return axis1->axisValue(0); + + const TableAxis *axis2 = model->axis2(); + TableAxisVariable var2 = axis2->variable(); + if (var2 == TableAxisVariable::input_transition_time + || var2 == TableAxisVariable::input_net_transition) + return axis2->axisValue(0); + + const TableAxis *axis3 = model->axis3(); + TableAxisVariable var3 = axis3->variable(); + if (var3 == TableAxisVariable::input_transition_time + || var3 == TableAxisVariable::input_net_transition) + return axis3->axisValue(0); + } + return 0.0; +} + +//////////////////////////////////////////////////////////////// + +void +WriteSpice::writeDrvrParasitics(const Pin *drvr_pin, + const RiseFall *drvr_rf, + const NetSet &aggressor_nets, + const ParasiticAnalysisPt *parasitic_ap) +{ + Net *net = network_->net(drvr_pin); + const char *net_name = net ? network_->pathName(net) : network_->pathName(drvr_pin); + streamPrint(spice_stream_, "* Net %s\n", net_name); + + Parasitic *parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); + node_map_.clear(); + next_node_index_ = 1; + if (parasitic) + writeParasiticNetwork(drvr_pin, parasitic, aggressor_nets); + else { + parasitic = parasitics_->findPiElmore(drvr_pin, drvr_rf, parasitic_ap); + if (parasitic) + writePiElmore(drvr_pin, parasitic); + else { + streamPrint(spice_stream_, "* No parasitics found for this net.\n"); + writeNullParasitic(drvr_pin); + } + } +} + +void +WriteSpice::writeParasiticNetwork(const Pin *drvr_pin, + const Parasitic *parasitic, + const NetSet &coupling_nets) +{ + Set reachable_pins; + // 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); + + // Necessary but not sufficient. Need a DFS. + const Pin *pin1 = parasitics_->pin(node1); + if (pin1) + reachable_pins.insert(pin1); + const Pin *pin2 = parasitics_->pin(node2); + if (pin2) + reachable_pins.insert(pin2); + } + + // Add resistors from drvr to load for missing parasitic connections. + auto pin_iter = network_->connectedPinIterator(drvr_pin); + while (pin_iter->hasNext()) { + const Pin *pin = pin_iter->next(); + if (pin != drvr_pin + && network_->isLoad(pin) + && !network_->isHierarchical(pin) + && !reachable_pins.hasKey(pin)) { + streamPrint(spice_stream_, "R%d %s %s %.3e\n", + res_index_++, + network_->pathName(drvr_pin), + network_->pathName(pin), + short_ckt_resistance_); + } + } + delete pin_iter; + + // Sort coupling capacitors consistent regression results. + ParasiticCapacitorSeq capacitors = parasitics_->capacitors(parasitic); + sort(capacitors.begin(), capacitors.end(), + [=] (const ParasiticCapacitor *c1, + const ParasiticCapacitor *c2) { + return parasitics_->id(c1) < parasitics_->id(c2); + }); + const Net *net = pinNet(drvr_pin, network_); + for (ParasiticCapacitor *capacitor : capacitors) { + ParasiticNode *node1 = parasitics_->node1(capacitor); + ParasiticNode *node2 = parasitics_->node2(capacitor); + float cap = parasitics_->value(capacitor); + const Net *net1 = node1 ? parasitics_->net(node1, network_) : nullptr; + const Net *net2 = node2 ? parasitics_->net(node2, network_) : nullptr; + const ParasiticNode *net_node = nullptr; + const char *coupling_name; + if (net1 == net) { + net_node = node1; + coupling_name = net2 && coupling_nets.hasKey(net2) ? nodeName(node2) : "0"; + } + else if (net2 == net) { + net_node = node2; + coupling_name = net1 && coupling_nets.hasKey(net1) ? nodeName(node1) : "0"; + } + if (net_node) + streamPrint(spice_stream_, "C%d %s %s %.3e\n", + cap_index_++, + nodeName(net_node), + coupling_name, + cap); + } + + // Sort nodes for consistent regression results. + 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); + // Spice has a cow over zero value caps. + if (cap > 0.0) { + streamPrint(spice_stream_, "C%d %s 0 %.3e\n", + cap_index_++, + nodeName(node), + cap); + } + } +} + +Net * +pinNet(const Pin *pin, + const Network *network) +{ + 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) + return network->net(term); + } + return net; +} + +const char * +WriteSpice::nodeName(const ParasiticNode *node) +{ + const Pin *pin = parasitics_->pin(node); + if (pin) + return parasitics_->name(node); + else { + int node_index; + auto index_itr = node_map_.find(node); + if (index_itr == node_map_.end()) { + node_index = next_node_index_++; + node_map_[node] = node_index; + } + else + node_index = index_itr->second; + const Net *net = parasitics_->net(node, network_); + const char *net_name = network_->pathName(net); + return stringPrintTmp("%s/%d", net_name, node_index); + } +} + +void +WriteSpice::writePiElmore(const Pin *drvr_pin, + const Parasitic *parasitic) +{ + float c2, rpi, c1; + parasitics_->piModel(parasitic, c2, rpi, c1); + const char *c1_node = "n1"; + streamPrint(spice_stream_, "RPI %s %s %.3e\n", + network_->pathName(drvr_pin), + c1_node, + rpi); + if (c2 > 0.0) + streamPrint(spice_stream_, "C2 %s 0 %.3e\n", + network_->pathName(drvr_pin), + c2); + if (c1 > 0.0) + streamPrint(spice_stream_, "C1 %s 0 %.3e\n", + c1_node, + c1); + + int load_index = 3; + auto pin_iter = network_->connectedPinIterator(drvr_pin); + while (pin_iter->hasNext()) { + const Pin *load_pin = pin_iter->next(); + if (load_pin != drvr_pin + && network_->isLoad(load_pin) + && !network_->isHierarchical(load_pin)) { + float elmore; + bool exists; + parasitics_->findElmore(parasitic, load_pin, elmore, exists); + if (exists) { + streamPrint(spice_stream_, "E%d el%d 0 %s 0 1.0\n", + load_index, + load_index, + network_->pathName(drvr_pin)); + streamPrint(spice_stream_, "R%d el%d %s 1.0\n", + load_index, + load_index, + network_->pathName(load_pin)); + streamPrint(spice_stream_, "C%d %s 0 %.3e\n", + load_index, + network_->pathName(load_pin), + elmore); + } + else + // Add resistor from drvr to load for missing elmore. + streamPrint(spice_stream_, "R%d %s %s %.3e\n", + load_index, + network_->pathName(drvr_pin), + network_->pathName(load_pin), + short_ckt_resistance_); + load_index++; + } + } + delete pin_iter; +} + +void +WriteSpice::writeNullParasitic(const Pin *drvr_pin) +{ + // Add resistors from drvr to load for missing parasitic connections. + auto pin_iter = network_->connectedPinIterator(drvr_pin); + while (pin_iter->hasNext()) { + const Pin *load_pin = pin_iter->next(); + if (load_pin != drvr_pin + && network_->isLoad(load_pin) + && !network_->isHierarchical(load_pin)) { + streamPrint(spice_stream_, "R%d %s %s %.3e\n", + res_index_++, + network_->pathName(drvr_pin), + network_->pathName(load_pin), + short_ckt_resistance_); + } + } + delete pin_iter; +} + +//////////////////////////////////////////////////////////////// + +void +WriteSpice::writeVoltageSource(const char *node_name, + float voltage) +{ + streamPrint(spice_stream_, "v%d %s 0 %.3f\n", + volt_index_++, + node_name, + voltage); +} + +void +WriteSpice::writeWaveformVoltSource(const Pin *pin, + DriverWaveform *drvr_waveform, + const RiseFall *rf, + float delay, + float slew) +{ + float volt0, volt1, volt_factor; + if (rf == RiseFall::rise()) { + volt0 = gnd_voltage_; + volt1 = power_voltage_; + volt_factor = power_voltage_; + } + else { + volt0 = power_voltage_; + volt1 = gnd_voltage_; + volt_factor = -power_voltage_; + } + streamPrint(spice_stream_, "v%d %s 0 pwl(\n", + volt_index_++, + network_->pathName(pin)); + streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0); + Table1 waveform = drvr_waveform->waveform(slew); + const TableAxis *time_axis = waveform.axis1(); + for (size_t time_index = 0; time_index < time_axis->size(); time_index++) { + float time = delay + time_axis->axisValue(time_index); + float wave_volt = waveform.value(time_index); + float volt = volt0 + wave_volt * volt_factor; + streamPrint(spice_stream_, "+%.3e %.3e\n", time, volt); + } + streamPrint(spice_stream_, "+%.3e %.3e\n", max_time_, volt1); + streamPrint(spice_stream_, "+)\n"); +} + +void +WriteSpice::writeRampVoltSource(const Pin *pin, + const RiseFall *rf, + float time, + float slew) +{ + float volt0, volt1; + if (rf == RiseFall::rise()) { + volt0 = gnd_voltage_; + volt1 = power_voltage_; + } + else { + volt0 = power_voltage_; + volt1 = gnd_voltage_; + } + streamPrint(spice_stream_, "v%d %s 0 pwl(\n", + volt_index_++, + network_->pathName(pin)); + streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0); + writeWaveformEdge(rf, time, slew); + streamPrint(spice_stream_, "+%.3e %.3e\n", max_time_, volt1); + streamPrint(spice_stream_, "+)\n"); +} + +// Write PWL rise/fall edge that crosses threshold at time. +void +WriteSpice::writeWaveformEdge(const RiseFall *rf, + float time, + float slew) +{ + float volt0, volt1; + if (rf == RiseFall::rise()) { + volt0 = gnd_voltage_; + volt1 = power_voltage_; + } + else { + volt0 = power_voltage_; + volt1 = gnd_voltage_; + } + float threshold = default_library_->inputThreshold(rf); + float dt = railToRailSlew(slew, rf); + float time0 = time - dt * threshold; + float time1 = time0 + dt; + if (time0 > 0.0) + streamPrint(spice_stream_, "+%.3e %.3e\n", time0, volt0); + streamPrint(spice_stream_, "+%.3e %.3e\n", time1, volt1); +} + +float +WriteSpice::railToRailSlew(float slew, + const RiseFall *rf) +{ + float lower = default_library_->slewLowerThreshold(rf); + float upper = default_library_->slewUpperThreshold(rf); + return slew / (upper - lower); +} + +//////////////////////////////////////////////////////////////// + +// Find the logic values for expression inputs to enable paths from input_port. +void +WriteSpice::gatePortValues(const Pin *input_pin, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Edge *gate_edge, + // Return values. + LibertyPortLogicValues &port_values, + bool &is_clked) +{ + is_clked = false; + const Instance *inst = network_->instance(input_pin); + const LibertyPort *input_port = network_->libertyPort(input_pin); + const LibertyPort *drvr_port = network_->libertyPort(drvr_pin); + const FuncExpr *drvr_func = drvr_port->function(); + if (drvr_func) { + if (gate_edge + && gate_edge->role()->genericRole() == TimingRole::regClkToQ()) + regPortValues(input_pin, drvr_rf, drvr_port, drvr_func, + port_values, is_clked); + else + gatePortValues(inst, drvr_func, input_port, port_values); + } +} + +#if CUDD + +void +WriteSpice::gatePortValues(const Instance *, + const FuncExpr *expr, + const LibertyPort *input_port, + // Return values. + LibertyPortLogicValues &port_values) +{ + DdNode *bdd = bdd_.funcBdd(expr); + DdNode *input_node = bdd_.findNode(input_port); + unsigned input_node_index = Cudd_NodeReadIndex(input_node); + DdManager *cudd_mgr = bdd_.cuddMgr(); + DdNode *diff = Cudd_bddBooleanDiff(cudd_mgr, bdd, input_node_index); + int *cube; + CUDD_VALUE_TYPE value; + DdGen *cube_gen = Cudd_FirstCube(cudd_mgr, diff, &cube, &value); + + FuncExprPortIterator port_iter(expr); + while (port_iter.hasNext()) { + const LibertyPort *port = port_iter.next(); + if (port != input_port) { + DdNode *port_node = bdd_.findNode(port); + int var_index = Cudd_NodeReadIndex(port_node); + LogicValue value; + switch (cube[var_index]) { + case 0: + value = LogicValue::zero; + break; + case 1: + value = LogicValue::one; + break; + case 2: + default: + value = LogicValue::unknown; + break; + } + port_values[port] = value; + } + } + Cudd_GenFree(cube_gen); + Cudd_Ref(diff); + bdd_.clearVarMap(); +} + +#else + +void +WriteSpice::gatePortValues(const Instance *inst, + const FuncExpr *expr, + const LibertyPort *input_port, + // Return values. + LibertyPortLogicValues &port_values) +{ + FuncExpr *left = expr->left(); + FuncExpr *right = expr->right(); + switch (expr->op()) { + case FuncExpr::op_port: + break; + case FuncExpr::op_not: + gatePortValues(inst, left, input_port, port_values); + break; + case FuncExpr::op_or: + if (left->hasPort(input_port) + && right->op() == FuncExpr::op_port) { + gatePortValues(inst, left, input_port, port_values); + port_values[right->port()] = LogicValue::zero; + } + else if (left->hasPort(input_port) + && right->op() == FuncExpr::op_not + && right->left()->op() == FuncExpr::op_port) { + // input_port + !right_port + gatePortValues(inst, left, input_port, port_values); + port_values[right->left()->port()] = LogicValue::one; + } + else if (right->hasPort(input_port) + && left->op() == FuncExpr::op_port) { + gatePortValues(inst, right, input_port, port_values); + port_values[left->port()] = LogicValue::zero; + } + else if (right->hasPort(input_port) + && left->op() == FuncExpr::op_not + && left->left()->op() == FuncExpr::op_port) { + // input_port + !left_port + gatePortValues(inst, right, input_port, port_values); + port_values[left->left()->port()] = LogicValue::one; + } + else { + gatePortValues(inst, left, input_port, port_values); + gatePortValues(inst, right, input_port, port_values); + } + break; + case FuncExpr::op_and: + if (left->hasPort(input_port) + && right->op() == FuncExpr::op_port) { + gatePortValues(inst, left, input_port, port_values); + port_values[right->port()] = LogicValue::one; + } + else if (left->hasPort(input_port) + && right->op() == FuncExpr::op_not + && right->left()->op() == FuncExpr::op_port) { + // input_port * !right_port + gatePortValues(inst, left, input_port, port_values); + port_values[right->left()->port()] = LogicValue::zero; + } + else if (right->hasPort(input_port) + && left->op() == FuncExpr::op_port) { + gatePortValues(inst, right, input_port, port_values); + port_values[left->port()] = LogicValue::one; + } + else if (right->hasPort(input_port) + && left->op() == FuncExpr::op_not + && left->left()->op() == FuncExpr::op_port) { + // input_port * !left_port + gatePortValues(inst, right, input_port, port_values); + port_values[left->left()->port()] = LogicValue::zero; + } + else { + gatePortValues(inst, left, input_port, port_values); + gatePortValues(inst, right, input_port, port_values); + } + break; + case FuncExpr::op_xor: + // Need to know timing arc sense to get this right. + if (left->port() == input_port + && right->op() == FuncExpr::op_port) + port_values[right->port()] = LogicValue::zero; + else if (right->port() == input_port + && left->op() == FuncExpr::op_port) + port_values[left->port()] = LogicValue::zero; + else { + gatePortValues(inst, left, input_port, port_values); + gatePortValues(inst, right, input_port, port_values); + } + break; + case FuncExpr::op_one: + case FuncExpr::op_zero: + break; + } +} + +#endif + +void +WriteSpice::regPortValues(const Pin *input_pin, + const RiseFall *drvr_rf, + const LibertyPort *drvr_port, + const FuncExpr *drvr_func, + // Return values. + LibertyPortLogicValues &port_values, + bool &is_clked) +{ + is_clked = false; + LibertyPort *q_port = drvr_func->port(); + if (q_port) { + // Drvr (register/latch output) function should be a reference + // to an internal port like IQ or IQN. + LibertyCell *cell = drvr_port->libertyCell(); + Sequential *seq = cell->outputPortSequential(q_port); + if (seq) { + seqPortValues(seq, drvr_rf, port_values); + is_clked = true; + } + else { + const LibertyPort *input_port = network_->libertyPort(input_pin); + report_->error(1604, "no register/latch found for path from %s to %s,", + input_port->name(), + drvr_port->name()); + } + } +} + +void +WriteSpice::seqPortValues(Sequential *seq, + const RiseFall *rf, + // Return values. + LibertyPortLogicValues &port_values) +{ + FuncExpr *data = seq->data(); + LibertyPort *port = onePort(data); + if (port) { + TimingSense sense = data->portTimingSense(port); + switch (sense) { + case TimingSense::positive_unate: + if (rf == RiseFall::rise()) + port_values[port] = LogicValue::rise; + else + port_values[port] = LogicValue::fall; + break; + case TimingSense::negative_unate: + if (rf == RiseFall::rise()) + port_values[port] = LogicValue::fall; + else + port_values[port] = LogicValue::rise; + break; + case TimingSense::non_unate: + case TimingSense::none: + case TimingSense::unknown: + default: + break; + } + } +} + +// Pick a port, any port... +LibertyPort * +WriteSpice::onePort(FuncExpr *expr) +{ + FuncExpr *left = expr->left(); + FuncExpr *right = expr->right(); + LibertyPort *port; + switch (expr->op()) { + case FuncExpr::op_port: + return expr->port(); + case FuncExpr::op_not: + return onePort(left); + case FuncExpr::op_or: + case FuncExpr::op_and: + case FuncExpr::op_xor: + port = onePort(left); + if (port == nullptr) + port = onePort(right); + return port; + case FuncExpr::op_one: + case FuncExpr::op_zero: + default: + return nullptr; + } +} + +//////////////////////////////////////////////////////////////// + +PinSeq +WriteSpice::drvrLoads(const Pin *drvr_pin) +{ + PinSeq loads; + Vertex *drvr_vertex = graph_->pinDrvrVertex(drvr_pin); + 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(); + loads.push_back(load_pin); + } + } + return loads; +} + +void +WriteSpice::writeSubcktInstLoads(const Pin *drvr_pin, + const Pin *exclude) +{ + streamPrint(spice_stream_, "* Load pins\n"); + PinSeq drvr_loads = drvrLoads(drvr_pin); + // Do not sensitize side load gates. + LibertyPortLogicValues port_values; + for (const Pin *load_pin : drvr_loads) { + if (load_pin != exclude + && network_->direction(load_pin)->isAnyInput() + && !network_->isHierarchical(load_pin) + && !network_->isTopLevelPort(load_pin)) { + writeSubcktInst(load_pin); + writeSubcktInstVoltSrcs(load_pin, port_values, nullptr, 0); + streamPrint(spice_stream_, "\n"); + } + } +} + +//////////////////////////////////////////////////////////////// + +void +WriteSpice::writeMeasureDelayStmt(const Pin *from_pin, + const RiseFall *from_rf, + const Pin *to_pin, + const RiseFall *to_rf, + string prefix) +{ + const char *from_pin_name = network_->pathName(from_pin); + float from_threshold = power_voltage_ * default_library_->inputThreshold(from_rf); + const char *to_pin_name = network_->pathName(to_pin); + float to_threshold = power_voltage_ * default_library_->inputThreshold(to_rf); + streamPrint(spice_stream_, + ".measure tran %s_%s_delay_%s\n", + prefix.c_str(), + from_pin_name, + to_pin_name); + streamPrint(spice_stream_, + "+trig v(%s) val=%.3f %s=last\n", + from_pin_name, + from_threshold, + spiceTrans(from_rf)); + streamPrint(spice_stream_, + "+targ v(%s) val=%.3f %s=last\n", + to_pin_name, + to_threshold, + spiceTrans(to_rf)); +} + +void +WriteSpice::writeMeasureSlewStmt(const Pin *pin, + const RiseFall *rf, + string prefix) +{ + const char *pin_name = network_->pathName(pin); + const char *spice_rf = spiceTrans(rf); + float lower = power_voltage_ * default_library_->slewLowerThreshold(rf); + float upper = power_voltage_ * default_library_->slewUpperThreshold(rf); + float threshold1, threshold2; + if (rf == RiseFall::rise()) { + threshold1 = lower; + threshold2 = upper; + } + else { + threshold1 = upper; + threshold2 = lower; + } + streamPrint(spice_stream_, + ".measure tran %s_%s_slew\n", + prefix.c_str(), + pin_name); + streamPrint(spice_stream_, + "+trig v(%s) val=%.3f %s=last\n", + pin_name, + threshold1, + spice_rf); + streamPrint(spice_stream_, + "+targ v(%s) val=%.3f %s=last\n", + pin_name, + threshold2, + spice_rf); +} + +//////////////////////////////////////////////////////////////// + + +const char * +WriteSpice::spiceTrans(const RiseFall *rf) +{ + if (rf == RiseFall::rise()) + return "RISE"; + else + return "FALL"; +} + +// fprintf for c++ streams. +// Yes, I hate formatted output to ostream THAT much. +void +streamPrint(ofstream &stream, + const char *fmt, + ...) +{ + va_list args; + va_start(args, fmt); + char *result = nullptr; + if (vasprintf(&result, fmt, args) == -1) + criticalError(267, "out of memory"); + stream << result; + free(result); + va_end(args); +} + +} diff --git a/search/WriteSpice.hh b/search/WriteSpice.hh new file mode 100644 index 00000000..9d45d55f --- /dev/null +++ b/search/WriteSpice.hh @@ -0,0 +1,191 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2024, Parallax Software, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include +#include +#include +#include + +#include "StaState.hh" +#include "StringSet.hh" +#include "Liberty.hh" +#include "GraphClass.hh" +#include "Parasitics.hh" +#include "Bdd.hh" +#include "CircuitSim.hh" + +namespace sta { + +using std::string; +using std::ofstream; + +typedef std::map ParasiticNodeMap; +typedef Map CellSpicePortNames; +typedef Map LibertyPortLogicValues; +typedef std::vector StdStringSeq; + +// Utilities for writing a spice deck. +class WriteSpice : public StaState +{ +public: + WriteSpice(const char *spice_filename, + const char *subckt_filename, + const char *lib_subckt_filename, + const char *model_filename, + const char *power_name, + const char *gnd_name, + CircuitSim ckt_sim, + const StaState *sta); + +protected: + void initPowerGnd(const DcalcAnalysisPt *dcalc_ap); + void writeHeader(string &title, + float max_time, + float time_step); + void writePrintStmt(StdStringSeq &node_names); + void writeGnuplotFile(StdStringSeq &node_nanes); + void writeSubckts(StdStringSet &cell_names); + void findCellSubckts(StdStringSet &cell_names); + void recordSpicePortNames(const char *cell_name, + StringVector &tokens); + void writeSubcktInst(const Pin *input_pin); + void writeSubcktInstVoltSrcs(const Pin *input_pin, + LibertyPortLogicValues &port_values, + const Clock *clk, + DcalcAPIndex dcalc_ap_index); + float pgPortVoltage(LibertyPgPort *pg_port); + void writeVoltageSource(const char *inst_name, + const char *port_name, + float voltage); + void writeVoltageSource(LibertyCell *cell, + const char *inst_name, + const char *subckt_port_name, + const char *pg_port_name, + float voltage); + void writeClkedStepSource(const Pin *pin, + const RiseFall *rf, + const Clock *clk, + DcalcAPIndex dcalc_ap_index); + void writeDrvrParasitics(const Pin *drvr_pin, + const RiseFall *drvr_rf, + // Nets with parasitics to include coupling caps to. + const NetSet &coupling_nets, + const ParasiticAnalysisPt *parasitic_ap); + void writeParasiticNetwork(const Pin *drvr_pin, + const Parasitic *parasitic, + const NetSet &aggressor_nets); + void writePiElmore(const Pin *drvr_pin, + const Parasitic *parasitic); + void writeNullParasitic(const Pin *drvr_pin); + const char *nodeName(const ParasiticNode *node); + + void writeVoltageSource(const char *node_name, + float voltage); + void writeRampVoltSource(const Pin *pin, + const RiseFall *rf, + float time, + float slew); + void writeWaveformVoltSource(const Pin *pin, + DriverWaveform *drvr_waveform, + const RiseFall *rf, + float delay, + float slew); + void writeWaveformEdge(const RiseFall *rf, + float time, + float slew); + float railToRailSlew(float slew, + const RiseFall *rf); + void seqPortValues(Sequential *seq, + const RiseFall *rf, + // Return values. + LibertyPortLogicValues &port_values); + LibertyPort *onePort(FuncExpr *expr); + void writeMeasureDelayStmt(const Pin *from_pin, + const RiseFall *from_rf, + const Pin *to_pin, + const RiseFall *to_rf, + string prefix); + void writeMeasureSlewStmt(const Pin *pin, + const RiseFall *rf, + string prefix); + const char *spiceTrans(const RiseFall *rf); + float findSlew(Vertex *vertex, + const RiseFall *rf, + TimingArc *next_arc, + DcalcAPIndex dcalc_ap_index); + float slewAxisMinValue(TimingArc *arc); + float clkWaveformTimeOffset(const Clock *clk); + + void gatePortValues(const Pin *input_pin, + const Pin *drvr_pin, + const RiseFall *drvr_rf, + const Edge *gate_edge, + // Return values. + LibertyPortLogicValues &port_values, + bool &is_clked); + void regPortValues(const Pin *input_pin, + const RiseFall *drvr_rf, + const LibertyPort *drvr_port, + const FuncExpr *drvr_func, + // Return values. + LibertyPortLogicValues &port_values, + bool &is_clked); + void gatePortValues(const Instance *inst, + const FuncExpr *expr, + const LibertyPort *input_port, + // Return values. + LibertyPortLogicValues &port_values); + void writeSubcktInstLoads(const Pin *drvr_pin, + const Pin *exclude); + PinSeq drvrLoads(const Pin *drvr_pin); + void writeSubcktInstVoltSrcs(); + string replaceFileExt(string filename, + const char *ext); + + const char *spice_filename_; + const char *subckt_filename_; + const char *lib_subckt_filename_; + const char *model_filename_; + const char *power_name_; + const char *gnd_name_; + CircuitSim ckt_sim_; + + ofstream spice_stream_; + LibertyLibrary *default_library_; + float power_voltage_; + float gnd_voltage_; + float max_time_; + // Resistance to use to simulate a short circuit between spice nodes. + float short_ckt_resistance_; + // Input clock waveform cycles. + // Sequential device numbers. + int cap_index_; + int res_index_; + int volt_index_; + ParasiticNodeMap node_map_; + int next_node_index_; + CellSpicePortNames cell_spice_port_names_; + Bdd bdd_; +}; + +void +streamPrint(ofstream &stream, + const char *fmt, + ...) __attribute__((format (printf, 2, 3))); + +} // namespace diff --git a/tcl/CmdArgs.tcl b/tcl/CmdArgs.tcl index a53562d5..8fed92ee 100644 --- a/tcl/CmdArgs.tcl +++ b/tcl/CmdArgs.tcl @@ -477,6 +477,16 @@ proc parse_rise_fall_flags { flags_var } { } } +proc parse_rise_fall_arg { arg } { + if { $arg eq "r" || $arg eq "^" || $arg eq "rise" } { + return "rise" + } elseif { $arg eq "f" || $arg eq "v" || $arg eq "fall" } { + return "fall" + } else { + error "unknown rise/fall transition name." + } +} + proc parse_min_max_flags { flags_var } { upvar 1 $flags_var flags if { [info exists flags(-min)] && [info exists flags(-max)] } { diff --git a/tcl/Sdc.tcl b/tcl/Sdc.tcl index 25b4d142..4ce727b6 100644 --- a/tcl/Sdc.tcl +++ b/tcl/Sdc.tcl @@ -2943,6 +2943,10 @@ proc set_input_transition { args } { ################################################################ +# set_load -wire_load port external wire load +# set_load -pin_load port external pin load +# set_load port same as -pin_load +# set_load net overrides parasitics define_cmd_args "set_load" \ {[-corner corner] [-rise] [-fall] [-max] [-min] [-subtract_pin_load]\ [-pin_load] [-wire_load] capacitance objects} @@ -2958,7 +2962,7 @@ proc set_load { args } { set subtract_pin_load [info exists flags(-subtract_pin_load)] set corner [parse_corner_or_all keys] set min_max [parse_min_max_all_check_flags flags] - set tr [parse_rise_fall_flags flags] + set rf [parse_rise_fall_flags flags] set cap [lindex $args 0] check_positive_float "capacitance" $cap @@ -2969,11 +2973,11 @@ proc set_load { args } { # -pin_load is the default. if { $pin_load || (!$pin_load && !$wire_load) } { foreach port $ports { - set_port_ext_pin_cap $port $tr $corner $min_max $cap + set_port_ext_pin_cap $port $rf $corner $min_max $cap } } elseif { $wire_load } { foreach port $ports { - set_port_ext_wire_cap $port $subtract_pin_load $tr $corner $min_max $cap + set_port_ext_wire_cap $port $subtract_pin_load $rf $corner $min_max $cap } } } @@ -2984,7 +2988,7 @@ proc set_load { args } { if { $wire_load } { sta_warn 465 "-wire_load not allowed for net objects." } - if { $tr != "rise_fall" } { + if { $rf != "rise_fall" } { sta_warn 466 "-rise/-fall not allowed for net objects." } foreach net $nets { diff --git a/tcl/Search.tcl b/tcl/Search.tcl index da485fc1..4c5750ed 100644 --- a/tcl/Search.tcl +++ b/tcl/Search.tcl @@ -312,7 +312,7 @@ proc delays_are_inf { delays } { define_cmd_args "report_clock_skew" {[-setup|-hold]\ [-clock clocks]\ - [-corner corner]]\ + [-corner corner]\ [-digits digits]} proc_redirect report_clock_skew { @@ -351,6 +351,36 @@ proc_redirect report_clock_skew { ################################################################ +define_cmd_args "report_clock_latency" {[-clock clocks]\ + [-corner corner]\ + [-digits digits]} + +proc_redirect report_clock_latency { + global sta_report_default_digits + + parse_key_args "report_clock_" args \ + keys {-clock -corner -digits} flags {} + check_argc_eq0 "report_clock_latency" $args + + if [info exists keys(-clock)] { + set clks [get_clocks_warn "-clocks" $keys(-clock)] + } else { + set clks [all_clocks] + } + set corner [parse_corner_or_all keys] + if [info exists keys(-digits)] { + set digits $keys(-digits) + check_positive_integer "-digits" $digits + } else { + set digits $sta_report_default_digits + } + if { $clks != {} } { + report_clk_latency $clks $corner $digits + } +} + +################################################################ + define_cmd_args "report_checks" \ {[-from from_list|-rise_from from_list|-fall_from from_list]\ [-through through_list|-rise_through through_list|-fall_through through_list]\ @@ -648,15 +678,6 @@ proc report_capacitance_limits { net corner min_max violators verbose nosplit } ################################################################ -define_cmd_args "report_dcalc" \ - {[-from from_pin] [-to to_pin] [-corner corner] [-min] [-max] [-digits digits]} - -proc_redirect report_dcalc { - report_dcalc_cmd "report_dcalc" $args "-digits" -} - -################################################################ - define_cmd_args "report_disabled_edges" {} ################################################################ @@ -777,7 +798,7 @@ proc_redirect report_path { check_argc_eq2 "report_path" $args set pin_arg [lindex $args 0] - set tr [parse_rise_fall_arg [lindex $args 1]] + set rf [parse_rise_fall_arg [lindex $args 1]] set pin [get_port_pin_error "pin" $pin_arg] if { [$pin is_hierarchical] } { @@ -787,7 +808,7 @@ proc_redirect report_path { if { $vertex != "NULL" } { if { $report_all } { set first 1 - set path_iter [$vertex path_iterator $tr $min_max] + set path_iter [$vertex path_iterator $rf $min_max] while {[$path_iter has_next]} { set path [$path_iter next] if { $first } { @@ -804,7 +825,7 @@ proc_redirect report_path { } $path_iter finish } else { - set worst_path [vertex_worst_arrival_path_rf $vertex $tr $min_max] + set worst_path [vertex_worst_arrival_path_rf $vertex $rf $min_max] if { $worst_path != "NULL" } { if { $report_tags } { report_line "Tag: [$worst_path tag]" @@ -818,16 +839,6 @@ proc_redirect report_path { } } -proc parse_rise_fall_arg { arg } { - if { $arg eq "r" || $arg eq "^" || $arg eq "rise" } { - return "rise" - } elseif { $arg eq "f" || $arg eq "v" || $arg eq "fall" } { - return "fall" - } else { - error "unknown rise/fall transition name." - } -} - proc parse_report_path_options { cmd args_var default_format unknown_key_is_error } { variable path_options diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index d6d3b692..39d4ec55 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -3035,14 +3035,22 @@ report_path_cmd(PathRef *path) } void -report_clk_skew(ClockSet *clks, +report_clk_skew(ConstClockSeq clks, const Corner *corner, const SetupHold *setup_hold, int digits) { cmdLinkedNetwork(); Sta::sta()->reportClkSkew(clks, corner, setup_hold, digits); - delete clks; +} + +void +report_clk_latency(ConstClockSeq clks, + const Corner *corner, + int digits) +{ + cmdLinkedNetwork(); + Sta::sta()->reportClkLatency(clks, corner, digits); } float @@ -3534,16 +3542,14 @@ write_path_spice_cmd(PathRef *path, const char *subckt_filename, const char *lib_subckt_filename, const char *model_filename, - StdStringSet *off_path_pins, const char *power_name, const char *gnd_name, - bool measure_stmts) + CircuitSim ckt_sim) { Sta *sta = Sta::sta(); writePathSpice(path, spice_filename, subckt_filename, - lib_subckt_filename, model_filename, off_path_pins, - power_name, gnd_name, measure_stmts, sta); - delete off_path_pins; + lib_subckt_filename, model_filename, + power_name, gnd_name, ckt_sim, sta); } void diff --git a/tcl/StaTclTypes.i b/tcl/StaTclTypes.i index a2af7ecb..473452dc 100644 --- a/tcl/StaTclTypes.i +++ b/tcl/StaTclTypes.i @@ -1,4 +1,4 @@ - +// Swig TCL input/output type parsers. %{ #include "Machine.hh" @@ -22,6 +22,8 @@ #include "search/Tag.hh" #include "PathEnd.hh" #include "SearchClass.hh" +#include "CircuitSim.hh" +#include "ArcDelayCalc.hh" #include "Sta.hh" namespace sta { @@ -38,9 +40,9 @@ cmdGraph(); template Vector * -tclListSeq(Tcl_Obj *const source, - swig_type_info *swig_type, - Tcl_Interp *interp) +tclListSeqPtr(Tcl_Obj *const source, + swig_type_info *swig_type, + Tcl_Interp *interp) { int argc; Tcl_Obj **argv; @@ -60,11 +62,33 @@ tclListSeq(Tcl_Obj *const source, return nullptr; } +template +std::vector +tclListSeq(Tcl_Obj *const source, + swig_type_info *swig_type, + Tcl_Interp *interp) +{ + int argc; + Tcl_Obj **argv; + + std::vector seq; + if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK + && argc > 0) { + for (int i = 0; i < argc; i++) { + void *obj; + // Ignore returned TCL_ERROR because can't get swig_type_info. + SWIG_ConvertPtr(argv[i], &obj, swig_type, false); + seq.push_back(reinterpret_cast(obj)); + } + } + return seq; +} + template SET_TYPE * -tclListSet(Tcl_Obj *const source, - swig_type_info *swig_type, - Tcl_Interp *interp) +tclListSetPtr(Tcl_Obj *const source, + swig_type_info *swig_type, + Tcl_Interp *interp) { int argc; Tcl_Obj **argv; @@ -83,6 +107,29 @@ tclListSet(Tcl_Obj *const source, 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; + 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 SET_TYPE(); +} + template SET_TYPE * tclListNetworkSet(Tcl_Obj *const source, @@ -361,7 +408,7 @@ using namespace sta; } %typemap(in) CellSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_Cell, interp); + $1 = tclListSeqPtr($input, SWIGTYPE_p_Cell, interp); } %typemap(out) CellSeq { @@ -396,7 +443,7 @@ using namespace sta; } %typemap(in) PortSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_Port, interp); + $1 = tclListSeqPtr($input, SWIGTYPE_p_Port, interp); } %typemap(out) PortSeq { @@ -567,7 +614,7 @@ using namespace sta; } %typemap(in) InstanceSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_Instance, interp); + $1 = tclListSeqPtr($input, SWIGTYPE_p_Instance, interp); } %typemap(out) InstanceSeq { @@ -617,6 +664,10 @@ using namespace sta; seqPtrTclList($1, SWIGTYPE_p_Net, interp); } +%typemap(in) ConstNetSeq { + $1 = tclListSeq($input, SWIGTYPE_p_Net, interp); +} + %typemap(out) NetSeq { seqTclList($1, SWIGTYPE_p_Net, interp); } @@ -646,6 +697,10 @@ using namespace sta; Tcl_SetObjResult(interp, obj); } +%typemap(in) ConstClockSeq { + $1 = tclListSeq($input, SWIGTYPE_p_Clock, interp); +} + %typemap(out) ClockSeq* { seqPtrTclList($1, SWIGTYPE_p_Clock, interp); } @@ -660,7 +715,7 @@ using namespace sta; } %typemap(in) PinSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_Pin, interp); + $1 = tclListSeqPtr($input, SWIGTYPE_p_Pin, interp); } %typemap(in) PinSet* { @@ -687,8 +742,12 @@ using namespace sta; Tcl_SetObjResult(interp, list); } +%typemap(in) ConstClockSet { + $1 = tclListSet($input, SWIGTYPE_p_Clock, interp); +} + %typemap(in) ClockSet* { - $1 = tclListSet($input, SWIGTYPE_p_Clock, interp); + $1 = tclListSetPtr($input, SWIGTYPE_p_Clock, interp); } %typemap(out) ClockSet* { @@ -1011,7 +1070,7 @@ using namespace sta; } %typemap(in) ExceptionThruSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_ExceptionThru, interp); + $1 = tclListSeqPtr($input, SWIGTYPE_p_ExceptionThru, interp); } %typemap(out) Vertex* { @@ -1037,7 +1096,7 @@ using namespace sta; } %typemap(in) EdgeSeq* { - $1 = tclListSeq($input, SWIGTYPE_p_Edge, interp); + $1 = tclListSeqPtr($input, SWIGTYPE_p_Edge, interp); } %typemap(out) EdgeSeq { @@ -1348,3 +1407,22 @@ using namespace sta; break; } } + +%typemap(in) CircuitSim { + int length; + char *arg = Tcl_GetStringFromObj($input, &length); + if (stringEq(arg, "hspice")) + $1 = CircuitSim::hspice; + else if (stringEq(arg, "ngspice")) + $1 = CircuitSim::ngspice; + else if (stringEq(arg, "xyce")) + $1 = CircuitSim::xyce; + else { + tclArgError(interp, "unknown circuit simulator %s.", arg); + return TCL_ERROR; + } +} + +%typemap(in) ArcDcalcArgPtrSeq { + $1 = tclListSeq($input, SWIGTYPE_p_ArcDcalcArg, interp); +} diff --git a/tcl/WritePathSpice.tcl b/tcl/WritePathSpice.tcl index 8604471d..19541b72 100644 --- a/tcl/WritePathSpice.tcl +++ b/tcl/WritePathSpice.tcl @@ -22,13 +22,13 @@ define_cmd_args "write_path_spice" { -path_args path_args\ -model_file model_file\ -power power\ -ground ground\ - [-measure_stmts]} + [-simulator hspice|ngspice|xyce]} proc write_path_spice { args } { parse_key_args "write_path_spice" args \ keys {-spice_directory -lib_subckt_file -model_file \ - -power -ground -path_args} \ - flags {-measure_stmts} + -power -ground -path_args -simulator} \ + flags {} if { [info exists keys(-spice_directory)] } { set spice_dir [file nativename $keys(-spice_directory)] @@ -75,7 +75,7 @@ proc write_path_spice { args } { sta_error 609 "No -ground specified." } - set measure_stmts [info exists keys(-measure_stmts)] + set ckt_sim [parse_ckt_sim_key keys] if { ![info exists keys(-path_args)] } { sta_error 610 "No -path_args specified." @@ -92,11 +92,27 @@ 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 $measure_stmts + $lib_subckt_file $model_file $power $ground $ckt_sim incr path_index } } } +set ::ckt_sims {hspice ngspice xyce} + +proc parse_ckt_sim_key { keys_var } { + upvar 1 $keys_var keys + global ckt_sims + + set ckt_sim "ngspice" + if { [info exists keys(-simulator)] } { + set ckt_sim [file nativename $keys(-simulator)] + if { [lsearch $ckt_sims $ckt_sim] == -1 } { + sta_error 1710 "Unknown circuit simulator" + } + } + return $ckt_sim +} + # sta namespace end. }