Merge remote-tracking branch 'parallax_sta/master' into sta_update_latest_0505

This commit is contained in:
dsengupta0628 2026-05-06 13:37:38 +00:00
commit ac7dfe5fc2
28 changed files with 492 additions and 548 deletions

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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"; }

View File

@ -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<double, double> gateDelaySlew() = 0;
virtual std::pair<double, double> 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<double, double> Vo(double t);
// Load response to driver waveform (vl, dvl/dt).
std::pair<double, double> Vl(double t);
protected:
void luDecomp();
void luSolve();
void newtonRaphson();
// Find driver parameters t0, delta_t, Ceff.
void findDriverParams(double ceff);
std::pair<double, double> gateCapDelaySlew(double ceff);
std::tuple<double, double, double> gateDelays(double ceff);
// Partial derivatives of y(t) jacobian (dydt0, dyddt, dydcl).
std::tuple<double, double, double> 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<double, double> 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<double, double> 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<double, double> 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<double, double> 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<double, max_nr_order_> x_;
std::array<double, max_nr_order_> fvec_;
std::array<std::array<double, max_nr_order_>, max_nr_order_> fjac_;
std::array<double, max_nr_order_> scale_;
std::array<double, max_nr_order_> p_;
std::array<int, max_nr_order_> 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<double, double> gateDelaySlew() override;
std::pair<double, double> loadDelaySlew(const Pin *,
double elmore) override;
void evalDmpEqns() override;
protected:
double voCrossingUpperBound() override;
std::pair<double, double> V0(double t) override;
std::pair<double, double> 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<double, double> gateDelaySlew() override;
void evalDmpEqns() override;
protected:
double voCrossingUpperBound() override;
std::pair<double, double> V0(double t) override;
std::pair<double, double> 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<double, double> gateDelaySlew() override;
protected:
std::pair<double, double> V0(double t) override;
std::pair<double, double> 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.

View File

@ -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<double, double> gateDelaySlew() = 0;
virtual std::pair<double, double> 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<double, double> Vo(double t);
// Load response to driver waveform (vl, dvl/dt).
std::pair<double, double> Vl(double t);
protected:
void luDecomp();
void luSolve();
void newtonRaphson();
// Find driver parameters t0, delta_t, Ceff.
void findDriverParams(double ceff);
std::pair<double, double> gateCapDelaySlew(double ceff);
std::tuple<double, double, double> gateDelays(double ceff);
// Partial derivatives of y(t) jacobian (dydt0, dyddt, dydcl).
std::tuple<double, double, double> 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<double, double> 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<double, double> 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<double, double> 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<double, double> 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<double, max_nr_order_> x_;
std::array<double, max_nr_order_> fvec_;
std::array<std::array<double, max_nr_order_>, max_nr_order_> fjac_;
std::array<double, max_nr_order_> scale_;
std::array<double, max_nr_order_> p_;
std::array<int, max_nr_order_> 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<double, double> gateDelaySlew() override;
std::pair<double, double> loadDelaySlew(const Pin *,
double elmore) override;
void evalDmpEqns() override;
protected:
double voCrossingUpperBound() override;
std::pair<double, double> V0(double t) override;
std::pair<double, double> 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<double, double> gateDelaySlew() override;
void evalDmpEqns() override;
protected:
double voCrossingUpperBound() override;
std::pair<double, double> V0(double t) override;
std::pair<double, double> 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<double, double> gateDelaySlew() override;
protected:
std::pair<double, double> V0(double t) override;
std::pair<double, double> 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};
};

View File

@ -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 *

View File

@ -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

View File

@ -54,7 +54,7 @@ LumpedCapDelayCalc::LumpedCapDelayCalc(StaState *sta) :
ArcDelayCalc *
LumpedCapDelayCalc::copy()
{
return new LumpedCapDelayCalc(this);
return new LumpedCapDelayCalc(*this);
}
Parasitic *

View File

@ -42,7 +42,7 @@ UnitDelayCalc::UnitDelayCalc(StaState *sta) :
ArcDelayCalc *
UnitDelayCalc::copy()
{
return new UnitDelayCalc(this);
return new UnitDelayCalc(*this);
}
Parasitic *

View File

@ -9,7 +9,7 @@ See ApiChangeLog.txt for changes to the STA api.
The write_sdc command supports a -mode argument.
read_sdc [-mode mode]
write_sdc [-mode mode]
2026/03/23
----------

View File

@ -63,7 +63,6 @@ public:
{
}
// Copy constructor
BoundedHeap(const BoundedHeap& other) :
heap_(other.heap_),
max_size_(other.max_size_),

View File

@ -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;

View File

@ -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_; }

View File

@ -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_;
};

View File

@ -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

View File

@ -45,7 +45,7 @@ proc_redirect read_sdc {
if { [info exists keys(-mode)] } {
set mode_name $keys(-mode)
set prev_mode [cmd_mode_name]
set prev_mode [cmd_mode]
try {
set_cmd_mode $mode_name
include_file $filename $echo 0

View File

@ -107,7 +107,6 @@ GatedClk::isGatedClkEnable(Vertex *enable_vertex,
}
}
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -113,6 +113,7 @@ void
clear_network()
{
Sta *sta = Sta::sta();
sta->clear();
sta->network()->clear();
}
@ -1100,32 +1101,6 @@ set_use_default_arrival_clock(bool enable)
Sta::sta()->setUseDefaultArrivalClock(enable);
}
// For regression tests.
void
report_arrival_entries()
{
Sta *sta = Sta::sta();
Search *search = sta->search();
search->arrivalIterator()->reportEntries();
}
// For regression tests.
void
report_required_entries()
{
Sta *sta = Sta::sta();
Search *search = sta->search();
search->requiredIterator()->reportEntries();
}
// For regression tests.
void
levelize()
{
Sta *sta = Sta::sta();
sta->levelize()->findLevels();
}
%} // inline
////////////////////////////////////////////////////////////////

View File

@ -3310,7 +3310,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
@ -5102,7 +5102,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);
}

View File

@ -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
}

View File

@ -30,6 +30,9 @@
%{
#include <cctype>
#include <string>
#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 <class TYPE>
@ -256,14 +259,51 @@ setPtrTclList(SET_TYPE *set,
Tcl_SetObjResult(interp, list);
}
////////////////////////////////////////////////////////////////
} // namespace sta
using namespace sta;
%}
////////////////////////////////////////////////////////////////
%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<unsigned char>(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.
const char *
object_type(const char *obj)
{
if (is_object(obj))
return &obj[1 + sizeof(void*) * 2 + 3];
return "";
}
%}
////////////////////////////////////////////////////////////////
//
// SWIG type definitions.

View File

@ -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