From 801d621d6b235130c46f40137d1dcecdc3a22aa5 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 5 May 2026 17:08:16 -0700 Subject: [PATCH] Dmp delay calc inline algs Signed-off-by: James Cherry --- dcalc/DmpCeff.cc | 317 ++++-------------------------------------- dcalc/DmpCeff.hh | 273 ++++++++++++++++++++++++++++++++++-- dcalc/DmpDelayCalc.cc | 4 +- 3 files changed, 292 insertions(+), 302 deletions(-) diff --git a/dcalc/DmpCeff.cc b/dcalc/DmpCeff.cc index 7ce3e903..5d0aef1d 100644 --- a/dcalc/DmpCeff.cc +++ b/dcalc/DmpCeff.cc @@ -68,6 +68,17 @@ static const char *dmp_func_index_strings[] = {"y20", "y50", "Ipi"}; static double exp2(double x); +static double +gateModelRd(const LibertyCell *cell, + const GateTableModel *gate_model, + const RiseFall *rf, + double in_slew, + double c2, + double c1, + const Pvt *pvt); + +//////////////////////////////////////////////////////////////// + class DmpError : public Exception { public: @@ -78,156 +89,13 @@ private: std::string what_; }; -static double -gateModelRd(const LibertyCell *cell, - const GateTableModel *gate_model, - const RiseFall *rf, - double in_slew, - double c2, - double c1, - const Pvt *pvt); -//////////////////////////////////////////////////////////////// - -// Base class for Dartu/Menezes/Pileggi algorithm. -// Derived classes handle different cases of zero values in the Pi model. -class DmpAlg : public StaState +DmpError::DmpError(std::string_view what) : + what_(what) { -public: - DmpAlg(int nr_order, - StaState *sta); - ~DmpAlg() override = default; - virtual std::string_view name() = 0; - // Set driver model and pi model parameters for delay calculation. - 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, - double c2, - double rpi, - double c1); - virtual std::pair gateDelaySlew() = 0; - virtual std::pair loadDelaySlew(const Pin *load_pin, - double elmore); - double ceff() { return ceff_; } + //sta::print(stdout, "DmpError {}\n", what); +} - // Given x_ as a vector of input parameters, fill fvec_ with the - // 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 (vo, dvo_dt). - std::pair Vo(double t); - // Load response to driver waveform (vl, dvl/dt). - std::pair Vl(double t); - -protected: - void luDecomp(); - void luSolve(); - void newtonRaphson(); - // Find driver parameters t0, delta_t, Ceff. - void findDriverParams(double ceff); - std::pair gateCapDelaySlew(double ceff); - std::tuple gateDelays(double ceff); - // Partial derivatives of y(t) jacobian (dydt0, dyddt, dydcl). - std::tuple dy(double t, - double t0, - double dt, - double cl); - double y0dt(double t, - double cl); - double y0dcl(double t, - double cl); - void showX(); - void showFvec(); - void showJacobian(); - std::pair findDriverDelaySlew(); - double findVoCrossing(double vth, - double t_lower, - double t_upper); - void showVo(); - double findVlCrossing(double vth, - double t_lower, - double t_upper); - void showVl(); - void fail(std::string_view reason); - - // Output response to vs(t) ramp driving capacitive load (y, t1). - std::pair y(double t, - double t0, - double dt, - double cl); - // Output response to unit ramp driving capacitive load. - double y0(double t, - double cl); - // Output response to unit ramp driving pi model load. - // Unit ramp output at pi load (vo, dvo_dt). - virtual std::pair V0(double t) = 0; - // Upper bound on time that vo crosses vh. - virtual double voCrossingUpperBound() = 0; - // Load responce to driver unit ramp. - // Unit ramp load response (vl, dvl_dt). - virtual std::pair Vl0(double t) = 0; - // Upper bound on time that vl crosses vh. - double vlCrossingUpperBound(); - - // Inputs to the delay calculator. - const LibertyCell *drvr_cell_; - const LibertyLibrary *drvr_library_; - const Pvt *pvt_; - const GateTableModel *gate_model_; - double in_slew_; - double c2_{0.0}; - double rpi_{0.0}; - double c1_{0.0}; - - double rd_; - // Logic threshold (percentage of supply voltage). - double vth_; - // Slew lower limit (percentage of supply voltage). - double vl_; - // Slew upper limit (percentage of supply voltage). - double vh_; - // Table slews are scaled by slew_derate to get - // measured slews from vl to vh. - double slew_derate_; - - // Driver parameters calculated by this algorithm. - double t0_; - double dt_; - double ceff_; - - // Driver parameter Newton-Raphson state. - int nr_order_; - - static constexpr int max_nr_order_ = 3; - - std::array x_; - std::array fvec_; - std::array, max_nr_order_> fjac_; - std::array scale_; - std::array p_; - std::array index_; - - // Driver slew used to check load delay. - double drvr_slew_; - double vo_delay_; - // True if the driver parameters are valid for finding the load delays. - bool driver_valid_; - // Load rspf elmore delay. - double elmore_; - double p3_; - - // Tolerance (as a scale of value) for driver parameters (Ceff, delta t, t0). - static constexpr double driver_param_tol_ = .01; - // Waveform threshold crossing time tolerance (1.0 = 100%). - static constexpr double vth_time_tol_ = .01; - // Max iterations for findRoot. - static constexpr int find_root_max_iter_ = 20; - static inline int newton_raphson_max_iter_ = 100; - // A small number used by luDecomp. - static constexpr double tiny_double_ = 1.0e-20; -}; +//////////////////////////////////////////////////////////////// DmpAlg::DmpAlg(int nr_order, StaState *sta) : @@ -593,33 +461,6 @@ DmpAlg::fail(std::string_view reason) //////////////////////////////////////////////////////////////// -// Capacitive load. -class DmpCap : public DmpAlg -{ -public: - DmpCap(StaState *sta); - std::string_view 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; - std::pair gateDelaySlew() override; - std::pair loadDelaySlew(const Pin *, - double elmore) override; - void evalDmpEqns() override; - -protected: - double voCrossingUpperBound() override; - std::pair V0(double t) override; - std::pair Vl0(double t) override; -}; - DmpCap::DmpCap(StaState *sta) : DmpAlg(1, sta) @@ -692,53 +533,6 @@ DmpCap::Vl0(double) //////////////////////////////////////////////////////////////// -// No non-zero pi model parameters, two poles, one zero -class DmpPi : public DmpAlg -{ -public: - DmpPi(StaState *sta); - std::string_view 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; - std::pair gateDelaySlew() override; - void evalDmpEqns() override; - -protected: - double voCrossingUpperBound() override; - std::pair V0(double t) override; - std::pair Vl0(double t) override; - -private: - void findDriverParamsPi(); - double ipiIceff(double t0, - double dt, - double ceff_time, - double ceff); - - // Poles/zero. - double p1_{0.0}; - double p2_{0.0}; - double z1_{0.0}; - // Residues. - double k0_{0.0}; - double k1_{0.0}; - double k2_{0.0}; - double k3_{0.0}; - double k4_{0.0}; - // Ipi coefficients. - double A_{0.0}; - double B_{0.0}; - double D_{0.0}; -}; - DmpPi::DmpPi(StaState *sta) : DmpAlg(3, sta) @@ -940,18 +734,6 @@ DmpPi::voCrossingUpperBound() //////////////////////////////////////////////////////////////// -// Capacitive load, so Ceff is known. -// Solve for t0, delta t. -class DmpOnePole : public DmpAlg -{ -public: - DmpOnePole(StaState *sta); - void evalDmpEqns() override; - -protected: - double voCrossingUpperBound() override; -}; - DmpOnePole::DmpOnePole(StaState *sta) : DmpAlg(2, sta) @@ -1000,40 +782,6 @@ DmpOnePole::voCrossingUpperBound() //////////////////////////////////////////////////////////////// -// C2 = 0, one pole, one zero. -class DmpZeroC2 : public DmpOnePole -{ -public: - DmpZeroC2(StaState *sta); - std::string_view 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; - std::pair gateDelaySlew() override; - -protected: - std::pair V0(double t) override; - std::pair Vl0(double t) override; - double voCrossingUpperBound() override; - -private: - // Pole/zero. - double p1_{0.0}; - double z1_{0.0}; - // Residues. - double k0_{0.0}; - double k1_{0.0}; - double k2_{0.0}; - double k3_{0.0}; -}; - DmpZeroC2::DmpZeroC2(StaState *sta) : DmpOnePole(sta) { @@ -1260,19 +1008,12 @@ bool DmpCeffDelayCalc::unsuppored_model_warned_ = false; DmpCeffDelayCalc::DmpCeffDelayCalc(StaState *sta) : LumpedCapDelayCalc(sta), - dmp_cap_(new DmpCap(sta)), - dmp_pi_(new DmpPi(sta)), - dmp_zero_c2_(new DmpZeroC2(sta)) + dmp_cap_(sta), + dmp_pi_(sta), + dmp_zero_c2_(sta) { } -DmpCeffDelayCalc::~DmpCeffDelayCalc() -{ - delete dmp_cap_; - delete dmp_pi_; - delete dmp_zero_c2_; -} - ArcDcalcResult DmpCeffDelayCalc::gateDelay(const Pin *drvr_pin, const TimingArc *arc, @@ -1362,15 +1103,15 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, || rpi < rd * 1e-3 // c1/Rpi can be ignored. || (c1 == 0.0 || c1 < c2 * 1e-3 || rpi == 0.0)) - dmp_alg_ = dmp_cap_; + dmp_alg_ = &dmp_cap_; else if (c2 < c1 * 1e-3) - dmp_alg_ = dmp_zero_c2_; + dmp_alg_ = &dmp_zero_c2_; else // The full monty. - dmp_alg_ = dmp_pi_; + dmp_alg_ = &dmp_pi_; } else - dmp_alg_ = dmp_cap_; + dmp_alg_ = &dmp_cap_; dmp_alg_->init(drvr_library, drvr_cell, pvt, gate_model, rf, rd, in_slew, c2, rpi, c1); debugPrint(debug_, "dmp_ceff", 3, @@ -1473,15 +1214,9 @@ void DmpCeffDelayCalc::copyState(const StaState *sta) { StaState::copyState(sta); - dmp_cap_->copyState(sta); - dmp_pi_->copyState(sta); - dmp_zero_c2_->copyState(sta); -} - -DmpError::DmpError(std::string_view what) : - what_(what) -{ - //sta::print(stdout, "DmpError {}\n", what); + dmp_cap_.copyState(sta); + dmp_pi_.copyState(sta); + dmp_zero_c2_.copyState(sta); } // This saves about 2.5% in overall run time on designs with SPEF. diff --git a/dcalc/DmpCeff.hh b/dcalc/DmpCeff.hh index 1ca6209e..a2e8a144 100644 --- a/dcalc/DmpCeff.hh +++ b/dcalc/DmpCeff.hh @@ -32,19 +32,275 @@ namespace sta { -class DmpAlg; -class DmpCap; -class DmpPi; -class DmpZeroC2; class GateTableModel; +// Base class for Dartu/Menezes/Pileggi algorithm. +// Derived classes handle different cases of zero values in the Pi model. +class DmpAlg : public StaState +{ +public: + DmpAlg(int nr_order, + StaState *sta); + ~DmpAlg() override = default; + virtual std::string_view name() = 0; + // Set driver model and pi model parameters for delay calculation. + 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, + double c2, + double rpi, + double c1); + virtual std::pair gateDelaySlew() = 0; + virtual std::pair loadDelaySlew(const Pin *load_pin, + double elmore); + double ceff() { return ceff_; } + + // Given x_ as a vector of input parameters, fill fvec_ with the + // 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 (vo, dvo_dt). + std::pair Vo(double t); + // Load response to driver waveform (vl, dvl/dt). + std::pair Vl(double t); + +protected: + void luDecomp(); + void luSolve(); + void newtonRaphson(); + // Find driver parameters t0, delta_t, Ceff. + void findDriverParams(double ceff); + std::pair gateCapDelaySlew(double ceff); + std::tuple gateDelays(double ceff); + // Partial derivatives of y(t) jacobian (dydt0, dyddt, dydcl). + std::tuple dy(double t, + double t0, + double dt, + double cl); + double y0dt(double t, + double cl); + double y0dcl(double t, + double cl); + void showX(); + void showFvec(); + void showJacobian(); + std::pair findDriverDelaySlew(); + double findVoCrossing(double vth, + double t_lower, + double t_upper); + void showVo(); + double findVlCrossing(double vth, + double t_lower, + double t_upper); + void showVl(); + void fail(std::string_view reason); + + // Output response to vs(t) ramp driving capacitive load (y, t1). + std::pair y(double t, + double t0, + double dt, + double cl); + // Output response to unit ramp driving capacitive load. + double y0(double t, + double cl); + // Output response to unit ramp driving pi model load. + // Unit ramp output at pi load (vo, dvo_dt). + virtual std::pair V0(double t) = 0; + // Upper bound on time that vo crosses vh. + virtual double voCrossingUpperBound() = 0; + // Load responce to driver unit ramp. + // Unit ramp load response (vl, dvl_dt). + virtual std::pair Vl0(double t) = 0; + // Upper bound on time that vl crosses vh. + double vlCrossingUpperBound(); + + // Inputs to the delay calculator. + const LibertyCell *drvr_cell_; + const LibertyLibrary *drvr_library_; + const Pvt *pvt_; + const GateTableModel *gate_model_; + double in_slew_; + double c2_{0.0}; + double rpi_{0.0}; + double c1_{0.0}; + + double rd_; + // Logic threshold (percentage of supply voltage). + double vth_; + // Slew lower limit (percentage of supply voltage). + double vl_; + // Slew upper limit (percentage of supply voltage). + double vh_; + // Table slews are scaled by slew_derate to get + // measured slews from vl to vh. + double slew_derate_; + + // Driver parameters calculated by this algorithm. + double t0_; + double dt_; + double ceff_; + + // Driver parameter Newton-Raphson state. + int nr_order_; + + static constexpr int max_nr_order_ = 3; + + std::array x_; + std::array fvec_; + std::array, max_nr_order_> fjac_; + std::array scale_; + std::array p_; + std::array index_; + + // Driver slew used to check load delay. + double drvr_slew_; + double vo_delay_; + // True if the driver parameters are valid for finding the load delays. + bool driver_valid_; + // Load rspf elmore delay. + double elmore_; + double p3_; + + // Tolerance (as a scale of value) for driver parameters (Ceff, delta t, t0). + static constexpr double driver_param_tol_ = .01; + // Waveform threshold crossing time tolerance (1.0 = 100%). + static constexpr double vth_time_tol_ = .01; + // Max iterations for findRoot. + static constexpr int find_root_max_iter_ = 20; + static inline int newton_raphson_max_iter_ = 100; + // A small number used by luDecomp. + static constexpr double tiny_double_ = 1.0e-20; +}; + +// Capacitive load. +class DmpCap : public DmpAlg +{ +public: + DmpCap(StaState *sta); + std::string_view 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; + std::pair gateDelaySlew() override; + std::pair loadDelaySlew(const Pin *, + double elmore) override; + void evalDmpEqns() override; + +protected: + double voCrossingUpperBound() override; + std::pair V0(double t) override; + std::pair Vl0(double t) override; +}; + +// No non-zero pi model parameters, two poles, one zero +class DmpPi : public DmpAlg +{ +public: + DmpPi(StaState *sta); + std::string_view 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; + std::pair gateDelaySlew() override; + void evalDmpEqns() override; + +protected: + double voCrossingUpperBound() override; + std::pair V0(double t) override; + std::pair Vl0(double t) override; + +private: + void findDriverParamsPi(); + double ipiIceff(double t0, + double dt, + double ceff_time, + double ceff); + + // Poles/zero. + double p1_{0.0}; + double p2_{0.0}; + double z1_{0.0}; + // Residues. + double k0_{0.0}; + double k1_{0.0}; + double k2_{0.0}; + double k3_{0.0}; + double k4_{0.0}; + // Ipi coefficients. + double A_{0.0}; + double B_{0.0}; + double D_{0.0}; +}; + +// Capacitive load, so Ceff is known. +// Solve for t0, delta t. +class DmpOnePole : public DmpAlg +{ +public: + DmpOnePole(StaState *sta); + void evalDmpEqns() override; + +protected: + double voCrossingUpperBound() override; +}; + +// C2 = 0, one pole, one zero. +class DmpZeroC2 : public DmpOnePole +{ +public: + DmpZeroC2(StaState *sta); + std::string_view 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; + std::pair gateDelaySlew() override; + +protected: + std::pair V0(double t) override; + std::pair Vl0(double t) override; + double voCrossingUpperBound() override; + +private: + // Pole/zero. + double p1_{0.0}; + double z1_{0.0}; + // Residues. + double k0_{0.0}; + double k1_{0.0}; + double k2_{0.0}; + double k3_{0.0}; +}; + // Delay calculator using Dartu/Menezes/Pileggi effective capacitance // algorithm for RSPF loads. class DmpCeffDelayCalc : public LumpedCapDelayCalc { public: DmpCeffDelayCalc(StaState *sta); - ~DmpCeffDelayCalc() override; bool reduceSupported() const override { return true; } ArcDcalcResult gateDelay(const Pin *drvr_pin, const TimingArc *arc, @@ -94,10 +350,9 @@ protected: private: // Dmp algorithms for each special pi model case. - // These objects are reused to minimize make/deletes. - DmpCap *dmp_cap_; - DmpPi *dmp_pi_; - DmpZeroC2 *dmp_zero_c2_; + DmpCap dmp_cap_; + DmpPi dmp_pi_; + DmpZeroC2 dmp_zero_c2_; DmpAlg *dmp_alg_{nullptr}; }; diff --git a/dcalc/DmpDelayCalc.cc b/dcalc/DmpDelayCalc.cc index f94d2086..03fbe83e 100644 --- a/dcalc/DmpDelayCalc.cc +++ b/dcalc/DmpDelayCalc.cc @@ -77,7 +77,7 @@ DmpCeffElmoreDelayCalc::DmpCeffElmoreDelayCalc(StaState *sta) : ArcDelayCalc * DmpCeffElmoreDelayCalc::copy() { - return new DmpCeffElmoreDelayCalc(this); + return new DmpCeffElmoreDelayCalc(*this); } ArcDcalcResult @@ -213,7 +213,7 @@ DmpCeffTwoPoleDelayCalc::DmpCeffTwoPoleDelayCalc(StaState *sta) : ArcDelayCalc * DmpCeffTwoPoleDelayCalc::copy() { - return new DmpCeffTwoPoleDelayCalc(this); + return new DmpCeffTwoPoleDelayCalc(*this); } Parasitic *