diff --git a/BUILD b/BUILD index 6611edcf..bcae6ce4 100644 --- a/BUILD +++ b/BUILD @@ -120,7 +120,7 @@ tcl_srcs = [ "tcl/CmdArgs.tcl", "tcl/Property.tcl", "tcl/Sta.tcl", - "tcl/Variables.tcl", + "sdc/Variables.tcl", "tcl/Splash.tcl", "graph/Graph.tcl", "liberty/Liberty.tcl", @@ -147,7 +147,7 @@ exported_tcl = [ "tcl/Property.tcl", "tcl/Splash.tcl", "tcl/Sta.tcl", - "tcl/Variables.tcl", + "sdc/Variables.tcl", "sdc/Sdc.tcl", "sdf/Sdf.tcl", "search/Search.tcl", diff --git a/CMakeLists.txt b/CMakeLists.txt index a6eaddaf..f8ddda84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -257,7 +257,6 @@ set(STA_TCL_FILES tcl/Property.tcl tcl/Sta.tcl tcl/Splash.tcl - tcl/Variables.tcl dcalc/DelayCalc.tcl graph/Graph.tcl liberty/Liberty.tcl @@ -267,6 +266,7 @@ set(STA_TCL_FILES parasitics/Parasitics.tcl power/Power.tcl sdc/Sdc.tcl + sdc/Variables.tcl sdf/Sdf.tcl search/Search.tcl spice/WriteSpice.tcl diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc index 502a73eb..0fda825f 100644 --- a/dcalc/ArnoldiDelayCalc.cc +++ b/dcalc/ArnoldiDelayCalc.cc @@ -127,6 +127,7 @@ class ArnoldiDelayCalc : public LumpedCapDelayCalc { public: ArnoldiDelayCalc(StaState *sta); + ArnoldiDelayCalc(const ArnoldiDelayCalc &dcalc); ~ArnoldiDelayCalc() override; ArcDelayCalc *copy() override; std::string_view name() const override { return "arnoldi"; } @@ -262,10 +263,20 @@ ArnoldiDelayCalc::ArnoldiDelayCalc(StaState *sta) : _slewV = (double*)malloc(_pinNmax * sizeof(double)); } +ArnoldiDelayCalc::ArnoldiDelayCalc(const ArnoldiDelayCalc &dcalc) : + LumpedCapDelayCalc(dcalc), + reduce_(new ArnoldiReduce(this)), + delay_work_(delay_work_create()) +{ + _pinNmax = dcalc._pinNmax; + _delayV = (double*)malloc(_pinNmax * sizeof(double)); + _slewV = (double*)malloc(_pinNmax * sizeof(double)); +} + ArcDelayCalc * ArnoldiDelayCalc::copy() { - return new ArnoldiDelayCalc(this); + return new ArnoldiDelayCalc(*this); } ArnoldiDelayCalc::~ArnoldiDelayCalc() diff --git a/dcalc/CcsCeffDelayCalc.cc b/dcalc/CcsCeffDelayCalc.cc index 848ac227..9de98d81 100644 --- a/dcalc/CcsCeffDelayCalc.cc +++ b/dcalc/CcsCeffDelayCalc.cc @@ -60,12 +60,23 @@ CcsCeffDelayCalc::CcsCeffDelayCalc(StaState *sta) : { } -CcsCeffDelayCalc::~CcsCeffDelayCalc() { delete table_dcalc_; } +CcsCeffDelayCalc::CcsCeffDelayCalc(const CcsCeffDelayCalc &dcalc) : + LumpedCapDelayCalc(dcalc), + watch_pin_values_(dcalc.network_), + capacitance_unit_(dcalc.capacitance_unit_), + table_dcalc_(makeDmpCeffElmoreDelayCalc(this)) +{ +} + +CcsCeffDelayCalc::~CcsCeffDelayCalc() +{ + delete table_dcalc_; +} ArcDelayCalc * CcsCeffDelayCalc::copy() { - return new CcsCeffDelayCalc(this); + return new CcsCeffDelayCalc(*this); } ArcDcalcResult diff --git a/dcalc/CcsCeffDelayCalc.hh b/dcalc/CcsCeffDelayCalc.hh index 07a659b9..90f27561 100644 --- a/dcalc/CcsCeffDelayCalc.hh +++ b/dcalc/CcsCeffDelayCalc.hh @@ -39,6 +39,7 @@ class CcsCeffDelayCalc : public LumpedCapDelayCalc, { public: CcsCeffDelayCalc(StaState *sta); + CcsCeffDelayCalc(const CcsCeffDelayCalc &dcalc); ~CcsCeffDelayCalc() override; ArcDelayCalc *copy() override; std::string_view name() const override { return "ccs_ceff"; } 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 * diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 741353bf..3bf51343 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -292,6 +292,7 @@ class FindVertexDelays : public VertexVisitor { public: FindVertexDelays(GraphDelayCalc *graph_delay_calc1); + FindVertexDelays(const FindVertexDelays &find_vertex_delays); ~FindVertexDelays() override; void visit(Vertex *vertex) override; VertexVisitor *copy() const override; @@ -308,6 +309,11 @@ FindVertexDelays::FindVertexDelays(GraphDelayCalc *graph_delay_calc) : { } +FindVertexDelays::FindVertexDelays(const FindVertexDelays &find_vertex_delays) : + FindVertexDelays(find_vertex_delays.graph_delay_calc_) +{ +} + FindVertexDelays::~FindVertexDelays() { delete arc_delay_calc_; @@ -318,7 +324,7 @@ FindVertexDelays::copy() const { // Copy StaState::arc_delay_calc_ because it needs separate state // for each thread. - return new FindVertexDelays(graph_delay_calc_); + return new FindVertexDelays(*this); } void diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc index 41ef4250..3e8c989b 100644 --- a/dcalc/LumpedCapDelayCalc.cc +++ b/dcalc/LumpedCapDelayCalc.cc @@ -54,7 +54,7 @@ LumpedCapDelayCalc::LumpedCapDelayCalc(StaState *sta) : ArcDelayCalc * LumpedCapDelayCalc::copy() { - return new LumpedCapDelayCalc(this); + return new LumpedCapDelayCalc(*this); } Parasitic * diff --git a/dcalc/UnitDelayCalc.cc b/dcalc/UnitDelayCalc.cc index f376ec7b..8f3d9cc8 100644 --- a/dcalc/UnitDelayCalc.cc +++ b/dcalc/UnitDelayCalc.cc @@ -42,7 +42,7 @@ UnitDelayCalc::UnitDelayCalc(StaState *sta) : ArcDelayCalc * UnitDelayCalc::copy() { - return new UnitDelayCalc(this); + return new UnitDelayCalc(*this); } Parasitic * diff --git a/doc/ChangeLog.txt b/doc/ChangeLog.txt index b6238246..f4ab5751 100644 --- a/doc/ChangeLog.txt +++ b/doc/ChangeLog.txt @@ -4,6 +4,13 @@ OpenSTA Timing Analyzer Release Notes This file summarizes user visible changes for each release. See ApiChangeLog.txt for changes to the STA api. +2026/05/01 +---------- + +The write_sdc command supports a -mode argument. + + write_sdc [-mode mode] + 2026/03/23 ---------- diff --git a/include/sta/BoundedHeap.hh b/include/sta/BoundedHeap.hh index 6ae23ce0..eaebc9ef 100644 --- a/include/sta/BoundedHeap.hh +++ b/include/sta/BoundedHeap.hh @@ -63,7 +63,6 @@ public: { } - // Copy constructor BoundedHeap(const BoundedHeap& other) : heap_(other.heap_), max_size_(other.max_size_), diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index 233d363c..a3553048 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -327,7 +327,7 @@ protected: bool has_downstream_clk_pin_:1; bool visited1_:1; bool visited2_:1; - bool has_sim_value_; + bool has_sim_value_:1; private: friend class Graph; diff --git a/include/sta/Property.hh b/include/sta/Property.hh index adeee3cc..1bb1e149 100644 --- a/include/sta/Property.hh +++ b/include/sta/Property.hh @@ -199,9 +199,7 @@ public: PropertyValue(ClockSet *value); PropertyValue(ConstPathSeq *value); PropertyValue(PwrActivity *value); - // Copy constructor. PropertyValue(const PropertyValue &value); - // Move constructor. PropertyValue(PropertyValue &&value) noexcept; ~PropertyValue(); Type type() const { return type_; } diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 58506e1f..841dbe6b 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -738,15 +738,15 @@ protected: Vertex *to_vertex); // Return false to stop visiting. [[nodiscard]] bool visitArc(const Pin *from_pin, - Vertex *from_vertex, - const RiseFall *from_rf, - Path *from_path, - Edge *edge, - TimingArc *arc, - const Pin *to_pin, - Vertex *to_vertex, - const MinMax *min_max, - const Mode *mode); + Vertex *from_vertex, + const RiseFall *from_rf, + Path *from_path, + Edge *edge, + TimingArc *arc, + const Pin *to_pin, + Vertex *to_vertex, + const MinMax *min_max, + const Mode *mode); // This calls visit below with everything required to make to_path. // Return false to stop visiting. virtual bool visitFromPath(const Pin *from_pin, @@ -770,6 +770,7 @@ class ArrivalVisitor : public PathVisitor { public: ArrivalVisitor(const StaState *sta); + ArrivalVisitor(const ArrivalVisitor &arrival_visitor); ~ArrivalVisitor() override; // Initialize the visitor. void init(bool always_to_endpoints, @@ -797,9 +798,6 @@ public: TagGroupBldr *tagBldr() const { return tag_bldr_; } protected: - ArrivalVisitor(bool always_to_endpoints, - SearchPred *pred, - const StaState *sta); void init0(); void enqueueRefPinInputDelays(const Pin *ref_pin, const Sdc *sdc); @@ -842,6 +840,7 @@ class RequiredVisitor : public PathVisitor { public: RequiredVisitor(const StaState *sta); + RequiredVisitor(const RequiredVisitor &required_visitor); ~RequiredVisitor() override; VertexVisitor *copy() const override; void visit(Vertex *vertex) override; @@ -862,10 +861,7 @@ public: const MinMax *min_max) override; protected: - RequiredVisitor(bool make_tag_cache, - const StaState *sta); - - RequiredCmp *required_cmp_; + RequiredCmp required_cmp_; VisitPathEnds *visit_path_ends_; }; diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 36bfa0d7..561ce3aa 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -138,7 +138,7 @@ public: void setCmdScene(Scene *scene); SceneSeq makeSceneSeq(Scene *scene) const; - Mode *cmdMode() const { return cmd_scene_->mode(); } + Mode *cmdMode() const { return cmd_mode_; } const std::string &cmdModeName(); void setCmdMode(std::string_view mode_name); Mode *findMode(std::string_view mode_name) const; @@ -1042,6 +1042,13 @@ public: const Scene *scene, const MinMax *min_max, int digits); + void writeSdc(std::string_view filename, + std::string_view mode_name, + bool leaf, + bool native, + int digits, + bool gzip, + bool no_timestamp); void writeSdc(const Sdc *sdc, std::string_view filename, // Map hierarchical pins and instances to leaf pins and instances. @@ -1610,6 +1617,7 @@ protected: void checkLibrarayPocv(); Scene *cmd_scene_{nullptr}; + Mode *cmd_mode_{nullptr}; CmdNamespace cmd_namespace_{CmdNamespace::sdc}; Instance *current_instance_{nullptr}; SceneNameMap scene_name_map_; diff --git a/power/Power.cc b/power/Power.cc index f5333f62..c5075522 100644 --- a/power/Power.cc +++ b/power/Power.cc @@ -575,6 +575,7 @@ public: PropActivityVisitor(Power *power, const Mode *mode, BfsFwdIterator *bfs); + PropActivityVisitor(const PropActivityVisitor &visitor); VertexVisitor *copy() const override; void visit(Vertex *vertex) override; InstanceSet &visitedRegs() { return visited_regs_; } @@ -606,10 +607,15 @@ PropActivityVisitor::PropActivityVisitor(Power *power, { } +PropActivityVisitor::PropActivityVisitor(const PropActivityVisitor &visitor) : + PropActivityVisitor(visitor.power_, visitor.mode_, visitor.bfs_) +{ +} + VertexVisitor * PropActivityVisitor::copy() const { - return new PropActivityVisitor(power_, mode_, bfs_); + return new PropActivityVisitor(*this); } void diff --git a/sdc/Sdc.i b/sdc/Sdc.i index 0a02cb07..4b3050b0 100644 --- a/sdc/Sdc.i +++ b/sdc/Sdc.i @@ -94,15 +94,15 @@ private: void write_sdc_cmd(std::string filename, - bool leaf, - bool compatible, - int digits, - bool gzip, - bool no_timestamp) + std::string mode_name, + bool leaf, + bool compatible, + int digits, + bool gzip, + bool no_timestamp) { Sta *sta = Sta::sta(); - const Sdc *sdc = sta->cmdSdc(); - sta->writeSdc(sdc, filename, leaf, compatible, digits, gzip, no_timestamp); + sta->writeSdc(filename, mode_name, leaf, compatible, digits, gzip, no_timestamp); } void diff --git a/sdc/Sdc.tcl b/sdc/Sdc.tcl index d8e5aef1..5588c8f1 100644 --- a/sdc/Sdc.tcl +++ b/sdc/Sdc.tcl @@ -42,31 +42,38 @@ proc_redirect read_sdc { check_argc_eq1 "read_sdc" $args set echo [info exists flags(-echo)] set filename [file nativename [lindex $args 0]] - set mode_name {} + if { [info exists keys(-mode)] } { set mode_name $keys(-mode) - } - set prev_mode [cmd_mode_name] - try { - set_mode_cmd $mode_name - include_file $filename $echo 0 - } finally { - if { $prev_mode != "default" } { - set_mode_cmd $prev_mode + set prev_mode [cmd_mode] + try { + set_cmd_mode $mode_name + include_file $filename $echo 0 + } finally { + if { $prev_mode != "default" } { + set_cmd_mode $prev_mode + } } + } else { + include_file $filename $echo 0 } } ################################################################ define_cmd_args "write_sdc" \ - {[-map_hpins] [-digits digits] [-gzip] [-no_timestamp] filename} + {[-mode mode] [-map_hpins] [-digits digits] [-gzip] [-no_timestamp] filename} proc write_sdc { args } { - parse_key_args "write_sdc" args keys {-digits -significant_digits} \ + parse_key_args "write_sdc" args keys {-mode -digits} \ flags {-map_hpins -compatible -gzip -no_timestamp} check_argc_eq1 "write_sdc" $args + set mode [cmd_mode] + if { [info exists keys(-mode)] } { + set mode $keys(-mode) + } + set digits 4 if { [info exists keys(-digits)] } { set digits $keys(-digits) @@ -78,7 +85,7 @@ proc write_sdc { args } { set no_timestamp [info exists flags(-no_timestamp)] set map_hpins [info exists flags(-map_hpins)] set native [expr ![info exists flags(-compatible)]] - write_sdc_cmd $filename $map_hpins $native $digits $gzip $no_timestamp + write_sdc_cmd $filename $mode $map_hpins $native $digits $gzip $no_timestamp } ################################################################ diff --git a/tcl/Variables.tcl b/sdc/Variables.tcl similarity index 100% rename from tcl/Variables.tcl rename to sdc/Variables.tcl diff --git a/sdf/Sdf.tcl b/sdf/Sdf.tcl index df0a775c..bdbb1de8 100644 --- a/sdf/Sdf.tcl +++ b/sdf/Sdf.tcl @@ -180,7 +180,7 @@ define_cmd_args "write_sdf" \ proc_redirect write_sdf { parse_key_args "write_sdf" args \ - keys {-corner -scene -divider -digits -significant_digits} \ + keys {-corner -scene -divider -digits} \ flags {-include_typ -gzip -no_timestamp -no_version} check_argc_eq1 "write_sdf" $args set scene [parse_scene keys] diff --git a/search/GatedClk.cc b/search/GatedClk.cc index 11880d02..ad79dbdb 100644 --- a/search/GatedClk.cc +++ b/search/GatedClk.cc @@ -107,7 +107,6 @@ GatedClk::isGatedClkEnable(Vertex *enable_vertex, } } } - } } diff --git a/search/Genclks.cc b/search/Genclks.cc index 2123ea1b..851a601a 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -693,17 +693,11 @@ public: BfsFwdIterator *insert_iter, GenclkInfo *genclk_info, const Mode *mode); + GenclkSrcArrivalVisitor(const GenclkSrcArrivalVisitor &visitor); VertexVisitor *copy() const override; void visit(Vertex *vertex) override; protected: - GenclkSrcArrivalVisitor(Clock *gclk, - BfsFwdIterator *insert_iter, - GenclkInfo *genclk_info, - bool always_to_endpoints, - SearchPred *pred, - const Mode *mode); - Clock *gclk_; BfsFwdIterator *insert_iter_; GenclkInfo *genclk_info_; @@ -728,29 +722,22 @@ GenclkSrcArrivalVisitor::GenclkSrcArrivalVisitor(Clock *gclk, { } -// Copy constructor. -GenclkSrcArrivalVisitor::GenclkSrcArrivalVisitor(Clock *gclk, - BfsFwdIterator *insert_iter, - GenclkInfo *genclk_info, - bool always_to_endpoints, - SearchPred *pred, - const Mode *mode) : - ArrivalVisitor(always_to_endpoints, pred, this), - gclk_(gclk), - insert_iter_(insert_iter), - genclk_info_(genclk_info), - srch_pred_(gclk, genclk_info, this), - mode_(mode), - sdc_(mode->sdc()), - genclks_(mode->genclks()) +GenclkSrcArrivalVisitor::GenclkSrcArrivalVisitor(const GenclkSrcArrivalVisitor &visitor) : + ArrivalVisitor(visitor), + gclk_(visitor.gclk_), + insert_iter_(visitor.insert_iter_), + genclk_info_(visitor.genclk_info_), + srch_pred_(visitor.gclk_, visitor.genclk_info_, this), + mode_(visitor.mode_), + sdc_(visitor.sdc_), + genclks_(visitor.genclks_) { } VertexVisitor * GenclkSrcArrivalVisitor::copy() const { - return new GenclkSrcArrivalVisitor(gclk_, insert_iter_, genclk_info_, - always_to_endpoints_, pred_, mode_); + return new GenclkSrcArrivalVisitor(*this); } void diff --git a/search/PathEnum.cc b/search/PathEnum.cc index c285b8f9..7c65f26e 100644 --- a/search/PathEnum.cc +++ b/search/PathEnum.cc @@ -246,6 +246,7 @@ public: bool unique_pins, bool unique_edges, PathEnum *path_enum); + PathEnumFaninVisitor(const PathEnumFaninVisitor &visitor); VertexVisitor *copy() const override; void visitFaninPathsThru(Path *before_div, Vertex *prev_vertex, @@ -327,11 +328,16 @@ PathEnumFaninVisitor::PathEnumFaninVisitor(PathEnd *path_end, { } +PathEnumFaninVisitor::PathEnumFaninVisitor(const PathEnumFaninVisitor &visitor) : + PathEnumFaninVisitor(visitor.path_end_, visitor.before_div_, visitor.unique_pins_, + visitor.unique_edges_, visitor.path_enum_) +{ +} + VertexVisitor * PathEnumFaninVisitor::copy() const { - return new PathEnumFaninVisitor(path_end_, before_div_, unique_pins_, - unique_edges_, path_enum_); + return new PathEnumFaninVisitor(*this); } void diff --git a/search/PathGroup.cc b/search/PathGroup.cc index 6750613c..725b52c7 100644 --- a/search/PathGroup.cc +++ b/search/PathGroup.cc @@ -995,7 +995,7 @@ MakeEndpointPathEnds::~MakeEndpointPathEnds() VertexVisitor * MakeEndpointPathEnds::copy() const { - return new MakeEndpointPathEnds(path_end_visitor_, scenes_, min_max_, sta_); + return new MakeEndpointPathEnds(*this); } void diff --git a/search/Search.cc b/search/Search.cc index 081daac8..ee735a0c 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -1090,14 +1090,11 @@ ArrivalVisitor::ArrivalVisitor(const StaState *sta) : init(true, false, nullptr); } -// Copy constructor. -ArrivalVisitor::ArrivalVisitor(bool always_to_endpoints, - SearchPred *pred, - const StaState *sta) : - PathVisitor(pred, true, sta) +ArrivalVisitor::ArrivalVisitor(const ArrivalVisitor &arrival_visitor) : + PathVisitor(arrival_visitor.pred_, true, &arrival_visitor) { init0(); - init(always_to_endpoints, false, pred); + init(arrival_visitor.always_to_endpoints_, false, arrival_visitor.pred_); } void @@ -1122,7 +1119,7 @@ ArrivalVisitor::init(bool always_to_endpoints, VertexVisitor * ArrivalVisitor::copy() const { - return new ArrivalVisitor(always_to_endpoints_, pred_, this); + return new ArrivalVisitor(*this); } void @@ -1966,7 +1963,10 @@ PathVisitor::PathVisitor(SearchPred *pred, { } -PathVisitor::~PathVisitor() { delete tag_cache_; } +PathVisitor::~PathVisitor() +{ + delete tag_cache_; +} void PathVisitor::visitFaninPaths(Vertex *to_vertex) @@ -2775,23 +2775,19 @@ Search::reportArrivals(Vertex *vertex, bool report_prev = false; std::string prev_str; if (report_prev) { - prev_str = "prev "; Path *prev_path = path->prevPath(); if (prev_path) { - prev_str += prev_path->to_string(this); - prev_str += " "; const Edge *prev_edge = path->prevEdge(this); TimingArc *arc = path->prevArc(this); - prev_str += prev_edge->from(graph_)->to_string(this); - prev_str += " "; - prev_str += arc->fromEdge()->to_string(); - prev_str += " -> "; - prev_str += prev_edge->to(graph_)->to_string(this); - prev_str += " "; - prev_str += arc->toEdge()->to_string(); + prev_str = sta::format("prev {} {} {} -> {} {}", + prev_path->to_string(this), + prev_edge->from(graph_)->to_string(this), + arc->fromEdge()->to_string(), + prev_edge->to(graph_)->to_string(this), + arc->toEdge()->to_string()); } else - prev_str += "NULL"; + prev_str = "prev NULL"; } report_->report(" {} {} {} / {} {}{}", rf->shortName(), path->minMax(this)->to_string(), @@ -3297,44 +3293,28 @@ Search::seedInvalidRequireds() class FindEndRequiredVisitor : public PathEndVisitor { public: - FindEndRequiredVisitor(RequiredCmp *required_cmp, + FindEndRequiredVisitor(RequiredCmp &required_cmp, const StaState *sta); FindEndRequiredVisitor(const StaState *sta); - ~FindEndRequiredVisitor() override; PathEndVisitor *copy() const override; void visit(PathEnd *path_end) override; protected: const StaState *sta_; - RequiredCmp *required_cmp_; - bool own_required_cmp_; + RequiredCmp &required_cmp_; }; -FindEndRequiredVisitor::FindEndRequiredVisitor(RequiredCmp *required_cmp, +FindEndRequiredVisitor::FindEndRequiredVisitor(RequiredCmp &required_cmp, const StaState *sta) : sta_(sta), - required_cmp_(required_cmp), - own_required_cmp_(false) + required_cmp_(required_cmp) { } -FindEndRequiredVisitor::FindEndRequiredVisitor(const StaState *sta) : - sta_(sta), - required_cmp_(new RequiredCmp), - own_required_cmp_(true) -{ -} - -FindEndRequiredVisitor::~FindEndRequiredVisitor() -{ - if (own_required_cmp_) - delete required_cmp_; -} - PathEndVisitor * FindEndRequiredVisitor::copy() const { - return new FindEndRequiredVisitor(sta_); + return new FindEndRequiredVisitor(*this); } void @@ -3345,7 +3325,7 @@ FindEndRequiredVisitor::visit(PathEnd *path_end) const MinMax *min_max = path->minMax(sta_)->opposite(); size_t path_index = path->pathIndex(sta_); Required required = path_end->requiredTime(sta_); - required_cmp_->requiredSet(path_index, required, min_max, sta_); + required_cmp_.requiredSet(path_index, required, min_max, sta_); } } @@ -3355,7 +3335,7 @@ Search::seedRequired(Vertex *vertex) debugPrint(debug_, "search", 2, "required seed {}", vertex->to_string(this)); RequiredCmp required_cmp; - FindEndRequiredVisitor seeder(&required_cmp, this); + FindEndRequiredVisitor seeder(required_cmp, this); required_cmp.requiredsInit(vertex, this); visit_path_ends_->visitPathEnds(vertex, &seeder); // Enqueue fanin vertices for back-propagating required times. @@ -3367,7 +3347,7 @@ void Search::seedRequiredEnqueueFanin(Vertex *vertex) { RequiredCmp required_cmp; - FindEndRequiredVisitor seeder(&required_cmp, this); + FindEndRequiredVisitor seeder(required_cmp, this); required_cmp.requiredsInit(vertex, this); visit_path_ends_->visitPathEnds(vertex, &seeder); // Enqueue fanin vertices for back-propagating required times. @@ -3442,31 +3422,25 @@ RequiredCmp::required(size_t path_index) RequiredVisitor::RequiredVisitor(const StaState *sta) : PathVisitor(sta), - required_cmp_(new RequiredCmp), visit_path_ends_(new VisitPathEnds(sta)) { } -RequiredVisitor::RequiredVisitor(bool make_tag_cache, - const StaState *sta) : - PathVisitor(sta->search()->evalPred(), - make_tag_cache, - sta), - required_cmp_(new RequiredCmp), - visit_path_ends_(new VisitPathEnds(sta)) +RequiredVisitor::RequiredVisitor(const RequiredVisitor &required_visitor) : + PathVisitor(required_visitor.search()->evalPred(), true, &required_visitor), + visit_path_ends_(new VisitPathEnds(&required_visitor)) { } RequiredVisitor::~RequiredVisitor() { - delete required_cmp_; delete visit_path_ends_; } VertexVisitor * RequiredVisitor::copy() const { - return new RequiredVisitor(true, this); + return new RequiredVisitor(*this); } void @@ -3474,7 +3448,7 @@ RequiredVisitor::visit(Vertex *vertex) { debugPrint(debug_, "search", 2, "find required {}", vertex->to_string(this)); - required_cmp_->requiredsInit(vertex, this); + required_cmp_.requiredsInit(vertex, this); // Back propagate requireds from fanout. visitFanoutPaths(vertex); // Check for constraints at endpoints that set required times. @@ -3482,7 +3456,7 @@ RequiredVisitor::visit(Vertex *vertex) FindEndRequiredVisitor seeder(required_cmp_, this); visit_path_ends_->visitPathEnds(vertex, &seeder); } - bool changed = required_cmp_->requiredsSave(vertex, this); + bool changed = required_cmp_.requiredsSave(vertex, this); search_->tnsInvalid(vertex); if (changed) @@ -3528,8 +3502,8 @@ RequiredVisitor::visitFromToPath(const Pin *, delayAsString(arc_delay, this), delayAsString(from_required, this), min_max == MinMax::max() ? "<" : ">", - delayAsString(required_cmp_->required(path_index), this)); - required_cmp_->requiredSet(path_index, from_required, req_min, this); + delayAsString(required_cmp_.required(path_index), this)); + required_cmp_.requiredSet(path_index, from_required, req_min, this); } else { if (search_->crprApproxMissingRequireds()) { @@ -3552,8 +3526,8 @@ RequiredVisitor::visitFromToPath(const Pin *, delayAsString(arc_delay, this), delayAsString(from_required, this), min_max == MinMax::max() ? "<" : ">", - delayAsString(required_cmp_->required(path_index), this)); - required_cmp_->requiredSet(path_index, from_required, req_min, this); + delayAsString(required_cmp_.required(path_index), this)); + required_cmp_.requiredSet(path_index, from_required, req_min, this); break; } } diff --git a/search/Search.i b/search/Search.i index 3a6f1b31..62b48564 100644 --- a/search/Search.i +++ b/search/Search.i @@ -113,6 +113,7 @@ void clear_network() { Sta *sta = Sta::sta(); + sta->clear(); sta->network()->clear(); } @@ -818,8 +819,14 @@ cmd_mode_name() return Sta::sta()->cmdMode()->name(); } +Mode * +cmd_mode() +{ + return Sta::sta()->cmdMode(); +} + void -set_mode_cmd(std::string mode_name) +set_cmd_mode(std::string mode_name) { Sta::sta()->setCmdMode(mode_name); } @@ -830,6 +837,12 @@ find_modes(std::string mode_name) return Sta::sta()->findModes(mode_name); } +Mode * +find_mode(std::string mode_name) +{ + return Sta::sta()->findMode(mode_name); +} + //////////////////////////////////////////////////////////////// CheckErrorSeq & diff --git a/search/Sta.cc b/search/Sta.cc index 4c29e355..990ecc9a 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -570,30 +570,46 @@ Sta::clearNonSdc() Sdc * Sta::cmdSdc() const { - return cmdMode()->sdc(); + return cmd_mode_->sdc(); } void Sta::setCmdMode(std::string_view mode_name) { - if (!mode_name.empty()) { - if (!mode_name_map_.contains(mode_name)) { - if (modes_.size() == 1 && modes_[0]->name() == "default") { - // No need for default mode if one is defined. - delete modes_[0]; - mode_name_map_.clear(); - modes_.clear(); + Mode *mode = findKey(mode_name_map_, std::string(mode_name)); + if (mode) { + // Sync scene with mode. Note that multiple scenes can share a mode. + Scene *mode_scene = nullptr; + for (Scene *scene : scenes_) { + if (scene->mode() == mode) { + if (mode_scene) { + report_->warn(1556, "multiple scenes reference mode {}", mode_name); + break; + } + mode_scene = scene; } - Mode *mode = new Mode(mode_name, mode_name_map_.size(), this); - mode_name_map_[std::string(mode_name)] = mode; - modes_.push_back(mode); - mode->sim()->setMode(mode); - mode->sim()->setObserver(new StaSimObserver(this)); - - if (scenes_.size() == 1 && scenes_[0]->name() == "default") - scenes_[0]->setMode(mode); - updateComponentsState(); } + if (mode_scene) + cmd_scene_ = mode_scene; + cmd_mode_ = mode; + } + else { + if (modes_.size() == 1 && modes_[0]->name() == "default") { + // No need for default mode if one is defined. + delete modes_[0]; + mode_name_map_.clear(); + modes_.clear(); + } + Mode *mode = new Mode(mode_name, mode_name_map_.size(), this); + mode_name_map_[std::string(mode_name)] = mode; + modes_.push_back(mode); + mode->sim()->setMode(mode); + mode->sim()->setObserver(new StaSimObserver(this)); + cmd_mode_ = mode; + + if (scenes_.size() == 1 && scenes_[0]->name() == "default") + scenes_[0]->setMode(mode); + updateComponentsState(); } } @@ -2190,6 +2206,22 @@ Sta::checkExceptionToPins(ExceptionTo *to, } } +void +Sta::writeSdc(std::string_view filename, + std::string_view mode_name, + bool leaf, + bool native, + int digits, + bool gzip, + bool no_timestamp) +{ + Mode *mode = findMode(mode_name); + if (mode) + writeSdc(mode->sdc(), filename, leaf, native, digits, gzip, no_timestamp); + else + report_->warn(1561, "mode {} not found.", mode_name); +} + void Sta::writeSdc(const Sdc *sdc, std::string_view filename, @@ -2514,6 +2546,7 @@ Sta::makeDefaultScene() makeScene(name, mode, parasitics); cmd_scene_ = scenes_[0]; + cmd_mode_ = mode; } // define_corners (before read_liberty). @@ -2603,8 +2636,8 @@ Sta::makeScene(const std::string &name, if (scenes_.size() == 1 && findScene("default")) deleteScenes(); - Scene *scene = - new Scene(name, scenes_.size(), mode, parasitics_min, parasitics_max); + Scene *scene = new Scene(name, scenes_.size(), mode, + parasitics_min, parasitics_max); scene_name_map_[name] = scene; scenes_.push_back(scene); mode->addScene(scene); @@ -2696,6 +2729,7 @@ void Sta::setCmdScene(Scene *scene) { cmd_scene_ = scene; + cmd_mode_ = scene->mode(); } SceneSeq @@ -3270,7 +3304,7 @@ EndpointPathEndVisitor::EndpointPathEndVisitor(std::string_view path_group_name, PathEndVisitor * EndpointPathEndVisitor::copy() const { - return new EndpointPathEndVisitor(path_group_name_, min_max_, sta_); + return new EndpointPathEndVisitor(*this); } void @@ -3523,7 +3557,7 @@ Sta::findRequired(Vertex *vertex) search_->findAllArrivals(); if (search_->isEndpoint(vertex) // Need to include downstream required times if there is fanout. - && !hasFanout(vertex, search_->searchAdj(), graph_, cmdMode())) + && !hasFanout(vertex, search_->searchAdj(), graph_, cmd_mode_)) search_->seedRequired(vertex); else search_->findRequireds(vertex->level()); @@ -3921,14 +3955,14 @@ Sta::findLogicConstants() { ensureGraph(); // Sdc independent constants so any mode should return the same values. - Sim *sim = cmdMode()->sim(); + Sim *sim = cmd_mode_->sim(); sim->findLogicConstants(); } void Sta::clearLogicConstants() { - Sim *sim = cmdMode()->sim(); + Sim *sim = cmd_mode_->sim(); sim->clear(); } @@ -5062,7 +5096,8 @@ Sta::clockDomains(const Pin *pin, const Mode *mode) { searchPreamble(); - search_->findAllArrivals(); + Vertex *vertex = graph_->pinLoadVertex(pin); + search_->findArrivals(vertex->level()); return search_->clockDomains(pin, mode); } diff --git a/tcl/CmdUtil.tcl b/tcl/CmdUtil.tcl index 74fda26f..80d9b3e0 100644 --- a/tcl/CmdUtil.tcl +++ b/tcl/CmdUtil.tcl @@ -191,53 +191,55 @@ proc set_unit_values { unit key suffix key_var } { ################################################################ -define_cmd_args "delete_from_list" {list objs} +define_cmd_args "delete_from_list" {list delete} -proc delete_from_list { list objects } { - delete_objects_from_list_cmd $list $objects +proc delete_from_list { list delete } { + delete_objects_from_list_cmd $list $delete } -proc delete_objects_from_list_cmd { list objects } { - set list0 [lindex $list 0] - set list_is_object [is_object $list0] - set list_type [object_type $list0] - foreach obj $objects { - # If the list is a collection of tcl objects (returned by get_*), - # convert the obj to be removed from a name to an object of the same - # type. - if {$list_is_object && ![is_object $obj]} { - if {$list_type == "Clock"} { - set obj [find_clock $obj] - } elseif {$list_type == "Port"} { - set top_instance [top_instance] - set top_cell [$top_instance cell] - set obj [$top_cell find_port $obj] - } elseif {$list_type == "Pin"} { - set obj [find_pin $obj] - } elseif {$list_type == "Instance"} { - set obj [find_instance $obj] - } elseif {$list_type == "Net"} { - set obj [find_net $obj] - } elseif {$list_type == "LibertyLibrary"} { - set obj [find_liberty $obj] - } elseif {$list_type == "LibertyCell"} { - set obj [find_liberty_cell $obj] - } elseif {$list_type == "LibertyPort"} { - set obj [get_lib_pins $obj] - } else { - sta_error 164 "unsupported object type $list_type." +proc delete_objects_from_list_cmd { list delete } { + if { $list != {} } { + set list0 [lindex $list 0] + set list_is_objects [is_object $list0] + foreach obj $delete { + # If the list is a collection of tcl objects (returned by get_*), + # convert the obj to be removed from a name to an object of the same + # type. + if {$list_is_objects && ![is_object $obj]} { + set list_type [object_type $list0] + if {$list_type == "Clock"} { + set obj [find_clock $obj] + } elseif {$list_type == "Port"} { + set top_instance [top_instance] + set top_cell [$top_instance cell] + set obj [$top_cell find_port $obj] + } elseif {$list_type == "Pin"} { + set obj [find_pin $obj] + } elseif {$list_type == "Instance"} { + set obj [find_instance $obj] + } elseif {$list_type == "Net"} { + set obj [find_net $obj] + } elseif {$list_type == "LibertyLibrary"} { + set obj [find_liberty $obj] + } elseif {$list_type == "LibertyCell"} { + set obj [find_liberty_cell $obj] + } elseif {$list_type == "LibertyPort"} { + set obj [get_lib_pins $obj] + } else { + sta_error 164 "unsupported object type $list_type." + } + } + set index [lsearch $list $obj] + if { $index != -1 } { + set list [lreplace $list $index $index] } - } - set index [lsearch $list $obj] - if { $index != -1 } { - set list [lreplace $list $index $index] } } return $list } - + ################################################################ - + proc set_cmd_namespace { namespc } { if { $namespc == "sdc" || $namespc == "sta" } { set_cmd_namespace_cmd $namespc @@ -245,7 +247,7 @@ proc set_cmd_namespace { namespc } { sta_error 165 "unknown namespace $namespc." } } - + ################################################################ define_cmd_args "report_object_full_names" {objects} @@ -295,32 +297,5 @@ proc full_name_cmp { obj1 obj2 } { return [string compare [get_full_name $obj1] [get_full_name $obj2]] } -proc get_object_type { obj } { - set object_type [object_type $obj] - if { $object_type == "Clock" } { - return "clock" - } elseif { $object_type == "LibertyCell" } { - return "lib_cell" - } elseif { $object_type == "LibertyPort" } { - return "lib_pin" - } elseif { $object_type == "Cell" } { - return "cell" - } elseif { $object_type == "Instance" } { - return "instance" - } elseif { $object_type == "Port" } { - return "port" - } elseif { $object_type == "Pin" } { - return "pin" - } elseif { $object_type == "Net" } { - return "net" - } elseif { $object_type == "Edge" } { - return "timing_arc" - } elseif { $object_type == "TimingArcSet" } { - return "timing_arc" - } else { - return "?" - } -} - -# sta namespace end. +# namespace sta } diff --git a/tcl/Sta.tcl b/tcl/Sta.tcl index 2db64f5e..ee560962 100644 --- a/tcl/Sta.tcl +++ b/tcl/Sta.tcl @@ -102,7 +102,7 @@ define_cmd_args "set_scene" {scene_name} proc set_scene { args } { check_argc_eq1 "set_scene" $args - set_scene_cmd [lindex $args 0] + set_cmd_scene [lindex $args 0] } ################################################################ @@ -141,7 +141,7 @@ define_cmd_args "set_mode" {mode_name} proc set_mode { args } { check_argc_eq1 "set_mode" $args - set_mode_cmd [lindex $args 0] + set_cmd_mode [lindex $args 0] } ################################################################ diff --git a/tcl/StaTclTypes.i b/tcl/StaTclTypes.i index 65a6b0f3..b002cb42 100644 --- a/tcl/StaTclTypes.i +++ b/tcl/StaTclTypes.i @@ -30,6 +30,9 @@ %{ +#include +#include + #include "Network.hh" #include "Liberty.hh" #include "FuncExpr.hh" @@ -52,7 +55,7 @@ namespace sta { typedef MinMaxAll MinMaxAllNull; #if TCL_MAJOR_VERSION < 9 - typedef int Tcl_Size; +typedef int Tcl_Size; #endif template @@ -256,14 +259,51 @@ setPtrTclList(SET_TYPE *set, Tcl_SetObjResult(interp, list); } -//////////////////////////////////////////////////////////////// - } // namespace sta using namespace sta; %} +//////////////////////////////////////////////////////////////// + +%inline %{ + +inline bool +is_object(const char *obj) +{ + // _hexaddress_p_type + const std::string s(obj); + if (s.empty() || s[0] != '_') + return false; + const size_t hex_digits = sizeof(void *) * 2; + if (s.size() < 1 + hex_digits + 3) + return false; + for (size_t i = 1; i < 1 + hex_digits; i++) { + if (!std::isxdigit(static_cast(s[i]))) + return false; + } + if (s.compare(1 + hex_digits, 3, "_p_") != 0) + return false; + for (size_t i = 1 + hex_digits + 3; i < s.size(); i++) { + char ch = s[i]; + if (!(std::isalnum(ch) || ch == '_')) + return false; + } + return true; +} + +// Assumes is_object is true. +inline const char * +object_type(const char *obj) +{ + if (is_object(obj)) + return &obj[1 + sizeof(void*) * 2 + 3]; + return ""; +} + +%} + //////////////////////////////////////////////////////////////// // // SWIG type definitions. diff --git a/test/regression.tcl b/test/regression.tcl index 3afe8287..523589be 100755 --- a/test/regression.tcl +++ b/test/regression.tcl @@ -156,11 +156,8 @@ proc expand_tests { argv } { lappend tests $test } } - } elseif { [lsearch [group_tests "all"] $arg] != -1 } { - lappend tests $arg } else { - puts "Error: test $arg not found." - incr errors(no_cmd) + lappend tests $arg } } return $tests @@ -525,15 +522,11 @@ proc show_summary {} { if { $valgrind_shared_lib_failure } { puts "WARNING: valgrind failed because the executable is not statically linked." } - puts "See $result_dir for log files" set test_count [llength $tests] if { [found_errors] } { if { $errors(error) != 0 } { puts "Errored $errors(error)/$test_count" } - if { $errors(fail) != 0 } { - puts "Failed $errors(fail)/$test_count" - } if { $errors(leak) != 0 } { puts "Memory leaks in $errors(leak)/$test_count" } @@ -547,7 +540,7 @@ proc show_summary {} { puts "No cmd tcl file for $errors(no_cmd)/$test_count" } if { $errors(fail) != 0 } { - puts "See $diff_file for differences" + puts "Failed $errors(fail)/$test_count" } } else { puts "Passed $test_count" diff --git a/util/Util.i b/util/Util.i index cb08647a..ce128f5e 100644 --- a/util/Util.i +++ b/util/Util.i @@ -224,37 +224,6 @@ set_debug(const char *what, Sta::sta()->setDebugLevel(what, level); } -//////////////////////////////////////////////////////////////// - -bool -is_object(const char *obj) -{ - // _hexaddress_p_type - const char *s = obj; - char ch = *s++; - if (ch != '_') - return false; - while (*s && isxdigit(*s)) - s++; - if ((s - obj - 1) == sizeof(void*) * 2 - && *s && *s++ == '_' - && *s && *s++ == 'p' - && *s && *s++ == '_') { - while (*s && *s != ' ') - s++; - return *s == '\0'; - } - else - return false; -} - -// Assumes is_object is true. -const char * -object_type(const char *obj) -{ - return &obj[1 + sizeof(void*) * 2 + 3]; -} - //////////////////////////////////////////////////////////////// // // Units diff --git a/verilog/VerilogWriter.cc b/verilog/VerilogWriter.cc index 4f5e5fc6..c5d3fe7a 100644 --- a/verilog/VerilogWriter.cc +++ b/verilog/VerilogWriter.cc @@ -447,12 +447,13 @@ VerilogWriter::writeAssigns(const Instance *inst) if (term) { Net *net = network_->net(term); Port *port = network_->port(pin); - if (port + if (net + && port && (include_pwr_gnd_ || !(network_->isPower(net) || network_->isGround(net))) && (network_->direction(port)->isAnyOutput() || (include_pwr_gnd_ && network_->direction(port)->isPowerGround())) - && !stringEqual(network_->name(port), network_->name(net))) { + && network_->name(port) != network_->name(net)) { // Port name is different from net name. std::string port_vname = netVerilogName(std::string(network_->name(port))); std::string net_vname = netVerilogName(std::string(network_->name(net)));