diff --git a/CMakeLists.txt b/CMakeLists.txt
index 25573174..eaa3c353 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
# OpenSTA, Static Timing Analyzer
-# Copyright (c) 2023, Parallax Software, Inc.
+# Copyright (c) 2024, Parallax Software, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -24,14 +24,14 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14)
cmake_policy(SET CMP0086 NEW)
endif()
-project(STA VERSION 2.4.0
+project(STA VERSION 2.5.0
LANGUAGES CXX
)
option(USE_CUDD "Use CUDD BDD package")
option(CUDD_DIR "CUDD BDD package directory")
-set(CMAKE_VERBOSE_MAKEFILE ON)
+set(CMAKE_VERBOSE_MAKEFILE OFF)
set(STA_HOME ${PROJECT_SOURCE_DIR})
message(STATUS "STA version: ${PROJECT_VERSION}")
@@ -62,6 +62,7 @@ set(STA_SOURCE
app/StaMain.cc
dcalc/ArcDelayCalc.cc
+ dcalc/ArcDcalcWaveforms.cc
dcalc/ArnoldiDelayCalc.cc
dcalc/ArnoldiReduce.cc
dcalc/DcalcAnalysisPt.cc
@@ -69,11 +70,11 @@ set(STA_SOURCE
dcalc/DelayCalcBase.cc
dcalc/DmpCeff.cc
dcalc/DmpDelayCalc.cc
+ dcalc/FindRoot.cc
dcalc/GraphDelayCalc.cc
dcalc/LumpedCapDelayCalc.cc
dcalc/NetCaps.cc
dcalc/ParallelDelayCalc.cc
- dcalc/SlewDegradeDelayCalc.cc
dcalc/UnitDelayCalc.cc
graph/DelayFloat.cc
@@ -114,7 +115,6 @@ set(STA_SOURCE
parasitics/ConcreteParasitics.cc
parasitics/EstimateParasitics.cc
- parasitics/NullParasitics.cc
parasitics/Parasitics.cc
parasitics/ReduceParasitics.cc
parasitics/ReportParasiticAnnotation.cc
@@ -325,16 +325,20 @@ set_property(SOURCE ${STA_SWIG_FILE}
-I${STA_HOME}/verilog
)
-set_property(SOURCE ${STA_SWIG_FILE}
- PROPERTY DEPENDS
+set(SWIG_FILES
${STA_HOME}/dcalc/DelayCalc.i
${STA_HOME}/parasitics/Parasitics.i
${STA_HOME}/power/Power.i
${STA_HOME}/sdf/Sdf.i
${STA_HOME}/tcl/Exception.i
${STA_HOME}/tcl/StaTcl.i
+ ${STA_HOME}/tcl/StaTclTypes.i
${STA_HOME}/tcl/NetworkEdit.i
${STA_HOME}/verilog/Verilog.i
+ )
+
+set_property(SOURCE ${STA_SWIG_FILE}
+ PROPERTY DEPENDS ${SWIG_FILES}
)
swig_add_library(sta_swig
@@ -343,16 +347,14 @@ swig_add_library(sta_swig
SOURCES ${STA_SWIG_FILE}
)
-get_target_property(SWIG_FILES sta_swig SOURCES)
+get_target_property(STA_SWIG_CXX_FILE sta_swig SOURCES)
-foreach(SWIG_FILE ${SWIG_FILES})
- set_source_files_properties(${SWIG_FILE}
- PROPERTIES
- # No simple way to modify the swig template that emits code full of warnings
- # so suppress them.
- COMPILE_OPTIONS "-Wno-cast-qual;-Wno-missing-braces;-Wno-deprecated-declarations"
+set_source_files_properties(${STA_SWIG_CXX_FILE}
+ PROPERTIES
+ # No simple way to modify the swig template that emits code full of warnings
+ # so suppress them.
+ COMPILE_OPTIONS "-Wno-cast-qual;-Wno-missing-braces;-Wno-deprecated-declarations"
)
-endforeach()
target_link_libraries(sta_swig
PUBLIC
@@ -578,6 +580,7 @@ add_custom_target(sta_tags etags -o TAGS
${STA_SOURCE}
*/*.hh
include/sta/*.hh
+ ${SWIG_FILES}
${STA_TCL_FILES}
${SWIG_TCL_FILES}
WORKING_DIRECTORY ${STA_HOME}
diff --git a/app/Main.cc b/app/Main.cc
index c9a01274..9b45ae21 100644
--- a/app/Main.cc
+++ b/app/Main.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
diff --git a/app/StaApp.i b/app/StaApp.i
index 35f95468..fde2e64d 100644
--- a/app/StaApp.i
+++ b/app/StaApp.i
@@ -1,7 +1,7 @@
%module sta
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -17,6 +17,7 @@
// along with this program. If not, see .
%include "Exception.i"
+%include "StaTclTypes.i"
%include "StaTcl.i"
%include "Verilog.i"
%include "NetworkEdit.i"
diff --git a/app/StaMain.cc b/app/StaMain.cc
index fb350b64..f78dfa3e 100644
--- a/app/StaMain.cc
+++ b/app/StaMain.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
diff --git a/cmake/FindTCL.cmake b/cmake/FindTCL.cmake
index 52fd8495..33104447 100644
--- a/cmake/FindTCL.cmake
+++ b/cmake/FindTCL.cmake
@@ -63,7 +63,7 @@ get_filename_component(TCL_LIB_PARENT2 "${TCL_LIB_PARENT1}" PATH)
if (NOT TCL_HEADER)
find_file(TCL_HEADER tcl.h
PATHS ${TCL_LIB_PARENT1} ${TCL_LIB_PARENT2}
- PATH_SUFFIXES include include/tcl
+ PATH_SUFFIXES include include/tcl include/tcl-tk
NO_DEFAULT_PATH
)
endif()
diff --git a/dcalc/ArcDcalcWaveforms.cc b/dcalc/ArcDcalcWaveforms.cc
new file mode 100644
index 00000000..90f83b9c
--- /dev/null
+++ b/dcalc/ArcDcalcWaveforms.cc
@@ -0,0 +1,43 @@
+// OpenSTA, Static Timing Analyzer
+// Copyright (c) 2024, Parallax Software, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#include "ArcDcalcWaveforms.hh"
+
+
+namespace sta {
+
+Table1
+ArcDcalcWaveforms::inputWaveform(const Pin *,
+ const RiseFall *,
+ const Corner *,
+ const MinMax *)
+{
+ return Table1();
+}
+
+Table1
+ArcDcalcWaveforms::drvrRampWaveform(const Pin *,
+ const RiseFall *,
+ const Pin *,
+ const RiseFall *,
+ const Pin *,
+ const Corner *,
+ const MinMax *)
+{
+ return Table1();
+}
+
+} // namespace
diff --git a/dcalc/ArcDcalcWaveforms.hh b/dcalc/ArcDcalcWaveforms.hh
new file mode 100644
index 00000000..7015a27a
--- /dev/null
+++ b/dcalc/ArcDcalcWaveforms.hh
@@ -0,0 +1,59 @@
+// OpenSTA, Static Timing Analyzer
+// Copyright (c) 2024, Parallax Software, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#pragma once
+
+#include "MinMax.hh"
+#include "TableModel.hh"
+#include "NetworkClass.hh"
+
+namespace sta {
+
+class Corner;
+class DcalcAnalysisPt;
+
+// Abstract class for the graph delay calculator traversal to interface
+class ArcDcalcWaveforms
+{
+public:
+ virtual Table1 inputWaveform(const Pin *in_pin,
+ const RiseFall *in_rf,
+ const Corner *corner,
+ const MinMax *min_max);
+ virtual Table1 drvrWaveform(const Pin *in_pin,
+ const RiseFall *in_rf,
+ const Pin *drvr_pin,
+ const RiseFall *drvr_rf,
+ const Corner *corner,
+ const MinMax *min_max) = 0;
+ virtual Table1 loadWaveform(const Pin *in_pin,
+ const RiseFall *in_rf,
+ const Pin *drvr_pin,
+ const RiseFall *drvr_rf,
+ const Pin *load_pin,
+ const Corner *corner,
+ const MinMax *min_max) = 0;
+ virtual Table1 drvrRampWaveform(const Pin *in_pin,
+ const RiseFall *in_rf,
+ const Pin *drvr_pin,
+ const RiseFall *drvr_rf,
+ const Pin *load_pin,
+ const Corner *corner,
+ const MinMax *min_max);
+};
+
+} // namespace
+
diff --git a/dcalc/ArcDelayCalc.cc b/dcalc/ArcDelayCalc.cc
index 56825b3b..4b5a3cb7 100644
--- a/dcalc/ArcDelayCalc.cc
+++ b/dcalc/ArcDelayCalc.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -16,10 +16,6 @@
#include "ArcDelayCalc.hh"
-#include "TimingModel.hh"
-#include "TimingArc.hh"
-#include "GraphDelayCalc.hh"
-
namespace sta {
ArcDelayCalc::ArcDelayCalc(StaState *sta):
@@ -27,27 +23,114 @@ ArcDelayCalc::ArcDelayCalc(StaState *sta):
{
}
-TimingModel *
-ArcDelayCalc::model(const TimingArc *arc,
- const DcalcAnalysisPt *dcalc_ap) const
+void
+ArcDelayCalc::gateDelay(const TimingArc *arc,
+ const Slew &in_slew,
+ float load_cap,
+ const Parasitic *parasitic,
+ float,
+ const Pvt *,
+ const DcalcAnalysisPt *dcalc_ap,
+ // Return values.
+ ArcDelay &gate_delay,
+ Slew &drvr_slew)
{
- const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
- const TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex());
- return corner_arc->model(op_cond);
+ LoadPinIndexMap load_pin_index_map(network_);
+ ArcDcalcResult dcalc_result = gateDelay(nullptr, arc, in_slew, load_cap, parasitic,
+ load_pin_index_map, dcalc_ap);
+ gate_delay = dcalc_result.gateDelay();
+ drvr_slew = dcalc_result.drvrSlew();
}
-GateTimingModel *
-ArcDelayCalc::gateModel(const TimingArc *arc,
- const DcalcAnalysisPt *dcalc_ap) const
+////////////////////////////////////////////////////////////////
+
+ArcDcalcArg::ArcDcalcArg() :
+ drvr_pin_(nullptr),
+ edge_(nullptr),
+ arc_(nullptr),
+ in_slew_(0.0),
+ parasitic_(nullptr)
{
- return dynamic_cast(model(arc, dcalc_ap));
}
-CheckTimingModel *
-ArcDelayCalc::checkModel(const TimingArc *arc,
- const DcalcAnalysisPt *dcalc_ap) const
+ArcDcalcArg::ArcDcalcArg(const Pin *drvr_pin,
+ Edge *edge,
+ const TimingArc *arc,
+ const Slew in_slew,
+ const Parasitic *parasitic) :
+ drvr_pin_(drvr_pin),
+ edge_(edge),
+ arc_(arc),
+ in_slew_(in_slew),
+ parasitic_(parasitic)
{
- return dynamic_cast(model(arc, dcalc_ap));
+}
+
+void
+ArcDcalcArg::setParasitic(const Parasitic *parasitic)
+{
+ parasitic_ = parasitic;
+}
+
+////////////////////////////////////////////////////////////////
+
+ArcDcalcResult::ArcDcalcResult() :
+ gate_delay_(0.0),
+ drvr_slew_(0.0)
+{
+}
+
+ArcDcalcResult::ArcDcalcResult(size_t load_count) :
+ gate_delay_(0.0),
+ drvr_slew_(0.0)
+{
+ wire_delays_.resize(load_count);
+ load_slews_.resize(load_count);
+}
+
+void
+ArcDcalcResult::setGateDelay(ArcDelay gate_delay)
+{
+ gate_delay_ = gate_delay;
+}
+
+void
+ArcDcalcResult::setDrvrSlew(Slew drvr_slew)
+{
+ drvr_slew_ = drvr_slew;
+}
+
+ArcDelay
+ArcDcalcResult::wireDelay(size_t load_idx) const
+{
+ return wire_delays_[load_idx];
+}
+
+void
+ArcDcalcResult::setWireDelay(size_t load_idx,
+ ArcDelay wire_delay)
+{
+ wire_delays_[load_idx] = wire_delay;
+}
+
+void
+ArcDcalcResult::setLoadCount(size_t load_count)
+{
+ wire_delays_.resize(load_count);
+ load_slews_.resize(load_count);
+}
+
+Slew
+ArcDcalcResult::loadSlew(size_t load_idx) const
+{
+ return load_slews_[load_idx];
+}
+
+void
+ArcDcalcResult::setLoadSlew(size_t load_idx,
+ Slew load_slew)
+{
+ load_slews_[load_idx] = load_slew;
}
} // namespace
diff --git a/dcalc/Arnoldi.hh b/dcalc/Arnoldi.hh
index 0437e914..3dc238b1 100644
--- a/dcalc/Arnoldi.hh
+++ b/dcalc/Arnoldi.hh
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -64,6 +64,8 @@ public:
rcmodel();
virtual ~rcmodel();
virtual float capacitance() const;
+ virtual PinSet unannotatedLoads(const Pin *drvr_pin,
+ const Parasitics *parasitics) const;
const Pin **pinV; // [n]
};
@@ -74,7 +76,6 @@ struct timing_table
const LibertyCell *cell;
const Pvt *pvt;
float in_slew;
- float relcap;
};
} // namespace
diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc
index 15610b41..5cb2cf86 100644
--- a/dcalc/ArnoldiDelayCalc.cc
+++ b/dcalc/ArnoldiDelayCalc.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -30,6 +30,7 @@
#include "TimingModel.hh"
#include "TimingArc.hh"
#include "TableModel.hh"
+#include "PortDirection.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Parasitics.hh"
@@ -117,34 +118,33 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
- ReducedParasiticType reducedParasiticType() const override;
- void inputPortDelay(const Pin *port_pin,
- float in_slew,
- const RiseFall *rf,
- const Parasitic *parasitic,
- const DcalcAnalysisPt *dcalc_ap) override;
- void gateDelay(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- // Return values.
- ArcDelay &gate_delay,
- Slew &drvr_slew) override;
- void loadDelay(const Pin *load_pin,
- // Return values.
- ArcDelay &wire_delay,
- Slew &load_slew) override;
- string reportGateDelay(const TimingArc *arc,
+ Parasitic *reduceParasitic(const Parasitic *parasitic_network,
+ const Pin *drvr_pin,
+ const RiseFall *rf,
+ const DcalcAnalysisPt *dcalc_ap) override;
+ ArcDcalcResult inputPortDelay(const Pin *port_pin,
+ float in_slew,
+ const RiseFall *rf,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap) override;
+ ArcDcalcResult gateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
+ const Slew &in_slew,
+ // Pass in load_cap or parasitic.
+ float load_cap,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap) override;
+ string reportGateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
const Slew &in_slew,
float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
+ void finishDrvrPin() override;
void delay_work_set_thresholds(delay_work *D,
double lo,
double hi,
@@ -152,14 +152,12 @@ public:
double derate);
private:
- void gateDelaySlew(const LibertyCell *drvr_cell,
- const GateTableModel *table_model,
- const Slew &in_slew,
- float related_out_cap,
- const Pvt *pvt,
- // Return values.
- ArcDelay &gate_delay,
- Slew &drvr_slew);
+ ArcDcalcResult gateDelaySlew(const LibertyCell *drvr_cell,
+ const TimingArc *arc,
+ const GateTableModel *table_model,
+ const Slew &in_slew,
+ const LoadPinIndexMap &load_pin_index_map,
+ const Pvt *pvt);
void ar1_ceff_delay(delay_work *D,
timing_table *tab,
arnoldi1 *mod,
@@ -224,9 +222,9 @@ private:
double *_delayV;
double *_slewV;
int pin_n_;
- bool input_port_;
ArnoldiReduce *reduce_;
delay_work *delay_work_;
+ vector unsaved_parasitics_;
};
ArcDelayCalc *
@@ -266,65 +264,70 @@ ArnoldiDelayCalc::findParasitic(const Pin *drvr_pin,
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
- // set_load net has precidence over parasitics.
- if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) {
- const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
- Parasitic *parasitic_network =
- parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
- bool delete_parasitic_network = false;
-
- const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
- const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
- if (parasitic_network == nullptr) {
- Wireload *wireload = sdc_->wireload(cnst_min_max);
- if (wireload) {
- float pin_cap, wire_cap, fanout;
- bool has_wire_cap;
- graph_delay_calc_->netCaps(drvr_pin, drvr_rf, dcalc_ap,
- pin_cap, wire_cap, fanout, has_wire_cap);
- parasitic_network = parasitics_->makeWireloadNetwork(drvr_pin, wireload,
- fanout, op_cond,
- parasitic_ap);
- delete_parasitic_network = true;
- }
+ // set_load net has precedence over parasitics.
+ if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
+ || network_->direction(drvr_pin)->isInternal())
+ return nullptr;
+ const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
+ Parasitic *parasitic_network =
+ parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
+ const MinMax *min_max = dcalc_ap->constraintMinMax();
+ if (parasitic_network == nullptr) {
+ Wireload *wireload = sdc_->wireload(min_max);
+ if (wireload) {
+ float pin_cap, wire_cap, fanout;
+ bool has_wire_cap;
+ graph_delay_calc_->netCaps(drvr_pin, drvr_rf, dcalc_ap,
+ pin_cap, wire_cap, fanout, has_wire_cap);
+ parasitic_network = parasitics_->makeWireloadNetwork(drvr_pin, wireload,
+ fanout, min_max,
+ parasitic_ap);
}
+ }
- if (parasitic_network) {
- parasitic = reduce_->reduceToArnoldi(parasitic_network,
- drvr_pin,
- parasitic_ap->couplingCapFactor(),
- drvr_rf, op_cond, corner,
- cnst_min_max, parasitic_ap);
- if (delete_parasitic_network) {
- Net *net = network_->net(drvr_pin);
- parasitics_->deleteParasiticNetwork(net, parasitic_ap);
- }
- // Arnoldi parasitics are their own class that are not saved in the parasitic db.
- unsaved_parasitics_.push_back(parasitic);
- }
+ if (parasitic_network) {
+ rcmodel *rcmodel = reduce_->reduceToArnoldi(parasitic_network, drvr_pin,
+ parasitic_ap->couplingCapFactor(),
+ drvr_rf, corner, min_max, parasitic_ap);
+ // Arnoldi parasitics are their own class that are not saved in the parasitic db.
+ unsaved_parasitics_.push_back(rcmodel);
+ parasitic = rcmodel;
}
return parasitic;
}
-ReducedParasiticType
-ArnoldiDelayCalc::reducedParasiticType() const
+Parasitic *
+ArnoldiDelayCalc::reduceParasitic(const Parasitic *,
+ const Pin *,
+ const RiseFall *,
+ const DcalcAnalysisPt *)
{
- return ReducedParasiticType::arnoldi;
+ // Decline because reduced arnoldi parasitics are not stored in the parasitics db.
+ return nullptr;
}
void
-ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
- float in_slew,
- const RiseFall *rf,
- const Parasitic *parasitic,
- const DcalcAnalysisPt *dcalc_ap)
+ArnoldiDelayCalc::finishDrvrPin()
+{
+ for (auto parasitic : unsaved_parasitics_)
+ delete parasitic;
+ unsaved_parasitics_.clear();
+}
+
+ArcDcalcResult
+ArnoldiDelayCalc::inputPortDelay(const Pin *,
+ float in_slew,
+ const RiseFall *rf,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *)
{
- LumpedCapDelayCalc::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap);
rcmodel_ = nullptr;
_delayV[0] = 0.0;
_slewV[0] = in_slew;
- int j;
+ LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
+ ArcDcalcResult dcalc_result(load_pin_index_map.size());
if (parasitic) {
rcmodel_ = reinterpret_cast(const_cast(parasitic));
pin_n_ = rcmodel_->n;
@@ -335,69 +338,67 @@ ArnoldiDelayCalc::inputPortDelay(const Pin *drvr_pin,
_delayV = (double*)realloc(_delayV,_pinNmax * sizeof(double));
_slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double));
}
- pin_n_ = 1;
pin_n_ = rcmodel_->n;
- double slew_derate = drvr_library_->slewDerateFromLibrary();
- double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_);
- double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_);
- bool rising = (drvr_rf_ == RiseFall::rise());
- delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising,
- slew_derate);
+ double slew_derate = drvr_library->slewDerateFromLibrary();
+ double lo_thresh = drvr_library->slewLowerThreshold(rf);
+ double hi_thresh = drvr_library->slewUpperThreshold(rf);
+ bool rising = (rf == RiseFall::rise());
+ delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising, slew_derate);
delay_c *c = delay_work_->c;
double c_log = c->vlg;
- for (j=1;jelmore(j);
- _delayV[j] = 0.6931472*elmore;
- _slewV[j] = in_slew + c_log*elmore/slew_derate;
+ double wire_delay = 0.6931472*elmore;
+ double load_slew = in_slew + c_log*elmore/slew_derate;
+ _delayV[j] = wire_delay;
+ _slewV[j] = load_slew;
+
+ const Pin *load_pin = rcmodel_->pinV[j];
+ auto load_idx_itr = load_pin_index_map.find(load_pin);
+ if (load_idx_itr != load_pin_index_map.end()) {
+ size_t load_idx = load_idx_itr->second;
+ dcalc_result.setWireDelay(load_idx, wire_delay);
+ dcalc_result.setLoadSlew(load_idx, load_slew);
+ }
}
}
-}
-
-void
-ArnoldiDelayCalc::gateDelay(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- // Return values.
- ArcDelay &gate_delay,
- Slew &drvr_slew)
-{
- input_port_ = false;
- drvr_rf_ = arc->toEdge()->asRiseFall();
- const LibertyCell *drvr_cell = arc->from()->libertyCell();
- drvr_library_ = drvr_cell->libertyLibrary();
- drvr_parasitic_ = drvr_parasitic;
- ConcreteParasitic *drvr_cparasitic =
- reinterpret_cast(const_cast(drvr_parasitic));
- rcmodel_ = dynamic_cast(drvr_cparasitic);
- GateTimingModel *model = gateModel(arc, dcalc_ap);
- GateTableModel *table_model = dynamic_cast(model);
- if (table_model && rcmodel_)
- gateDelaySlew(drvr_cell, table_model, in_slew,
- related_out_cap, pvt,
- gate_delay, drvr_slew);
else
- LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
- related_out_cap, pvt, dcalc_ap,
- gate_delay, drvr_slew);
- drvr_slew_ = drvr_slew;
- multi_drvr_slew_factor_ = 1.0F;
+ dcalc_result = makeResult(drvr_library, rf, 0.0, in_slew, load_pin_index_map);
+ return dcalc_result;
}
-void
+ArcDcalcResult
+ArnoldiDelayCalc::gateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
+ const Slew &in_slew,
+ float load_cap,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap)
+{
+ const LibertyCell *drvr_cell = arc->from()->libertyCell();
+ ConcreteParasitic *cparasitic =
+ reinterpret_cast(const_cast(parasitic));
+ rcmodel_ = dynamic_cast(cparasitic);
+ GateTableModel *table_model = gateTableModel(arc, dcalc_ap);
+ if (table_model && rcmodel_) {
+ const Pvt *pvt = pinPvt(drvr_pin, dcalc_ap);
+ return gateDelaySlew(drvr_cell, arc, table_model, in_slew, load_pin_index_map, pvt);
+ }
+ else
+ return LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap,
+ parasitic, load_pin_index_map, dcalc_ap);
+}
+
+ArcDcalcResult
ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
+ const TimingArc *arc,
const GateTableModel *table_model,
const Slew &in_slew,
- float related_out_cap,
- const Pvt *pvt,
- // Return values.
- ArcDelay &gate_delay,
- Slew &drvr_slew)
+ const LoadPinIndexMap &load_pin_index_map,
+ const Pvt *pvt)
{
pin_n_ = rcmodel_->n;
if (pin_n_ >= _pinNmax) {
@@ -407,12 +408,15 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
_slewV = (double*)realloc(_slewV,_pinNmax * sizeof(double));
}
+ ArcDcalcResult dcalc_result(load_pin_index_map.size());
pin_n_ = rcmodel_->n;
- if (table_model) {
- double slew_derate = drvr_library_->slewDerateFromLibrary();
- double lo_thresh = drvr_library_->slewLowerThreshold(drvr_rf_);
- double hi_thresh = drvr_library_->slewUpperThreshold(drvr_rf_);
- bool rising = (drvr_rf_ == RiseFall::rise());
+ const RiseFall *rf = arc->toEdge()->asRiseFall();
+ if (table_model && rf) {
+ const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
+ double slew_derate = drvr_library->slewDerateFromLibrary();
+ double lo_thresh = drvr_library->slewLowerThreshold(rf);
+ double hi_thresh = drvr_library->slewUpperThreshold(rf);
+ bool rising = (rf == RiseFall::rise());
delay_work_set_thresholds(delay_work_, lo_thresh, hi_thresh, rising,
slew_derate);
if (rcmodel_->order > 0) {
@@ -421,48 +425,43 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
tab.cell = drvr_cell;
tab.pvt = pvt;
tab.in_slew = delayAsFloat(in_slew);
- tab.relcap = related_out_cap;
ar1_ceff_delay(delay_work_, &tab, rcmodel_,
_delayV, _slewV);
}
- gate_delay = _delayV[0];
- drvr_slew = _slewV[0];
- }
-}
+ dcalc_result.setGateDelay(_delayV[0]);
+ dcalc_result.setDrvrSlew(_slewV[0]);
-void
-ArnoldiDelayCalc::loadDelay(const Pin *load_pin,
- // Return values.
- ArcDelay &wire_delay,
- Slew &load_slew)
-{
- // This does not appear to handle input port parasitics correctly.
- wire_delay = 0.0;
- load_slew = drvr_slew_ * multi_drvr_slew_factor_;
- if (rcmodel_) {
- // HACK
- for (int i = 0; i < rcmodel_->n; i++) {
- if (rcmodel_->pinV[i] == load_pin) {
- wire_delay = _delayV[i] - _delayV[0];
- load_slew = _slewV[i] * multi_drvr_slew_factor_;
- break;
+ if (rcmodel_) {
+ for (int i = 0; i < rcmodel_->n; i++) {
+ const Pin *load_pin = rcmodel_->pinV[i];
+ auto load_idx_itr = load_pin_index_map.find(load_pin);
+ if (load_idx_itr != load_pin_index_map.end()) {
+ size_t load_idx = load_idx_itr->second;
+ ArcDelay wire_delay = _delayV[i] - _delayV[0];
+ Slew load_slew = _slewV[i];
+ thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
+ dcalc_result.setWireDelay(load_idx, wire_delay);
+ dcalc_result.setLoadSlew(load_idx, load_slew);
+ }
}
}
}
- thresholdAdjust(load_pin, wire_delay, load_slew);
+ return dcalc_result;
}
string
-ArnoldiDelayCalc::reportGateDelay(const TimingArc *,
- const Slew &,
- float,
- const Parasitic *,
- float,
- const Pvt *,
- const DcalcAnalysisPt *,
- int)
+ArnoldiDelayCalc::reportGateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
+ const Slew &in_slew,
+ float load_cap,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap,
+ int digits)
{
- return "";
+ return LumpedCapDelayCalc::reportGateDelay(drvr_pin, arc, in_slew, load_cap,
+ parasitic, load_pin_index_map,
+ dcalc_ap, digits);
}
////////////////////////////////////////////////////////////////
@@ -1310,12 +1309,11 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D,
c1 = ctot;
ArcDelay d1;
Slew s1;
- tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1);
+ tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1);
tlohi = slew_derate*delayAsFloat(s1);
r = tlohi/(c_log*c1);
if (rdelay>0.0 && r > rdelay)
r = rdelay;
- // else printf("from rdelay %g to r %g\n",rdelay,r);
return r;
}
@@ -1332,7 +1330,7 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
double tlohi,smin,s;
ArcDelay d1;
Slew s1;
- tab->table->gateDelay(tab->pvt, tab->in_slew, c, tab->relcap, pocv_enabled_, d1, s1);
+ tab->table->gateDelay(tab->pvt, tab->in_slew, c, pocv_enabled_, d1, s1);
tlohi = slew_derate*delayAsFloat(s1);
smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
if (c_log*r*c >= tlohi) {
@@ -1365,8 +1363,8 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
return 0.0;
ArcDelay d1, d2;
Slew s1, s2;
- tab->table->gateDelay(tab->pvt, tab->in_slew, c1, tab->relcap, pocv_enabled_, d1, s1);
- tab->table->gateDelay(tab->pvt, tab->in_slew, c2, tab->relcap, pocv_enabled_, d2, s2);
+ tab->table->gateDelay(tab->pvt, tab->in_slew, c1, pocv_enabled_, d1, s1);
+ tab->table->gateDelay(tab->pvt, tab->in_slew, c2, pocv_enabled_, d2, s2);
double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
if (dt50 <= 0.0)
return 0.0;
@@ -1418,8 +1416,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(s));
thix = ra_solve_for_t(p,s,vhi);
tlox = ra_solve_for_t(p,s,vlo);
- tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, tab->relcap, pocv_enabled_,
- df, sf);
+ tab->table->gateDelay(tab->pvt,tab->in_slew, ctot, pocv_enabled_, df, sf);
debugPrint(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s",
units_->timeUnit()->asString(tab->in_slew),
units_->capacitanceUnit()->asString(ctot),
@@ -1430,7 +1427,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(tlox-thix));
}
ceff = ctot;
- tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_,
+ tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_,
df, sf);
t50_sy = delayAsFloat(df);
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
@@ -1472,7 +1469,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
units_->timeUnit()->asString(ceff_time),
units_->capacitanceUnit()->asString(ceff));
- tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, tab->relcap, pocv_enabled_, df, sf);
+ tab->table->gateDelay(tab->pvt, tab->in_slew, ceff, pocv_enabled_, df, sf);
t50_sy = delayAsFloat(df);
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
for (j=0;jn;j++) {
diff --git a/dcalc/ArnoldiDelayCalc.hh b/dcalc/ArnoldiDelayCalc.hh
index 2616ab0d..20b0e626 100644
--- a/dcalc/ArnoldiDelayCalc.hh
+++ b/dcalc/ArnoldiDelayCalc.hh
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
diff --git a/dcalc/ArnoldiReduce.cc b/dcalc/ArnoldiReduce.cc
index 8e019426..5c80c382 100644
--- a/dcalc/ArnoldiReduce.cc
+++ b/dcalc/ArnoldiReduce.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -46,6 +46,14 @@ rcmodel::capacitance() const
return ctot;
}
+PinSet
+rcmodel::unannotatedLoads(const Pin *,
+ const Parasitics *) const
+{
+ // This should never be called because the rcmodel is not saved in the Parasitics.
+ return PinSet();
+}
+
struct ts_point
{
ParasiticNode *node_;
@@ -62,7 +70,7 @@ struct ts_point
struct ts_edge
{
- ConcreteParasiticResistor *resistor_;
+ ParasiticResistor *resistor_;
ts_point *from;
ts_point *to;
};
@@ -131,23 +139,21 @@ ArnoldiReduce::~ArnoldiReduce()
free(ts_pointV);
}
-Parasitic *
+rcmodel *
ArnoldiReduce::reduceToArnoldi(Parasitic *parasitic,
const Pin *drvr_pin,
float coupling_cap_factor,
const RiseFall *rf,
- const OperatingConditions *op_cond,
const Corner *corner,
- const MinMax *cnst_min_max,
+ const MinMax *min_max,
const ParasiticAnalysisPt *ap)
{
parasitic_network_ = reinterpret_cast(parasitic);
drvr_pin_ = drvr_pin;
coupling_cap_factor_ = coupling_cap_factor;
rf_ = rf;
- op_cond_ = op_cond;
corner_ = corner;
- cnst_min_max_ = cnst_min_max;
+ min_max_ = min_max;
ap_ = ap;
loadWork();
return makeRcmodelDrv();
@@ -158,18 +164,21 @@ ArnoldiReduce::loadWork()
{
pt_map_.clear();
- int resistor_count = 0;
- ConcreteParasiticDeviceSet devices;
- parasitic_network_->devices(&devices);
- ConcreteParasiticDeviceSet::Iterator device_iter(devices);
- while (device_iter.hasNext()) {
- ParasiticDevice *device = device_iter.next();
- if (parasitics_->isResistor(device))
- resistor_count++;
- }
+ const ParasiticResistorSeq &resistors = parasitics_->resistors(parasitic_network_);
+ int resistor_count = resistors.size();
- termN = parasitic_network_->pinNodes()->size();
- int subnode_count = parasitic_network_->subNodes()->size();
+ termN = 0;
+ int subnode_count = 0;
+ ParasiticNodeSeq nodes = parasitics_->nodes(parasitic_network_);
+ for (ParasiticNode *node : nodes) {
+ if (!parasitics_->isExternal(node)) {
+ const Pin *pin = parasitics_->pin(node);
+ if (pin)
+ termN++;
+ else
+ subnode_count++;
+ }
+ }
ts_pointN = subnode_count + 1 + termN;
ts_edgeN = resistor_count;
allocPoints();
@@ -191,50 +200,42 @@ ArnoldiReduce::loadWork()
pend = pterm0;
e = e0;
int index = 0;
- ConcreteParasiticSubNodeMap::Iterator
- sub_node_iter(parasitic_network_->subNodes());
- while (sub_node_iter.hasNext()) {
- ConcreteParasiticSubNode *node = sub_node_iter.next();
- pt_map_[node] = index;
- p = p0 + index;
- p->node_ = node;
- p->eN = 0;
- p->is_term = false;
- index++;
+
+ for (ParasiticNode *node : nodes) {
+ if (!parasitics_->isExternal(node)) {
+ const Pin *pin = parasitics_->pin(node);
+ if (pin) {
+ p = pend++;
+ pt_map_[node] = p - p0;
+ p->node_ = node;
+ p->eN = 0;
+ p->is_term = true;
+ tindex = p - pterm0;
+ p->tindex = tindex;
+ pinV[tindex] = pin;
+ }
+ else {
+ pt_map_[node] = index;
+ p = p0 + index;
+ p->node_ = node;
+ p->eN = 0;
+ p->is_term = false;
+ index++;
+ }
+ }
}
- ConcreteParasiticPinNodeMap::Iterator
- pin_node_iter(parasitic_network_->pinNodes());
- while (pin_node_iter.hasNext()) {
- ConcreteParasiticPinNode *node = pin_node_iter.next();
- p = pend++;
- pt_map_[node] = p - p0;
- p->node_ = node;
- p->eN = 0;
- p->is_term = true;
- tindex = p - pterm0;
- p->tindex = tindex;
- const Pin *pin = parasitics_->connectionPin(node);
- pinV[tindex] = pin;
- }
-
ts_edge **eV = ts_eV;
- ConcreteParasiticDeviceSet::Iterator device_iter2(devices);
- while (device_iter2.hasNext()) {
- ParasiticDevice *device = device_iter2.next();
- if (parasitics_->isResistor(device)) {
- ConcreteParasiticResistor *resistor =
- reinterpret_cast(device);
- ts_point *pt1 = findPt(resistor->node1());
- ts_point *pt2 = findPt(resistor->node2());
- e->from = pt1;
- e->to = pt2;
- e->resistor_ = resistor;
- pt1->eN++;
- if (e->from != e->to)
- pt2->eN++;
- e++;
- }
+ for (ParasiticResistor *resistor : resistors) {
+ ts_point *pt1 = findPt(parasitics_->node1(resistor));
+ ts_point *pt2 = findPt(parasitics_->node2(resistor));
+ e->from = pt1;
+ e->to = pt2;
+ e->resistor_ = resistor;
+ pt1->eN++;
+ if (e->from != e->to)
+ pt2->eN++;
+ e++;
}
for (p=p0;p!=pend;p++) {
@@ -313,8 +314,7 @@ ArnoldiReduce::findPt(ParasiticNode *node)
rcmodel *
ArnoldiReduce::makeRcmodelDrv()
{
- ParasiticNode *drv_node = parasitics_->findNode(parasitic_network_,
- drvr_pin_);
+ ParasiticNode *drv_node = parasitics_->findNode(parasitic_network_, drvr_pin_);
ts_point *pdrv = findPt(drv_node);
makeRcmodelDfs(pdrv);
getRC();
@@ -322,8 +322,7 @@ ArnoldiReduce::makeRcmodelDrv()
return nullptr;
setTerms(pdrv);
makeRcmodelFromTs();
- rcmodel *mod = makeRcmodelFromW();
- return mod;
+ return makeRcmodelFromW();
}
#define ts_orient( pp, ee) \
@@ -415,7 +414,7 @@ ArnoldiReduce::getRC()
p->r = 0.0;
if (p->node_) {
ParasiticNode *node = p->node_;
- double cap = parasitics_->nodeGndCap(node, ap_)
+ double cap = parasitics_->nodeGndCap(node)
+ pinCapacitance(node);
if (cap > 0.0) {
p->c = cap;
@@ -424,7 +423,7 @@ ArnoldiReduce::getRC()
else
p->c = 0.0;
if (p->in_edge && p->in_edge->resistor_)
- p->r = parasitics_->value(p->in_edge->resistor_, ap_);
+ p->r = parasitics_->value(p->in_edge->resistor_);
if (!(p->r>=0.0 && p->r<100e+3)) { // 0 < r < 100kohm
debugPrint(debug_, "arnoldi", 1,
"R value %g out of range, drvr pin %s",
@@ -433,20 +432,33 @@ ArnoldiReduce::getRC()
}
}
}
+ for (ParasiticCapacitor *capacitor : parasitics_->capacitors(parasitic_network_)) {
+ float cap = parasitics_->value(capacitor) * ap_->couplingCapFactor();
+ ParasiticNode *node1 = parasitics_->node1(capacitor);
+ if (!parasitics_->isExternal(node1)) {
+ ts_point *pt = findPt(node1);
+ pt->c += cap;
+ }
+ ParasiticNode *node2 = parasitics_->node2(capacitor);
+ if (!parasitics_->isExternal(node2)) {
+ ts_point *pt = findPt(node2);
+ pt->c += cap;
+ }
+ }
}
float
ArnoldiReduce::pinCapacitance(ParasiticNode *node)
{
- const Pin *pin = parasitics_->connectionPin(node);
+ const Pin *pin = parasitics_->pin(node);
float pin_cap = 0.0;
if (pin) {
Port *port = network_->port(pin);
LibertyPort *lib_port = network_->libertyPort(port);
if (lib_port)
- pin_cap = sdc_->pinCapacitance(pin,rf_, op_cond_, corner_, cnst_min_max_);
+ pin_cap = sdc_->pinCapacitance(pin,rf_, corner_, min_max_);
else if (network_->isTopLevelPort(pin))
- pin_cap = sdc_->portExtCap(port, rf_, corner_, cnst_min_max_);
+ pin_cap = sdc_->portExtCap(port, rf_, corner_, min_max_);
}
return pin_cap;
}
diff --git a/dcalc/ArnoldiReduce.hh b/dcalc/ArnoldiReduce.hh
index e299f929..ad49da34 100644
--- a/dcalc/ArnoldiReduce.hh
+++ b/dcalc/ArnoldiReduce.hh
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -37,21 +37,20 @@ class rcmodel;
struct ts_edge;
struct ts_point;
-typedef Map ArnolidPtMap;
+typedef Map ArnolidPtMap;
class ArnoldiReduce : public StaState
{
public:
ArnoldiReduce(StaState *sta);
~ArnoldiReduce();
- Parasitic *reduceToArnoldi(Parasitic *parasitic,
- const Pin *drvr_pin,
- float coupling_cap_factor,
- const RiseFall *rf,
- const OperatingConditions *op_cond,
- const Corner *corner,
- const MinMax *cnst_min_max,
- const ParasiticAnalysisPt *ap);
+ rcmodel *reduceToArnoldi(Parasitic *parasitic,
+ const Pin *drvr_pin,
+ float coupling_cap_factor,
+ const RiseFall *rf,
+ const Corner *corner,
+ const MinMax *cnst_min_max,
+ const ParasiticAnalysisPt *ap);
protected:
void loadWork();
@@ -70,9 +69,8 @@ protected:
const Pin *drvr_pin_;
float coupling_cap_factor_;
const RiseFall *rf_;
- const OperatingConditions *op_cond_;
const Corner *corner_;
- const MinMax *cnst_min_max_;
+ const MinMax *min_max_;
const ParasiticAnalysisPt *ap_;
// ParasiticNode -> ts_point index.
ArnolidPtMap pt_map_;
diff --git a/dcalc/DcalcAnalysisPt.cc b/dcalc/DcalcAnalysisPt.cc
index 1995f245..3b2b71bd 100644
--- a/dcalc/DcalcAnalysisPt.cc
+++ b/dcalc/DcalcAnalysisPt.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
diff --git a/dcalc/DelayCalc.cc b/dcalc/DelayCalc.cc
index 2c5c1ba0..ab032824 100644
--- a/dcalc/DelayCalc.cc
+++ b/dcalc/DelayCalc.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -20,7 +20,6 @@
#include "StringUtil.hh"
#include "UnitDelayCalc.hh"
#include "LumpedCapDelayCalc.hh"
-#include "SlewDegradeDelayCalc.hh"
#include "DmpDelayCalc.hh"
#include "ArnoldiDelayCalc.hh"
@@ -35,7 +34,6 @@ registerDelayCalcs()
{
registerDelayCalc("unit", makeUnitDelayCalc);
registerDelayCalc("lumped_cap", makeLumpedCapDelayCalc);
- registerDelayCalc("slew_degrade", makeSlewDegradeDelayCalc);
registerDelayCalc("dmp_ceff_elmore", makeDmpCeffElmoreDelayCalc);
registerDelayCalc("dmp_ceff_two_pole", makeDmpCeffTwoPoleDelayCalc);
registerDelayCalc("arnoldi", makeArnoldiDelayCalc);
diff --git a/dcalc/DelayCalc.i b/dcalc/DelayCalc.i
index 52711847..d94565d4 100644
--- a/dcalc/DelayCalc.i
+++ b/dcalc/DelayCalc.i
@@ -3,7 +3,7 @@
%{
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -19,6 +19,8 @@
// along with this program. If not, see .
#include "Sta.hh"
+#include "ArcDelayCalc.hh"
+#include "dcalc/ArcDcalcWaveforms.hh"
%}
@@ -59,4 +61,76 @@ report_delay_calc_cmd(Edge *edge,
return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits);
}
+////////////////////////////////////////////////////////////////
+
+Table1
+ccs_input_waveform(const Pin *in_pin,
+ const RiseFall *in_rf,
+ const Corner *corner,
+ const MinMax *min_max)
+{
+ cmdLinkedNetwork();
+ Sta *sta = Sta::sta();
+ ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc());
+ if (arc_dcalc)
+ return arc_dcalc->inputWaveform(in_pin, in_rf, corner, min_max);
+ else
+ return Table1();
+}
+
+Table1
+ccs_driver_waveform(const Pin *in_pin,
+ const RiseFall *in_rf,
+ const Pin *drvr_pin,
+ const RiseFall *drvr_rf,
+ const Corner *corner,
+ const MinMax *min_max)
+{
+ cmdLinkedNetwork();
+ Sta *sta = Sta::sta();
+ ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc());
+ if (arc_dcalc)
+ return arc_dcalc->drvrWaveform(in_pin, in_rf, drvr_pin, drvr_rf, corner, min_max);
+ else
+ return Table1();
+}
+
+Table1
+ccs_driver_ramp_waveform(const Pin *in_pin,
+ const RiseFall *in_rf,
+ const Pin *drvr_pin,
+ const RiseFall *drvr_rf,
+ const Pin *load_pin,
+ const Corner *corner,
+ const MinMax *min_max)
+{
+ cmdLinkedNetwork();
+ Sta *sta = Sta::sta();
+ ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc());
+ if (arc_dcalc)
+ return arc_dcalc->drvrRampWaveform(in_pin, in_rf, drvr_pin, drvr_rf,
+ load_pin, corner, min_max);
+ else
+ return Table1();
+}
+
+Table1
+ccs_load_waveform(const Pin *in_pin,
+ const RiseFall *in_rf,
+ const Pin *drvr_pin,
+ const RiseFall *drvr_rf,
+ const Pin *load_pin,
+ const Corner *corner,
+ const MinMax *min_max)
+{
+ cmdLinkedNetwork();
+ Sta *sta = Sta::sta();
+ ArcDcalcWaveforms *arc_dcalc = dynamic_cast(sta->arcDelayCalc());
+ if (arc_dcalc)
+ return arc_dcalc->loadWaveform(in_pin, in_rf, drvr_pin, drvr_rf,
+ load_pin, corner, min_max);
+ else
+ return Table1();
+}
+
%} // inline
diff --git a/dcalc/DelayCalc.tcl b/dcalc/DelayCalc.tcl
index e2cde430..7af909e5 100644
--- a/dcalc/DelayCalc.tcl
+++ b/dcalc/DelayCalc.tcl
@@ -1,5 +1,5 @@
# OpenSTA, Static Timing Analyzer
-# Copyright (c) 2023, Parallax Software, Inc.
+# Copyright (c) 2024, Parallax Software, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -116,7 +116,7 @@ proc set_delay_calculator { alg } {
if { [is_delay_calc_name $alg] } {
set_delay_calculator_cmd $alg
} else {
- sta_error 435 "delay calculator $alg not found."
+ sta_error 180 "delay calculator $alg not found."
}
}
@@ -145,38 +145,38 @@ proc set_assigned_delay_cmd { cmd cmd_args } {
if [info exists keys(-from)] {
set from_pins [get_port_pins_error "from_pins" $keys(-from)]
} else {
- sta_error 442 "$cmd missing -from argument."
+ sta_error 181 "$cmd missing -from argument."
}
if [info exists keys(-to)] {
set to_pins [get_port_pins_error "to_pins" $keys(-to)]
} else {
- sta_error 443 "$cmd missing -to argument."
+ sta_error 182 "$cmd missing -to argument."
}
set delay [lindex $cmd_args 0]
if {![string is double $delay]} {
- sta_error 444 "$cmd delay is not a float."
+ sta_error 183 "$cmd delay is not a float."
}
set delay [time_ui_sta $delay]
if {[info exists flags(-cell)] && [info exists flags(-net)]} {
- sta_error 445 "set_annotated_delay -cell and -net options are mutually excluive."
+ sta_error 184 "set_annotated_delay -cell and -net options are mutually excluive."
} elseif {[info exists flags(-cell)]} {
if { $from_pins != {} } {
set inst [[lindex $from_pins 0] instance]
foreach pin $from_pins {
if {[$pin instance] != $inst} {
- sta_error 446 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]."
+ sta_error 185 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]."
}
}
foreach pin $to_pins {
if {[$pin instance] != $inst} {
- sta_error 447 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]"
+ sta_error 186 "$cmd pin [get_full_name $pin] is not attached to instance [get_full_name $inst]"
}
}
}
} elseif {![info exists flags(-net)]} {
- sta_error 448 "$cmd -cell or -net required."
+ sta_error 187 "$cmd -cell or -net required."
}
foreach from_pin $from_pins {
set from_vertices [$from_pin vertices]
@@ -240,7 +240,7 @@ proc set_assigned_check_cmd { cmd cmd_args } {
if { [info exists keys(-from)] } {
set from_pins [get_port_pins_error "from_pins" $keys(-from)]
} else {
- sta_error 449 "$cmd missing -from argument."
+ sta_error 188 "$cmd missing -from argument."
}
set from_rf "rise_fall"
if { [info exists keys(-clock)] } {
@@ -249,14 +249,14 @@ proc set_assigned_check_cmd { cmd cmd_args } {
|| $clk_arg eq "fall" } {
set from_rf $clk_arg
} else {
- sta_error 450 "$cmd -clock must be rise or fall."
+ sta_error 189 "$cmd -clock must be rise or fall."
}
}
if { [info exists keys(-to)] } {
set to_pins [get_port_pins_error "to_pins" $keys(-to)]
} else {
- sta_error 451 "$cmd missing -to argument."
+ sta_error 190 "$cmd missing -to argument."
}
set to_rf [parse_rise_fall_flags flags]
set corner [parse_corner keys]
@@ -271,7 +271,7 @@ proc set_assigned_check_cmd { cmd cmd_args } {
} elseif { [info exists flags(-removal)] } {
set role "removal"
} else {
- sta_error 452 "$cmd missing -setup|-hold|-recovery|-removal check type.."
+ sta_error 191 "$cmd missing -setup|-hold|-recovery|-removal check type.."
}
set cond ""
if { [info exists key(-cond)] } {
@@ -279,7 +279,7 @@ proc set_assigned_check_cmd { cmd cmd_args } {
}
set check_value [lindex $cmd_args 0]
if { ![string is double $check_value] } {
- sta_error 453 "$cmd check_value is not a float."
+ sta_error 192 "$cmd check_value is not a float."
}
set check_value [time_ui_sta $check_value]
@@ -347,7 +347,7 @@ proc set_assigned_transition { args } {
set slew [lindex $args 0]
if {![string is double $slew]} {
- sta_error 428 "set_assigned_transition transition is not a float."
+ sta_error 210 "set_assigned_transition transition is not a float."
}
set slew [time_ui_sta $slew]
set pins [get_port_pins_error "pins" [lindex $args 1]]
diff --git a/dcalc/DelayCalcBase.cc b/dcalc/DelayCalcBase.cc
index c2639664..7db5663f 100644
--- a/dcalc/DelayCalcBase.cc
+++ b/dcalc/DelayCalcBase.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -18,53 +18,85 @@
#include "Liberty.hh"
#include "TimingArc.hh"
+#include "TimingModel.hh"
+#include "TableModel.hh"
#include "Network.hh"
#include "Parasitics.hh"
+#include "Sdc.hh"
+#include "Corner.hh"
+#include "DcalcAnalysisPt.hh"
namespace sta {
+using std::log;
+
DelayCalcBase::DelayCalcBase(StaState *sta) :
ArcDelayCalc(sta)
{
}
+void
+DelayCalcBase::reduceParasitic(const Parasitic *parasitic_network,
+ const Net *net,
+ const Corner *corner,
+ const MinMaxAll *min_max)
+{
+ NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net);
+ while (pin_iter->hasNext()) {
+ const Pin *pin = pin_iter->next();
+ if (network_->isDriver(pin)) {
+ for (RiseFall *rf : RiseFall::range()) {
+ for (const MinMax *min_max : min_max->range()) {
+ if (corner == nullptr) {
+ for (const Corner *corner1 : *corners_) {
+ DcalcAnalysisPt *dcalc_ap = corner1->findDcalcAnalysisPt(min_max);
+ reduceParasitic(parasitic_network, pin, rf, dcalc_ap);
+ }
+ }
+ else {
+ DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
+ reduceParasitic(parasitic_network, pin, rf, dcalc_ap);
+ }
+ }
+ }
+ }
+ }
+ delete pin_iter;
+}
+
+TimingModel *
+DelayCalcBase::model(const TimingArc *arc,
+ const DcalcAnalysisPt *dcalc_ap) const
+{
+ const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
+ const TimingArc *corner_arc = arc->cornerArc(dcalc_ap->libertyIndex());
+ return corner_arc->model(op_cond);
+}
+
+GateTimingModel *
+DelayCalcBase::gateModel(const TimingArc *arc,
+ const DcalcAnalysisPt *dcalc_ap) const
+{
+ return dynamic_cast(model(arc, dcalc_ap));
+}
+
+GateTableModel *
+DelayCalcBase::gateTableModel(const TimingArc *arc,
+ const DcalcAnalysisPt *dcalc_ap) const
+{
+ return dynamic_cast(model(arc, dcalc_ap));
+}
+
+CheckTimingModel *
+DelayCalcBase::checkModel(const TimingArc *arc,
+ const DcalcAnalysisPt *dcalc_ap) const
+{
+ return dynamic_cast(model(arc, dcalc_ap));
+}
+
void
DelayCalcBase::finishDrvrPin()
{
- for (auto parasitic : unsaved_parasitics_)
- parasitics_->deleteUnsavedParasitic(parasitic);
- unsaved_parasitics_.clear();
- for (auto drvr_pin : reduced_parasitic_drvrs_)
- parasitics_->deleteDrvrReducedParasitics(drvr_pin);
- reduced_parasitic_drvrs_.clear();
-}
-
-void
-DelayCalcBase::inputPortDelay(const Pin *,
- float in_slew,
- const RiseFall *rf,
- const Parasitic *parasitic,
- const DcalcAnalysisPt *)
-{
- drvr_cell_ = nullptr;
- drvr_library_ = network_->defaultLibertyLibrary();
- drvr_slew_ = in_slew;
- drvr_rf_ = rf;
- drvr_parasitic_ = parasitic;
- input_port_ = true;
-}
-
-void
-DelayCalcBase::gateDelayInit(const TimingArc *arc,
- const Slew &in_slew,
- const Parasitic *drvr_parasitic)
-{
- drvr_cell_ = arc->from()->libertyCell();
- drvr_library_ = drvr_cell_->libertyLibrary();
- drvr_rf_ = arc->toEdge()->asRiseFall();
- drvr_slew_ = in_slew;
- drvr_parasitic_ = drvr_parasitic;
- input_port_ = false;
}
// For DSPF on an input port the elmore delay is used as the time
@@ -73,40 +105,47 @@ DelayCalcBase::gateDelayInit(const TimingArc *arc,
// Note that this uses the driver thresholds and relies on
// thresholdAdjust to convert the delay and slew to the load's thresholds.
void
-DelayCalcBase::dspfWireDelaySlew(const Pin *,
+DelayCalcBase::dspfWireDelaySlew(const Pin *load_pin,
+ const RiseFall *rf,
+ Slew drvr_slew,
float elmore,
ArcDelay &wire_delay,
Slew &load_slew)
{
- float vth = drvr_library_->inputThreshold(drvr_rf_);
- float vl = drvr_library_->slewLowerThreshold(drvr_rf_);
- float vh = drvr_library_->slewUpperThreshold(drvr_rf_);
- float slew_derate = drvr_library_->slewDerateFromLibrary();
+
+ LibertyLibrary *load_library = thresholdLibrary(load_pin);
+ float vth = load_library->inputThreshold(rf);
+ float vl = load_library->slewLowerThreshold(rf);
+ float vh = load_library->slewUpperThreshold(rf);
+ float slew_derate = load_library->slewDerateFromLibrary();
wire_delay = -elmore * log(1.0 - vth);
- load_slew = drvr_slew_ + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate;
+ load_slew = drvr_slew + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate;
+ load_slew = drvr_slew + elmore * log((1.0 - vl) / (1.0 - vh)) / slew_derate;
}
void
DelayCalcBase::thresholdAdjust(const Pin *load_pin,
+ const LibertyLibrary *drvr_library,
+ const RiseFall *rf,
ArcDelay &load_delay,
Slew &load_slew)
{
LibertyLibrary *load_library = thresholdLibrary(load_pin);
if (load_library
- && drvr_library_
- && load_library != drvr_library_) {
- float drvr_vth = drvr_library_->outputThreshold(drvr_rf_);
- float load_vth = load_library->inputThreshold(drvr_rf_);
- float drvr_slew_delta = drvr_library_->slewUpperThreshold(drvr_rf_)
- - drvr_library_->slewLowerThreshold(drvr_rf_);
+ && drvr_library
+ && load_library != drvr_library) {
+ float drvr_vth = drvr_library->outputThreshold(rf);
+ float load_vth = load_library->inputThreshold(rf);
+ float drvr_slew_delta = drvr_library->slewUpperThreshold(rf)
+ - drvr_library->slewLowerThreshold(rf);
float load_delay_delta =
delayAsFloat(load_slew) * ((load_vth - drvr_vth) / drvr_slew_delta);
- load_delay += (drvr_rf_ == RiseFall::rise())
+ load_delay += (rf == RiseFall::rise())
? load_delay_delta
: -load_delay_delta;
- float load_slew_delta = load_library->slewUpperThreshold(drvr_rf_)
- - load_library->slewLowerThreshold(drvr_rf_);
- float drvr_slew_derate = drvr_library_->slewDerateFromLibrary();
+ float load_slew_delta = load_library->slewUpperThreshold(rf)
+ - load_library->slewLowerThreshold(rf);
+ float drvr_slew_derate = drvr_library->slewDerateFromLibrary();
float load_slew_derate = load_library->slewDerateFromLibrary();
load_slew = load_slew * ((load_slew_delta / load_slew_derate)
/ (drvr_slew_delta / drvr_slew_derate));
@@ -129,4 +168,55 @@ DelayCalcBase::thresholdLibrary(const Pin *load_pin)
}
}
+ArcDelay
+DelayCalcBase::checkDelay(const Pin *check_pin,
+ const TimingArc *arc,
+ const Slew &from_slew,
+ const Slew &to_slew,
+ float related_out_cap,
+ const DcalcAnalysisPt *dcalc_ap)
+{
+ CheckTimingModel *model = checkModel(arc, dcalc_ap);
+ if (model) {
+ float from_slew1 = delayAsFloat(from_slew);
+ float to_slew1 = delayAsFloat(to_slew);
+ return model->checkDelay(pinPvt(check_pin, dcalc_ap), from_slew1, to_slew1,
+ related_out_cap, pocv_enabled_);
+ }
+ else
+ return delay_zero;
+}
+
+string
+DelayCalcBase::reportCheckDelay(const Pin *check_pin,
+ const TimingArc *arc,
+ const Slew &from_slew,
+ const char *from_slew_annotation,
+ const Slew &to_slew,
+ float related_out_cap,
+ const DcalcAnalysisPt *dcalc_ap,
+ int digits)
+{
+ CheckTimingModel *model = checkModel(arc, dcalc_ap);
+ if (model) {
+ float from_slew1 = delayAsFloat(from_slew);
+ float to_slew1 = delayAsFloat(to_slew);
+ return model->reportCheckDelay(pinPvt(check_pin, dcalc_ap), from_slew1,
+ from_slew_annotation, to_slew1,
+ related_out_cap, false, digits);
+ }
+ return "";
+}
+
+const Pvt *
+DelayCalcBase::pinPvt(const Pin *pin,
+ const DcalcAnalysisPt *dcalc_ap)
+{
+ const Instance *drvr_inst = network_->instance(pin);
+ const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
+ if (pvt == nullptr)
+ pvt = dcalc_ap->operatingConditions();
+ return pvt;
+}
+
} // namespace
diff --git a/dcalc/DelayCalcBase.hh b/dcalc/DelayCalcBase.hh
index 248e8e5a..76137d0b 100644
--- a/dcalc/DelayCalcBase.hh
+++ b/dcalc/DelayCalcBase.hh
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -20,44 +20,64 @@
namespace sta {
+class GateTableModel;
+
class DelayCalcBase : public ArcDelayCalc
{
public:
explicit DelayCalcBase(StaState *sta);
- void inputPortDelay(const Pin *port_pin,
- float in_slew,
- const RiseFall *rf,
- const Parasitic *parasitic,
+ void finishDrvrPin() override;
+
+ void reduceParasitic(const Parasitic *parasitic_network,
+ const Net *net,
+ const Corner *corner,
+ const MinMaxAll *min_max) override;
+
+ ArcDelay checkDelay(const Pin *check_pin,
+ const TimingArc *arc,
+ const Slew &from_slew,
+ const Slew &to_slew,
+ float related_out_cap,
const DcalcAnalysisPt *dcalc_ap) override;
- void finishDrvrPin() override;
+
+ string reportCheckDelay(const Pin *check_pin,
+ const TimingArc *arc,
+ const Slew &from_slew,
+ const char *from_slew_annotation,
+ const Slew &to_slew,
+ float related_out_cap,
+ const DcalcAnalysisPt *dcalc_ap,
+ int digits) override;
protected:
- void gateDelayInit(const TimingArc *arc,
- const Slew &in_slew,
- const Parasitic *drvr_parasitic);
+ GateTimingModel *gateModel(const TimingArc *arc,
+ const DcalcAnalysisPt *dcalc_ap) const;
+ GateTableModel *gateTableModel(const TimingArc *arc,
+ const DcalcAnalysisPt *dcalc_ap) const;
+ CheckTimingModel *checkModel(const TimingArc *arc,
+ const DcalcAnalysisPt *dcalc_ap) const;
+ TimingModel *model(const TimingArc *arc,
+ const DcalcAnalysisPt *dcalc_ap) const;
// Find the liberty library to use for logic/slew thresholds.
LibertyLibrary *thresholdLibrary(const Pin *load_pin);
// Adjust load_delay and load_slew from driver thresholds to load thresholds.
void thresholdAdjust(const Pin *load_pin,
+ const LibertyLibrary *drvr_library,
+ const RiseFall *rf,
ArcDelay &load_delay,
Slew &load_slew);
// Helper function for input ports driving dspf parasitic.
void dspfWireDelaySlew(const Pin *load_pin,
- float elmore,
+ const RiseFall *rf,
+ Slew drvr_slew,
+ float elmore,
+ // Return values.
ArcDelay &wire_delay,
Slew &load_slew);
+ const Pvt *pinPvt(const Pin *pin,
+ const DcalcAnalysisPt *dcalc_ap);
- Slew drvr_slew_;
- const LibertyCell *drvr_cell_;
- const LibertyLibrary *drvr_library_;
- const Parasitic *drvr_parasitic_;
- bool input_port_;
- const RiseFall *drvr_rf_;
- // Parasitics returned by findParasitic that are reduced or estimated
- // that can be deleted after delay calculation for the driver pin
- // is finished.
- Vector unsaved_parasitics_;
- Vector reduced_parasitic_drvrs_;
+ using ArcDelayCalc::reduceParasitic;
};
} // namespace
diff --git a/dcalc/DmpCeff.cc b/dcalc/DmpCeff.cc
index 0d298a78..70cf302f 100644
--- a/dcalc/DmpCeff.cc
+++ b/dcalc/DmpCeff.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -38,6 +38,7 @@
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "ArcDelayCalc.hh"
+#include "FindRoot.hh"
namespace sta {
@@ -47,6 +48,7 @@ using std::max;
using std::sqrt;
using std::log;
using std::isnan;
+using std::function;
// Tolerance (as a scale of value) for driver parameters (Ceff, delta t, t0).
static const double driver_param_tol = .01;
@@ -88,38 +90,15 @@ gateModelRd(const LibertyCell *cell,
double in_slew,
double c2,
double c1,
- float related_out_cap,
const Pvt *pvt,
bool pocv_enabled);
static void
-evalDmpEqnsState(void *state);
-static void
-evalVoEqns(void *state,
- double x,
- double &y,
- double &dy);
-static void
-evalVlEqns(void *state,
- double x,
- double &y,
- double &dy);
-
-static double
-findRoot(void (*func)(void *state, double x, double &y, double &dy),
- void *state,
- double x1,
- double x2,
- double x_tol,
- int max_iter);
-static void
newtonRaphson(const int max_iter,
double x[],
const int n,
const double x_tol,
// eval(state) is called to fill fvec and fjac.
- // Returns false if fails.
- void (*eval)(void *state),
- void *state,
+ function eval,
// Temporaries supplied by caller.
double *fvec,
double **fjac,
@@ -155,14 +134,15 @@ public:
const RiseFall *rf,
double rd,
double in_slew,
- float related_out_cap,
double c2,
double rpi,
double c1);
- virtual void gateDelaySlew(double &delay,
+ virtual void gateDelaySlew(// Return values.
+ double &delay,
double &slew) = 0;
virtual void loadDelaySlew(const Pin *load_pin,
double elmore,
+ // Return values.
ArcDelay &delay,
Slew &slew);
double ceff() { return ceff_; }
@@ -171,29 +151,34 @@ public:
// equations evaluated at x_ and fjac_ with the jabobian evaluated at x_.
virtual void evalDmpEqns() = 0;
// Output response to vs(t) ramp driving pi model load.
- double vo(double t);
- double dVoDt(double t);
+ void Vo(double t,
+ // Return values.
+ double &vo,
+ double &dol_dt);
// Load responce to driver waveform.
- double vl(double t);
- double dVlDt(double t);
- double vCross() { return v_cross_; }
+ void Vl(double t,
+ // Return values.
+ double &vl,
+ double &dvl_dt);
protected:
// Find driver parameters t0, delta_t, Ceff.
void findDriverParams(double ceff);
void gateCapDelaySlew(double cl,
+ // Return values.
double &delay,
double &slew);
void gateDelays(double ceff,
+ // Return values.
double &t_vth,
double &t_vl,
double &slew);
- virtual double dv0dt(double t) = 0;
// Partial derivatives of y(t) (jacobian).
void dy(double t,
double t0,
double dt,
double cl,
+ // Return values.
double &dydt0,
double &dyddt,
double &dydcl);
@@ -204,11 +189,16 @@ protected:
void showX();
void showFvec();
void showJacobian();
- void findDriverDelaySlew(double &delay,
+ void findDriverDelaySlew(// Return values.
+ double &delay,
double &slew);
- double findVoCrossing(double vth);
+ double findVoCrossing(double vth,
+ double lower_bound,
+ double upper_bound);
void showVo();
- double findVlCrossing(double vth);
+ double findVlCrossing(double vth,
+ double lower_bound,
+ double upper_bound);
void showVl();
void fail(const char *reason);
@@ -221,11 +211,17 @@ protected:
double y0(double t,
double cl);
// Output response to unit ramp driving pi model load.
- virtual double v0(double t) = 0;
+ virtual void V0(double t,
+ // Return values.
+ double &vo,
+ double &dvo_dt) = 0;
// Upper bound on time that vo crosses vh.
virtual double voCrossingUpperBound() = 0;
// Load responce to driver unit ramp.
- virtual double vl0(double t) = 0;
+ virtual void Vl0(double t,
+ // Return values.
+ double &vl,
+ double &dvl_dt) = 0;
// Upper bound on time that vl crosses vh.
double vlCrossingUpperBound();
@@ -235,7 +231,6 @@ protected:
const Pvt *pvt_;
const GateTableModel *gate_model_;
double in_slew_;
- float related_out_cap_;
double c2_;
double rpi_;
double c1_;
@@ -273,12 +268,6 @@ protected:
// Load rspf elmore delay.
double elmore_;
double p3_;
-
-private:
- virtual double dvl0dt(double t) = 0;
-
- // Implicit argument passed to evalVoEqns, evalVlEqns.
- double v_cross_;
};
DmpAlg::DmpAlg(int nr_order,
@@ -319,7 +308,6 @@ DmpAlg::init(const LibertyLibrary *drvr_library,
const RiseFall *rf,
double rd,
double in_slew,
- float related_out_cap,
// Pi model.
double c2,
double rpi,
@@ -331,7 +319,6 @@ DmpAlg::init(const LibertyLibrary *drvr_library,
gate_model_ = gate_model;
rd_ = rd;
in_slew_ = in_slew;
- related_out_cap_ = related_out_cap;
c2_ = c2;
rpi_ = rpi;
c1_ = c1;
@@ -355,8 +342,9 @@ DmpAlg::findDriverParams(double ceff)
double t0 = t_vth + log(1.0 - vth_) * rd_ * ceff - vth_ * dt;
x_[DmpParam::dt] = dt;
x_[DmpParam::t0] = t0;
- newtonRaphson(100, x_, nr_order_, driver_param_tol, evalDmpEqnsState,
- this, fvec_, fjac_, index_, p_, scale_);
+ newtonRaphson(100, x_, nr_order_, driver_param_tol,
+ [=] () { evalDmpEqns(); },
+ fvec_, fjac_, index_, p_, scale_);
t0_ = x_[DmpParam::t0];
dt_ = x_[DmpParam::dt];
debugPrint(debug_, "dmp_ceff", 3, " t0 = %s dt = %s ceff = %s",
@@ -367,29 +355,24 @@ DmpAlg::findDriverParams(double ceff)
showVo();
}
-static void
-evalDmpEqnsState(void *state)
-{
- DmpAlg *alg = reinterpret_cast(state);
- alg->evalDmpEqns();
-}
-
void
DmpAlg::gateCapDelaySlew(double ceff,
- double &delay,
+ // Return values.
+ double &delay,
double &slew)
{
ArcDelay model_delay;
Slew model_slew;
- gate_model_->gateDelay(pvt_, in_slew_, ceff, related_out_cap_,
- pocv_enabled_, model_delay, model_slew);
+ gate_model_->gateDelay(pvt_, in_slew_, ceff, pocv_enabled_,
+ model_delay, model_slew);
delay = delayAsFloat(model_delay);
slew = delayAsFloat(model_slew);
}
void
DmpAlg::gateDelays(double ceff,
- double &t_vth,
+ // Return values.
+ double &t_vth,
double &t_vl,
double &slew)
{
@@ -493,58 +476,68 @@ DmpAlg::showJacobian()
}
void
-DmpAlg::findDriverDelaySlew(double &delay,
+DmpAlg::findDriverDelaySlew(// Return values.
+ double &delay,
double &slew)
{
- delay = findVoCrossing(vth_);
- double tl = findVoCrossing(vl_);
- double th = findVoCrossing(vh_);
+ double t_upper = voCrossingUpperBound();
+ delay = findVoCrossing(vth_, t0_, t_upper);
+ double tl = findVoCrossing(vl_, t0_, delay);
+ double th = findVoCrossing(vh_, delay, t_upper);
// Convert measured slew to table slew.
slew = (th - tl) / slew_derate_;
}
// Find t such that vo(t)=v.
double
-DmpAlg::findVoCrossing(double vth)
+DmpAlg::findVoCrossing(double vth,
+ double t_lower,
+ double t_upper)
{
- v_cross_ = vth;
- double ub = voCrossingUpperBound();
- return findRoot(evalVoEqns, this, t0_, ub, vth_time_tol, find_root_max_iter);
+ FindRootFunc vo_func = [=] (double t,
+ double &y,
+ double &dy) {
+ double vo, vo_dt;
+ Vo(t, vo, vo_dt);
+ y = vo - vth;
+ dy = vo_dt;
+ };
+ bool fail;
+ double t_vth = findRoot(vo_func, t_lower, t_upper, vth_time_tol,
+ find_root_max_iter, fail);
+ if (fail)
+ throw DmpError("find Vo crossing failed");
+ return t_vth;
}
-static void
-evalVoEqns(void *state,
- double x,
- double &y,
- double &dy)
-{
- DmpAlg *pi_ceff = reinterpret_cast(state);
- y = pi_ceff->vo(x) - pi_ceff->vCross();
- dy = pi_ceff->dVoDt(x);
-}
-
-double
-DmpAlg::vo(double t)
+void
+DmpAlg::Vo(double t,
+ // Return values.
+ double &vo,
+ double &dvo_dt)
{
double t1 = t - t0_;
- if (t1 <= 0.0)
- return 0.0;
- else if (t1 <= dt_)
- return v0(t1) / dt_;
- else
- return (v0(t1) - v0(t1 - dt_)) / dt_;
-}
+ if (t1 <= 0.0) {
+ vo = 0.0;
+ dvo_dt = 0.0;
+ }
+ else if (t1 <= dt_) {
+ double v0, dv0_dt;
+ V0(t1, v0, dv0_dt);
-double
-DmpAlg::dVoDt(double t)
-{
- double t1 = t - t0_;
- if (t1 <= 0)
- return 0.0;
- else if (t1 <= dt_)
- return dv0dt(t1) / dt_;
- else
- return (dv0dt(t1) - dv0dt(t1 - dt_)) / dt_;
+ vo = v0 / dt_;
+ dvo_dt = dv0_dt / dt_;
+ }
+ else {
+ double v0, dv0_dt;
+ V0(t1, v0, dv0_dt);
+
+ double v0_dt, dv0_dt_dt;
+ V0(t1 - dt_, v0_dt, dv0_dt_dt);
+
+ vo = (v0 - v0_dt) / dt_;
+ dvo_dt = (dv0_dt - dv0_dt_dt) / dt_;
+ }
}
void
@@ -552,8 +545,11 @@ DmpAlg::showVo()
{
report_->reportLine(" t vo(t)");
double ub = voCrossingUpperBound();
- for (double t = t0_; t < t0_ + ub; t += dt_ / 10.0)
- report_->reportLine(" %g %g", t, vo(t));
+ for (double t = t0_; t < t0_ + ub; t += dt_ / 10.0) {
+ double vo, dvo_dt;
+ Vo(t, vo, dvo_dt);
+ report_->reportLine(" %g %g", t, vo);
+ }
}
void
@@ -577,9 +573,11 @@ DmpAlg::loadDelaySlew(const Pin *,
showVl();
elmore_ = elmore;
p3_ = 1.0 / elmore;
- double load_delay = findVlCrossing(vth_);
- double tl = findVlCrossing(vl_);
- double th = findVlCrossing(vh_);
+ double t_lower = t0_;
+ double t_upper = vlCrossingUpperBound();
+ double load_delay = findVlCrossing(vth_, t_lower, t_upper);
+ double tl = findVlCrossing(vl_, t_lower, load_delay);
+ double th = findVlCrossing(vh_, load_delay, t_upper);
// Measure delay from Vo, the load dependent source excitation.
double delay1 = load_delay - vo_delay_;
// Convert measured slew to reported/table slew.
@@ -609,13 +607,25 @@ DmpAlg::loadDelaySlew(const Pin *,
}
// Find t such that vl(t)=v.
-// Return true if successful.
double
-DmpAlg::findVlCrossing(double vth)
+DmpAlg::findVlCrossing(double vth,
+ double t_lower,
+ double t_upper)
{
- v_cross_ = vth;
- double ub = vlCrossingUpperBound();
- return findRoot(evalVlEqns, this, t0_, ub, vth_time_tol, find_root_max_iter);
+ FindRootFunc vl_func = [=] (double t,
+ double &y,
+ double &dy) {
+ double vl, vl_dt;
+ Vl(t, vl, vl_dt);
+ y = vl - vth;
+ dy = vl_dt;
+ };
+ bool fail;
+ double t_vth = findRoot(vl_func, t_lower, t_upper, vth_time_tol,
+ find_root_max_iter, fail);
+ if (fail)
+ throw DmpError("find Vl crossing failed");
+ return t_vth;
}
double
@@ -624,39 +634,33 @@ DmpAlg::vlCrossingUpperBound()
return voCrossingUpperBound() + elmore_ * 2.0;
}
-static void
-evalVlEqns(void *state,
- double x,
- double &y,
- double &dy)
-{
- DmpAlg *pi_ceff = reinterpret_cast(state);
- y = pi_ceff->vl(x) - pi_ceff->vCross();
- dy = pi_ceff->dVlDt(x);
-}
-
-double
-DmpAlg::vl(double t)
+void
+DmpAlg::Vl(double t,
+ // Return values.
+ double &vl,
+ double &dvl_dt)
{
double t1 = t - t0_;
- if (t1 <= 0)
- return 0.0;
- else if (t1 <= dt_)
- return vl0(t1) / dt_;
- else
- return (vl0(t1) - vl0(t1 - dt_)) / dt_;
-}
+ if (t1 <= 0.0) {
+ vl = 0.0;
+ dvl_dt = 0.0;
+ }
+ else if (t1 <= dt_) {
+ double vl0, dvl0_dt;
+ Vl0(t1, vl0, dvl0_dt);
+ vl = vl0 / dt_;
+ dvl_dt = dvl0_dt / dt_;
+ }
+ else {
+ double vl0, dvl0_dt;
+ Vl0(t1, vl0, dvl0_dt);
-double
-DmpAlg::dVlDt(double t)
-{
- double t1 = t - t0_;
- if (t1 <= 0)
- return 0.0;
- else if (t1 <= dt_)
- return dvl0dt(t1) / dt_;
- else
- return (dvl0dt(t1) - dvl0dt(t1 - dt_)) / dt_;
+ double vl0_dt, dvl0_dt_dt;
+ Vl0(t1 - dt_, vl0_dt, dvl0_dt_dt);
+
+ vl = (vl0 - vl0_dt) / dt_;
+ dvl_dt = (dvl0_dt - dvl0_dt_dt) / dt_;
+ }
}
void
@@ -664,8 +668,11 @@ DmpAlg::showVl()
{
report_->reportLine(" t vl(t)");
double ub = vlCrossingUpperBound();
- for (double t = t0_; t < t0_ + ub * 2.0; t += ub / 10.0)
- report_->reportLine(" %g %g", t, vl(t));
+ for (double t = t0_; t < t0_ + ub * 2.0; t += ub / 10.0) {
+ double vl, dvl_dt;
+ Vl(t, vl, dvl_dt);
+ report_->reportLine(" %g %g", t, vl);
+ }
}
void
@@ -688,32 +695,37 @@ class DmpCap : public DmpAlg
{
public:
DmpCap(StaState *sta);
- virtual const char *name() { return "cap"; }
- virtual void init(const LibertyLibrary *library,
- const LibertyCell *drvr_cell,
- const Pvt *pvt,
- const GateTableModel *gate_model,
- const RiseFall *rf,
- double rd,
- double in_slew,
- float related_out_cap,
- double c2,
- double rpi,
- double c1);
- virtual void gateDelaySlew(double &delay,
- double &slew);
- virtual void loadDelaySlew(const Pin *,
- double elmore,
- ArcDelay &delay,
- Slew &slew);
- virtual void evalDmpEqns();
- virtual double voCrossingUpperBound();
+ const char *name() override { return "cap"; }
+ void init(const LibertyLibrary *library,
+ const LibertyCell *drvr_cell,
+ const Pvt *pvt,
+ const GateTableModel *gate_model,
+ const RiseFall *rf,
+ double rd,
+ double in_slew,
+ double c2,
+ double rpi,
+ double c1) override;
+ void gateDelaySlew(// Return values.
+ double &delay,
+ double &slew) override;
+ void loadDelaySlew(const Pin *,
+ double elmore,
+ // Return values.
+ ArcDelay &delay,
+ Slew &slew) override;
+ void evalDmpEqns() override;
+ double voCrossingUpperBound() override;
private:
- virtual double v0(double t);
- virtual double dv0dt(double t);
- virtual double vl0(double t);
- virtual double dvl0dt(double t);
+ void V0(double t,
+ // Return values.
+ double &vo,
+ double &dvo_dt) override;
+ void Vl0(double t,
+ // Return values.
+ double &vl,
+ double &dvl_dt) override;
};
DmpCap::DmpCap(StaState *sta):
@@ -729,19 +741,19 @@ DmpCap::init(const LibertyLibrary *drvr_library,
const RiseFall *rf,
double rd,
double in_slew,
- float related_out_cap,
double c2,
double rpi,
double c1)
{
debugPrint(debug_, "dmp_ceff", 3, "Using DMP cap");
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf,
- rd, in_slew, related_out_cap, c2, rpi, c1);
+ rd, in_slew, c2, rpi, c1);
ceff_ = c1 + c2;
}
void
-DmpCap::gateDelaySlew(double &delay,
+DmpCap::gateDelaySlew(// Return values.
+ double &delay,
double &slew)
{
debugPrint(debug_, "dmp_ceff", 3, " ceff = %s",
@@ -765,16 +777,14 @@ DmpCap::evalDmpEqns()
{
}
-double
-DmpCap::v0(double)
+void
+DmpCap::V0(double,
+ // Return values.
+ double &vo,
+ double &dvo_dt)
{
- return 0.0;
-}
-
-double
-DmpCap::dv0dt(double)
-{
- return 0.0;
+ vo = 0.0;
+ dvo_dt = 0.0;
}
double
@@ -783,16 +793,14 @@ DmpCap::voCrossingUpperBound()
return 0.0;
}
-double
-DmpCap::vl0(double)
+void
+DmpCap::Vl0(double ,
+ // Return values.
+ double &vl,
+ double &dvl_dt)
{
- return 0.0;
-}
-
-double
-DmpCap::dvl0dt(double)
-{
- return 0.0;
+ vl = 0.0;
+ dvl_dt = 0.0;
}
////////////////////////////////////////////////////////////////
@@ -802,33 +810,37 @@ class DmpPi : public DmpAlg
{
public:
DmpPi(StaState *sta);
- virtual const char *name() { return "Pi"; }
- virtual void init(const LibertyLibrary *library,
- const LibertyCell *drvr_cell,
- const Pvt *pvt,
- const GateTableModel *gate_model,
- const RiseFall *rf,
- double rd,
- double in_slew,
- float related_out_cap,
- double c2,
- double rpi,
- double c1);
- virtual void gateDelaySlew(double &delay,
- double &slew);
- virtual void evalDmpEqns();
- virtual double voCrossingUpperBound();
+ const char *name() override { return "Pi"; }
+ void init(const LibertyLibrary *library,
+ const LibertyCell *drvr_cell,
+ const Pvt *pvt,
+ const GateTableModel *gate_model,
+ const RiseFall *rf,
+ double rd,
+ double in_slew,
+ double c2,
+ double rpi,
+ double c1) override;
+ void gateDelaySlew(// Return values.
+ double &delay,
+ double &slew) override;
+ void evalDmpEqns() override;
+ double voCrossingUpperBound() override;
private:
void findDriverParamsPi();
- virtual double v0(double t);
- virtual double dv0dt(double t);
double ipiIceff(double t0,
double dt,
double ceff_time,
double ceff);
- virtual double vl0(double t);
- virtual double dvl0dt(double t);
+ void V0(double t,
+ // Return values.
+ double &vo,
+ double &dvo_dt) override;
+ void Vl0(double t,
+ // Return values.
+ double &vl,
+ double &dvl_dt) override;
// Poles/zero.
double p1_;
@@ -870,14 +882,13 @@ DmpPi::init(const LibertyLibrary *drvr_library,
const RiseFall *rf,
double rd,
double in_slew,
- float related_out_cap,
double c2,
double rpi,
double c1)
{
debugPrint(debug_, "dmp_ceff", 3, "Using DMP Pi");
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd,
- in_slew, related_out_cap, c2, rpi, c1);
+ in_slew, c2, rpi, c1);
// Find poles/zeros.
z1_ = 1.0 / (rpi_ * c1_);
@@ -901,7 +912,8 @@ DmpPi::init(const LibertyLibrary *drvr_library,
}
void
-DmpPi::gateDelaySlew(double &delay,
+DmpPi::gateDelaySlew(// Return values.
+ double &delay,
double &slew)
{
driver_valid_ = false;
@@ -1030,27 +1042,35 @@ DmpPi::ipiIceff(double, double dt,
return ipi - iceff;
}
-double
-DmpPi::v0(double t)
+void
+DmpPi::V0(double t,
+ // Return values.
+ double &vo,
+ double &dvo_dt)
{
- return k0_ * (k1_ + k2_ * t + k3_ * exp2(-p1_ * t) + k4_ * exp2(-p2_ * t));
+ double exp_p1 = exp2(-p1_ * t);
+ double exp_p2 = exp2(-p2_ * t);
+ vo = k0_ * (k1_ + k2_ * t + k3_ * exp_p1 + k4_ * exp_p2);
+ dvo_dt = k0_ * (k2_ - k3_ * p1_ * exp_p1 - k4_ * p2_ * exp_p2);
}
-double
-DmpPi::dv0dt(double t)
-{
- return k0_ * (k2_ - k3_ * p1_ * exp2(-p1_ * t) - k4_ * p2_ * exp2(-p2_ * t));
-}
-
-double
-DmpPi::vl0(double t)
+void
+DmpPi::Vl0(double t,
+ // Return values.
+ double &vl,
+ double &dvl_dt)
{
double D1 = k0_ * (k1_ - k2_ / p3_);
double D3 = -p3_ * k0_ * k3_ / (p1_ - p3_);
double D4 = -p3_ * k0_ * k4_ / (p2_ - p3_);
double D5 = k0_ * (k2_ / p3_ - k1_ + p3_ * k3_ / (p1_ - p3_)
+ p3_ * k4_ / (p2_ - p3_));
- return D1 + t + D3 * exp2(-p1_ * t) + D4 * exp2(-p2_ * t) + D5 * exp2(-p3_ * t);
+ double exp_p1 = exp2(-p1_ * t);
+ double exp_p2 = exp2(-p2_ * t);
+ double exp_p3 = exp2(-p3_ * t);
+ vl = D1 + t + D3 * exp_p1 + D4 * exp_p2 + D5 * exp_p3;
+ dvl_dt = 1.0 - D3 * p1_ * exp_p1 - D4 * p2_ * exp_p2
+ - D5 * p3_ * exp_p3;
}
double
@@ -1059,17 +1079,6 @@ DmpPi::voCrossingUpperBound()
return t0_ + dt_ + (c1_ + c2_) * (rd_ + rpi_) * 2.0;
}
-double
-DmpPi::dvl0dt(double t)
-{
- double D3 = -p3_ * k0_ * k3_ / (p1_ - p3_);
- double D4 = -p3_ * k0_ * k4_ / (p2_ - p3_);
- double D5 = k0_ * (k2_ / p3_ - k1_ + p3_ * k3_ / (p1_ - p3_)
- + p3_ * k4_ / (p2_ - p3_));
- return 1.0 - D3 * p1_ * exp2(-p1_ * t) - D4 * p2_ * exp2(-p2_ * t)
- - D5 * p3_ * exp2(-p3_ * t);
-}
-
////////////////////////////////////////////////////////////////
// Capacitive load, so Ceff is known.
@@ -1078,8 +1087,8 @@ class DmpOnePole : public DmpAlg
{
public:
DmpOnePole(StaState *sta);
- virtual void evalDmpEqns();
- virtual double voCrossingUpperBound();
+ void evalDmpEqns() override;
+ double voCrossingUpperBound() override;
};
DmpOnePole::DmpOnePole(StaState *sta) :
@@ -1136,27 +1145,31 @@ class DmpZeroC2 : public DmpOnePole
{
public:
DmpZeroC2(StaState *sta);
- virtual const char *name() { return "c2=0"; }
- virtual void init(const LibertyLibrary *drvr_library,
- const LibertyCell *drvr_cell,
- const Pvt *pvt,
- const GateTableModel *gate_model,
- const RiseFall *rf,
- double rd,
- double in_slew,
- float related_out_cap,
- double c2,
- double rpi,
- double c1);
- virtual void gateDelaySlew(double &delay,
- double &slew);
+ const char *name() override { return "c2=0"; }
+ void init(const LibertyLibrary *drvr_library,
+ const LibertyCell *drvr_cell,
+ const Pvt *pvt,
+ const GateTableModel *gate_model,
+ const RiseFall *rf,
+ double rd,
+ double in_slew,
+ double c2,
+ double rpi,
+ double c1) override;
+ void gateDelaySlew(// Return values.
+ double &delay,
+ double &slew) override;
private:
- virtual double v0(double t);
- virtual double dv0dt(double t);
- virtual double vl0(double t);
- virtual double dvl0dt(double t);
- virtual double voCrossingUpperBound();
+ void V0(double t,
+ // Return values.
+ double &vo,
+ double &dvo_dt) override;
+ void Vl0(double t,
+ // Return values.
+ double &vl,
+ double &dvl_dt) override;
+ double voCrossingUpperBound() override;
// Pole/zero.
double p1_;
@@ -1187,14 +1200,13 @@ DmpZeroC2::init(const LibertyLibrary *drvr_library,
const RiseFall *rf,
double rd,
double in_slew,
- float related_out_cap,
double c2,
double rpi,
double c1)
{
debugPrint(debug_, "dmp_ceff", 3, "Using DMP C2=0");
DmpAlg::init(drvr_library, drvr_cell, pvt, gate_model, rf, rd,
- in_slew, related_out_cap, c2, rpi, c1);
+ in_slew, c2, rpi, c1);
ceff_ = c1;
z1_ = 1.0 / (rpi_ * c1_);
@@ -1207,7 +1219,8 @@ DmpZeroC2::init(const LibertyLibrary *drvr_library,
}
void
-DmpZeroC2::gateDelaySlew(double &delay,
+DmpZeroC2::gateDelaySlew(// Return values.
+ double &delay,
double &slew)
{
try {
@@ -1227,33 +1240,30 @@ DmpZeroC2::gateDelaySlew(double &delay,
drvr_slew_ = slew;
}
-double
-DmpZeroC2::v0(double t)
+void
+DmpZeroC2::V0(double t,
+ // Return values.
+ double &vo,
+ double &dvo_dt)
{
- return k0_ * (k1_ + k2_ * t + k3_ * exp2(-p1_ * t));
+ double exp_p1 = exp2(-p1_ * t);
+ vo = k0_ * (k1_ + k2_ * t + k3_ * exp_p1);
+ dvo_dt = k0_ * (k2_ - k3_ * p1_ * exp_p1);
}
-double
-DmpZeroC2::dv0dt(double t)
-{
- return k0_ * (k2_ - k3_ * p1_ * exp2(-p1_ * t));
-}
-
-double
-DmpZeroC2::vl0(double t)
+void
+DmpZeroC2::Vl0(double t,
+ // Return values.
+ double &vl,
+ double &dvl_dt)
{
double D1 = k0_ * (k1_ - k2_ / p3_);
double D3 = -p3_ * k0_ * k3_ / (p1_ - p3_);
double D5 = k0_ * (k2_ / p3_ - k1_ + p3_ * k3_ / (p1_ - p3_));
- return D1 + t + D3 * exp2(-p1_ * t) + D5 * exp2(-p3_ * t);
-}
-
-double
-DmpZeroC2::dvl0dt(double t)
-{
- double D3 = -p3_ * k0_ * k3_ / (p1_ - p3_);
- double D5 = k0_ * (k2_ / p3_ - k1_ + p3_ * k3_ / (p1_ - p3_));
- return 1.0 - D3 * p1_ * exp2(-p1_ * t) - D5 * p3_ * exp2(-p3_ * t);
+ double exp_p1 = exp2(-p1_ * t);
+ double exp_p3 = exp2(-p3_ * t);
+ vl = D1 + t + D3 * exp_p1 + D5 * exp_p3;
+ dvl_dt = 1.0 - D3 * p1_ * exp_p1 - D5 * p3_ * exp_p3;
}
double
@@ -1264,70 +1274,6 @@ DmpZeroC2::voCrossingUpperBound()
////////////////////////////////////////////////////////////////
-// Find the root of a function between x1 and x2 using a combination
-// of Newton-Raphson and bisection search.
-// x_tol is a percentage that change in x must be less than (1.0 = 100%).
-// error is non-null if a problem occurs.
-static double
-findRoot(void (*func)(void *state, double x, double &y, double &dy),
- void *state,
- double x1,
- double x2,
- double x_tol,
- int max_iter)
-{
- double y1, y2, dy;
- func(state, x1, y1, dy);
- func(state, x2, y2, dy);
-
- if ((y1 > 0.0 && y2 > 0.0) || (y1 < 0.0 && y2 < 0.0))
- throw DmpError("findRoot: initial bounds do not surround a root");
-
- if (y1 == 0.0)
- return x1;
-
- if (y2 == 0.0)
- return x2;
-
- if (y1 > 0.0) {
- // Swap x1/x2 so func(x1) < 0.
- double tmp = x1;
- x1 = x2;
- x2 = tmp;
- }
- double root = (x1 + x2) * 0.5;
- double dx_prev = abs(x2 - x1);
- double dx = dx_prev;
- double y;
- func(state, root, y, dy);
- for (int iter = 0; iter < max_iter; iter++) {
- // Newton/raphson out of range.
- if ((((root - x2) * dy - y) * ((root - x1) * dy - y) > 0.0)
- // Not decreasing fast enough.
- || (abs(2.0 * y) > abs(dx_prev * dy))) {
- // Bisect x1/x2 interval.
- dx_prev = dx;
- dx = (x2 - x1) * 0.5;
- root = x1 + dx;
- }
- else {
- dx_prev = dx;
- dx = y / dy;
- root -= dx;
- }
- if (abs(dx) <= x_tol * abs(root))
- // Converged.
- return root;
-
- func(state, root, y, dy);
- if (y < 0.0)
- x1 = root;
- else
- x2 = root;
- }
- throw DmpError("findRoot: max iterations exceeded");
-}
-
// Newton-Raphson iteration to find zeros of a function.
// x_tol is percentage that all changes in x must be less than (1.0 = 100%).
// Eval(state) is called to fill fvec and fjac (returns false if fails).
@@ -1337,8 +1283,7 @@ newtonRaphson(const int max_iter,
double x[],
const int size,
const double x_tol,
- void (*eval)(void *state),
- void *state,
+ function eval,
// Temporaries supplied by caller.
double *fvec,
double **fjac,
@@ -1347,7 +1292,7 @@ newtonRaphson(const int max_iter,
double *scale)
{
for (int k = 0; k < max_iter; k++) {
- eval(state);
+ eval();
for (int i = 0; i < size; i++)
// Right-hand side of linear equations.
p[i] = -fvec[i];
@@ -1408,7 +1353,7 @@ luDecomp(double **a,
a[i][j] = sum;
}
// Run down jth subdiag to form the residuals after the elimination
- // of the first j-1 subdiags. These residuals divided by the
+ // of the first j-1 subdiags. These residuals diviyded by the
// appropriate diagonal term will become the multipliers in the
// elimination of the jth. subdiag. Find index of largest scaled
// term in imax.
@@ -1543,64 +1488,58 @@ DmpCeffDelayCalc::~DmpCeffDelayCalc()
delete dmp_zero_c2_;
}
-void
-DmpCeffDelayCalc::inputPortDelay(const Pin *port_pin,
- float in_slew,
- const RiseFall *rf,
- const Parasitic *parasitic,
- const DcalcAnalysisPt *dcalc_ap)
+ArcDcalcResult
+DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
+ const Slew &in_slew,
+ float load_cap,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap)
{
- dmp_alg_ = nullptr;
- LumpedCapDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
-}
-
-void
-DmpCeffDelayCalc::gateDelay(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- // Return values.
- ArcDelay &gate_delay,
- Slew &drvr_slew)
-{
- input_port_ = false;
- drvr_rf_ = arc->toEdge()->asRiseFall();
+ const RiseFall *rf = arc->toEdge()->asRiseFall();
const LibertyCell *drvr_cell = arc->from()->libertyCell();
- drvr_library_ = drvr_cell->libertyLibrary();
- drvr_parasitic_ = drvr_parasitic;
+ const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
- GateTimingModel *model = gateModel(arc, dcalc_ap);
- GateTableModel *table_model = dynamic_cast(model);
- if (table_model && drvr_parasitic) {
+ GateTableModel *table_model = gateTableModel(arc, dcalc_ap);
+ if (table_model && parasitic) {
float in_slew1 = delayAsFloat(in_slew);
float c2, rpi, c1;
- parasitics_->piModel(drvr_parasitic, c2, rpi, c1);
+ parasitics_->piModel(parasitic, c2, rpi, c1);
if (isnan(c2) || isnan(c1) || isnan(rpi))
- report_->error(618, "parasitic Pi model has NaNs.");
- setCeffAlgorithm(drvr_library_, drvr_cell, pvt, table_model,
- drvr_rf_, in_slew1, related_out_cap,
- c2, rpi, c1);
- double dmp_gate_delay, dmp_drvr_slew;
- gateDelaySlew(dmp_gate_delay, dmp_drvr_slew);
- gate_delay = dmp_gate_delay;
- drvr_slew = dmp_drvr_slew;
+ report_->error(1040, "parasitic Pi model has NaNs.");
+ setCeffAlgorithm(drvr_library, drvr_cell, pinPvt(drvr_pin, dcalc_ap),
+ table_model, rf, in_slew1, c2, rpi, c1);
+ double gate_delay, drvr_slew;
+ gateDelaySlew(gate_delay, drvr_slew);
+ ArcDcalcResult dcalc_result(load_pin_index_map.size());
+ dcalc_result.setGateDelay(gate_delay);
+ dcalc_result.setDrvrSlew(drvr_slew);
+
+ for (auto load_pin_index : load_pin_index_map) {
+ const Pin *load_pin = load_pin_index.first;
+ size_t load_idx = load_pin_index.second;
+ ArcDelay wire_delay;
+ Slew load_slew;
+ loadDelaySlew(load_pin, drvr_slew, rf, drvr_library, parasitic,
+ wire_delay, load_slew);
+ dcalc_result.setWireDelay(load_idx, wire_delay);
+ dcalc_result.setLoadSlew(load_idx, load_slew);
+ }
+ return dcalc_result;
}
else {
- LumpedCapDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
- related_out_cap, pvt, dcalc_ap,
- gate_delay, drvr_slew);
- if (drvr_parasitic
+ ArcDcalcResult dcalc_result =
+ LumpedCapDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
+ load_pin_index_map, dcalc_ap);
+ if (parasitic
&& !unsuppored_model_warned_) {
unsuppored_model_warned_ = true;
- report_->warn(1, "cell %s delay model not supported on SPF parasitics by DMP delay calculator",
+ report_->warn(1041, "cell %s delay model not supported on SPF parasitics by DMP delay calculator",
drvr_cell->name());
}
+ return dcalc_result;
}
- drvr_slew_ = drvr_slew;
- multi_drvr_slew_factor_ = 1.0F;
}
void
@@ -1610,7 +1549,6 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
- float related_out_cap,
double c2,
double rpi,
double c1)
@@ -1618,7 +1556,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
double rd = 0.0;
if (gate_model) {
rd = gateModelRd(drvr_cell, gate_model, rf, in_slew, c2, c1,
- related_out_cap, pvt, pocv_enabled_);
+ pvt, pocv_enabled_);
// Zero Rd means the table is constant and thus independent of load cap.
if (rd < 1e-2
// Rpi is small compared to Rd, which makes the load capacitive.
@@ -1635,7 +1573,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
else
dmp_alg_ = dmp_cap_;
dmp_alg_->init(drvr_library, drvr_cell, pvt, gate_model,
- drvr_rf_, rd, in_slew, related_out_cap, c2, rpi, c1);
+ rf, rd, in_slew, c2, rpi, c1);
debugPrint(debug_, "dmp_ceff", 3,
" DMP in_slew = %s c2 = %s rpi = %s c1 = %s Rd = %s (%s alg)",
units_->timeUnit()->asString(in_slew),
@@ -1646,51 +1584,29 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
dmp_alg_->name());
}
-float
-DmpCeffDelayCalc::ceff(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap)
-{
- ArcDelay gate_delay;
- Slew drvr_slew;
- gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap,
- gate_delay, drvr_slew);
- if (dmp_alg_)
- return dmp_alg_->ceff();
- else
- return load_cap;
-}
-
string
-DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc,
+DmpCeffDelayCalc::reportGateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
const Slew &in_slew,
float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits)
{
- ArcDelay gate_delay;
- Slew drvr_slew;
- gateDelay(arc, in_slew, load_cap, drvr_parasitic, related_out_cap, pvt, dcalc_ap,
- gate_delay, drvr_slew);
+ gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic, load_pin_index_map, dcalc_ap);
GateTimingModel *model = gateModel(arc, dcalc_ap);
float c_eff = 0.0;
string result;
- if (drvr_parasitic_ && dmp_alg_) {
+ if (parasitic && dmp_alg_) {
c_eff = dmp_alg_->ceff();
- const LibertyCell *drvr_cell = arc->from()->libertyCell();
+ const LibertyCell *drvr_cell = arc->to()->libertyCell();
const LibertyLibrary *drvr_library = drvr_cell->libertyLibrary();
const Units *units = drvr_library->units();
const Unit *cap_unit = units->capacitanceUnit();
const Unit *res_unit = units->resistanceUnit();
float c2, rpi, c1;
- parasitics_->piModel(drvr_parasitic_, c2, rpi, c1);
+ parasitics_->piModel(parasitic, c2, rpi, c1);
result += "Pi model C2=";
result += cap_unit->asString(c2, digits);
result += " Rpi=";
@@ -1705,7 +1621,7 @@ DmpCeffDelayCalc::reportGateDelay(const TimingArc *arc,
c_eff = load_cap;
if (model) {
float in_slew1 = delayAsFloat(in_slew);
- result += model->reportGateDelay(pvt, in_slew1, c_eff, related_out_cap,
+ result += model->reportGateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, c_eff,
pocv_enabled_, digits);
}
return result;
@@ -1718,7 +1634,6 @@ gateModelRd(const LibertyCell *cell,
double in_slew,
double c2,
double c1,
- float related_out_cap,
const Pvt *pvt,
bool pocv_enabled)
{
@@ -1726,25 +1641,26 @@ gateModelRd(const LibertyCell *cell,
float cap2 = cap1 + 1e-15;
ArcDelay d1, d2;
Slew s1, s2;
- gate_model->gateDelay(pvt, in_slew, cap1, related_out_cap, pocv_enabled, d1, s1);
- gate_model->gateDelay(pvt, in_slew, cap2, related_out_cap, pocv_enabled, d2, s2);
+ gate_model->gateDelay(pvt, in_slew, cap1, pocv_enabled, d1, s1);
+ gate_model->gateDelay(pvt, in_slew, cap2, pocv_enabled, d2, s2);
double vth = cell->libertyLibrary()->outputThreshold(rf);
float rd = -log(vth) * abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1);
return rd;
}
void
-DmpCeffDelayCalc::gateDelaySlew(double &delay,
+DmpCeffDelayCalc::gateDelaySlew(// Return values.
+ double &delay,
double &slew)
{
dmp_alg_->gateDelaySlew(delay, slew);
}
void
-DmpCeffDelayCalc::loadDelaySlew(const Pin *load_pin,
- double elmore,
- ArcDelay &delay,
- Slew &slew)
+DmpCeffDelayCalc::loadDelaySlewElmore(const Pin *load_pin,
+ double elmore,
+ ArcDelay &delay,
+ Slew &slew)
{
if (dmp_alg_)
dmp_alg_->loadDelaySlew(load_pin, elmore, delay, slew);
diff --git a/dcalc/DmpCeff.hh b/dcalc/DmpCeff.hh
index b79dbdc6..fadc0140 100644
--- a/dcalc/DmpCeff.hh
+++ b/dcalc/DmpCeff.hh
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -34,45 +34,39 @@ class DmpCeffDelayCalc : public LumpedCapDelayCalc
public:
DmpCeffDelayCalc(StaState *sta);
virtual ~DmpCeffDelayCalc();
- virtual void inputPortDelay(const Pin *port_pin,
- float in_slew,
- const RiseFall *rf,
- const Parasitic *parasitic,
- const DcalcAnalysisPt *dcalc_ap);
- virtual void gateDelay(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- // return values
- ArcDelay &gate_delay,
- Slew &drvr_slew);
- virtual float ceff(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap);
- virtual string reportGateDelay(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- int digits);
- virtual void copyState(const StaState *sta);
+ ArcDcalcResult gateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
+ const Slew &in_slew,
+ float load_cap,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap) override;
+ string reportGateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
+ const Slew &in_slew,
+ float load_cap,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap,
+ int digits) override;
+ void copyState(const StaState *sta) override;
protected:
- void gateDelaySlew(double &delay,
+ virtual void loadDelaySlew(const Pin *load_pin,
+ double drvr_slew,
+ const RiseFall *rf,
+ const LibertyLibrary *drvr_library,
+ const Parasitic *parasitic,
+ // Return values.
+ ArcDelay &wire_delay,
+ Slew &load_slew) = 0;
+ void gateDelaySlew(// Return values.
+ double &delay,
double &slew);
- void loadDelaySlew(const Pin *load_pin,
- double elmore,
- ArcDelay &delay,
- Slew &slew);
+ void loadDelaySlewElmore(const Pin *load_pin,
+ double elmore,
+ ArcDelay &delay,
+ Slew &slew);
// Select the appropriate special case Dartu/Menezes/Pileggi algorithm.
void setCeffAlgorithm(const LibertyLibrary *library,
const LibertyCell *cell,
@@ -80,7 +74,6 @@ protected:
const GateTableModel *gate_model,
const RiseFall *rf,
double in_slew,
- float related_out_cap,
double c2,
double rpi,
double c1);
diff --git a/dcalc/DmpDelayCalc.cc b/dcalc/DmpDelayCalc.cc
index ed97468a..8006a0f8 100644
--- a/dcalc/DmpDelayCalc.cc
+++ b/dcalc/DmpDelayCalc.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -19,12 +19,13 @@
#include "TableModel.hh"
#include "TimingArc.hh"
#include "Liberty.hh"
+#include "PortDirection.hh"
+#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
#include "DmpCeff.hh"
-#include "Network.hh"
namespace sta {
@@ -35,9 +36,22 @@ class DmpCeffElmoreDelayCalc : public DmpCeffDelayCalc
public:
DmpCeffElmoreDelayCalc(StaState *sta);
ArcDelayCalc *copy() override;
- void loadDelay(const Pin *load_pin,
- ArcDelay &wire_delay,
- Slew &load_slew) override;
+ ArcDcalcResult inputPortDelay(const Pin *port_pin,
+ float in_slew,
+ const RiseFall *rf,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap) override;
+
+protected:
+ void loadDelaySlew(const Pin *load_pin,
+ double drvr_slew,
+ const RiseFall *rf,
+ const LibertyLibrary *drvr_library,
+ const Parasitic *parasitic,
+ // Return values.
+ ArcDelay &wire_delay,
+ Slew &load_slew) override;
};
ArcDelayCalc *
@@ -57,26 +71,54 @@ DmpCeffElmoreDelayCalc::copy()
return new DmpCeffElmoreDelayCalc(this);
}
-void
-DmpCeffElmoreDelayCalc::loadDelay(const Pin *load_pin,
- ArcDelay &wire_delay,
- Slew &load_slew)
+ArcDcalcResult
+DmpCeffElmoreDelayCalc::inputPortDelay(const Pin *,
+ float in_slew,
+ const RiseFall *rf,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *)
{
- ArcDelay wire_delay1 = 0.0;
- Slew load_slew1 = drvr_slew_;
+ ArcDcalcResult dcalc_result(load_pin_index_map.size());
+ LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
+ for (auto load_pin_index : load_pin_index_map) {
+ const Pin *load_pin = load_pin_index.first;
+ size_t load_idx = load_pin_index.second;
+ ArcDelay wire_delay = 0.0;
+ Slew load_slew = in_slew;
+ bool elmore_exists = false;
+ float elmore = 0.0;
+ if (parasitic)
+ parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists);
+ if (elmore_exists)
+ // Input port with no external driver.
+ dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew);
+ thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
+ dcalc_result.setWireDelay(load_idx, wire_delay);
+ dcalc_result.setLoadSlew(load_idx, load_slew);
+ }
+ return dcalc_result;
+}
+
+void
+DmpCeffElmoreDelayCalc::loadDelaySlew(const Pin *load_pin,
+ double drvr_slew,
+ const RiseFall *rf,
+ const LibertyLibrary *drvr_library,
+ const Parasitic *parasitic,
+ // Return values.
+ ArcDelay &wire_delay,
+ Slew &load_slew)
+{
+ wire_delay = 0.0;
+ load_slew = drvr_slew;
bool elmore_exists = false;
float elmore = 0.0;
- if (drvr_parasitic_)
- parasitics_->findElmore(drvr_parasitic_, load_pin, elmore, elmore_exists);
- if (elmore_exists) {
- if (input_port_)
- dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
- else
- loadDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
- }
- thresholdAdjust(load_pin, wire_delay1, load_slew1);
- wire_delay = wire_delay1;
- load_slew = load_slew1 * multi_drvr_slew_factor_;
+ if (parasitic)
+ parasitics_->findElmore(parasitic, load_pin, elmore, elmore_exists);
+ if (elmore_exists)
+ loadDelaySlewElmore(load_pin, elmore, wire_delay, load_slew);
+ thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
}
////////////////////////////////////////////////////////////////
@@ -91,28 +133,31 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
- ReducedParasiticType reducedParasiticType() const override;
- void inputPortDelay(const Pin *port_pin,
- float in_slew,
- const RiseFall *rf,
- const Parasitic *parasitic,
- const DcalcAnalysisPt *dcalc_ap) override;
- void gateDelay(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- // Return values.
- ArcDelay &gate_delay,
- Slew &drvr_slew) override;
- void loadDelay(const Pin *load_pin,
- ArcDelay &wire_delay,
- Slew &load_slew) override;
+ ArcDcalcResult inputPortDelay(const Pin *port_pin,
+ float in_slew,
+ const RiseFall *rf,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap) override;
+ ArcDcalcResult gateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
+ const Slew &in_slew,
+ float load_cap,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap) override;
private:
- void loadDelay(Parasitic *pole_residue,
+ void loadDelaySlew(const Pin *load_pin,
+ double drvr_slew,
+ const RiseFall *rf,
+ const LibertyLibrary *drvr_library,
+ const Parasitic *parasitic,
+ // Return values.
+ ArcDelay &wire_delay,
+ Slew &load_slew) override;
+ void loadDelay(double drvr_slew,
+ Parasitic *pole_residue,
double p1,
double k1,
ArcDelay &wire_delay,
@@ -164,104 +209,117 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin,
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
- // set_load net has precidence over parasitics.
- if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) {
- const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
- if (parasitics_->haveParasitics()) {
- // Prefer PiPoleResidue.
- parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap);
- if (parasitic == nullptr) {
- parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
- if (parasitic == nullptr) {
- Parasitic *parasitic_network =
- parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
- if (parasitic_network) {
- parasitics_->reduceToPiPoleResidue2(parasitic_network, drvr_pin,
- dcalc_ap->operatingConditions(),
- corner,
- dcalc_ap->constraintMinMax(),
- parasitic_ap);
- parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap);
- reduced_parasitic_drvrs_.push_back(drvr_pin);
- }
- }
- }
- }
- else {
- const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
- Wireload *wireload = sdc_->wireload(cnst_min_max);
- if (wireload) {
- float pin_cap, wire_cap, fanout;
- bool has_wire_cap;
- graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
- pin_cap, wire_cap, fanout, has_wire_cap);
- parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
- fanout, pin_cap,
- dcalc_ap->operatingConditions(),
- corner,
- cnst_min_max,
- parasitic_ap);
- // Estimated parasitics are not recorded in the "database", so
- // save it for deletion after the drvr pin delay calc is finished.
- if (parasitic)
- unsaved_parasitics_.push_back(parasitic);
- }
- }
+ // set_load net has precedence over parasitics.
+ if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
+ || network_->direction(drvr_pin)->isInternal())
+ return nullptr;
+ const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
+ // Prefer PiPoleResidue.
+ parasitic = parasitics_->findPiPoleResidue(drvr_pin, rf, parasitic_ap);
+ if (parasitic)
+ return parasitic;
+ parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
+ if (parasitic)
+ return parasitic;
+ Parasitic *parasitic_network =
+ parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
+ if (parasitic_network) {
+ parasitic = parasitics_->reduceToPiPoleResidue2(parasitic_network, drvr_pin, rf,
+ corner,
+ dcalc_ap->constraintMinMax(),
+ parasitic_ap);
+ if (parasitic)
+ return parasitic;
+ }
+ const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
+ Wireload *wireload = sdc_->wireload(cnst_min_max);
+ if (wireload) {
+ float pin_cap, wire_cap, fanout;
+ bool has_wire_cap;
+ graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap, pin_cap, wire_cap,
+ fanout, has_wire_cap);
+ parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
+ fanout, pin_cap, corner,
+ cnst_min_max);
}
return parasitic;
}
-ReducedParasiticType
-DmpCeffTwoPoleDelayCalc::reducedParasiticType() const
+ArcDcalcResult
+DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *,
+ float in_slew,
+ const RiseFall *rf,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *)
{
- return ReducedParasiticType::pi_pole_residue2;
+ ArcDcalcResult dcalc_result(load_pin_index_map.size());
+ ArcDelay wire_delay = 0.0;
+ Slew load_slew = in_slew;
+ LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
+ for (auto load_pin_index : load_pin_index_map) {
+ const Pin *load_pin = load_pin_index.first;
+ size_t load_idx = load_pin_index.second;
+ if (parasitics_->isPiPoleResidue(parasitic)) {
+ const Parasitic *pole_residue = parasitics_->findPoleResidue(parasitic, load_pin);
+ if (pole_residue) {
+ size_t pole_count = parasitics_->poleResidueCount(pole_residue);
+ if (pole_count >= 1) {
+ ComplexFloat pole1, residue1;
+ // Find the 1st (elmore) pole.
+ parasitics_->poleResidue(pole_residue, 0, pole1, residue1);
+ if (pole1.imag() == 0.0
+ && residue1.imag() == 0.0) {
+ float p1 = pole1.real();
+ float elmore = 1.0F / p1;
+ dspfWireDelaySlew(load_pin, rf, in_slew, elmore, wire_delay, load_slew);
+ thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
+ }
+ }
+ }
+ }
+ dcalc_result.setWireDelay(load_idx, wire_delay);
+ dcalc_result.setLoadSlew(load_idx, load_slew);
+ }
+ return dcalc_result;
+}
+
+ArcDcalcResult
+DmpCeffTwoPoleDelayCalc::gateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
+ const Slew &in_slew,
+ float load_cap,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap)
+{
+ const LibertyLibrary *drvr_library = arc->to()->libertyLibrary();
+ const RiseFall *rf = arc->toEdge()->asRiseFall();
+ vth_ = drvr_library->outputThreshold(rf);
+ vl_ = drvr_library->slewLowerThreshold(rf);
+ vh_ = drvr_library->slewUpperThreshold(rf);
+ slew_derate_ = drvr_library->slewDerateFromLibrary();
+ return DmpCeffDelayCalc::gateDelay(drvr_pin, arc, in_slew, load_cap, parasitic,
+ load_pin_index_map, dcalc_ap) ;
}
void
-DmpCeffTwoPoleDelayCalc::inputPortDelay(const Pin *port_pin,
- float in_slew,
- const RiseFall *rf,
- const Parasitic *parasitic,
- const DcalcAnalysisPt *dcalc_ap)
+DmpCeffTwoPoleDelayCalc::loadDelaySlew(const Pin *load_pin,
+ double drvr_slew,
+ const RiseFall *rf,
+ const LibertyLibrary *drvr_library,
+ const Parasitic *parasitic,
+ // Return values.
+ ArcDelay &wire_delay,
+ Slew &load_slew)
{
parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(parasitic);
- DmpCeffDelayCalc::inputPortDelay(port_pin, in_slew, rf, parasitic, dcalc_ap);
-}
-
-void
-DmpCeffTwoPoleDelayCalc::gateDelay(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- // Return values.
- ArcDelay &gate_delay,
- Slew &drvr_slew)
-{
- gateDelayInit(arc, in_slew, drvr_parasitic);
- parasitic_is_pole_residue_ = parasitics_->isPiPoleResidue(drvr_parasitic);
- vth_ = drvr_library_->outputThreshold(drvr_rf_);
- vl_ = drvr_library_->slewLowerThreshold(drvr_rf_);
- vh_ = drvr_library_->slewUpperThreshold(drvr_rf_);
- slew_derate_ = drvr_library_->slewDerateFromLibrary();
- DmpCeffDelayCalc::gateDelay(arc, in_slew, load_cap, drvr_parasitic,
- related_out_cap, pvt, dcalc_ap,
- gate_delay, drvr_slew);
-}
-
-void
-DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin,
- ArcDelay &wire_delay,
- Slew &load_slew)
-{
// Should handle PiElmore parasitic.
- ArcDelay wire_delay1 = 0.0;
- Slew load_slew1 = drvr_slew_;
+ wire_delay = 0.0;
+ load_slew = drvr_slew;
Parasitic *pole_residue = 0;
if (parasitic_is_pole_residue_)
- pole_residue = parasitics_->findPoleResidue(drvr_parasitic_, load_pin);
+ pole_residue = parasitics_->findPoleResidue(parasitic, load_pin);
if (pole_residue) {
size_t pole_count = parasitics_->poleResidueCount(pole_residue);
if (pole_count >= 1) {
@@ -272,37 +330,31 @@ DmpCeffTwoPoleDelayCalc::loadDelay(const Pin *load_pin,
&& residue1.imag() == 0.0) {
float p1 = pole1.real();
float k1 = residue1.real();
- if (input_port_) {
- float elmore = 1.0F / p1;
- // Input port with no external driver.
- dspfWireDelaySlew(load_pin, elmore, wire_delay1, load_slew1);
- }
- else {
- if (pole_count >= 2)
- loadDelay(pole_residue, p1, k1, wire_delay1, load_slew1);
- else {
- float elmore = 1.0F / p1;
- wire_delay1 = elmore;
- load_slew1 = drvr_slew_;
- }
- }
+ if (pole_count >= 2)
+ loadDelay(drvr_slew, pole_residue, p1, k1, wire_delay, load_slew);
+ else {
+ float elmore = 1.0F / p1;
+ wire_delay = elmore;
+ load_slew = drvr_slew;
+ }
}
}
}
- thresholdAdjust(load_pin, wire_delay1, load_slew1);
- wire_delay = wire_delay1;
- load_slew = load_slew1 * multi_drvr_slew_factor_;
+ thresholdAdjust(load_pin, drvr_library, rf, wire_delay, load_slew);
}
void
-DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue,
- double p1, double k1,
- ArcDelay &wire_delay,
+DmpCeffTwoPoleDelayCalc::loadDelay(double drvr_slew,
+ Parasitic *pole_residue,
+ double p1,
+ double k1,
+ // Return values.
+ ArcDelay &wire_delay,
Slew &load_slew)
{
ComplexFloat pole2, residue2;
parasitics_->poleResidue(pole_residue, 1, pole2, residue2);
- if (!delayZero(drvr_slew_)
+ if (!delayZero(drvr_slew)
&& pole2.imag() == 0.0
&& residue2.imag() == 0.0) {
double p2 = pole2.real();
@@ -311,7 +363,7 @@ DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue,
double k2_p2_2 = k2 / (p2 * p2);
double B = k1_p1_2 + k2_p2_2;
// Convert tt to 0:1 range.
- float tt = delayAsFloat(drvr_slew_) * slew_derate_ / (vh_ - vl_);
+ float tt = delayAsFloat(drvr_slew) * slew_derate_ / (vh_ - vl_);
double y_tt = (tt - B + k1_p1_2 * exp(-p1 * tt)
+ k2_p2_2 * exp(-p2 * tt)) / tt;
wire_delay = loadDelay(vth_, p1, p2, k1, k2, B, k1_p1_2, k2_p2_2, tt, y_tt)
diff --git a/dcalc/DmpDelayCalc.hh b/dcalc/DmpDelayCalc.hh
index f604e6dc..c5c8cbd3 100644
--- a/dcalc/DmpDelayCalc.hh
+++ b/dcalc/DmpDelayCalc.hh
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
diff --git a/dcalc/FindRoot.cc b/dcalc/FindRoot.cc
new file mode 100644
index 00000000..a6bdde60
--- /dev/null
+++ b/dcalc/FindRoot.cc
@@ -0,0 +1,106 @@
+// OpenSTA, Static Timing Analyzer
+// Copyright (c) 2023, Parallax Software, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#include "FindRoot.hh"
+
+#include // abs
+
+namespace sta {
+
+using std::abs;
+
+double
+findRoot(FindRootFunc func,
+ double x1,
+ double x2,
+ double x_tol,
+ int max_iter,
+ // Return value.
+ bool &fail)
+{
+ double y1, y2, dy1;
+ func(x1, y1, dy1);
+ func(x2, y2, dy1);
+ return findRoot(func, x1, y1, x2, y2, x_tol, max_iter, fail);
+}
+
+double
+findRoot(FindRootFunc func,
+ double x1,
+ double y1,
+ double x2,
+ double y2,
+ double x_tol,
+ int max_iter,
+ // Return value.
+ bool &fail)
+{
+ if ((y1 > 0.0 && y2 > 0.0) || (y1 < 0.0 && y2 < 0.0)) {
+ // Initial bounds do not surround a root.
+ fail = true;
+ return 0.0;
+ }
+
+ if (y1 == 0.0) {
+ fail = false;
+ return x1;
+ }
+
+ if (y2 == 0.0) {
+ fail = false;
+ return x2;
+ }
+
+ if (y1 > 0.0)
+ // Swap x1/x2 so func(x1) < 0.
+ std::swap(x1, x2);
+ double root = (x1 + x2) * 0.5;
+ double dx_prev = abs(x2 - x1);
+ double dx = dx_prev;
+ double y, dy;
+ func(root, y, dy);
+ for (int iter = 0; iter < max_iter; iter++) {
+ // Newton/raphson out of range.
+ if ((((root - x2) * dy - y) * ((root - x1) * dy - y) > 0.0)
+ // Not decreasing fast enough.
+ || (abs(2.0 * y) > abs(dx_prev * dy))) {
+ // Bisect x1/x2 interval.
+ dx_prev = dx;
+ dx = (x2 - x1) * 0.5;
+ root = x1 + dx;
+ }
+ else {
+ dx_prev = dx;
+ dx = y / dy;
+ root -= dx;
+ }
+ if (abs(dx) <= x_tol * abs(root)) {
+ // Converged.
+ fail = false;
+ return root;
+ }
+
+ func(root, y, dy);
+ if (y < 0.0)
+ x1 = root;
+ else
+ x2 = root;
+ }
+ fail = true;
+ return root;
+}
+
+} // namespace
diff --git a/dcalc/SlewDegradeDelayCalc.hh b/dcalc/FindRoot.hh
similarity index 59%
rename from dcalc/SlewDegradeDelayCalc.hh
rename to dcalc/FindRoot.hh
index 7195985d..1a62df8b 100644
--- a/dcalc/SlewDegradeDelayCalc.hh
+++ b/dcalc/FindRoot.hh
@@ -16,12 +16,33 @@
#pragma once
+#include
+
namespace sta {
-class ArcDelayCalc;
-class StaState;
+typedef const std::function FindRootFunc;
-ArcDelayCalc *
-makeSlewDegradeDelayCalc(StaState *sta);
+double
+findRoot(FindRootFunc func,
+ double x1,
+ double x2,
+ double x_tol,
+ int max_iter,
+ // Return value.
+ bool &fail);
+
+double
+findRoot(FindRootFunc func,
+ double x1,
+ double y1,
+ double x2,
+ double y2,
+ double x_tol,
+ int max_iter,
+ // Return value.
+ bool &fail);
} // namespace
diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc
index 3f18bd2f..da3b40d0 100644
--- a/dcalc/GraphDelayCalc.cc
+++ b/dcalc/GraphDelayCalc.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -59,7 +59,6 @@ GraphDelayCalc::GraphDelayCalc(StaState *sta) :
search_non_latch_pred_(new SearchPredNonLatch2(sta)),
clk_pred_(new ClkTreeSearchPred(sta)),
iter_(new BfsFwdIterator(BfsIndex::dcalc, search_non_latch_pred_, sta)),
- multi_drvr_nets_found_(false),
incremental_delay_tolerance_(0.0)
{
}
@@ -103,7 +102,6 @@ GraphDelayCalc::clear()
{
delaysInvalid();
deleteMultiDrvrNets();
- multi_drvr_nets_found_ = false;
}
float
@@ -183,25 +181,10 @@ GraphDelayCalc::deleteVertexBefore(Vertex *vertex)
invalid_delays_->erase(vertex);
MultiDrvrNet *multi_drvr = multiDrvrNet(vertex);
if (multi_drvr) {
- VertexSet *drvrs = multi_drvr->drvrs();
- drvrs->erase(vertex);
- multi_drvr_net_map_.erase(vertex);
- if (drvrs->empty())
- delete multi_drvr;
- else {
- Level max_drvr_level = 0;
- Vertex *max_drvr = nullptr;
- for (Vertex *drvr_vertex : *drvrs) {
- Level drvr_level = drvr_vertex->level();
- if (max_drvr == nullptr
- || drvr_level > max_drvr_level) {
- max_drvr = drvr_vertex;
- max_drvr_level = drvr_level;
- }
- }
- multi_drvr->setDcalcDrvr(max_drvr);
- multi_drvr->findCaps(sdc_);
- }
+ // Don't bother incrementally updating MultiDrvrNet.
+ for (Vertex *drvr_vertex : multi_drvr->drvrs())
+ multi_drvr_net_map_.erase(drvr_vertex);
+ delete multi_drvr;
}
}
@@ -382,19 +365,23 @@ GraphDelayCalc::seedNoDrvrCellSlew(Vertex *drvr_vertex,
Delay drive_delay = delay_zero;
float drive_res;
drive->driveResistance(rf, cnst_min_max, drive_res, exists);
- Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap);
+ const Parasitic *parasitic;
+ float cap;
+ parasiticLoad(drvr_pin, rf, dcalc_ap, nullptr, arc_delay_calc,
+ cap, parasitic);
if (exists) {
- float cap = loadCap(drvr_pin, parasitic, rf, dcalc_ap);
drive_delay = cap * drive_res;
slew = cap * drive_res;
}
const MinMax *slew_min_max = dcalc_ap->slewMinMax();
if (!drvr_vertex->slewAnnotated(rf, slew_min_max))
graph_->setSlew(drvr_vertex, rf, ap_index, slew);
- arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf,
- parasitic, dcalc_ap);
- annotateLoadDelays(drvr_vertex, rf, drive_delay, false, dcalc_ap,
- arc_delay_calc);
+ LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
+ ArcDcalcResult dcalc_result =
+ arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, parasitic,
+ load_pin_index_map, dcalc_ap);
+ annotateLoadDelays(drvr_vertex, rf, dcalc_result, load_pin_index_map,
+ drive_delay, false, dcalc_ap);
arc_delay_calc->finishDrvrPin();
}
@@ -417,11 +404,13 @@ GraphDelayCalc::seedNoDrvrSlew(Vertex *drvr_vertex,
if (!drvr_vertex->slewAnnotated(rf, slew_min_max))
graph_->setSlew(drvr_vertex, rf, ap_index, slew);
Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap);
- arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf,
- parasitic, dcalc_ap);
- annotateLoadDelays(drvr_vertex, rf, delay_zero, false, dcalc_ap,
- arc_delay_calc);
- arc_delay_calc->finishDrvrPin();
+ LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
+ ArcDcalcResult dcalc_result =
+ arc_delay_calc->inputPortDelay(drvr_pin, delayAsFloat(slew), rf, parasitic,
+ load_pin_index_map, dcalc_ap);
+ annotateLoadDelays(drvr_vertex, rf, dcalc_result, load_pin_index_map, delay_zero,
+ false, dcalc_ap);
+ arc_delay_calc_->finishDrvrPin();
}
void
@@ -488,7 +477,7 @@ GraphDelayCalc::findPortIndex(const LibertyCell *cell,
return index;
index++;
}
- report_->critical(207, "port not found in cell");
+ report_->critical(1100, "port not found in cell.");
return 0;
}
@@ -513,6 +502,7 @@ GraphDelayCalc::findInputDriverDelay(const LibertyCell *drvr_cell,
}
}
}
+ arc_delay_calc_->finishDrvrPin();
}
// Driving cell delay is the load dependent delay, which is the gate
@@ -531,25 +521,28 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
arc->to()->name(),
arc->toEdge()->asString(),
arc->role()->asString());
- RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
+ const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
if (drvr_rf) {
DcalcAPIndex ap_index = dcalc_ap->index();
- const Pvt *pvt = dcalc_ap->operatingConditions();
- Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf,
- dcalc_ap);
- float load_cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap);
+ const Parasitic *parasitic;
+ float load_cap;
+ parasiticLoad(drvr_pin, drvr_rf, dcalc_ap, nullptr, arc_delay_calc_,
+ load_cap, parasitic);
- ArcDelay intrinsic_delay;
- Slew intrinsic_slew;
- arc_delay_calc_->gateDelay(arc, Slew(from_slew), 0.0, 0, 0.0, pvt, dcalc_ap,
- intrinsic_delay, intrinsic_slew);
+ LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
+ ArcDcalcResult intrinsic_result =
+ arc_delay_calc_->gateDelay(drvr_pin, arc, Slew(from_slew), 0.0, nullptr,
+ load_pin_index_map, dcalc_ap);
+ ArcDelay intrinsic_delay = intrinsic_result.gateDelay();
+
+ ArcDcalcResult gate_result = arc_delay_calc_->gateDelay(drvr_pin, arc,
+ Slew(from_slew), load_cap,
+ parasitic,
+ load_pin_index_map,
+ dcalc_ap);
+ ArcDelay gate_delay = gate_result.gateDelay();
+ Slew gate_slew = gate_result.drvrSlew();
- // For input drivers there is no instance to find a related_output_pin.
- ArcDelay gate_delay;
- Slew gate_slew;
- arc_delay_calc_->gateDelay(arc, Slew(from_slew), load_cap,
- drvr_parasitic, 0.0, pvt, dcalc_ap,
- gate_delay, gate_slew);
ArcDelay load_delay = gate_delay - intrinsic_delay;
debugPrint(debug_, "delay_calc", 3,
" gate delay = %s intrinsic = %s slew = %s",
@@ -557,8 +550,9 @@ GraphDelayCalc::findInputArcDelay(const Pin *drvr_pin,
delayAsString(intrinsic_delay, this),
delayAsString(gate_slew, this));
graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew);
- annotateLoadDelays(drvr_vertex, drvr_rf, load_delay, false, dcalc_ap,
- arc_delay_calc_);
+ annotateLoadDelays(drvr_vertex, drvr_rf, gate_result, load_pin_index_map,
+ load_delay, false, dcalc_ap);
+ arc_delay_calc_->finishDrvrPin();
}
}
@@ -651,47 +645,64 @@ GraphDelayCalc::findDriverDelays(Vertex *drvr_vertex,
{
bool delay_changed = false;
MultiDrvrNet *multi_drvr = findMultiDrvrNet(drvr_vertex);
- if (multi_drvr
- && multi_drvr->parallelGates(network_)) {
- Vertex *dcalc_drvr = multi_drvr->dcalcDrvr();
- if (drvr_vertex == dcalc_drvr) {
- initLoadSlews(drvr_vertex);
- arc_delay_calc->findParallelGateDelays(multi_drvr, this);
- for (Vertex *drvr_vertex : *multi_drvr->drvrs())
- delay_changed |= findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc);
- }
- }
- else {
+ if (multi_drvr == nullptr
+ || (multi_drvr
+ && (!multi_drvr->parallelGates(network_)
+ || drvr_vertex == multi_drvr->dcalcDrvr()))) {
initLoadSlews(drvr_vertex);
- delay_changed = findDriverDelays1(drvr_vertex, nullptr, arc_delay_calc);
+ delay_changed |= findDriverDelays1(drvr_vertex, multi_drvr, arc_delay_calc);
}
- arc_delay_calc->finishDrvrPin();
+ arc_delay_calc_->finishDrvrPin();
return delay_changed;
}
MultiDrvrNet *
GraphDelayCalc::findMultiDrvrNet(Vertex *drvr_vertex)
{
- MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex);
- if (multi_drvr)
+ // Avoid locking for single driver nets.
+ if (hasMultiDrvrs(drvr_vertex)) {
+ UniqueLock lock(multi_drvr_lock_);
+ MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex);
+ if (multi_drvr)
+ return multi_drvr;
+ multi_drvr = makeMultiDrvrNet(drvr_vertex);
return multi_drvr;
- else {
- const PinSet *drvrs = network_->drivers(drvr_vertex->pin());
- if (drvrs && drvrs->size() > 1) {
- PinSet drvrs1(network_);
- // Filter input ports and non-leaf drivers.
- for (const Pin *pin : *drvrs) {
- if (isLeafDriver(pin, network_))
- drvrs1.insert(pin);
- }
- MultiDrvrNet *multi_drvr = nullptr;
- if (drvrs1.size() > 1)
- multi_drvr = makeMultiDrvrNet(drvrs1);
- return multi_drvr;
- }
- else
- return nullptr;
}
+ return nullptr;
+}
+
+bool
+GraphDelayCalc::hasMultiDrvrs(Vertex *drvr_vertex)
+{
+ Vertex *load_vertex = firstLoad(drvr_vertex);
+ if (load_vertex) {
+ int drvr_count = 0;
+ VertexInEdgeIterator edge_iter(load_vertex, graph_);
+ while (edge_iter.hasNext()) {
+ Edge *edge = edge_iter.next();
+ if (edge->isWire()) {
+ Vertex *drvr = edge->from(graph_);
+ if (isLeafDriver(drvr->pin(), network_))
+ drvr_count++;
+ }
+ if (drvr_count > 1)
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+Vertex *
+GraphDelayCalc::firstLoad(Vertex *drvr_vertex)
+{
+ VertexOutEdgeIterator edge_iter(drvr_vertex, graph_);
+ while (edge_iter.hasNext()) {
+ Edge *wire_edge = edge_iter.next();
+ if (wire_edge->isWire())
+ return wire_edge->to(graph_);
+ }
+ return nullptr;
}
static bool
@@ -710,31 +721,41 @@ GraphDelayCalc::multiDrvrNet(const Vertex *drvr_vertex) const
}
MultiDrvrNet *
-GraphDelayCalc::makeMultiDrvrNet(PinSet &drvr_pins)
+GraphDelayCalc::makeMultiDrvrNet(Vertex *drvr_vertex)
{
- debugPrint(debug_, "delay_calc", 3, "multi-driver net");
- VertexSet *drvr_vertices = new VertexSet(graph_);
- MultiDrvrNet *multi_drvr = new MultiDrvrNet(drvr_vertices);
- Level max_drvr_level = 0;
- Vertex *max_drvr = nullptr;
- PinSet::Iterator pin_iter(drvr_pins);
- while (pin_iter.hasNext()) {
- const Pin *pin = pin_iter.next();
- Vertex *drvr_vertex = graph_->pinDrvrVertex(pin);
- debugPrint(debug_, "delay_calc", 3, " %s",
- network_->pathName(pin));
- multi_drvr_net_map_[drvr_vertex] = multi_drvr;
- drvr_vertices->insert(drvr_vertex);
- Level drvr_level = drvr_vertex->level();
- if (max_drvr == nullptr
- || drvr_level > max_drvr_level) {
- max_drvr = drvr_vertex;
- max_drvr_level = drvr_level;
+ Vertex *load_vertex = firstLoad(drvr_vertex);
+ if (load_vertex) {
+ debugPrint(debug_, "delay_calc", 3, "multi-driver net");
+ MultiDrvrNet *multi_drvr = new MultiDrvrNet;
+ VertexSeq &drvr_vertices = multi_drvr->drvrs();
+ Level max_drvr_level = 0;
+ Vertex *max_drvr = nullptr;
+ VertexInEdgeIterator edge_iter(load_vertex, graph_);
+ while (edge_iter.hasNext()) {
+ Edge *edge = edge_iter.next();
+ if (edge->isWire()) {
+ Vertex *drvr = edge->from(graph_);
+ const Pin *drvr_pin = drvr->pin();
+ if (isLeafDriver(drvr_pin, network_)) {
+ debugPrint(debug_, "delay_calc", 3, " %s",
+ network_->pathName(drvr_pin));
+ multi_drvr_net_map_[drvr] = multi_drvr;
+ drvr_vertices.push_back(drvr);
+ Level drvr_level = drvr->level();
+ if (max_drvr == nullptr
+ || drvr_level > max_drvr_level) {
+ max_drvr = drvr;
+ max_drvr_level = drvr_level;
+ }
+ }
+ }
}
+ multi_drvr->setDcalcDrvr(max_drvr);
+ multi_drvr->findCaps(sdc_);
+ return multi_drvr;
}
- multi_drvr->setDcalcDrvr(max_drvr);
- multi_drvr->findCaps(sdc_);
- return multi_drvr;
+ report_->critical(1101, "mult_drvr missing load.");
+ return nullptr;
}
void
@@ -763,10 +784,17 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex,
MultiDrvrNet *multi_drvr,
ArcDelayCalc *arc_delay_calc)
{
- const Pin *drvr_pin = drvr_vertex->pin();
- Instance *drvr_inst = network_->instance(drvr_pin);
initSlew(drvr_vertex);
- initWireDelays(drvr_vertex);
+ if (multi_drvr
+ && multi_drvr->parallelGates(network_)) {
+ // Only init on the trigger driver.
+ if (drvr_vertex == multi_drvr->dcalcDrvr()) {
+ for (auto vertex : multi_drvr->drvrs())
+ initWireDelays(vertex);
+ }
+ }
+ else
+ initWireDelays(drvr_vertex);
bool delay_changed = false;
bool has_delays = false;
VertexInEdgeIterator edge_iter(drvr_vertex, graph_);
@@ -777,8 +805,8 @@ GraphDelayCalc::findDriverDelays1(Vertex *drvr_vertex,
if (search_pred_->searchFrom(from_vertex)
&& search_pred_->searchThru(edge)
&& !edge->role()->isLatchDtoQ()) {
- delay_changed |= findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex,
- multi_drvr, edge, arc_delay_calc);
+ delay_changed |= findDriverEdgeDelays(drvr_vertex, multi_drvr, edge,
+ arc_delay_calc);
has_delays = true;
}
}
@@ -812,53 +840,319 @@ GraphDelayCalc::findLatchEdgeDelays(Edge *edge)
Instance *drvr_inst = network_->instance(drvr_pin);
debugPrint(debug_, "delay_calc", 2, "find latch D->Q %s",
sdc_network_->pathName(drvr_inst));
- bool delay_changed = findDriverEdgeDelays(drvr_inst, drvr_pin, drvr_vertex,
- nullptr, edge, arc_delay_calc_);
+ bool delay_changed = findDriverEdgeDelays(drvr_vertex, nullptr, edge,
+ arc_delay_calc_);
if (delay_changed && observer_)
observer_->delayChangedTo(drvr_vertex);
}
bool
-GraphDelayCalc::findDriverEdgeDelays(const Instance *drvr_inst,
- const Pin *drvr_pin,
- Vertex *drvr_vertex,
+GraphDelayCalc::findDriverEdgeDelays(Vertex *drvr_vertex,
const MultiDrvrNet *multi_drvr,
Edge *edge,
ArcDelayCalc *arc_delay_calc)
{
- Vertex *in_vertex = edge->from(graph_);
+ Vertex *from_vertex = edge->from(graph_);
const TimingArcSet *arc_set = edge->timingArcSet();
- const LibertyPort *related_out_port = arc_set->relatedOut();
- const Pin *related_out_pin = 0;
bool delay_changed = false;
- if (related_out_port)
- related_out_pin = network_->findPin(drvr_inst, related_out_port);
+ LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
- const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
- if (pvt == nullptr)
- pvt = dcalc_ap->operatingConditions();
- for (TimingArc *arc : arc_set->arcs()) {
- const RiseFall *rf = arc->toEdge()->asRiseFall();
- Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap);
- float related_out_cap = 0.0;
- if (related_out_pin) {
- Parasitic *related_out_parasitic =
- arc_delay_calc->findParasitic(related_out_pin, rf, dcalc_ap);
- related_out_cap = loadCap(related_out_pin, related_out_parasitic, rf, dcalc_ap);
- }
- delay_changed |= findArcDelay(drvr_pin, drvr_vertex, arc, parasitic,
- related_out_cap, in_vertex, edge, pvt, dcalc_ap,
- multi_drvr, arc_delay_calc);
- }
+ for (const TimingArc *arc : arc_set->arcs())
+ delay_changed |= findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc,
+ load_pin_index_map, dcalc_ap,
+ arc_delay_calc);
}
-
if (delay_changed && observer_) {
- observer_->delayChangedFrom(in_vertex);
+ observer_->delayChangedFrom(from_vertex);
observer_->delayChangedFrom(drvr_vertex);
}
return delay_changed;
}
+void
+GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex,
+ Edge *edge,
+ const TimingArc *arc,
+ const DcalcAnalysisPt *dcalc_ap,
+ ArcDelayCalc *arc_delay_calc)
+{
+ MultiDrvrNet *multi_drvr = multiDrvrNet(drvr_vertex);
+ LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(drvr_vertex);
+ findDriverArcDelays(drvr_vertex, multi_drvr, edge, arc,
+ load_pin_index_map, dcalc_ap,
+ arc_delay_calc);
+}
+
+bool
+GraphDelayCalc::findDriverArcDelays(Vertex *drvr_vertex,
+ const MultiDrvrNet *multi_drvr,
+ Edge *edge,
+ const TimingArc *arc,
+ LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap,
+ ArcDelayCalc *arc_delay_calc)
+{
+ bool delay_changed = false;
+ const RiseFall *from_rf = arc->fromEdge()->asRiseFall();
+ const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
+ if (from_rf && drvr_rf) {
+ const Pin *drvr_pin = drvr_vertex->pin();
+ const Parasitic *parasitic;
+ float load_cap;
+ parasiticLoad(drvr_pin, drvr_rf, dcalc_ap, multi_drvr, arc_delay_calc,
+ load_cap, parasitic);
+
+ if (multi_drvr
+ && multi_drvr->parallelGates(network_)) {
+ ArcDcalcArgSeq dcalc_args = makeArcDcalcArgs(drvr_vertex, multi_drvr,
+ edge, arc, dcalc_ap,
+ arc_delay_calc);
+ ArcDcalcResultSeq dcalc_results =
+ arc_delay_calc->gateDelays(dcalc_args, load_cap, load_pin_index_map,
+ dcalc_ap);
+ for (size_t drvr_idx = 0; drvr_idx < dcalc_args.size(); drvr_idx++) {
+ ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
+ ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
+ delay_changed |= annotateDelaysSlews(dcalc_arg.edge(), dcalc_arg.arc(),
+ dcalc_result, load_pin_index_map,
+ dcalc_ap);
+ }
+ }
+ else {
+ Vertex *from_vertex = edge->from(graph_);
+ const Slew in_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap);
+ ArcDcalcResult dcalc_result = arc_delay_calc->gateDelay(drvr_pin, arc, in_slew,
+ load_cap, parasitic,
+ load_pin_index_map,
+ dcalc_ap);
+ delay_changed |= annotateDelaysSlews(edge, arc, dcalc_result,
+ load_pin_index_map, dcalc_ap);
+ }
+ arc_delay_calc->finishDrvrPin();
+ }
+ return delay_changed;
+}
+
+ArcDcalcArgSeq
+GraphDelayCalc::makeArcDcalcArgs(Vertex *drvr_vertex,
+ const MultiDrvrNet *multi_drvr,
+ Edge *edge,
+ const TimingArc *arc,
+ const DcalcAnalysisPt *dcalc_ap,
+ ArcDelayCalc *arc_delay_calc)
+{
+ ArcDcalcArgSeq dcalc_args;
+ for (auto drvr_vertex1 : multi_drvr->drvrs()) {
+ Edge *edge1 = nullptr;
+ const TimingArc *arc1 = nullptr;
+ if (drvr_vertex1 == drvr_vertex) {
+ edge1 = edge;
+ arc1 = arc;
+ }
+ else
+ findParallelEdge(drvr_vertex1, edge, arc, edge1, arc1);
+ // Shockingly one fpga vendor connects outputs with no timing arcs together.
+ if (edge1) {
+ Vertex *from_vertex = edge1->from(graph_);
+ const RiseFall *from_rf = arc1->fromEdge()->asRiseFall();
+ const RiseFall *drvr_rf = arc1->toEdge()->asRiseFall();
+ const Slew in_slew = edgeFromSlew(from_vertex, from_rf, edge1, dcalc_ap);
+ const Pin *drvr_pin1 = drvr_vertex1->pin();
+ Parasitic *parasitic = arc_delay_calc->findParasitic(drvr_pin1, drvr_rf,
+ dcalc_ap);
+ dcalc_args.push_back(ArcDcalcArg(drvr_pin1, edge1, arc1, in_slew,
+ parasitic));
+ }
+ }
+ return dcalc_args;
+}
+
+// Find an edge/arc for parallel driver vertex to go along with the
+// primary driver drvr_edge/drvr_arc.
+void
+GraphDelayCalc::findParallelEdge(Vertex *vertex,
+ Edge *drvr_edge,
+ const TimingArc *drvr_arc,
+ // Return values.
+ Edge *&edge,
+ const TimingArc *&arc)
+{
+ LibertyCell *drvr_cell = drvr_arc->from()->libertyCell();
+ LibertyCell *vertex_cell = network_->libertyCell(network_->instance(vertex->pin()));
+ if (vertex_cell == drvr_cell) {
+ // Homogeneous drivers.
+ arc = drvr_arc;
+ LibertyPort *from_port = network_->libertyPort(drvr_edge->from(graph_)->pin());
+ VertexInEdgeIterator edge_iter(vertex, graph_);
+ while (edge_iter.hasNext()) {
+ edge = edge_iter.next();
+ if (network_->libertyPort(edge->from(graph_)->pin()) == from_port)
+ return;
+ }
+ }
+ else {
+ VertexInEdgeIterator edge_iter(vertex, graph_);
+ while (edge_iter.hasNext()) {
+ edge = edge_iter.next();
+ for (TimingArc *arc1 : edge->timingArcSet()->arcs()) {
+ if (arc1->fromEdge() == drvr_arc->fromEdge()
+ && arc1->toEdge() == drvr_arc->toEdge()) {
+ arc = arc1;
+ return;
+ }
+ }
+ }
+ }
+ edge = nullptr;
+ arc = nullptr;
+}
+
+bool
+GraphDelayCalc::annotateDelaysSlews(Edge *edge,
+ const TimingArc *arc,
+ ArcDcalcResult &dcalc_result,
+ LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap)
+{
+ bool delay_changed = annotateDelaySlew(edge, arc,
+ dcalc_result.gateDelay(),
+ dcalc_result.drvrSlew(), dcalc_ap);
+ if (!edge->role()->isLatchDtoQ()) {
+ Vertex *drvr_vertex = edge->to(graph_);
+ annotateLoadDelays(drvr_vertex, arc->toEdge()->asRiseFall(), dcalc_result,
+ load_pin_index_map, delay_zero, true, dcalc_ap);
+ }
+ return delay_changed;
+}
+
+// Annotate the gate delay and merge the slew at the driver pin.
+// Annotate the wire delays from the gate output to
+// each load pin, and the merge the slews at each load pin.
+bool
+GraphDelayCalc::annotateDelaySlew(Edge *edge,
+ const TimingArc *arc,
+ ArcDelay &gate_delay,
+ Slew &gate_slew,
+ const DcalcAnalysisPt *dcalc_ap)
+{
+ bool delay_changed = false;
+ DcalcAPIndex ap_index = dcalc_ap->index();
+ debugPrint(debug_, "delay_calc", 3,
+ " %s %s -> %s %s (%s) corner:%s/%s",
+ arc->from()->name(),
+ arc->fromEdge()->asString(),
+ arc->to()->name(),
+ arc->toEdge()->asString(),
+ arc->role()->asString(),
+ dcalc_ap->corner()->name(),
+ dcalc_ap->delayMinMax()->asString());
+ debugPrint(debug_, "delay_calc", 3,
+ " gate delay = %s slew = %s",
+ delayAsString(gate_delay, this),
+ delayAsString(gate_slew, this));
+ Vertex *drvr_vertex = edge->to(graph_);
+ const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
+ // Merge slews.
+ const Slew &drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index);
+ const MinMax *slew_min_max = dcalc_ap->slewMinMax();
+ if (delayGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax(), this)
+ && !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)
+ && !edge->role()->isLatchDtoQ())
+ graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew);
+ if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) {
+ const ArcDelay &prev_gate_delay = graph_->arcDelay(edge,arc,ap_index);
+ float gate_delay1 = delayAsFloat(gate_delay);
+ float prev_gate_delay1 = delayAsFloat(prev_gate_delay);
+ if (prev_gate_delay1 == 0.0
+ || (abs(gate_delay1 - prev_gate_delay1) / prev_gate_delay1
+ > incremental_delay_tolerance_))
+ delay_changed = true;
+ graph_->setArcDelay(edge, arc, ap_index, gate_delay);
+ }
+ return delay_changed;
+}
+
+// Annotate wire arc delays and load pin slews.
+// extra_delay is additional wire delay to add to delay returned
+// by the delay calculator.
+void
+GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex,
+ const RiseFall *drvr_rf,
+ ArcDcalcResult &dcalc_result,
+ LoadPinIndexMap &load_pin_index_map,
+ const ArcDelay &extra_delay,
+ bool merge,
+ const DcalcAnalysisPt *dcalc_ap)
+{
+ DcalcAPIndex ap_index = dcalc_ap->index();
+ const MinMax *slew_min_max = dcalc_ap->slewMinMax();
+ VertexOutEdgeIterator edge_iter(drvr_vertex, graph_);
+ while (edge_iter.hasNext()) {
+ Edge *wire_edge = edge_iter.next();
+ if (wire_edge->isWire()) {
+ Vertex *load_vertex = wire_edge->to(graph_);
+ Pin *load_pin = load_vertex->pin();
+ size_t load_idx = load_pin_index_map[load_pin];
+ ArcDelay wire_delay = dcalc_result.wireDelay(load_idx);
+ Slew load_slew = dcalc_result.loadSlew(load_idx);
+ debugPrint(debug_, "delay_calc", 3,
+ " %s load delay = %s slew = %s",
+ load_vertex->name(sdc_network_),
+ delayAsString(wire_delay, this),
+ delayAsString(load_slew, this));
+ if (!load_vertex->slewAnnotated(drvr_rf, slew_min_max)) {
+ if (drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)) {
+ // Copy the driver slew to the load if it is annotated.
+ const Slew &drvr_slew = graph_->slew(drvr_vertex,drvr_rf,ap_index);
+ graph_->setSlew(load_vertex, drvr_rf, ap_index, drvr_slew);
+ }
+ else {
+ const Slew &slew = graph_->slew(load_vertex, drvr_rf, ap_index);
+ if (!merge
+ || delayGreater(load_slew, slew, slew_min_max, this))
+ graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew);
+ }
+ }
+ if (!graph_->wireDelayAnnotated(wire_edge, drvr_rf, ap_index)) {
+ // Multiple timing arcs with the same output transition
+ // annotate the same wire edges so they must be combined
+ // rather than set.
+ const ArcDelay &delay = graph_->wireArcDelay(wire_edge, drvr_rf, ap_index);
+ Delay wire_delay_extra = extra_delay + wire_delay;
+ const MinMax *delay_min_max = dcalc_ap->delayMinMax();
+ if (!merge
+ || delayGreater(wire_delay_extra, delay, delay_min_max, this)) {
+ graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, wire_delay_extra);
+ if (observer_)
+ observer_->delayChangedTo(load_vertex);
+ }
+ }
+ // Enqueue bidirect driver from load vertex.
+ if (sdc_->bidirectDrvrSlewFromLoad(load_pin))
+ iter_->enqueue(graph_->pinDrvrVertex(load_pin));
+ }
+ }
+}
+
+LoadPinIndexMap
+GraphDelayCalc::makeLoadPinIndexMap(Vertex *drvr_vertex)
+{
+ LoadPinIndexMap load_pin_index_map(network_);
+ size_t load_idx = 0;
+ VertexOutEdgeIterator edge_iter(drvr_vertex, graph_);
+ while (edge_iter.hasNext()) {
+ Edge *wire_edge = edge_iter.next();
+ if (wire_edge->isWire()) {
+ Vertex *load_vertex = wire_edge->to(graph_);
+ const Pin *load_pin = load_vertex->pin();
+ load_pin_index_map[load_pin] = load_idx;
+ load_idx++;
+ }
+ }
+ return load_pin_index_map;
+}
+
+// External
float
GraphDelayCalc::loadCap(const Pin *drvr_pin,
const DcalcAnalysisPt *dcalc_ap) const
@@ -866,93 +1160,104 @@ GraphDelayCalc::loadCap(const Pin *drvr_pin,
const MinMax *min_max = dcalc_ap->constraintMinMax();
float load_cap = 0.0;
for (auto drvr_rf : RiseFall::range()) {
- Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf,
- dcalc_ap);
- float cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, nullptr);
- arc_delay_calc_->finishDrvrPin();
+ float cap = loadCap(drvr_pin, drvr_rf, dcalc_ap);
if (min_max->compare(cap, load_cap))
load_cap = cap;
}
+ arc_delay_calc_->finishDrvrPin();
return load_cap;
}
+// External
float
GraphDelayCalc::loadCap(const Pin *drvr_pin,
- const RiseFall *drvr_rf,
- const DcalcAnalysisPt *dcalc_ap) const
-{
- Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_rf,
- dcalc_ap);
- float cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, nullptr);
- return cap;
-}
-
-float
-GraphDelayCalc::loadCap(const Pin *drvr_pin,
- const Parasitic *drvr_parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) const
-{
- return loadCap(drvr_pin, drvr_parasitic, rf, dcalc_ap, nullptr);
-}
-
-float
-GraphDelayCalc::loadCap(const Pin *drvr_pin,
- const Parasitic *drvr_parasitic,
- const RiseFall *rf,
- const DcalcAnalysisPt *dcalc_ap,
- const MultiDrvrNet *multi_drvr) const
{
float pin_cap, wire_cap;
- bool has_net_load;
- float fanout;
- if (multi_drvr)
- multi_drvr->netCaps(rf, dcalc_ap,
- pin_cap, wire_cap, fanout, has_net_load);
- else
- netCaps(drvr_pin, rf, dcalc_ap,
- pin_cap, wire_cap, fanout, has_net_load);
- loadCap(drvr_parasitic, has_net_load, pin_cap, wire_cap);
- return wire_cap + pin_cap;
+ loadCap(drvr_pin, rf, dcalc_ap, pin_cap, wire_cap);
+ return pin_cap + wire_cap;
}
+// External
void
GraphDelayCalc::loadCap(const Pin *drvr_pin,
- const Parasitic *drvr_parasitic,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap,
- // Return values.
float &pin_cap,
float &wire_cap) const
{
- bool has_net_load;
- float fanout;
- // Find pin and external pin/wire capacitance.
- netCaps(drvr_pin, rf, dcalc_ap,
- pin_cap, wire_cap, fanout, has_net_load);
- loadCap(drvr_parasitic, has_net_load, pin_cap, wire_cap);
+ MultiDrvrNet *multi_drvr = nullptr;
+ if (graph_) {
+ Vertex *drvr_vertex = graph_->pinDrvrVertex(drvr_pin);
+ multi_drvr = multiDrvrNet(drvr_vertex);
+ }
+ const Parasitic *parasitic;
+ parasiticLoad(drvr_pin, rf, dcalc_ap, multi_drvr, arc_delay_calc_,
+ pin_cap, wire_cap, parasitic);
+ arc_delay_calc_->finishDrvrPin();
+}
+
+float
+GraphDelayCalc::loadCap(const Pin *drvr_pin,
+ const RiseFall *rf,
+ const DcalcAnalysisPt *dcalc_ap,
+ ArcDelayCalc *arc_delay_calc) const
+{
+ const Parasitic *parasitic;
+ float pin_cap, wire_cap;
+ parasiticLoad(drvr_pin, rf, dcalc_ap, nullptr, arc_delay_calc,
+ pin_cap, wire_cap, parasitic);
+ return pin_cap + wire_cap;
}
void
-GraphDelayCalc::loadCap(const Parasitic *drvr_parasitic,
- bool has_net_load,
- // Return values.
- float &pin_cap,
- float &wire_cap) const
+GraphDelayCalc::parasiticLoad(const Pin *drvr_pin,
+ const RiseFall *rf,
+ const DcalcAnalysisPt *dcalc_ap,
+ const MultiDrvrNet *multi_drvr,
+ ArcDelayCalc *arc_delay_calc,
+ // Return values.
+ float &load_cap,
+ const Parasitic *¶sitic) const
{
- // set_load net has precidence over parasitics.
- if (!has_net_load && drvr_parasitic) {
- if (parasitics_->isParasiticNetwork(drvr_parasitic))
- wire_cap += parasitics_->capacitance(drvr_parasitic);
+ float pin_cap, wire_cap;
+ parasiticLoad(drvr_pin, rf, dcalc_ap, multi_drvr, arc_delay_calc,
+ pin_cap, wire_cap, parasitic);
+ load_cap = pin_cap + wire_cap;
+}
+
+void
+GraphDelayCalc::parasiticLoad(const Pin *drvr_pin,
+ const RiseFall *rf,
+ const DcalcAnalysisPt *dcalc_ap,
+ const MultiDrvrNet *multi_drvr,
+ ArcDelayCalc *arc_delay_calc,
+ // Return values.
+ float &pin_cap,
+ float &wire_cap,
+ const Parasitic *¶sitic) const
+{
+ bool has_net_load;
+ float fanout;
+ netCaps(drvr_pin, rf, dcalc_ap, multi_drvr,
+ pin_cap, wire_cap, fanout, has_net_load);
+
+ parasitic = arc_delay_calc->findParasitic(drvr_pin, rf, dcalc_ap);
+ // set_load net has precedence over parasitics.
+ if (!has_net_load && parasitic) {
+ if (parasitics_->isParasiticNetwork(parasitic))
+ wire_cap += parasitics_->capacitance(parasitic);
else {
// PiModel includes both pin and external caps.
- float cap = parasitics_->capacitance(drvr_parasitic);
- if (pin_cap > cap) {
- pin_cap = 0.0;
- wire_cap = cap;
+ float parasitic_cap = parasitics_->capacitance(parasitic);
+ if (parasitic_cap >= pin_cap)
+ wire_cap = parasitic_cap - pin_cap;
+ else {
+ wire_cap = 0.0;
+ // Ignore parasitic if pin cap is greater.
+ parasitic = nullptr;
}
- else
- wire_cap = cap - pin_cap;
}
}
}
@@ -972,15 +1277,29 @@ GraphDelayCalc::netCaps(const Pin *drvr_pin,
Vertex *drvr_vertex = graph_->pinDrvrVertex(drvr_pin);
multi_drvr = multiDrvrNet(drvr_vertex);
}
+ netCaps(drvr_pin, rf, dcalc_ap, multi_drvr,
+ pin_cap, wire_cap, fanout, has_net_load);
+}
+
+void
+GraphDelayCalc::netCaps(const Pin *drvr_pin,
+ const RiseFall *rf,
+ const DcalcAnalysisPt *dcalc_ap,
+ const MultiDrvrNet *multi_drvr,
+ // Return values.
+ float &pin_cap,
+ float &wire_cap,
+ float &fanout,
+ bool &has_net_load) const
+{
if (multi_drvr)
multi_drvr->netCaps(rf, dcalc_ap,
pin_cap, wire_cap, fanout, has_net_load);
else {
- const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
const Corner *corner = dcalc_ap->corner();
const MinMax *min_max = dcalc_ap->constraintMinMax();
// Find pin and external pin/wire capacitance.
- sdc_->connectedCap(drvr_pin, rf, op_cond, corner, min_max,
+ sdc_->connectedCap(drvr_pin, rf, corner, min_max,
pin_cap, wire_cap, fanout, has_net_load);
}
}
@@ -1049,80 +1368,6 @@ GraphDelayCalc::initWireDelays(Vertex *drvr_vertex)
}
}
-// Call the arc delay calculator to find the delay thru a single gate
-// input to output timing arc, The wire delays from the gate output to
-// each load pin, and the slew at each load pin. Annotate the graph
-// with the results.
-bool
-GraphDelayCalc::findArcDelay(const Pin *drvr_pin,
- Vertex *drvr_vertex,
- const TimingArc *arc,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- Vertex *from_vertex,
- Edge *edge,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- const MultiDrvrNet *multi_drvr,
- ArcDelayCalc *arc_delay_calc)
-{
- bool delay_changed = false;
- RiseFall *from_rf = arc->fromEdge()->asRiseFall();
- RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
- if (from_rf && drvr_rf) {
- DcalcAPIndex ap_index = dcalc_ap->index();
- debugPrint(debug_, "delay_calc", 3,
- " %s %s -> %s %s (%s) corner:%s/%s",
- arc->from()->name(),
- arc->fromEdge()->asString(),
- arc->to()->name(),
- arc->toEdge()->asString(),
- arc->role()->asString(),
- dcalc_ap->corner()->name(),
- dcalc_ap->delayMinMax()->asString());
- // Delay calculation is done even when the gate delays/slews are
- // annotated because the wire delays may not be annotated.
- const Slew from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap);
- ArcDelay gate_delay;
- Slew gate_slew;
- float load_cap = loadCap(drvr_pin, drvr_parasitic, drvr_rf, dcalc_ap, multi_drvr);
- if (multi_drvr
- && multi_drvr->parallelGates(network_))
- arc_delay_calc->parallelGateDelay(drvr_pin, arc, from_slew, load_cap,
- drvr_parasitic, related_out_cap, pvt, dcalc_ap,
- gate_delay, gate_slew);
- else
- arc_delay_calc->gateDelay(arc, from_slew, load_cap, drvr_parasitic,
- related_out_cap, pvt, dcalc_ap,
- gate_delay, gate_slew);
- debugPrint(debug_, "delay_calc", 3,
- " gate delay = %s slew = %s",
- delayAsString(gate_delay, this),
- delayAsString(gate_slew, this));
- // Merge slews.
- const Slew &drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index);
- const MinMax *slew_min_max = dcalc_ap->slewMinMax();
- if (delayGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax(), this)
- && !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)
- && !edge->role()->isLatchDtoQ())
- graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew);
- if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) {
- const ArcDelay &prev_gate_delay = graph_->arcDelay(edge,arc,ap_index);
- float gate_delay1 = delayAsFloat(gate_delay);
- float prev_gate_delay1 = delayAsFloat(prev_gate_delay);
- if (prev_gate_delay1 == 0.0
- || (abs(gate_delay1 - prev_gate_delay1) / prev_gate_delay1
- > incremental_delay_tolerance_))
- delay_changed = true;
- graph_->setArcDelay(edge, arc, ap_index, gate_delay);
- }
- if (!edge->role()->isLatchDtoQ())
- annotateLoadDelays(drvr_vertex, drvr_rf, delay_zero, true, dcalc_ap,
- arc_delay_calc);
- }
- return delay_changed;
-}
-
// Use clock slew for register/latch clk->q edges.
Slew
GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex,
@@ -1139,69 +1384,6 @@ GraphDelayCalc::edgeFromSlew(const Vertex *from_vertex,
return graph_->slew(from_vertex, from_rf, dcalc_ap->index());
}
-// Annotate wire arc delays and load pin slews.
-// extra_delay is additional wire delay to add to delay returned
-// by the delay calculator.
-void
-GraphDelayCalc::annotateLoadDelays(Vertex *drvr_vertex,
- const RiseFall *drvr_rf,
- const ArcDelay &extra_delay,
- bool merge,
- const DcalcAnalysisPt *dcalc_ap,
- ArcDelayCalc *arc_delay_calc)
-{
- DcalcAPIndex ap_index = dcalc_ap->index();
- const MinMax *slew_min_max = dcalc_ap->slewMinMax();
- VertexOutEdgeIterator edge_iter(drvr_vertex, graph_);
- while (edge_iter.hasNext()) {
- Edge *wire_edge = edge_iter.next();
- if (wire_edge->isWire()) {
- Vertex *load_vertex = wire_edge->to(graph_);
- Pin *load_pin = load_vertex->pin();
- ArcDelay wire_delay;
- Slew load_slew;
- arc_delay_calc->loadDelay(load_pin, wire_delay, load_slew);
- debugPrint(debug_, "delay_calc", 3,
- " %s load delay = %s slew = %s",
- load_vertex->name(sdc_network_),
- delayAsString(wire_delay, this),
- delayAsString(load_slew, this));
- if (!load_vertex->slewAnnotated(drvr_rf, slew_min_max)) {
- if (drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)) {
- // Copy the driver slew to the load if it is annotated.
- const Slew &drvr_slew = graph_->slew(drvr_vertex,drvr_rf,ap_index);
- graph_->setSlew(load_vertex, drvr_rf, ap_index, drvr_slew);
- }
- else {
- const Slew &slew = graph_->slew(load_vertex, drvr_rf, ap_index);
- if (!merge
- || delayGreater(load_slew, slew, slew_min_max, this))
- graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew);
- }
- }
- if (!graph_->wireDelayAnnotated(wire_edge, drvr_rf, ap_index)) {
- // Multiple timing arcs with the same output transition
- // annotate the same wire edges so they must be combined
- // rather than set.
- const ArcDelay &delay = graph_->wireArcDelay(wire_edge, drvr_rf,
- ap_index);
- Delay wire_delay_extra = extra_delay + wire_delay;
- const MinMax *delay_min_max = dcalc_ap->delayMinMax();
- if (!merge
- || delayGreater(wire_delay_extra, delay, delay_min_max, this)) {
- graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index,
- wire_delay_extra);
- if (observer_)
- observer_->delayChangedTo(load_vertex);
- }
- }
- // Enqueue bidirect driver from load vertex.
- if (sdc_->bidirectDrvrSlewFromLoad(load_pin))
- iter_->enqueue(graph_->pinDrvrVertex(load_pin));
- }
- }
-}
-
void
GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
ArcDelayCalc *arc_delay_calc)
@@ -1227,9 +1409,6 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
DcalcAPIndex ap_index = dcalc_ap->index();
if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) {
- const Pvt *pvt = sdc_->pvt(inst,dcalc_ap->constraintMinMax());
- if (pvt == nullptr)
- pvt = dcalc_ap->operatingConditions();
const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf,
dcalc_ap);
int slew_index = dcalc_ap->checkDataSlewIndex();
@@ -1246,21 +1425,17 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
delayAsString(from_slew, this),
delayAsString(to_slew, this));
float related_out_cap = 0.0;
- if (related_out_pin) {
- Parasitic *related_out_parasitic =
- arc_delay_calc->findParasitic(related_out_pin, to_rf, dcalc_ap);
- related_out_cap = loadCap(related_out_pin,
- related_out_parasitic,
- to_rf, dcalc_ap);
- }
- ArcDelay check_delay;
- arc_delay_calc->checkDelay(arc, from_slew, to_slew, related_out_cap,
- pvt, dcalc_ap, check_delay);
+ if (related_out_pin)
+ related_out_cap = loadCap(related_out_pin, to_rf,dcalc_ap,arc_delay_calc);
+ ArcDelay check_delay = arc_delay_calc->checkDelay(to_pin, arc, from_slew,
+ to_slew, related_out_cap,
+ dcalc_ap);
debugPrint(debug_, "delay_calc", 3,
" check_delay = %s",
delayAsString(check_delay, this));
graph_->setArcDelay(edge, arc, ap_index, check_delay);
delay_changed = true;
+ arc_delay_calc_->finishDrvrPin();
}
}
}
@@ -1285,47 +1460,6 @@ GraphDelayCalc::checkEdgeClkSlew(const Vertex *from_vertex,
////////////////////////////////////////////////////////////////
-float
-GraphDelayCalc::ceff(Edge *edge,
- TimingArc *arc,
- const DcalcAnalysisPt *dcalc_ap)
-{
- Vertex *from_vertex = edge->from(graph_);
- Vertex *to_vertex = edge->to(graph_);
- Pin *to_pin = to_vertex->pin();
- Instance *inst = network_->instance(to_pin);
- const TimingArcSet *arc_set = edge->timingArcSet();
- float ceff = 0.0;
- const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax());
- if (pvt == nullptr)
- pvt = dcalc_ap->operatingConditions();
- RiseFall *from_rf = arc->fromEdge()->asRiseFall();
- RiseFall *to_rf = arc->toEdge()->asRiseFall();
- if (from_rf && to_rf) {
- const LibertyPort *related_out_port = arc_set->relatedOut();
- const Pin *related_out_pin = 0;
- if (related_out_port)
- related_out_pin = network_->findPin(inst, related_out_port);
- float related_out_cap = 0.0;
- if (related_out_pin) {
- Parasitic *related_out_parasitic =
- arc_delay_calc_->findParasitic(related_out_pin, to_rf, dcalc_ap);
- related_out_cap = loadCap(related_out_pin, related_out_parasitic,
- to_rf, dcalc_ap);
- }
- Parasitic *to_parasitic = arc_delay_calc_->findParasitic(to_pin, to_rf,
- dcalc_ap);
- const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap);
- float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap);
- ceff = arc_delay_calc_->ceff(arc, from_slew, load_cap, to_parasitic,
- related_out_cap, pvt, dcalc_ap);
- arc_delay_calc_->finishDrvrPin();
- }
- return ceff;
-}
-
-////////////////////////////////////////////////////////////////
-
string
GraphDelayCalc::reportDelayCalc(const Edge *edge,
const TimingArc *arc,
@@ -1341,9 +1475,6 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge,
const TimingArcSet *arc_set = edge->timingArcSet();
string result;
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
- const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax());
- if (pvt == nullptr)
- pvt = dcalc_ap->operatingConditions();
RiseFall *from_rf = arc->fromEdge()->asRiseFall();
RiseFall *to_rf = arc->toEdge()->asRiseFall();
if (from_rf && to_rf) {
@@ -1352,29 +1483,28 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge,
if (related_out_port)
related_out_pin = network_->findPin(inst, related_out_port);
float related_out_cap = 0.0;
- if (related_out_pin) {
- Parasitic *related_out_parasitic =
- arc_delay_calc_->findParasitic(related_out_pin, to_rf, dcalc_ap);
- related_out_cap = loadCap(related_out_pin, related_out_parasitic,
- to_rf, dcalc_ap);
- }
+ if (related_out_pin)
+ related_out_cap = loadCap(related_out_pin, to_rf, dcalc_ap, arc_delay_calc_);
if (role->isTimingCheck()) {
const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, dcalc_ap);
int slew_index = dcalc_ap->checkDataSlewIndex();
const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index);
bool from_ideal_clk = clk_network_->isIdealClock(from_vertex->pin());
const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr;
- result = arc_delay_calc_->reportCheckDelay(arc, from_slew, from_slew_annotation,
- to_slew, related_out_cap, pvt,
- dcalc_ap, digits);
+ result = arc_delay_calc_->reportCheckDelay(to_pin, arc, from_slew,
+ from_slew_annotation, to_slew,
+ related_out_cap, dcalc_ap, digits);
}
else {
- Parasitic *to_parasitic =
- arc_delay_calc_->findParasitic(to_pin, to_rf, dcalc_ap);
const Slew &from_slew = edgeFromSlew(from_vertex, from_rf, edge, dcalc_ap);
- float load_cap = loadCap(to_pin, to_parasitic, to_rf, dcalc_ap);
- result = arc_delay_calc_->reportGateDelay(arc, from_slew, load_cap, to_parasitic,
- related_out_cap, pvt, dcalc_ap, digits);
+ const Parasitic *to_parasitic;
+ float load_cap;
+ parasiticLoad(to_pin, to_rf, dcalc_ap, nullptr, arc_delay_calc_,
+ load_cap, to_parasitic);
+ LoadPinIndexMap load_pin_index_map = makeLoadPinIndexMap(to_vertex);
+ result = arc_delay_calc_->reportGateDelay(to_pin, arc, from_slew, load_cap,
+ to_parasitic, load_pin_index_map,
+ dcalc_ap, digits);
}
arc_delay_calc_->finishDrvrPin();
}
@@ -1441,17 +1571,11 @@ GraphDelayCalc::minPeriod(const Pin *pin,
////////////////////////////////////////////////////////////////
-MultiDrvrNet::MultiDrvrNet(VertexSet *drvrs) :
- dcalc_drvr_(nullptr),
- drvrs_(drvrs)
+MultiDrvrNet::MultiDrvrNet() :
+ dcalc_drvr_(nullptr)
{
}
-MultiDrvrNet::~MultiDrvrNet()
-{
- delete drvrs_;
-}
-
void
MultiDrvrNet::netCaps(const RiseFall *drvr_rf,
const DcalcAnalysisPt *dcalc_ap,
@@ -1480,7 +1604,6 @@ MultiDrvrNet::findCaps(const Sdc *sdc)
for (auto dcalc_ap : corners->dcalcAnalysisPts()) {
DcalcAPIndex ap_index = dcalc_ap->index();
const Corner *corner = dcalc_ap->corner();
- const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
const MinMax *min_max = dcalc_ap->constraintMinMax();
for (auto drvr_rf : RiseFall::range()) {
int drvr_rf_index = drvr_rf->index();
@@ -1489,7 +1612,7 @@ MultiDrvrNet::findCaps(const Sdc *sdc)
float pin_cap, wire_cap, fanout;
bool has_net_load;
// Find pin and external pin/wire capacitance.
- sdc->connectedCap(drvr_pin, drvr_rf, op_cond, corner, min_max,
+ sdc->connectedCap(drvr_pin, drvr_rf, corner, min_max,
pin_cap, wire_cap, fanout, has_net_load);
net_caps.init(pin_cap, wire_cap, fanout, has_net_load);
}
diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc
index 5e99dd7a..67cecec0 100644
--- a/dcalc/LumpedCapDelayCalc.cc
+++ b/dcalc/LumpedCapDelayCalc.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#include "TimingArc.hh"
#include "TimingModel.hh"
#include "Liberty.hh"
+#include "PortDirection.hh"
#include "Network.hh"
#include "Sdc.hh"
#include "Parasitics.hh"
@@ -57,176 +58,131 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
{
Parasitic *parasitic = nullptr;
const Corner *corner = dcalc_ap->corner();
- // set_load net has precidence over parasitics.
- if (!sdc_->drvrPinHasWireCap(drvr_pin, corner)) {
- const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
- if (parasitics_->haveParasitics()) {
- // Prefer PiElmore.
- parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
- if (parasitic == nullptr) {
- Parasitic *parasitic_network =
- parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
- if (parasitic_network) {
- parasitics_->reduceToPiElmore(parasitic_network, drvr_pin,
- dcalc_ap->operatingConditions(),
- corner,
- dcalc_ap->constraintMinMax(),
- parasitic_ap);
- parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
- reduced_parasitic_drvrs_.push_back(drvr_pin);
- }
- }
- }
- else {
- const MinMax *cnst_min_max = dcalc_ap->constraintMinMax();
- Wireload *wireload = sdc_->wireload(cnst_min_max);
- if (wireload) {
- float pin_cap, wire_cap, fanout;
- bool has_net_load;
- graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
- pin_cap, wire_cap, fanout, has_net_load);
- parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload,
- fanout, pin_cap,
- dcalc_ap->operatingConditions(),
- corner,
- cnst_min_max,
- parasitic_ap);
- // Estimated parasitics are not recorded in the "database", so save
- // it for deletion after the drvr pin delay calc is finished.
- if (parasitic)
- unsaved_parasitics_.push_back(parasitic);
- }
- }
+ // set_load net has precedence over parasitics.
+ if (sdc_->drvrPinHasWireCap(drvr_pin, corner)
+ || network_->direction(drvr_pin)->isInternal())
+ return nullptr;
+ const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
+ // Prefer PiElmore.
+ parasitic = parasitics_->findPiElmore(drvr_pin, rf, parasitic_ap);
+ if (parasitic)
+ return parasitic;
+ Parasitic *parasitic_network = parasitics_->findParasiticNetwork(drvr_pin,
+ parasitic_ap);
+ if (parasitic_network) {
+ parasitic = reduceParasitic(parasitic_network, drvr_pin, rf, dcalc_ap);
+ if (parasitic)
+ return parasitic;
+ }
+ const MinMax *min_max = dcalc_ap->constraintMinMax();
+ Wireload *wireload = sdc_->wireload(min_max);
+ if (wireload) {
+ float pin_cap, wire_cap, fanout;
+ bool has_net_load;
+ graph_delay_calc_->netCaps(drvr_pin, rf, dcalc_ap,
+ pin_cap, wire_cap, fanout, has_net_load);
+ parasitic = parasitics_->estimatePiElmore(drvr_pin, rf, wireload, fanout,
+ pin_cap, corner, min_max);
}
return parasitic;
}
-ReducedParasiticType
-LumpedCapDelayCalc::reducedParasiticType() const
+Parasitic *
+LumpedCapDelayCalc::reduceParasitic(const Parasitic *parasitic_network,
+ const Pin *drvr_pin,
+ const RiseFall *rf,
+ const DcalcAnalysisPt *dcalc_ap)
+
{
- return ReducedParasiticType::pi_elmore;
+ const Corner *corner = dcalc_ap->corner();
+ const ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
+ return parasitics_->reduceToPiElmore(parasitic_network, drvr_pin, rf,
+ corner, dcalc_ap->constraintMinMax(),
+ parasitic_ap);
}
-float
-LumpedCapDelayCalc::ceff(const TimingArc *,
- const Slew &,
- float load_cap,
- const Parasitic *,
- float,
- const Pvt *,
- const DcalcAnalysisPt *)
+ArcDcalcResult
+LumpedCapDelayCalc::inputPortDelay(const Pin *,
+ float in_slew,
+ const RiseFall *rf,
+ const Parasitic *,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *)
{
- return load_cap;
+ const LibertyLibrary *drvr_library = network_->defaultLibertyLibrary();
+ return makeResult(drvr_library,rf, 0.0, in_slew, load_pin_index_map);
}
-void
-LumpedCapDelayCalc::gateDelay(const TimingArc *arc,
+ArcDcalcResult
+LumpedCapDelayCalc::gateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
const Slew &in_slew,
float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- // Return values.
- ArcDelay &gate_delay,
- Slew &drvr_slew)
+ const Parasitic *,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap)
{
- gateDelayInit(arc, in_slew, drvr_parasitic);
GateTimingModel *model = gateModel(arc, dcalc_ap);
debugPrint(debug_, "delay_calc", 3,
- " in_slew = %s load_cap = %s related_load_cap = %s lumped",
+ " in_slew = %s load_cap = %s lumped",
delayAsString(in_slew, this),
- units()->capacitanceUnit()->asString(load_cap),
- units()->capacitanceUnit()->asString(related_out_cap));
+ units()->capacitanceUnit()->asString(load_cap));
+ const RiseFall *rf = arc->toEdge()->asRiseFall();
+ const LibertyLibrary *drvr_library = arc->to()->libertyLibrary();
if (model) {
- ArcDelay gate_delay1;
- Slew drvr_slew1;
+ ArcDelay gate_delay;
+ Slew drvr_slew;
float in_slew1 = delayAsFloat(in_slew);
// NaNs cause seg faults during table lookup.
- if (isnan(load_cap) || isnan(related_out_cap) || isnan(delayAsFloat(in_slew)))
- report_->error(710, "gate delay input variable is NaN");
- model->gateDelay(pvt, in_slew1, load_cap, related_out_cap,
- pocv_enabled_, gate_delay1, drvr_slew1);
- gate_delay = gate_delay1;
- drvr_slew = drvr_slew1;
- drvr_slew_ = drvr_slew1;
- }
- else {
- gate_delay = delay_zero;
- drvr_slew = delay_zero;
- drvr_slew_ = 0.0;
+ if (isnan(load_cap) || isnan(delayAsFloat(in_slew)))
+ report_->error(1350, "gate delay input variable is NaN");
+ model->gateDelay(pinPvt(drvr_pin, dcalc_ap), in_slew1, load_cap, pocv_enabled_,
+ gate_delay, drvr_slew);
+ return makeResult(drvr_library, rf, gate_delay, drvr_slew, load_pin_index_map);
}
+ else
+ return makeResult(drvr_library, rf, delay_zero, delay_zero, load_pin_index_map);
}
-void
-LumpedCapDelayCalc::loadDelay(const Pin *load_pin,
- ArcDelay &wire_delay,
- Slew &load_slew)
+ArcDcalcResult
+LumpedCapDelayCalc::makeResult(const LibertyLibrary *drvr_library,
+ const RiseFall *rf,
+ ArcDelay gate_delay,
+ Slew drvr_slew,
+ const LoadPinIndexMap &load_pin_index_map)
{
- Delay wire_delay1 = 0.0;
- Slew load_slew1 = drvr_slew_ * multi_drvr_slew_factor_;
- thresholdAdjust(load_pin, wire_delay1, load_slew1);
- wire_delay = wire_delay1;
- load_slew = load_slew1;
+ ArcDcalcResult dcalc_result(load_pin_index_map.size());
+ dcalc_result.setGateDelay(gate_delay);
+ dcalc_result.setDrvrSlew(drvr_slew);
+
+ for (auto load_pin_index : load_pin_index_map) {
+ const Pin *load_pin = load_pin_index.first;
+ size_t load_idx = load_pin_index.second;
+ ArcDelay wire_delay = 0.0;
+ thresholdAdjust(load_pin, drvr_library, rf, wire_delay, drvr_slew);
+ dcalc_result.setWireDelay(load_idx, wire_delay);
+ dcalc_result.setLoadSlew(load_idx, drvr_slew);
+ }
+ return dcalc_result;
}
string
-LumpedCapDelayCalc::reportGateDelay(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- int digits)
+LumpedCapDelayCalc::reportGateDelay(const Pin *check_pin,
+ const TimingArc *arc,
+ const Slew &in_slew,
+ float load_cap,
+ const Parasitic *,
+ const LoadPinIndexMap &,
+ const DcalcAnalysisPt *dcalc_ap,
+ int digits)
{
GateTimingModel *model = gateModel(arc, dcalc_ap);
if (model) {
float in_slew1 = delayAsFloat(in_slew);
- return model->reportGateDelay(pvt, in_slew1, load_cap, related_out_cap,
+ return model->reportGateDelay(pinPvt(check_pin, dcalc_ap), in_slew1, load_cap,
false, digits);
}
return "";
}
-void
-LumpedCapDelayCalc::checkDelay(const TimingArc *arc,
- const Slew &from_slew,
- const Slew &to_slew,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- // Return values.
- ArcDelay &margin)
-{
- CheckTimingModel *model = checkModel(arc, dcalc_ap);
- if (model) {
- float from_slew1 = delayAsFloat(from_slew);
- float to_slew1 = delayAsFloat(to_slew);
- model->checkDelay(pvt, from_slew1, to_slew1, related_out_cap, pocv_enabled_, margin);
- }
- else
- margin = delay_zero;
-}
-
-string
-LumpedCapDelayCalc::reportCheckDelay(const TimingArc *arc,
- const Slew &from_slew,
- const char *from_slew_annotation,
- const Slew &to_slew,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- int digits)
-{
- CheckTimingModel *model = checkModel(arc, dcalc_ap);
- if (model) {
- float from_slew1 = delayAsFloat(from_slew);
- float to_slew1 = delayAsFloat(to_slew);
- return model->reportCheckDelay(pvt, from_slew1, from_slew_annotation,
- to_slew1, related_out_cap, false, digits);
- }
- return "";
-}
-
} // namespace
diff --git a/dcalc/LumpedCapDelayCalc.hh b/dcalc/LumpedCapDelayCalc.hh
index db7473c0..b62a2faf 100644
--- a/dcalc/LumpedCapDelayCalc.hh
+++ b/dcalc/LumpedCapDelayCalc.hh
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -30,54 +30,40 @@ public:
Parasitic *findParasitic(const Pin *drvr_pin,
const RiseFall *rf,
const DcalcAnalysisPt *dcalc_ap) override;
- ReducedParasiticType reducedParasiticType() const override;
- void gateDelay(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- // Return values.
- ArcDelay &gate_delay,
- Slew &drvr_slew) override;
- float ceff(const TimingArc *arc,
- const Slew &in_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap) override;
- void loadDelay(const Pin *load_pin,
- // Return values.
- ArcDelay &wire_delay,
- Slew &load_slew) override;
- void checkDelay(const TimingArc *arc,
- const Slew &from_slew,
- const Slew &to_slew,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- // Return values.
- ArcDelay &margin) override;
- string reportGateDelay(const TimingArc *arc,
+ Parasitic *reduceParasitic(const Parasitic *parasitic_network,
+ const Pin *drvr_pin,
+ const RiseFall *rf,
+ const DcalcAnalysisPt *dcalc_ap) override;
+ ArcDcalcResult inputPortDelay(const Pin *port_pin,
+ float in_slew,
+ const RiseFall *rf,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap) override;
+ ArcDcalcResult gateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
+ const Slew &in_slew,
+ float load_cap,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap) override;
+ string reportGateDelay(const Pin *drvr_pin,
+ const TimingArc *arc,
const Slew &in_slew,
float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
+ const Parasitic *parasitic,
+ const LoadPinIndexMap &load_pin_index_map,
const DcalcAnalysisPt *dcalc_ap,
int digits) override;
- string reportCheckDelay(const TimingArc *arc,
- const Slew &from_slew,
- const char *from_slew_annotation,
- const Slew &to_slew,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- int digits) override;
protected:
+ ArcDcalcResult makeResult(const LibertyLibrary *drvr_library,
+ const RiseFall *rf,
+ ArcDelay gate_delay,
+ Slew drvr_slew,
+ const LoadPinIndexMap &load_pin_index_map);
+
+ using ArcDelayCalc::reduceParasitic;
};
ArcDelayCalc *
diff --git a/dcalc/NetCaps.cc b/dcalc/NetCaps.cc
index 4521eb99..44fc5924 100644
--- a/dcalc/NetCaps.cc
+++ b/dcalc/NetCaps.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
diff --git a/dcalc/NetCaps.hh b/dcalc/NetCaps.hh
index ca1ad970..311a5104 100644
--- a/dcalc/NetCaps.hh
+++ b/dcalc/NetCaps.hh
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
diff --git a/dcalc/ParallelDelayCalc.cc b/dcalc/ParallelDelayCalc.cc
index 62fd90a6..732a239f 100644
--- a/dcalc/ParallelDelayCalc.cc
+++ b/dcalc/ParallelDelayCalc.cc
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -31,141 +31,81 @@ ParallelDelayCalc::ParallelDelayCalc(StaState *sta):
{
}
-void
-ParallelDelayCalc::inputPortDelay(const Pin *drvr_pin,
- float in_slew,
- const RiseFall *rf,
- const Parasitic *parasitic,
- const DcalcAnalysisPt *dcalc_ap)
+ArcDcalcResultSeq
+ParallelDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
+ float load_cap,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap)
{
- DelayCalcBase::inputPortDelay(drvr_pin, in_slew, rf, parasitic, dcalc_ap);
- multi_drvr_slew_factor_ = 1.0;
-}
-
-void
-ParallelDelayCalc::gateDelayInit(const TimingArc *arc,
- const Slew &in_slew,
- const Parasitic *drvr_parasitic)
-{
- DelayCalcBase::gateDelayInit(arc, in_slew, drvr_parasitic);
- multi_drvr_slew_factor_ = 1.0F;
-}
-
-void
-ParallelDelayCalc::findParallelGateDelays(const MultiDrvrNet *multi_drvr,
- GraphDelayCalc *dcalc)
-{
- int count = RiseFall::index_count * corners_->dcalcAnalysisPtCount();
- parallel_delays_.resize(count);
- parallel_slews_.resize(count);
- for (auto dcalc_ap : corners_->dcalcAnalysisPts()) {
- for (auto drvr_rf : RiseFall::range()) {
- DcalcAPIndex ap_index = dcalc_ap->index();
- int drvr_rf_index = drvr_rf->index();
- int index = ap_index * RiseFall::index_count + drvr_rf_index;
- findMultiDrvrGateDelay(multi_drvr, drvr_rf, dcalc_ap, dcalc,
- parallel_delays_[index],
- parallel_slews_[index]);
- }
+ if (dcalc_args.size() == 1) {
+ ArcDcalcArg &dcalc_arg = dcalc_args[0];
+ ArcDcalcResult dcalc_result = gateDelay(dcalc_arg.drvrPin(), dcalc_arg.arc(),
+ dcalc_arg.inSlew(),
+ load_cap, dcalc_arg.parasitic(),
+ load_pin_index_map, dcalc_ap);
+ ArcDcalcResultSeq dcalc_results;
+ dcalc_results.push_back(dcalc_result);
+ return dcalc_results;
}
+ return gateDelaysParallel(dcalc_args, load_cap, load_pin_index_map, dcalc_ap);
}
-void
-ParallelDelayCalc::findMultiDrvrGateDelay(const MultiDrvrNet *multi_drvr,
- const RiseFall *drvr_rf,
- const DcalcAnalysisPt *dcalc_ap,
- GraphDelayCalc *dcalc,
- // Return values.
- ArcDelay ¶llel_delay,
- Slew ¶llel_slew)
+ArcDcalcResultSeq
+ParallelDelayCalc::gateDelaysParallel(ArcDcalcArgSeq &dcalc_args,
+ float load_cap,
+ const LoadPinIndexMap &load_pin_index_map,
+ const DcalcAnalysisPt *dcalc_ap)
{
- ArcDelay delay_sum = 0.0;
+ size_t drvr_count = dcalc_args.size();
+ ArcDcalcResultSeq dcalc_results(drvr_count);
Slew slew_sum = 0.0;
- for (Vertex *drvr_vertex : *multi_drvr->drvrs()) {
- Pin *drvr_pin = drvr_vertex->pin();
- Instance *drvr_inst = network_->instance(drvr_pin);
- const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
- if (pvt == nullptr)
- pvt = dcalc_ap->operatingConditions();
- VertexInEdgeIterator edge_iter(drvr_vertex, graph_);
- while (edge_iter.hasNext()) {
- Edge *edge = edge_iter.next();
- TimingArcSet *arc_set = edge->timingArcSet();
- const LibertyPort *related_out_port = arc_set->relatedOut();
- for (TimingArc *arc : arc_set->arcs()) {
- RiseFall *arc_rf = arc->toEdge()->asRiseFall();
- if (arc_rf == drvr_rf) {
- Vertex *from_vertex = edge->from(graph_);
- RiseFall *from_rf = arc->fromEdge()->asRiseFall();
- Slew from_slew = dcalc->edgeFromSlew(from_vertex, from_rf,
- edge, dcalc_ap);
- ArcDelay intrinsic_delay;
- Slew intrinsic_slew;
- gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
- intrinsic_delay, intrinsic_slew);
- Parasitic *parasitic = findParasitic(drvr_pin, drvr_rf, dcalc_ap);
- const Pin *related_out_pin = 0;
- float related_out_cap = 0.0;
- if (related_out_port) {
- Instance *inst = network_->instance(drvr_pin);
- related_out_pin = network_->findPin(inst, related_out_port);
- if (related_out_pin) {
- Parasitic *related_out_parasitic = findParasitic(related_out_pin,
- drvr_rf,
- dcalc_ap);
- related_out_cap = dcalc->loadCap(related_out_pin,
- related_out_parasitic,
- drvr_rf, dcalc_ap);
- }
- }
- float load_cap = dcalc->loadCap(drvr_pin, parasitic,
- drvr_rf, dcalc_ap);
- ArcDelay gate_delay;
- Slew gate_slew;
- gateDelay(arc, from_slew, load_cap, parasitic,
- related_out_cap, pvt, dcalc_ap,
- gate_delay, gate_slew);
- delay_sum += 1.0F / (gate_delay - intrinsic_delay);
- slew_sum += 1.0F / gate_slew;
- }
- }
+ ArcDelay load_delay_sum = 0.0;
+ vector intrinsic_delays(dcalc_args.size());
+ vector load_delays(dcalc_args.size());
+ for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
+ ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
+ ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
+ const Pin *drvr_pin = dcalc_arg.drvrPin();
+ const TimingArc *arc = dcalc_arg.arc();
+ Slew in_slew = dcalc_arg.inSlew();
+
+ ArcDcalcResult intrinsic_result = gateDelay(drvr_pin, arc, in_slew, 0.0, nullptr,
+ load_pin_index_map, dcalc_ap);
+ ArcDelay intrinsic_delay = intrinsic_result.gateDelay();
+ intrinsic_delays[drvr_idx] = intrinsic_result.gateDelay();
+
+ ArcDcalcResult gate_result = gateDelay(drvr_pin, arc, in_slew, load_cap,
+ dcalc_arg.parasitic(),
+ load_pin_index_map, dcalc_ap);
+ ArcDelay gate_delay = gate_result.gateDelay();
+ Slew drvr_slew = gate_result.drvrSlew();
+ ArcDelay load_delay = gate_delay - intrinsic_delay;
+ load_delays[drvr_idx] = load_delay;
+
+ if (!delayZero(load_delay))
+ load_delay_sum += 1.0 / load_delay;
+ if (!delayZero(drvr_slew))
+ slew_sum += 1.0 / drvr_slew;
+
+ dcalc_result.setLoadCount(load_pin_index_map.size());
+ for (auto load_pin_index : load_pin_index_map) {
+ size_t load_idx = load_pin_index.second;
+ dcalc_result.setWireDelay(load_idx, gate_result.wireDelay(load_idx));
+ dcalc_result.setLoadSlew(load_idx, gate_result.loadSlew(load_idx));
}
}
- parallel_delay = 1.0F / delay_sum;
- parallel_slew = 1.0F / slew_sum;
-}
-void
-ParallelDelayCalc::parallelGateDelay(const Pin *,
- const TimingArc *arc,
- const Slew &from_slew,
- float load_cap,
- const Parasitic *drvr_parasitic,
- float related_out_cap,
- const Pvt *pvt,
- const DcalcAnalysisPt *dcalc_ap,
- // Return values.
- ArcDelay &gate_delay,
- Slew &gate_slew)
-{
- ArcDelay intrinsic_delay;
- Slew intrinsic_slew;
- gateDelay(arc, from_slew, 0.0, 0, 0.0, pvt, dcalc_ap,
- intrinsic_delay, intrinsic_slew);
- const RiseFall *drvr_rf = arc->toEdge()->asRiseFall();
- int index = dcalc_ap->index() * RiseFall::index_count + drvr_rf->index();
- ArcDelay parallel_delay = parallel_delays_[index];
- Slew parallel_slew = parallel_slews_[index];
- gate_delay = parallel_delay + intrinsic_delay;
- gate_slew = parallel_slew;
+ ArcDelay gate_load_delay = delayZero(load_delay_sum)
+ ? delay_zero
+ : 1.0 / load_delay_sum;
+ ArcDelay drvr_slew = delayZero(slew_sum) ? delay_zero : 1.0 / slew_sum;
- Delay gate_delay1;
- Slew gate_slew1;
- gateDelay(arc, from_slew, load_cap, drvr_parasitic,
- related_out_cap, pvt, dcalc_ap,
- gate_delay1, gate_slew1);
- float factor = delayRatio(gate_slew, gate_slew1);
- multi_drvr_slew_factor_ = factor;
+ for (size_t drvr_idx = 0; drvr_idx < drvr_count; drvr_idx++) {
+ ArcDcalcResult &dcalc_result = dcalc_results[drvr_idx];
+ dcalc_result.setGateDelay(intrinsic_delays[drvr_idx] + gate_load_delay);
+ dcalc_result.setDrvrSlew(drvr_slew);
+ }
+ return dcalc_results;
}
} // namespace
diff --git a/dcalc/ParallelDelayCalc.hh b/dcalc/ParallelDelayCalc.hh
index 68510e99..7f361218 100644
--- a/dcalc/ParallelDelayCalc.hh
+++ b/dcalc/ParallelDelayCalc.hh
@@ -1,5 +1,5 @@
// OpenSTA, Static Timing Analyzer
-// Copyright (c) 2023, Parallax Software, Inc.
+// Copyright (c) 2024, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -17,52 +17,26 @@
#pragma once
#include
+#include