Merge pull request #357 from The-OpenROAD-Project-staging/sta_update_latest_0505
Sta update latest 0505
This commit is contained in:
commit
2110ea71a2
4
BUILD
4
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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"; }
|
||||
|
|
|
|||
317
dcalc/DmpCeff.cc
317
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<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.
|
||||
|
|
|
|||
273
dcalc/DmpCeff.hh
273
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<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};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ LumpedCapDelayCalc::LumpedCapDelayCalc(StaState *sta) :
|
|||
ArcDelayCalc *
|
||||
LumpedCapDelayCalc::copy()
|
||||
{
|
||||
return new LumpedCapDelayCalc(this);
|
||||
return new LumpedCapDelayCalc(*this);
|
||||
}
|
||||
|
||||
Parasitic *
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ UnitDelayCalc::UnitDelayCalc(StaState *sta) :
|
|||
ArcDelayCalc *
|
||||
UnitDelayCalc::copy()
|
||||
{
|
||||
return new UnitDelayCalc(this);
|
||||
return new UnitDelayCalc(*this);
|
||||
}
|
||||
|
||||
Parasitic *
|
||||
|
|
|
|||
|
|
@ -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
|
||||
----------
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
BoundedHeap(const BoundedHeap& other) :
|
||||
heap_(other.heap_),
|
||||
max_size_(other.max_size_),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_; }
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
14
sdc/Sdc.i
14
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
|
||||
|
|
|
|||
31
sdc/Sdc.tcl
31
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
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -107,7 +107,6 @@ GatedClk::isGatedClkEnable(Vertex *enable_vertex,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 &
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
109
tcl/CmdUtil.tcl
109
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
|
|
|||
|
|
@ -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 %{
|
||||
|
||||
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.
|
||||
inline const char *
|
||||
object_type(const char *obj)
|
||||
{
|
||||
if (is_object(obj))
|
||||
return &obj[1 + sizeof(void*) * 2 + 3];
|
||||
return "";
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SWIG type definitions.
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
31
util/Util.i
31
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
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
|
|
|||
Loading…
Reference in New Issue