report_power, pocv support
This commit is contained in:
parent
9071a01306
commit
ddf897d4e6
|
|
@ -534,7 +534,7 @@ STA_LIBS="../search/libsearch.la ../sdf/libsdf.la ../graph/libgraph.la ../dcalc/
|
|||
|
||||
SWIG_DEPEND="../tcl/StaException.i ../tcl/StaTcl.i ../tcl/NetworkEdit.i ../sdf/Sdf.i ../dcalc/DelayCalc.i ../parasitics/Parasitics.i ../tcl/StaTcl.i"
|
||||
|
||||
TCL_INIT_FILES="../tcl/Util.tcl ../dcalc/DelayCalc.tcl ../tcl/Graph.tcl ../tcl/Liberty.tcl ../tcl/Link.tcl ../tcl/Network.tcl ../tcl/NetworkEdit.tcl ../parasitics/Parasitics.tcl ../tcl/Sdc.tcl ../sdf/Sdf.tcl ../tcl/Search.tcl ../tcl/Cmds.tcl ../tcl/Variables.tcl ../tcl/Sta.tcl ../tcl/Splash.tcl"
|
||||
TCL_INIT_FILES="../tcl/Util.tcl ../dcalc/DelayCalc.tcl ../tcl/Graph.tcl ../tcl/Liberty.tcl ../tcl/Link.tcl ../tcl/Network.tcl ../tcl/NetworkEdit.tcl ../parasitics/Parasitics.tcl ../tcl/Sdc.tcl ../sdf/Sdf.tcl ../tcl/Search.tcl ../tcl/Cmds.tcl ../tcl/Variables.tcl ../tcl/Sta.tcl ../tcl/Power.tcl ../tcl/Splash.tcl"
|
||||
|
||||
if test "$TCL_INCLUDE"; then
|
||||
STA_INCLUDE="$STA_INCLUDE -I$TCL_INCLUDE"
|
||||
|
|
|
|||
|
|
@ -86,7 +86,8 @@ public:
|
|||
float related_out_cap,
|
||||
const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &gate_delay, Slew &drvr_slew) = 0;
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) = 0;
|
||||
// Find the wire delay and load slew of a load pin.
|
||||
// Called after inputPortDelay or gateDelay.
|
||||
virtual void loadDelay(const Pin *load_pin,
|
||||
|
|
@ -94,16 +95,27 @@ public:
|
|||
ArcDelay &wire_delay,
|
||||
Slew &load_slew) = 0;
|
||||
virtual void setMultiDrvrSlewFactor(float factor) = 0;
|
||||
// Ceff for parasitics with pi models.
|
||||
virtual float ceff(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap) = 0;
|
||||
|
||||
// Find the delay for a timing check arc given the arc's
|
||||
// from/clock, to/data slews and related output pin parasitic.
|
||||
virtual ArcDelay checkDelay(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const Slew &to_slew,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap) = 0;
|
||||
virtual void checkDelay(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const Slew &to_slew,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &margin) = 0;
|
||||
// Report delay and slew calculation.
|
||||
virtual void reportGateDelay(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
|
|||
tab.table = table_model;
|
||||
tab.cell = drvr_cell;
|
||||
tab.pvt = pvt;
|
||||
tab.in_slew = in_slew;
|
||||
tab.in_slew = delayAsFloat(in_slew);
|
||||
tab.relcap = related_out_cap;
|
||||
ar1_ceff_delay(delay_work_, &tab, rcmodel_,
|
||||
_delayV, _slewV);
|
||||
|
|
@ -1303,12 +1303,14 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D,
|
|||
delay_c *c = D->c;
|
||||
double slew_derate = c->slew_derate;
|
||||
double c_log = c->vlg;
|
||||
float c1,d1,s1;
|
||||
float c1;
|
||||
double tlohi,r;
|
||||
c1 = ctot;
|
||||
ArcDelay d1;
|
||||
Slew s1;
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
|
||||
c1, tab->relcap, d1, s1);
|
||||
tlohi = slew_derate*s1;
|
||||
tlohi = slew_derate*delayAsFloat(s1);
|
||||
r = tlohi/(c_log*c1);
|
||||
if (rdelay>0.0 && r > rdelay)
|
||||
r = rdelay;
|
||||
|
|
@ -1327,10 +1329,11 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
|
|||
double c_log = con->vlg;
|
||||
double c_smin = con->smin;
|
||||
double tlohi,smin,s;
|
||||
float d1,s1;
|
||||
ArcDelay d1;
|
||||
Slew s1;
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
|
||||
c, tab->relcap, d1, s1);
|
||||
tlohi = slew_derate*s1;
|
||||
tlohi = slew_derate*delayAsFloat(s1);
|
||||
smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
|
||||
if (c_log*r*c >= tlohi) {
|
||||
// printf("hit smin\n");
|
||||
|
|
@ -1360,13 +1363,13 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
|
|||
float c2 = 0.5*c1;
|
||||
if (c1==c2)
|
||||
return 0.0;
|
||||
float d1, s1;
|
||||
ArcDelay d1, d2;
|
||||
Slew s1, s2;
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
|
||||
c1, tab->relcap, d1, s1);
|
||||
float d2, s2;
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
|
||||
c2, tab->relcap, d2, s2);
|
||||
double dt50 = d1-d2;
|
||||
double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
|
||||
if (dt50 <= 0.0)
|
||||
return 0.0;
|
||||
double rdelay = dt50/(c1-c2);
|
||||
|
|
@ -1386,7 +1389,8 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
|||
double vlo = con->vlo;
|
||||
double ctot = mod->ctot;
|
||||
double ceff,tlohi,t50_sy,r,s,t50_sr,rdelay;
|
||||
float df,sf;
|
||||
ArcDelay df;
|
||||
Slew sf;
|
||||
|
||||
debugPrint1(debug_, "arnoldi", 1, "\nctot=%s\n",
|
||||
units_->capacitanceUnit()->asString(ctot));
|
||||
|
|
@ -1422,8 +1426,8 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
|||
"table slew (in_slew %s ctot %s) = %s\n",
|
||||
units_->timeUnit()->asString(tab->in_slew),
|
||||
units_->capacitanceUnit()->asString(ctot),
|
||||
units_->timeUnit()->asString(sf));
|
||||
tlohi = slew_derate*sf;
|
||||
delayAsString(sf, units_));
|
||||
tlohi = slew_derate*delayAsFloat(sf);
|
||||
debugPrint2(debug_, "arnoldi", 1, "tlohi %s %s\n",
|
||||
units_->timeUnit()->asString(tlohi),
|
||||
units_->timeUnit()->asString(tlox-thix));
|
||||
|
|
@ -1431,7 +1435,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
|||
ceff = ctot;
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
|
||||
ceff, tab->relcap, df, sf);
|
||||
t50_sy = df;
|
||||
t50_sy = delayAsFloat(df);
|
||||
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
|
||||
|
||||
// calculate s,r,mod -> t50_srmod,
|
||||
|
|
@ -1473,7 +1477,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
|
|||
|
||||
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, ceff,
|
||||
tab->relcap, df, sf);
|
||||
t50_sy = df;
|
||||
t50_sy = delayAsFloat(df);
|
||||
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
|
||||
for (j=0;j<mod->n;j++) {
|
||||
rr = delay_work_get_residues(D,j);
|
||||
|
|
|
|||
|
|
@ -372,14 +372,15 @@ DmpAlg::gateCapDelaySlew(double ceff,
|
|||
double &delay,
|
||||
double &slew)
|
||||
{
|
||||
float model_delay, model_slew;
|
||||
ArcDelay model_delay;
|
||||
Slew model_slew;
|
||||
gate_model_->gateDelay(drvr_cell_, pvt_,
|
||||
static_cast<float>(in_slew_),
|
||||
static_cast<float>(ceff),
|
||||
related_out_cap_,
|
||||
model_delay, model_slew);
|
||||
delay = model_delay;
|
||||
slew = model_slew;
|
||||
delay = delayAsFloat(model_delay);
|
||||
slew = delayAsFloat(model_slew);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1665,6 +1666,24 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
|
|||
dmp_alg_->name());
|
||||
}
|
||||
|
||||
float
|
||||
DmpCeffDelayCalc::ceff(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
ArcDelay gate_delay;
|
||||
Slew drvr_slew;
|
||||
gateDelay(drvr_cell, arc, in_slew, load_cap,
|
||||
drvr_parasitic, related_out_cap, pvt, dcalc_ap,
|
||||
gate_delay, drvr_slew);
|
||||
return ceff();
|
||||
}
|
||||
|
||||
void
|
||||
DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
|
|
@ -1723,9 +1742,11 @@ gateModelRd(const LibertyCell *cell,
|
|||
float cap1 = static_cast<float>((c1 + c2) * .75);
|
||||
float cap2 = cap1 * 1.1F;
|
||||
float in_slew1 = static_cast<float>(in_slew);
|
||||
float d1 = gate_model->gateDelay(cell, pvt, in_slew1, cap1, related_out_cap);
|
||||
float d2 = gate_model->gateDelay(cell, pvt, in_slew1, cap2, related_out_cap);
|
||||
return abs(d1 - d2) / (cap2 - cap1);
|
||||
ArcDelay d1, d2;
|
||||
Slew s1, s2;
|
||||
gate_model->gateDelay(cell, pvt, in_slew1, cap1, related_out_cap, d1, s1);
|
||||
gate_model->gateDelay(cell, pvt, in_slew1, cap2, related_out_cap, d2, s2);
|
||||
return abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -50,6 +50,14 @@ public:
|
|||
// return values
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew);
|
||||
virtual float ceff(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
virtual void reportGateDelay(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
|
|
|
|||
|
|
@ -70,6 +70,14 @@ GraphDelayCalc::loadCap(const Pin *,
|
|||
pin_cap = wire_cap = 0.0F;
|
||||
}
|
||||
|
||||
float
|
||||
GraphDelayCalc::loadCap(const Pin *,
|
||||
const TransRiseFall *,
|
||||
const DcalcAnalysisPt *) const
|
||||
{
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
float
|
||||
GraphDelayCalc::loadCap(const Pin *,
|
||||
Parasitic *,
|
||||
|
|
|
|||
|
|
@ -80,6 +80,10 @@ public:
|
|||
float &pin_cap,
|
||||
float &wire_cap) const;
|
||||
// Load pin_cap + wire_cap.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const TransRiseFall *to_tr,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
// Load pin_cap + wire_cap.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
Parasitic *drvr_parasitic,
|
||||
const TransRiseFall *tr,
|
||||
|
|
@ -92,6 +96,9 @@ public:
|
|||
float &wire_cap,
|
||||
float &fanout,
|
||||
bool &has_set_load) const;
|
||||
virtual float ceff(Edge *edge,
|
||||
TimingArc *arc,
|
||||
const DcalcAnalysisPt *dcalc_ap) = 0;
|
||||
// Precedence:
|
||||
// SDF annotation
|
||||
// Liberty library
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ FindVertexDelays::copy()
|
|||
{
|
||||
// Copy StaState::arc_delay_calc_ because it needs separate state
|
||||
// for each thread.
|
||||
return new FindVertexDelays(graph_delay_calc1_, arc_delay_calc_->copy(), true);
|
||||
return new FindVertexDelays(graph_delay_calc1_,arc_delay_calc_->copy(),true);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1023,8 +1023,7 @@ GraphDelayCalc1::findDriverEdgeDelays(LibertyCell *drvr_cell,
|
|||
DcalcAnalysisPtIterator ap_iter(this);
|
||||
while (ap_iter.hasNext()) {
|
||||
DcalcAnalysisPt *dcalc_ap = ap_iter.next();
|
||||
const Pvt *pvt = sdc_->pvt(drvr_inst,
|
||||
dcalc_ap->constraintMinMax());
|
||||
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
|
||||
if (pvt == NULL)
|
||||
pvt = dcalc_ap->operatingConditions();
|
||||
TimingArcSetArcIterator *arc_iter = arc_set->timingArcIterator();
|
||||
|
|
@ -1065,13 +1064,28 @@ GraphDelayCalc1::findDriverEdgeDelays(LibertyCell *drvr_cell,
|
|||
return delay_changed;
|
||||
}
|
||||
|
||||
float
|
||||
GraphDelayCalc1::loadCap(const Pin *drvr_pin,
|
||||
const TransRiseFall *drvr_tr,
|
||||
const DcalcAnalysisPt *dcalc_ap) const
|
||||
{
|
||||
Parasitic *drvr_parasitic;
|
||||
bool delete_parasitic;
|
||||
arc_delay_calc_->findParasitic(drvr_pin, drvr_tr, dcalc_ap,
|
||||
drvr_parasitic, delete_parasitic);
|
||||
float load_cap = loadCap(drvr_pin, NULL, drvr_parasitic, drvr_tr, dcalc_ap);
|
||||
arc_delay_calc_->finish(drvr_pin, drvr_tr, dcalc_ap,
|
||||
drvr_parasitic, delete_parasitic);
|
||||
return load_cap;
|
||||
}
|
||||
|
||||
float
|
||||
GraphDelayCalc1::loadCap(const Pin *drvr_pin,
|
||||
Parasitic *drvr_parasitic,
|
||||
const TransRiseFall *tr,
|
||||
const DcalcAnalysisPt *dcalc_ap) const
|
||||
{
|
||||
return loadCap(drvr_pin, 0, drvr_parasitic, tr, dcalc_ap);
|
||||
return loadCap(drvr_pin, NULL, drvr_parasitic, tr, dcalc_ap);
|
||||
}
|
||||
|
||||
float
|
||||
|
|
@ -1160,7 +1174,7 @@ GraphDelayCalc1::netCaps(const Pin *drvr_pin,
|
|||
const MinMax *min_max = dcalc_ap->constraintMinMax();
|
||||
// Find pin and external pin/wire capacitance.
|
||||
sdc_->connectedCap(drvr_pin, tr, op_cond, corner, min_max,
|
||||
pin_cap, wire_cap, fanout, has_set_load);
|
||||
pin_cap, wire_cap, fanout, has_set_load);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1602,10 +1616,12 @@ GraphDelayCalc1::findCheckEdgeDelays(Edge *edge,
|
|||
arc_delay_calc->finish(related_out_pin, to_tr, dcalc_ap,
|
||||
related_out_parasitic, delete_related);
|
||||
}
|
||||
ArcDelay check_delay = arc_delay_calc->checkDelay(cell, arc,
|
||||
from_slew, to_slew,
|
||||
related_out_cap,
|
||||
pvt, dcalc_ap);
|
||||
ArcDelay check_delay;
|
||||
arc_delay_calc->checkDelay(cell, arc,
|
||||
from_slew, to_slew,
|
||||
related_out_cap,
|
||||
pvt, dcalc_ap,
|
||||
check_delay);
|
||||
debugPrint1(debug_, "delay_calc", 3,
|
||||
" check_delay = %s\n",
|
||||
delayAsString(check_delay, units_));
|
||||
|
|
@ -1727,6 +1743,54 @@ GraphDelayCalc1::isIdealClk(const Vertex *vertex) const
|
|||
&& clks->size() > 0;
|
||||
}
|
||||
|
||||
float
|
||||
GraphDelayCalc1::ceff(Edge *edge,
|
||||
TimingArc *arc,
|
||||
const DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
Vertex *from_vertex = edge->from(graph_);
|
||||
Vertex *to_vertex = edge->to(graph_);
|
||||
Pin *to_pin = to_vertex->pin();
|
||||
Instance *inst = network_->instance(to_pin);
|
||||
LibertyCell *cell = network_->libertyCell(inst);
|
||||
TimingArcSet *arc_set = edge->timingArcSet();
|
||||
float ceff = 0.0;
|
||||
const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax());
|
||||
if (pvt == NULL)
|
||||
pvt = dcalc_ap->operatingConditions();
|
||||
TransRiseFall *from_tr = arc->fromTrans()->asRiseFall();
|
||||
TransRiseFall *to_tr = arc->toTrans()->asRiseFall();
|
||||
if (from_tr && to_tr) {
|
||||
const LibertyPort *related_out_port = arc_set->relatedOut();
|
||||
const Pin *related_out_pin = 0;
|
||||
if (related_out_port)
|
||||
related_out_pin = network_->findPin(inst, related_out_port);
|
||||
float related_out_cap = 0.0;
|
||||
if (related_out_pin) {
|
||||
Parasitic *related_out_parasitic;
|
||||
bool delete_related;
|
||||
arc_delay_calc_->findParasitic(related_out_pin, to_tr, dcalc_ap,
|
||||
related_out_parasitic, delete_related);
|
||||
related_out_cap = loadCap(related_out_pin, related_out_parasitic,
|
||||
to_tr, dcalc_ap);
|
||||
arc_delay_calc_->finish(related_out_pin, to_tr, dcalc_ap,
|
||||
related_out_parasitic, delete_related);
|
||||
}
|
||||
Parasitic *to_parasitic;
|
||||
bool delete_to_parasitic;
|
||||
arc_delay_calc_->findParasitic(to_pin, to_tr, dcalc_ap,
|
||||
to_parasitic, delete_to_parasitic);
|
||||
const Slew &from_slew = edgeFromSlew(from_vertex, from_tr, edge, dcalc_ap);
|
||||
float load_cap = loadCap(to_pin, to_parasitic, to_tr, dcalc_ap);
|
||||
ceff = arc_delay_calc_->ceff(cell, arc,
|
||||
from_slew, load_cap, to_parasitic,
|
||||
related_out_cap, pvt, dcalc_ap);
|
||||
arc_delay_calc_->finish(to_pin, to_tr, dcalc_ap,
|
||||
to_parasitic, delete_to_parasitic);
|
||||
}
|
||||
return ceff;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
string *
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ public:
|
|||
virtual float incrementalDelayTolerance();
|
||||
virtual void setIncrementalDelayTolerance(float tol);
|
||||
virtual void setObserver(DelayCalcObserver *observer);
|
||||
// Load pin_cap + wire_cap.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const TransRiseFall *drvr_tr,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
virtual void loadCap(const Pin *drvr_pin,
|
||||
Parasitic *drvr_parasitic,
|
||||
const TransRiseFall *tr,
|
||||
|
|
@ -70,6 +74,9 @@ public:
|
|||
float &wire_cap,
|
||||
float &fanout,
|
||||
bool &has_set_load) const;
|
||||
float ceff(Edge *edge,
|
||||
TimingArc *arc,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
|
||||
protected:
|
||||
void seedInvalidDelays();
|
||||
|
|
|
|||
|
|
@ -122,6 +122,19 @@ LumpedCapDelayCalc::inputPortDelay(const Pin *, float in_slew,
|
|||
multi_drvr_slew_factor_ = 1.0F;
|
||||
}
|
||||
|
||||
float
|
||||
LumpedCapDelayCalc::ceff(const LibertyCell *,
|
||||
TimingArc *,
|
||||
const Slew &,
|
||||
float load_cap,
|
||||
Parasitic *,
|
||||
float,
|
||||
const Pvt *,
|
||||
const DcalcAnalysisPt *)
|
||||
{
|
||||
return load_cap;
|
||||
}
|
||||
|
||||
void
|
||||
LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
|
|
@ -142,7 +155,8 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
|
|||
units()->capacitanceUnit()->asString(load_cap),
|
||||
units()->capacitanceUnit()->asString(related_out_cap));
|
||||
if (model) {
|
||||
float gate_delay1, drvr_slew1;
|
||||
ArcDelay gate_delay1;
|
||||
Slew drvr_slew1;
|
||||
float in_slew1 = delayAsFloat(in_slew);
|
||||
model->gateDelay(drvr_cell, pvt, in_slew1, load_cap, related_out_cap,
|
||||
gate_delay1, drvr_slew1);
|
||||
|
|
@ -235,23 +249,25 @@ LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
|
|||
}
|
||||
}
|
||||
|
||||
ArcDelay
|
||||
void
|
||||
LumpedCapDelayCalc::checkDelay(const LibertyCell *cell,
|
||||
TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const Slew &to_slew,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap)
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &margin)
|
||||
{
|
||||
CheckTimingModel *model = checkModel(arc, dcalc_ap);
|
||||
if (model) {
|
||||
float from_slew1 = delayAsFloat(from_slew);
|
||||
float to_slew1 = delayAsFloat(to_slew);
|
||||
return model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap);
|
||||
model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap, margin);
|
||||
}
|
||||
else
|
||||
return delay_zero;
|
||||
margin = delay_zero;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -60,13 +60,23 @@ public:
|
|||
// Return values.
|
||||
ArcDelay &wire_delay,
|
||||
Slew &load_slew);
|
||||
virtual ArcDelay checkDelay(const LibertyCell *cell,
|
||||
TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const Slew &to_slew,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
virtual void checkDelay(const LibertyCell *cell,
|
||||
TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const Slew &to_slew,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &margin);
|
||||
virtual float ceff(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
virtual void reportGateDelay(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
|
|
|
|||
|
|
@ -92,6 +92,19 @@ UnitDelayCalc::loadDelay(const Pin *,
|
|||
load_slew = 0.0;
|
||||
}
|
||||
|
||||
float
|
||||
UnitDelayCalc::ceff(const LibertyCell *,
|
||||
TimingArc *,
|
||||
const Slew &,
|
||||
float,
|
||||
Parasitic *,
|
||||
float,
|
||||
const Pvt *,
|
||||
const DcalcAnalysisPt *)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
UnitDelayCalc::reportGateDelay(const LibertyCell *,
|
||||
TimingArc *,
|
||||
|
|
@ -108,16 +121,18 @@ UnitDelayCalc::reportGateDelay(const LibertyCell *,
|
|||
*result += "Slew = 0.0\n";
|
||||
}
|
||||
|
||||
ArcDelay
|
||||
void
|
||||
UnitDelayCalc::checkDelay(const LibertyCell *,
|
||||
TimingArc *,
|
||||
const Slew &,
|
||||
const Slew &,
|
||||
float,
|
||||
const Pvt *,
|
||||
const DcalcAnalysisPt *)
|
||||
const DcalcAnalysisPt *,
|
||||
// Return values.
|
||||
ArcDelay &margin)
|
||||
{
|
||||
return units_->timeUnit()->scale();
|
||||
margin = units_->timeUnit()->scale();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -54,18 +54,28 @@ public:
|
|||
ArcDelay &wire_delay,
|
||||
Slew &load_slew);
|
||||
virtual void setMultiDrvrSlewFactor(float) {}
|
||||
virtual float ceff(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
float load_cap,
|
||||
Parasitic *drvr_parasitic,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
virtual void inputPortDelay(const Pin *port_pin,
|
||||
float in_slew,
|
||||
const TransRiseFall *tr,
|
||||
Parasitic *parasitic,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
virtual ArcDelay checkDelay(const LibertyCell *cell,
|
||||
TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const Slew &to_slew,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
virtual void checkDelay(const LibertyCell *cell,
|
||||
TimingArc *arc,
|
||||
const Slew &from_slew,
|
||||
const Slew &to_slew,
|
||||
float related_out_cap,
|
||||
const Pvt *pvt,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
ArcDelay &margin);
|
||||
virtual void reportGateDelay(const LibertyCell *drvr_cell,
|
||||
TimingArc *arc,
|
||||
const Slew &in_slew,
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
|
|
@ -0,0 +1,39 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2018, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Machine.hh"
|
||||
#include "StringUtil.hh"
|
||||
#include "Units.hh"
|
||||
#include "StaState.hh"
|
||||
#include "Delay.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const Units *units)
|
||||
{
|
||||
return delayAsString(delay, units, units->timeUnit()->digits());
|
||||
}
|
||||
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta)
|
||||
{
|
||||
return delayAsString(delay, sta->units(), sta->units()->timeUnit()->digits());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -14,12 +14,20 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef STA_DELAY_H
|
||||
#define STA_DELAY_H
|
||||
|
||||
// Define one of the following:
|
||||
|
||||
// Define DELAY_FLOAT to use the float definitions.
|
||||
#define DELAY_FLOAT
|
||||
|
||||
// Define DELAY_FLOAT_CLASS to use the Delay class definitions.
|
||||
// Define DELAY_FLOAT_CLASS to use the DelayClass definitions.
|
||||
//#define DELAY_FLOAT_CLASS
|
||||
|
||||
// Define DELAY_NORMAL2 to use the DelayNormal2 definitions.
|
||||
//#define DELAY_NORMAL2
|
||||
|
||||
#ifdef DELAY_FLOAT
|
||||
#include "DelayFloat.hh"
|
||||
#endif
|
||||
|
|
@ -27,3 +35,91 @@
|
|||
#ifdef DELAY_FLOAT_CLASS
|
||||
#include "DelayFloatClass.hh"
|
||||
#endif
|
||||
|
||||
#ifdef DELAY_NORMAL2
|
||||
#include "DelayNormal2.hh"
|
||||
#endif
|
||||
|
||||
namespace sta {
|
||||
|
||||
class Units;
|
||||
class StaState;
|
||||
|
||||
typedef Delay ArcDelay;
|
||||
typedef Delay Slew;
|
||||
typedef Delay Arrival;
|
||||
typedef Delay Required;
|
||||
typedef Delay Slack;
|
||||
|
||||
void
|
||||
initDelayConstants();
|
||||
Delay
|
||||
makeDelay(float delay,
|
||||
float sigma_early,
|
||||
float sigma_late);
|
||||
float
|
||||
delayAsFloat(const Delay &delay);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const Units *units);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const Units *units,
|
||||
int digits);
|
||||
// mean late+/early- sigma
|
||||
// early_late = NULL returns mean.
|
||||
float
|
||||
delayMeanSigma(const Delay &delay,
|
||||
const EarlyLate *early_late);
|
||||
const char *
|
||||
delayMeanSigmaString(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const Units *units,
|
||||
int digits);
|
||||
const Delay &
|
||||
delayInitValue(const MinMax *min_max);
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayFuzzyZero(const Delay &delay);
|
||||
bool
|
||||
delayFuzzyEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayFuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayFuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayFuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@ delayIsInitValue(const Delay &delay,
|
|||
return fuzzyEqual(delay, min_max->initValue());
|
||||
}
|
||||
|
||||
float
|
||||
delayAsFloat(const Delay &delay)
|
||||
{
|
||||
return delay;
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyZero(const Delay &delay)
|
||||
{
|
||||
|
|
@ -141,16 +147,27 @@ delayRatio(const Delay &delay1,
|
|||
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
Units *units)
|
||||
const Units *units,
|
||||
int digits)
|
||||
{
|
||||
return units->timeUnit()->asString(delay);
|
||||
return units->timeUnit()->asString(delay, digits);
|
||||
}
|
||||
|
||||
float
|
||||
delayMeanSigma(const Delay &delay,
|
||||
const EarlyLate *)
|
||||
{
|
||||
return delay;
|
||||
}
|
||||
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta)
|
||||
delayMeanSigmaString(const Delay &delay,
|
||||
const EarlyLate *,
|
||||
const Units *units,
|
||||
int digits)
|
||||
{
|
||||
return delayAsString(delay, sta->units());
|
||||
const Unit *unit = units->timeUnit();
|
||||
return unit->asString(delay, digits);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -18,75 +18,22 @@
|
|||
#define STA_DELAY_FLOAT_H
|
||||
|
||||
#include "MinMax.hh"
|
||||
#include "Pool.hh"
|
||||
|
||||
// Delay values defined as floats.
|
||||
|
||||
namespace sta {
|
||||
|
||||
class Units;
|
||||
class StaState;
|
||||
|
||||
typedef float Delay;
|
||||
typedef Delay ArcDelay;
|
||||
typedef Delay Slew;
|
||||
typedef Delay Arrival;
|
||||
typedef Delay Required;
|
||||
typedef Delay Slack;
|
||||
typedef Pool<float> DelayPool;
|
||||
|
||||
const Delay delay_zero = 0.0;
|
||||
|
||||
void initDelayConstants();
|
||||
|
||||
inline float delayAsFloat(const Delay &delay) { return delay; }
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
Units *units);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta);
|
||||
|
||||
const Delay &
|
||||
delayInitValue(const MinMax *min_max);
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayFuzzyZero(const Delay &delay);
|
||||
bool
|
||||
delayFuzzyEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool delayFuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayFuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayFuzzyLess(const Delay &delay1, const
|
||||
Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
inline Delay
|
||||
makeDelay(float delay,
|
||||
float,
|
||||
float)
|
||||
{
|
||||
return delay;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -50,12 +50,6 @@ Delay::Delay(float delay) :
|
|||
{
|
||||
}
|
||||
|
||||
float
|
||||
Delay::asFloat() const
|
||||
{
|
||||
return delay_;
|
||||
}
|
||||
|
||||
void
|
||||
Delay::operator=(const Delay &delay)
|
||||
{
|
||||
|
|
@ -273,6 +267,13 @@ operator+(float delay1,
|
|||
return Delay(delay1 + delayAsFloat(delay2));
|
||||
}
|
||||
|
||||
Delay
|
||||
operator-(float delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1 - delayAsFloat(delay2));
|
||||
}
|
||||
|
||||
Delay
|
||||
operator/(float delay1,
|
||||
const Delay &delay2)
|
||||
|
|
@ -280,13 +281,6 @@ operator/(float delay1,
|
|||
return Delay(delay1 / delayAsFloat(delay2));
|
||||
}
|
||||
|
||||
Delay
|
||||
operator*(float delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1 * delayAsFloat(delay2));
|
||||
}
|
||||
|
||||
Delay
|
||||
operator*(const Delay &delay1,
|
||||
float delay2)
|
||||
|
|
@ -303,16 +297,26 @@ delayRatio(const Delay &delay1,
|
|||
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
Units *units)
|
||||
const Units *units,
|
||||
int digits)
|
||||
{
|
||||
return units->timeUnit()->asString(delayAsFloat(delay));
|
||||
return units->timeUnit()->asString(delay.delay(), digits);
|
||||
}
|
||||
|
||||
float
|
||||
delayMeanSigma(const Delay &delay,
|
||||
const EarlyLate *)
|
||||
{
|
||||
return delay.delay();
|
||||
}
|
||||
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta)
|
||||
delayMeanSigmaString(const Delay &delay,
|
||||
const EarlyLate *,
|
||||
const Units *units,
|
||||
int digits)
|
||||
{
|
||||
return delayAsString(delay, sta->units());
|
||||
return units->timeUnit()->asString(delay.delay(), digits);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -18,29 +18,19 @@
|
|||
#define STA_DELAY_FLOAT_CLASS_H
|
||||
|
||||
#include "MinMax.hh"
|
||||
#include "Pool.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
// Delay values defined as objects that hold a float value.
|
||||
|
||||
class Units;
|
||||
class Delay;
|
||||
class StaState;
|
||||
|
||||
typedef Delay ArcDelay;
|
||||
typedef Delay Slew;
|
||||
typedef Delay Arrival;
|
||||
typedef Delay Required;
|
||||
typedef Delay Slack;
|
||||
typedef Pool<Delay> DelayPool;
|
||||
// Delay values defined as class objects that hold a float value.
|
||||
// This is really a trial balloon for delay values as objects
|
||||
// instead of simple floats.
|
||||
|
||||
class Delay
|
||||
{
|
||||
public:
|
||||
Delay();
|
||||
Delay(float delay);
|
||||
float asFloat() const;
|
||||
float delay() const { return delay_; }
|
||||
void operator=(const Delay &delay);
|
||||
void operator=(float delay);
|
||||
void operator+=(const Delay &delay);
|
||||
|
|
@ -63,8 +53,16 @@ private:
|
|||
|
||||
const Delay delay_zero(0.0);
|
||||
|
||||
void
|
||||
initDelayConstants();
|
||||
inline Delay
|
||||
makeDelay(float delay,
|
||||
float,
|
||||
float)
|
||||
{
|
||||
return Delay(delay);
|
||||
}
|
||||
|
||||
inline float
|
||||
delayAsFloat(const Delay &delay) { return delay.delay(); }
|
||||
|
||||
// Most non-operator functions on Delay are not defined as member
|
||||
// functions so they can be defined on floats, where there is no class
|
||||
|
|
@ -72,70 +70,29 @@ initDelayConstants();
|
|||
|
||||
Delay operator+(float delay1,
|
||||
const Delay &delay2);
|
||||
Delay operator-(float delay1,
|
||||
const Delay &delay2);
|
||||
// Used for parallel gate delay calc.
|
||||
Delay operator/(float delay1,
|
||||
const Delay &delay2);
|
||||
Delay operator*(float delay1,
|
||||
const Delay &delay2);
|
||||
// Used for parallel gate delay calc.
|
||||
Delay operator*(const Delay &delay2,
|
||||
float delay1);
|
||||
Delay operator*(const Delay &delay1,
|
||||
float delay2);
|
||||
inline float
|
||||
delayAsFloat(const Delay &delay) { return delay.asFloat(); }
|
||||
const char *delayAsString(const Delay &delay,
|
||||
Units *units);
|
||||
const char *delayAsString(const Delay &delay,
|
||||
const StaState *sta);
|
||||
const Delay &delayInitValue(const MinMax *min_max);
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayFuzzyZero(const Delay &delay);
|
||||
bool
|
||||
delayFuzzyEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
|
||||
bool
|
||||
delayFuzzyLess(const Delay &delay1,
|
||||
float delay2);
|
||||
bool
|
||||
delayFuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayFuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayFuzzyLessEqual(const Delay &delay1,
|
||||
float delay2);
|
||||
bool
|
||||
delayFuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyGreater(const Delay &delay1,
|
||||
float delay2);
|
||||
bool
|
||||
delayFuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayFuzzyGreaterEqual(const Delay &delay1,
|
||||
float delay2);
|
||||
bool
|
||||
delayFuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayFuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,389 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2018, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <cmath> // sqrt
|
||||
#include "Machine.hh"
|
||||
#include "StringUtil.hh"
|
||||
#include "Fuzzy.hh"
|
||||
#include "Units.hh"
|
||||
#include "StaState.hh"
|
||||
#include "Delay.hh"
|
||||
|
||||
// Conditional compilation based on delay abstraction from Delay.hh.
|
||||
#ifdef DELAY_NORMAL2
|
||||
|
||||
namespace sta {
|
||||
|
||||
#define square(x) ((x)*(x))
|
||||
|
||||
static Delay delay_init_values[MinMax::index_count];
|
||||
|
||||
void
|
||||
initDelayConstants()
|
||||
{
|
||||
delay_init_values[MinMax::minIndex()] = MinMax::min()->initValue();
|
||||
delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue();
|
||||
}
|
||||
|
||||
const Delay &
|
||||
delayInitValue(const MinMax *min_max)
|
||||
{
|
||||
return delay_init_values[min_max->index()];
|
||||
}
|
||||
|
||||
Delay::Delay() :
|
||||
mean_(0.0),
|
||||
sigma_{0.0, 0.0}
|
||||
{
|
||||
}
|
||||
|
||||
Delay::Delay(float mean) :
|
||||
mean_(mean),
|
||||
sigma_{0.0, 0.0}
|
||||
{
|
||||
}
|
||||
|
||||
Delay::Delay(float mean,
|
||||
float sigma_early,
|
||||
float sigma_late) :
|
||||
mean_(mean),
|
||||
sigma_{sigma_early, sigma_late}
|
||||
{
|
||||
}
|
||||
|
||||
float
|
||||
Delay::sigma(const EarlyLate *early_late) const
|
||||
{
|
||||
return sigma_[early_late->index()];
|
||||
}
|
||||
|
||||
void
|
||||
Delay::operator=(const Delay &delay)
|
||||
{
|
||||
mean_ = delay.mean_;
|
||||
sigma_[early_index] = delay.sigma_[early_index];
|
||||
sigma_[late_index] = delay.sigma_[late_index];
|
||||
}
|
||||
|
||||
void
|
||||
Delay::operator=(float delay)
|
||||
{
|
||||
mean_ = delay;
|
||||
sigma_[early_index] = 0.0;
|
||||
sigma_[late_index] = 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
Delay::operator+=(const Delay &delay)
|
||||
{
|
||||
mean_ += delay.mean_;
|
||||
sigma_[early_index] = sqrt(square(sigma_[early_index])
|
||||
+ square(delay.sigma_[early_index]));
|
||||
sigma_[late_index] = sqrt(square(sigma_[late_index])
|
||||
+ square(delay.sigma_[late_index]));
|
||||
}
|
||||
|
||||
void
|
||||
Delay::operator+=(float delay)
|
||||
{
|
||||
mean_ += delay;
|
||||
}
|
||||
|
||||
Delay
|
||||
Delay::operator+(const Delay &delay) const
|
||||
{
|
||||
return Delay(mean_ + delay.mean_,
|
||||
sqrt(square(sigma_[early_index])
|
||||
+ square(delay.sigma_[early_index])),
|
||||
sqrt(square(sigma_[late_index])
|
||||
+ square(delay.sigma_[late_index])));
|
||||
}
|
||||
|
||||
Delay
|
||||
Delay::operator+(float delay) const
|
||||
{
|
||||
return Delay(mean_ + delay, sigma_[early_index], sigma_[late_index]);
|
||||
}
|
||||
|
||||
Delay
|
||||
Delay::operator-(const Delay &delay) const
|
||||
{
|
||||
return Delay(mean_ - delay.mean_,
|
||||
sqrt(square(sigma_[early_index])
|
||||
+ square(delay.sigma_[early_index])),
|
||||
sqrt(square(sigma_[late_index])
|
||||
+ square(delay.sigma_[late_index])));
|
||||
}
|
||||
|
||||
Delay
|
||||
Delay::operator-(float delay) const
|
||||
{
|
||||
return Delay(mean_ - delay, sigma_[early_index], sigma_[late_index]);
|
||||
}
|
||||
|
||||
Delay
|
||||
Delay::operator-() const
|
||||
{
|
||||
return Delay(-mean_, sigma_[early_index], sigma_[late_index]);
|
||||
}
|
||||
|
||||
void
|
||||
Delay::operator-=(float delay)
|
||||
{
|
||||
mean_ -= - delay;
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator==(const Delay &delay) const
|
||||
{
|
||||
return mean_ == delay.mean_
|
||||
&& sigma_[early_index] == delay.sigma_[early_index]
|
||||
&& sigma_[late_index] == delay.sigma_[late_index];
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator>(const Delay &delay) const
|
||||
{
|
||||
return mean_ > delay.mean_;
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator>=(const Delay &delay) const
|
||||
{
|
||||
return mean_ >= delay.mean_;
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator<(const Delay &delay) const
|
||||
{
|
||||
return mean_ < delay.mean_;
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator<=(const Delay &delay) const
|
||||
{
|
||||
return mean_ <= delay.mean_;
|
||||
}
|
||||
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
return fuzzyEqual(delay.mean(), min_max->initValue())
|
||||
&& delay.sigmaEarly() == 0.0
|
||||
&& delay.sigmaLate() == 0.0;
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyZero(const Delay &delay)
|
||||
{
|
||||
return fuzzyZero(delay.mean())
|
||||
&& fuzzyZero(delay.sigmaEarly())
|
||||
&& fuzzyZero(delay.sigmaLate());
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyEqual(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyEqual(delay1.mean(), delay2.mean())
|
||||
&& fuzzyEqual(delay1.sigmaEarly(), delay2.sigmaEarly())
|
||||
&& fuzzyEqual(delay1.sigmaLate(), delay2.sigmaLate());
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyLess(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyLess(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyLess(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyLessEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyLessEqual(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyLessEqual(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyLessEqual(delay1.mean(), delay2.mean());
|
||||
else
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyGreater(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyGreater(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyGreater(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyGreaterEqual(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyGreater(delay1.mean(), delay2.mean());
|
||||
else
|
||||
return fuzzyLess(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
|
||||
else
|
||||
return fuzzyLessEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
delayFuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyLess(delay1.mean(), delay2.mean());
|
||||
else
|
||||
return fuzzyGreater(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
Delay
|
||||
operator+(float delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1 + delay2.mean(),
|
||||
delay2.sigmaEarly(),
|
||||
delay2.sigmaLate());
|
||||
}
|
||||
|
||||
Delay
|
||||
operator/(float delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1 / delay2.mean(),
|
||||
delay2.sigmaEarly(),
|
||||
delay2.sigmaLate());
|
||||
}
|
||||
|
||||
Delay
|
||||
operator*(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return Delay(delay1.mean() * delay2,
|
||||
delay1.sigmaEarly() * delay2,
|
||||
delay1.sigmaLate() * delay2);
|
||||
}
|
||||
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return delay1.mean() / delay2.mean();
|
||||
}
|
||||
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const Units *units,
|
||||
int digits)
|
||||
{
|
||||
const Unit *unit = units->timeUnit();
|
||||
float sigma_early = delay.sigmaEarly();
|
||||
float sigma_late = delay.sigmaLate();
|
||||
if (fuzzyEqual(sigma_early, sigma_late))
|
||||
return stringPrintTmp((digits + 2) * 2 + 2,
|
||||
"%s|%s",
|
||||
unit->asString(delay.mean(), digits),
|
||||
unit->asString(sigma_early, digits));
|
||||
else
|
||||
return stringPrintTmp((digits + 2) * 3 + 3,
|
||||
"%s|%s:%s",
|
||||
unit->asString(delay.mean(), digits),
|
||||
unit->asString(sigma_early, digits),
|
||||
unit->asString(sigma_late, digits));
|
||||
}
|
||||
|
||||
const char *
|
||||
delayMeanSigmaString(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const Units *units,
|
||||
int digits)
|
||||
{
|
||||
float mean_sigma = delay.mean();
|
||||
if (early_late == EarlyLate::early())
|
||||
mean_sigma -= delay.sigmaEarly();
|
||||
else if (early_late == EarlyLate::late())
|
||||
mean_sigma += delay.sigmaLate();
|
||||
return units->timeUnit()->asString(mean_sigma, digits);
|
||||
}
|
||||
|
||||
float
|
||||
delayMeanSigma(const Delay &delay,
|
||||
const EarlyLate *early_late)
|
||||
{
|
||||
if (early_late == EarlyLate::early())
|
||||
return delay.mean() - delay.sigmaEarly();
|
||||
else if (early_late == EarlyLate::late())
|
||||
return delay.mean() + delay.sigmaLate();
|
||||
else
|
||||
return delay.mean();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2018, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef STA_DELAY_FLOAT_CLASS_H
|
||||
#define STA_DELAY_FLOAT_CLASS_H
|
||||
|
||||
#include "MinMax.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
// Delay values defined as objects that hold a float value.
|
||||
|
||||
class Delay;
|
||||
|
||||
// Normal distribution with early(left)/late(right) std deviations.
|
||||
class Delay
|
||||
{
|
||||
public:
|
||||
Delay();
|
||||
Delay(float mean);
|
||||
Delay(float mean,
|
||||
float sigma_early,
|
||||
float sigma_late);
|
||||
float mean() const { return mean_; }
|
||||
float sigma(const EarlyLate *early_late) const;
|
||||
float sigmaEarly() const { return sigma_[early_index]; }
|
||||
float sigmaLate() const { return sigma_[late_index]; }
|
||||
void operator=(const Delay &delay);
|
||||
void operator=(float delay);
|
||||
void operator+=(const Delay &delay);
|
||||
void operator+=(float delay);
|
||||
Delay operator+(const Delay &delay) const;
|
||||
Delay operator+(float delay) const;
|
||||
Delay operator-(const Delay &delay) const;
|
||||
Delay operator-(float delay) const;
|
||||
Delay operator-() const;
|
||||
void operator-=(float delay);
|
||||
bool operator==(const Delay &delay) const;
|
||||
bool operator>(const Delay &delay) const;
|
||||
bool operator>=(const Delay &delay) const;
|
||||
bool operator<(const Delay &delay) const;
|
||||
bool operator<=(const Delay &delay) const;
|
||||
|
||||
protected:
|
||||
static const int early_index = 0;
|
||||
static const int late_index = 1;
|
||||
|
||||
private:
|
||||
float mean_;
|
||||
float sigma_[EarlyLate::index_count];
|
||||
};
|
||||
|
||||
const Delay delay_zero(0.0);
|
||||
|
||||
inline Delay
|
||||
makeDelay(float delay,
|
||||
float sigma_early,
|
||||
float sigma_late)
|
||||
{
|
||||
return Delay(delay, sigma_early, sigma_late);
|
||||
}
|
||||
|
||||
inline float
|
||||
delayAsFloat(const Delay &delay) { return delay.mean(); }
|
||||
|
||||
// Most non-operator functions on Delay are not defined as member
|
||||
// functions so they can be defined on floats, where there is no class
|
||||
// to define them.
|
||||
|
||||
Delay operator+(float delay1,
|
||||
const Delay &delay2);
|
||||
// Used for parallel gate delay calc.
|
||||
Delay operator/(float delay1,
|
||||
const Delay &delay2);
|
||||
// Used for parallel gate delay calc.
|
||||
Delay operator*(const Delay &delay1,
|
||||
float delay2);
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
|
@ -715,6 +715,7 @@ Graph::makeArcDelayPools(ArcIndex arc_count,
|
|||
arc_delays_[i] = pool;
|
||||
}
|
||||
|
||||
// Leave some room for edits.
|
||||
unsigned annot_size = arc_count * 1.2;
|
||||
arc_delay_annotated_.resize(annot_size * ap_count);
|
||||
}
|
||||
|
|
@ -747,7 +748,7 @@ Graph::makeEdgeArcDelays(Edge *edge)
|
|||
}
|
||||
edge->setArcDelays(arc_index);
|
||||
// Make sure there is room for delay_annotated flags.
|
||||
unsigned max_annot_index = arc_index + (arc_count * ap_count_);
|
||||
unsigned max_annot_index = (arc_index + arc_count) * ap_count_;
|
||||
if (max_annot_index >= arc_delay_annotated_.size()) {
|
||||
unsigned size = max_annot_index * 1.2;
|
||||
arc_delay_annotated_.resize(size);
|
||||
|
|
@ -832,7 +833,9 @@ Graph::arcDelayAnnotated(Edge *edge,
|
|||
TimingArc *arc,
|
||||
DcalcAPIndex ap_index) const
|
||||
{
|
||||
int index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index;
|
||||
unsigned index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index;
|
||||
if (index >= arc_delay_annotated_.size())
|
||||
internalError("arc_delay_annotated array bounds exceeded");
|
||||
return arc_delay_annotated_[index];
|
||||
}
|
||||
|
||||
|
|
@ -842,7 +845,9 @@ Graph::setArcDelayAnnotated(Edge *edge,
|
|||
DcalcAPIndex ap_index,
|
||||
bool annotated)
|
||||
{
|
||||
int index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index;
|
||||
unsigned index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index;
|
||||
if (index >= arc_delay_annotated_.size())
|
||||
internalError("arc_delay_annotated array bounds exceeded");
|
||||
arc_delay_annotated_[index] = annotated;
|
||||
}
|
||||
|
||||
|
|
@ -851,8 +856,10 @@ Graph::wireDelayAnnotated(Edge *edge,
|
|||
const TransRiseFall *tr,
|
||||
DcalcAPIndex ap_index) const
|
||||
{
|
||||
int index = (edge->arcDelays() + TimingArcSet::wireArcIndex(tr)) * ap_count_
|
||||
unsigned index = (edge->arcDelays() + TimingArcSet::wireArcIndex(tr)) * ap_count_
|
||||
+ ap_index;
|
||||
if (index >= arc_delay_annotated_.size())
|
||||
internalError("arc_delay_annotated array bounds exceeded");
|
||||
return arc_delay_annotated_[index];
|
||||
}
|
||||
|
||||
|
|
@ -862,8 +869,10 @@ Graph::setWireDelayAnnotated(Edge *edge,
|
|||
DcalcAPIndex ap_index,
|
||||
bool annotated)
|
||||
{
|
||||
int index = (edge->arcDelays() + TimingArcSet::wireArcIndex(tr)) * ap_count_
|
||||
unsigned index = (edge->arcDelays() + TimingArcSet::wireArcIndex(tr)) * ap_count_
|
||||
+ ap_index;
|
||||
if (index >= arc_delay_annotated_.size())
|
||||
internalError("arc_delay_annotated array bounds exceeded");
|
||||
arc_delay_annotated_[index] = annotated;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ enum VertexColor {
|
|||
vertex_color_black
|
||||
};
|
||||
|
||||
typedef Pool<Delay> DelayPool;
|
||||
typedef Pool<Vertex> VertexPool;
|
||||
typedef Pool<Edge> EdgePool;
|
||||
typedef Map<const Pin*, Vertex*> PinVertexMap;
|
||||
|
|
|
|||
|
|
@ -20,13 +20,16 @@ include_HEADERS = \
|
|||
Delay.hh \
|
||||
DelayFloat.hh \
|
||||
DelayFloatClass.hh \
|
||||
DelayNormal2.hh \
|
||||
Graph.hh \
|
||||
GraphClass.hh \
|
||||
GraphCmp.hh
|
||||
|
||||
libgraph_la_SOURCES = \
|
||||
Delay.cc \
|
||||
DelayFloat.cc \
|
||||
DelayFloatClass.cc \
|
||||
DelayNormal2.cc \
|
||||
Graph.cc \
|
||||
GraphCmp.cc
|
||||
|
||||
|
|
|
|||
|
|
@ -23,14 +23,15 @@
|
|||
namespace sta {
|
||||
|
||||
InternalPowerAttrs::InternalPowerAttrs() :
|
||||
when_(NULL)
|
||||
when_(NULL),
|
||||
models_{NULL, NULL},
|
||||
related_pg_pin_(NULL)
|
||||
{
|
||||
TransRiseFallIterator tr_iter;
|
||||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *tr = tr_iter.next();
|
||||
int tr_index = tr->index();
|
||||
models_[tr_index] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
InternalPowerAttrs::~InternalPowerAttrs()
|
||||
{
|
||||
stringDelete(related_pg_pin_);
|
||||
}
|
||||
|
||||
InternalPowerModel *
|
||||
|
|
@ -46,6 +47,13 @@ InternalPowerAttrs::setModel(TransRiseFall *tr,
|
|||
models_[tr->index()] = model;
|
||||
}
|
||||
|
||||
void
|
||||
InternalPowerAttrs::setRelatedPgPin(const char *related_pg_pin)
|
||||
{
|
||||
stringDelete(related_pg_pin_);
|
||||
related_pg_pin_ = stringCopy(related_pg_pin);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
InternalPower::InternalPower(LibertyCell *cell,
|
||||
|
|
@ -54,7 +62,8 @@ InternalPower::InternalPower(LibertyCell *cell,
|
|||
InternalPowerAttrs *attrs) :
|
||||
port_(port),
|
||||
related_port_(related_port),
|
||||
when_(attrs->when())
|
||||
when_(attrs->when()),
|
||||
related_pg_pin_(stringCopy(attrs->relatedPgPin()))
|
||||
{
|
||||
TransRiseFallIterator tr_iter;
|
||||
while (tr_iter.hasNext()) {
|
||||
|
|
@ -77,6 +86,7 @@ InternalPower::~InternalPower()
|
|||
}
|
||||
if (when_)
|
||||
when_->deleteSubexprs();
|
||||
stringDelete(related_pg_pin_);
|
||||
}
|
||||
|
||||
LibertyCell *
|
||||
|
|
|
|||
|
|
@ -30,15 +30,19 @@ class InternalPowerAttrs
|
|||
{
|
||||
public:
|
||||
InternalPowerAttrs();
|
||||
~InternalPowerAttrs();
|
||||
FuncExpr *when() const { return when_; }
|
||||
FuncExpr *&whenRef() { return when_; }
|
||||
void setModel(TransRiseFall *tr,
|
||||
InternalPowerModel *model);
|
||||
InternalPowerModel *model(TransRiseFall *tr) const;
|
||||
const char *relatedPgPin() const { return related_pg_pin_; }
|
||||
void setRelatedPgPin(const char *related_pg_pin);
|
||||
|
||||
protected:
|
||||
FuncExpr *when_;
|
||||
InternalPowerModel *models_[TransRiseFall::index_count];
|
||||
const char *related_pg_pin_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(InternalPowerAttrs);
|
||||
|
|
@ -56,6 +60,7 @@ public:
|
|||
LibertyPort *port() const { return port_; }
|
||||
LibertyPort *relatedPort() const { return related_port_; }
|
||||
FuncExpr *when() const { return when_; }
|
||||
const char *relatedPgPin() const { return related_pg_pin_; }
|
||||
float power(TransRiseFall *tr,
|
||||
const Pvt *pvt,
|
||||
float in_slew,
|
||||
|
|
@ -65,6 +70,7 @@ protected:
|
|||
LibertyPort *port_;
|
||||
LibertyPort *related_port_;
|
||||
FuncExpr *when_;
|
||||
const char *related_pg_pin_;
|
||||
InternalPowerModel *models_[TransRiseFall::index_count];
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -815,6 +815,8 @@ LibertyCell::LibertyCell(LibertyLibrary *library,
|
|||
liberty_library_(library),
|
||||
area_(0.0),
|
||||
dont_use_(false),
|
||||
is_macro_(false),
|
||||
is_pad_(false),
|
||||
has_internal_ports_(false),
|
||||
interface_timing_(false),
|
||||
clock_gate_type_(clock_gate_none),
|
||||
|
|
@ -833,7 +835,8 @@ LibertyCell::LibertyCell(LibertyLibrary *library,
|
|||
test_cell_(NULL),
|
||||
ocv_arc_depth_(0.0),
|
||||
ocv_derate_(NULL),
|
||||
is_disabled_constraint_(false)
|
||||
is_disabled_constraint_(false),
|
||||
leakage_power_(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -1040,6 +1043,18 @@ LibertyCell::setDontUse(bool dont_use)
|
|||
dont_use_ = dont_use;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyCell::setIsMacro(bool is_macro)
|
||||
{
|
||||
is_macro_ = is_macro;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyCell::LibertyCell::setIsPad(bool is_pad)
|
||||
{
|
||||
is_pad_ = is_pad;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyCell::setInterfaceTiming(bool value)
|
||||
{
|
||||
|
|
@ -1155,6 +1170,18 @@ LibertyCell::leakagePowerIterator()
|
|||
return new LibertyCellLeakagePowerIterator(leakage_powers_);
|
||||
}
|
||||
|
||||
float
|
||||
LibertyCell::leakagePower() const
|
||||
{
|
||||
return leakage_power_;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyCell::setLeakagePower(float leakage)
|
||||
{
|
||||
leakage_power_ = leakage;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyCell::finish(bool infer_latches,
|
||||
Report *report,
|
||||
|
|
@ -1808,6 +1835,7 @@ LibertyPort::LibertyPort(LibertyCell *cell,
|
|||
min_period_(0.0),
|
||||
pulse_clk_trigger_(NULL),
|
||||
pulse_clk_sense_(NULL),
|
||||
related_power_pin_(NULL),
|
||||
min_pulse_width_exists_(false),
|
||||
min_period_exists_(false),
|
||||
is_clk_(false),
|
||||
|
|
@ -1830,6 +1858,7 @@ LibertyPort::~LibertyPort()
|
|||
if (tristate_enable_)
|
||||
tristate_enable_->deleteSubexprs();
|
||||
delete scaled_ports_;
|
||||
stringDelete(related_power_pin_);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2197,6 +2226,12 @@ LibertyPort::setCornerPort(LibertyPort *corner_port,
|
|||
corner_ports_[ap_index] = corner_port;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyPort::setRelatedPowerPin(const char *related_power_pin)
|
||||
{
|
||||
related_power_pin_ = stringCopy(related_power_pin);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
|
|
@ -2686,7 +2721,7 @@ TestCell::setScanOutInv(LibertyPort *port)
|
|||
OcvDerate::OcvDerate(const char *name) :
|
||||
name_(name)
|
||||
{
|
||||
MinMaxIterator el_iter;
|
||||
EarlyLateIterator el_iter;
|
||||
while (el_iter.hasNext()) {
|
||||
EarlyLate *early_late = el_iter.next();
|
||||
int el_index = early_late->index();
|
||||
|
|
@ -2706,7 +2741,7 @@ OcvDerate::~OcvDerate()
|
|||
// Derating table models can be shared in multiple places in derate_;
|
||||
// Collect them in a set to avoid duplicate deletes.
|
||||
Set<Table*> models;
|
||||
MinMaxIterator el_iter;
|
||||
EarlyLateIterator el_iter;
|
||||
while (el_iter.hasNext()) {
|
||||
EarlyLate *early_late = el_iter.next();
|
||||
int el_index = early_late->index();
|
||||
|
|
|
|||
|
|
@ -383,6 +383,10 @@ public:
|
|||
void setArea(float area);
|
||||
bool dontUse() const { return dont_use_; }
|
||||
void setDontUse(bool dont_use);
|
||||
bool isMacro() const { return is_macro_; }
|
||||
void setIsMacro(bool is_macro);
|
||||
bool isPad() const { return is_pad_; }
|
||||
void setIsPad(bool is_pad);
|
||||
bool interfaceTiming() const { return interface_timing_; }
|
||||
void setInterfaceTiming(bool value);
|
||||
bool isClockGateLatchPosedge() const;
|
||||
|
|
@ -409,6 +413,7 @@ public:
|
|||
bool hasTimingArcs(LibertyPort *port) const;
|
||||
LibertyCellInternalPowerIterator *internalPowerIterator();
|
||||
LibertyCellLeakagePowerIterator *leakagePowerIterator();
|
||||
float leakagePower() const;
|
||||
bool hasSequentials() const;
|
||||
CellSequentialIterator *sequentialIterator() const;
|
||||
void makeSequential(int size,
|
||||
|
|
@ -444,6 +449,7 @@ public:
|
|||
LibertyCell *cornerCell(int ap_index);
|
||||
void setCornerCell(LibertyCell *corner_cell,
|
||||
int ap_index);
|
||||
void setLeakagePower(float leakage);
|
||||
|
||||
// AOCV
|
||||
float ocvArcDepth() const;
|
||||
|
|
@ -476,6 +482,8 @@ protected:
|
|||
LibertyLibrary *liberty_library_;
|
||||
float area_;
|
||||
bool dont_use_;
|
||||
bool is_macro_;
|
||||
bool is_pad_;
|
||||
bool has_internal_ports_;
|
||||
bool interface_timing_;
|
||||
ClockGateType clock_gate_type_;
|
||||
|
|
@ -505,6 +513,7 @@ protected:
|
|||
OcvDerateMap ocv_derate_map_;
|
||||
bool is_disabled_constraint_;
|
||||
Vector<LibertyCell*> corner_cells_;
|
||||
float leakage_power_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(LibertyCell);
|
||||
|
|
@ -637,6 +646,8 @@ public:
|
|||
LibertyPort *cornerPort(int ap_index);
|
||||
void setCornerPort(LibertyPort *corner_port,
|
||||
int ap_index);
|
||||
const char *relatedPowerPin() const { return related_power_pin_; }
|
||||
void setRelatedPowerPin(const char *related_power_pin);
|
||||
|
||||
static bool equiv(const LibertyPort *port1,
|
||||
const LibertyPort *port2);
|
||||
|
|
@ -670,6 +681,7 @@ protected:
|
|||
float min_pulse_width_[TransRiseFall::index_count];
|
||||
TransRiseFall *pulse_clk_trigger_;
|
||||
TransRiseFall *pulse_clk_sense_;
|
||||
const char *related_power_pin_;
|
||||
Vector<LibertyPort*> corner_ports_;
|
||||
|
||||
unsigned int min_pulse_width_exists_:TransRiseFall::index_count;
|
||||
|
|
|
|||
|
|
@ -287,6 +287,8 @@ LibertyReader::defineVisitors()
|
|||
&LibertyReader::visitClockGatingIntegratedCell);
|
||||
defineAttrVisitor("area", &LibertyReader::visitArea);
|
||||
defineAttrVisitor("dont_use", &LibertyReader::visitDontUse);
|
||||
defineAttrVisitor("is_macro", &LibertyReader::visitIsMacro);
|
||||
defineAttrVisitor("is_pad", &LibertyReader::visitIsPad);
|
||||
defineAttrVisitor("interface_timing", &LibertyReader::visitInterfaceTiming);
|
||||
defineAttrVisitor("scaling_factors", &LibertyReader::visitScalingFactors);
|
||||
|
||||
|
|
@ -399,6 +401,8 @@ LibertyReader::defineVisitors()
|
|||
&LibertyReader::endRiseFallPower);
|
||||
defineGroupVisitor("rise_power", &LibertyReader::beginRisePower,
|
||||
&LibertyReader::endRiseFallPower);
|
||||
defineAttrVisitor("related_power_pin", &LibertyReader::visitRelatedPowerPin);
|
||||
defineAttrVisitor("related_pg_pin", &LibertyReader::visitRelatedPgPin);
|
||||
|
||||
// AOCV attributes.
|
||||
defineAttrVisitor("ocv_arc_depth", &LibertyReader::visitOcvArcDepth);
|
||||
|
|
@ -417,6 +421,20 @@ LibertyReader::defineVisitors()
|
|||
defineAttrVisitor("rf_type", &LibertyReader::visitRfType);
|
||||
defineAttrVisitor("derate_type", &LibertyReader::visitDerateType);
|
||||
defineAttrVisitor("path_type", &LibertyReader::visitPathType);
|
||||
|
||||
// POCV attributes.
|
||||
defineGroupVisitor("ocv_sigma_cell_rise", &LibertyReader::beginOcvSigmaCellRise,
|
||||
&LibertyReader::endOcvSigmaCell);
|
||||
defineGroupVisitor("ocv_sigma_cell_fall", &LibertyReader::beginOcvSigmaCellFall,
|
||||
&LibertyReader::endOcvSigmaCell);
|
||||
defineGroupVisitor("ocv_sigma_rise_transition",
|
||||
&LibertyReader::beginOcvSigmaRiseTransition,
|
||||
&LibertyReader::endOcvSigmaTransition);
|
||||
defineGroupVisitor("ocv_sigma_fall_transition",
|
||||
&LibertyReader::beginOcvSigmaFallTransition,
|
||||
&LibertyReader::endOcvSigmaTransition);
|
||||
defineAttrVisitor("sigma_type", &LibertyReader::visitSigmaType);
|
||||
defineAttrVisitor("cell_leakage_power", &LibertyReader::visitCellLeakagePower);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -535,6 +553,8 @@ LibertyReader::beginLibrary(LibertyGroup *group)
|
|||
curr_scale_ = 1E-3F;
|
||||
// Default is 1;
|
||||
power_scale_ = 1;
|
||||
// Default is fJ.
|
||||
energy_scale_ = 1e-15;
|
||||
|
||||
library_->units()->timeUnit()->setScale(time_scale_);
|
||||
library_->units()->capacitanceUnit()->setScale(cap_scale_);
|
||||
|
|
@ -1720,7 +1740,11 @@ void
|
|||
LibertyReader::endCell(LibertyGroup *group)
|
||||
{
|
||||
if (cell_) {
|
||||
// Sequentials and leakage powers reference expressions outside of port definitions
|
||||
// so they do not require LibertyFunc's.
|
||||
makeCellSequentials();
|
||||
// Parse functions defined inside of port groups that reference other ports
|
||||
// and replace the references with the parsed expressions.
|
||||
parseCellFuncs();
|
||||
makeLeakagePowers();
|
||||
finishPortGroups();
|
||||
|
|
@ -2128,7 +2152,8 @@ TimingGroup::makeTableModels(LibertyReader *visitor)
|
|||
TableModel *constraint = constraint_[tr_index];
|
||||
TableModel *transition = transition_[tr_index];
|
||||
if (cell || transition) {
|
||||
models_[tr_index] = new GateTableModel(cell, transition);
|
||||
models_[tr_index] = new GateTableModel(cell, delay_sigma_[tr_index],
|
||||
transition, slew_sigma_[tr_index]);
|
||||
if (timing_type_ == timing_type_clear
|
||||
|| timing_type_ == timing_type_combinational
|
||||
|| timing_type_ == timing_type_combinational_fall
|
||||
|
|
@ -2142,11 +2167,10 @@ TimingGroup::makeTableModels(LibertyReader *visitor)
|
|||
|| timing_type_ == timing_type_three_state_enable
|
||||
|| timing_type_ == timing_type_three_state_enable_fall
|
||||
|| timing_type_ == timing_type_three_state_enable_rise) {
|
||||
const char *tr_name = tr == TransRiseFall::rise() ? "rise" : "fall";
|
||||
if (transition == NULL)
|
||||
visitor->libWarn(line_, "missing %s_transition.\n", tr_name);
|
||||
visitor->libWarn(line_, "missing %s_transition.\n", tr->name());
|
||||
if (cell == NULL)
|
||||
visitor->libWarn(line_, "missing cell_%s.\n", tr_name);
|
||||
visitor->libWarn(line_, "missing cell_%s.\n", tr->name());
|
||||
}
|
||||
}
|
||||
if (constraint)
|
||||
|
|
@ -2354,6 +2378,28 @@ LibertyReader::visitDontUse(LibertyAttr *attr)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitIsMacro(LibertyAttr *attr)
|
||||
{
|
||||
if (cell_) {
|
||||
bool is_macro, exists;
|
||||
getAttrBool(attr, is_macro, exists);
|
||||
if (exists)
|
||||
cell_->setIsMacro(is_macro);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitIsPad(LibertyAttr *attr)
|
||||
{
|
||||
if (cell_) {
|
||||
bool is_pad, exists;
|
||||
getAttrBool(attr, is_pad, exists);
|
||||
if (exists)
|
||||
cell_->setIsPad(is_pad);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitInterfaceTiming(LibertyAttr *attr)
|
||||
{
|
||||
|
|
@ -3705,6 +3751,7 @@ LibertyReader::beginTableModel(LibertyGroup *group,
|
|||
beginTable(group, scale);
|
||||
tr_ = tr;
|
||||
scale_factor_type_ = scale_factor_type;
|
||||
sigma_type_ = EarlyLateAll::all();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4248,6 +4295,20 @@ LibertyReader::parseFunc(const char *func,
|
|||
return parseFuncExpr(func, cell_, error_msg, report_);
|
||||
}
|
||||
|
||||
EarlyLateAll *
|
||||
LibertyReader::getAttrEarlyLate(LibertyAttr *attr)
|
||||
{
|
||||
const char *value = getAttrString(attr);
|
||||
if (stringEq(value, "early"))
|
||||
return EarlyLateAll::min();
|
||||
else if (stringEq(value, "late"))
|
||||
return EarlyLateAll::max();
|
||||
else {
|
||||
libWarn(attr, "unknown early/late value.\n");
|
||||
return EarlyLateAll::all();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
|
|
@ -4356,7 +4417,7 @@ void
|
|||
LibertyReader::beginFallPower(LibertyGroup *group)
|
||||
{
|
||||
if (internal_power_)
|
||||
beginTableModel(group, TransRiseFall::fall(), power_scale_,
|
||||
beginTableModel(group, TransRiseFall::fall(), energy_scale_,
|
||||
scale_factor_internal_power);
|
||||
}
|
||||
|
||||
|
|
@ -4364,7 +4425,7 @@ void
|
|||
LibertyReader::beginRisePower(LibertyGroup *group)
|
||||
{
|
||||
if (internal_power_)
|
||||
beginTableModel(group, TransRiseFall::rise(), power_scale_,
|
||||
beginTableModel(group, TransRiseFall::rise(), energy_scale_,
|
||||
scale_factor_internal_power);
|
||||
}
|
||||
|
||||
|
|
@ -4378,6 +4439,26 @@ LibertyReader::endRiseFallPower(LibertyGroup *)
|
|||
endTableModel();
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitRelatedPowerPin(LibertyAttr *attr)
|
||||
{
|
||||
if (ports_) {
|
||||
const char *related_power_pin = getAttrString(attr);
|
||||
LibertyPortSeq::Iterator port_iter(ports_);
|
||||
while (port_iter.hasNext()) {
|
||||
LibertyPort *port = port_iter.next();
|
||||
port->setRelatedPowerPin(stringCopy(related_power_pin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitRelatedPgPin(LibertyAttr *attr)
|
||||
{
|
||||
if (internal_power_)
|
||||
internal_power_->setRelatedPgPin(getAttrString(attr));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
|
|
@ -4438,7 +4519,7 @@ LibertyReader::beginOcvDerateFactors(LibertyGroup *group)
|
|||
{
|
||||
if (ocv_derate_) {
|
||||
rf_type_ = TransRiseFallBoth::riseFall();
|
||||
early_late_ = EarlyLateAll::all();
|
||||
derate_type_ = EarlyLateAll::all();
|
||||
path_type_ = path_type_clk_and_data;
|
||||
beginTable(group, 1.0);
|
||||
}
|
||||
|
|
@ -4448,7 +4529,7 @@ void
|
|||
LibertyReader::endOcvDerateFactors(LibertyGroup *)
|
||||
{
|
||||
if (ocv_derate_) {
|
||||
MinMaxIterator el_iter(early_late_);
|
||||
EarlyLateIterator el_iter(derate_type_);
|
||||
while (el_iter.hasNext()) {
|
||||
EarlyLate *early_late = el_iter.next();
|
||||
TransRiseFallIterator tr_iter(rf_type_);
|
||||
|
|
@ -4483,13 +4564,7 @@ LibertyReader::visitRfType(LibertyAttr *attr)
|
|||
void
|
||||
LibertyReader::visitDerateType(LibertyAttr *attr)
|
||||
{
|
||||
const char *derate_type = getAttrString(attr);
|
||||
if (stringEq(derate_type, "early"))
|
||||
early_late_ = EarlyLateAll::min();
|
||||
else if (stringEq(derate_type, "late"))
|
||||
early_late_ = EarlyLateAll::max();
|
||||
else
|
||||
libWarn(attr, "unknown derate type.\n");
|
||||
derate_type_ = getAttrEarlyLate(attr);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4508,6 +4583,92 @@ LibertyReader::visitPathType(LibertyAttr *attr)
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
LibertyReader::beginOcvSigmaCellRise(LibertyGroup *group)
|
||||
{
|
||||
beginTimingTableModel(group, TransRiseFall::rise(), scale_factor_unknown);
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::beginOcvSigmaCellFall(LibertyGroup *group)
|
||||
{
|
||||
beginTimingTableModel(group, TransRiseFall::fall(), scale_factor_unknown);
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::endOcvSigmaCell(LibertyGroup *group)
|
||||
{
|
||||
if (table_) {
|
||||
if (GateTableModel::checkAxes(table_)) {
|
||||
TableModel *table_model = new TableModel(table_, scale_factor_type_, tr_);
|
||||
if (sigma_type_ == EarlyLateAll::all()) {
|
||||
timing_->setDelaySigma(tr_, EarlyLate::min(), table_model);
|
||||
timing_->setDelaySigma(tr_, EarlyLate::max(), table_model);
|
||||
}
|
||||
else
|
||||
timing_->setDelaySigma(tr_, sigma_type_->asMinMax(), table_model);
|
||||
}
|
||||
else {
|
||||
libWarn(group, "unsupported model axis.\n");
|
||||
delete table_;
|
||||
}
|
||||
}
|
||||
endTableModel();
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::beginOcvSigmaRiseTransition(LibertyGroup *group)
|
||||
{
|
||||
beginTimingTableModel(group, TransRiseFall::rise(), scale_factor_unknown);
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::beginOcvSigmaFallTransition(LibertyGroup *group)
|
||||
{
|
||||
beginTimingTableModel(group, TransRiseFall::fall(), scale_factor_unknown);
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::endOcvSigmaTransition(LibertyGroup *group)
|
||||
{
|
||||
if (table_) {
|
||||
if (GateTableModel::checkAxes(table_)) {
|
||||
TableModel *table_model = new TableModel(table_, scale_factor_type_, tr_);
|
||||
if (sigma_type_ == EarlyLateAll::all()) {
|
||||
timing_->setSlewSigma(tr_, EarlyLate::min(), table_model);
|
||||
timing_->setSlewSigma(tr_, EarlyLate::max(), table_model);
|
||||
}
|
||||
else
|
||||
timing_->setSlewSigma(tr_, sigma_type_->asMinMax(), table_model);
|
||||
}
|
||||
else {
|
||||
libWarn(group, "unsupported model axis.\n");
|
||||
delete table_;
|
||||
}
|
||||
}
|
||||
endTableModel();
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitSigmaType(LibertyAttr *attr)
|
||||
{
|
||||
sigma_type_ = getAttrEarlyLate(attr);
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitCellLeakagePower(LibertyAttr *attr)
|
||||
{
|
||||
if (cell_) {
|
||||
float value;
|
||||
bool exists;
|
||||
getAttrFloat(attr, value, exists);
|
||||
if (exists)
|
||||
cell_->setLeakagePower(value * power_scale_);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
LibertyFunc::LibertyFunc(const char *expr,
|
||||
FuncExpr *&func_ref,
|
||||
bool invert,
|
||||
|
|
@ -4672,6 +4833,14 @@ TimingGroup::TimingGroup(int line) :
|
|||
intrinsic_exists_[tr_index] = false;
|
||||
resistance_[tr_index] = 0.0F;
|
||||
resistance_exists_[tr_index] = false;
|
||||
|
||||
MinMaxIterator el_iter;
|
||||
while (el_iter.hasNext()) {
|
||||
EarlyLate *early_late = el_iter.next();
|
||||
int el_index = early_late->index();
|
||||
delay_sigma_[tr_index][el_index] = NULL;
|
||||
slew_sigma_[tr_index][el_index] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4766,7 +4935,23 @@ TimingGroup::setTransition(TransRiseFall *tr,
|
|||
transition_[tr->index()] = model;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
void
|
||||
TimingGroup::setDelaySigma(TransRiseFall *tr,
|
||||
EarlyLate *early_late,
|
||||
TableModel *model)
|
||||
{
|
||||
delay_sigma_[tr->index()][early_late->index()] = model;
|
||||
}
|
||||
|
||||
void
|
||||
TimingGroup::setSlewSigma(TransRiseFall *tr,
|
||||
EarlyLate *early_late,
|
||||
TableModel *model)
|
||||
{
|
||||
slew_sigma_[tr->index()][early_late->index()] = model;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
InternalPowerGroup::InternalPowerGroup(int line) :
|
||||
InternalPowerAttrs(),
|
||||
|
|
|
|||
|
|
@ -175,8 +175,11 @@ public:
|
|||
virtual void visitClockGatingIntegratedCell(LibertyAttr *attr);
|
||||
virtual void visitArea(LibertyAttr *attr);
|
||||
virtual void visitDontUse(LibertyAttr *attr);
|
||||
void visitInterfaceTiming(LibertyAttr *attr);
|
||||
virtual void visitIsMacro(LibertyAttr *attr);
|
||||
virtual void visitIsPad(LibertyAttr *attr);
|
||||
virtual void visitInterfaceTiming(LibertyAttr *attr);
|
||||
virtual void visitScalingFactors(LibertyAttr *attr);
|
||||
virtual void visitCellLeakagePower(LibertyAttr *attr);
|
||||
|
||||
virtual void beginPin(LibertyGroup *group);
|
||||
virtual void endPin(LibertyGroup *group);
|
||||
|
|
@ -222,6 +225,7 @@ public:
|
|||
virtual void visitClockGateOutPin(LibertyAttr *attr);
|
||||
void visitIsPllFeedbackPin(LibertyAttr *attr);
|
||||
virtual void visitSignalType(LibertyAttr *attr);
|
||||
EarlyLateAll *getAttrEarlyLate(LibertyAttr *attr);
|
||||
virtual void visitClock(LibertyAttr *attr);
|
||||
|
||||
virtual void beginScalingFactors(LibertyGroup *group);
|
||||
|
|
@ -353,6 +357,8 @@ public:
|
|||
virtual void beginFallPower(LibertyGroup *group);
|
||||
virtual void beginRisePower(LibertyGroup *group);
|
||||
virtual void endRiseFallPower(LibertyGroup *group);
|
||||
virtual void visitRelatedPowerPin(LibertyAttr *attr);
|
||||
virtual void visitRelatedPgPin(LibertyAttr *attr);
|
||||
virtual void makeInternalPowers(LibertyPort *port,
|
||||
InternalPowerGroup *power_group);
|
||||
virtual void makeInternalPowers(LibertyPort *port,
|
||||
|
|
@ -372,6 +378,15 @@ public:
|
|||
virtual void visitDerateType(LibertyAttr *attr);
|
||||
virtual void visitPathType(LibertyAttr *attr);
|
||||
|
||||
// POCV attributes.
|
||||
virtual void beginOcvSigmaCellRise(LibertyGroup *group);
|
||||
virtual void beginOcvSigmaCellFall(LibertyGroup *group);
|
||||
virtual void endOcvSigmaCell(LibertyGroup *group);
|
||||
virtual void beginOcvSigmaRiseTransition(LibertyGroup *group);
|
||||
virtual void beginOcvSigmaFallTransition(LibertyGroup *group);
|
||||
virtual void endOcvSigmaTransition(LibertyGroup *group);
|
||||
virtual void visitSigmaType(LibertyAttr *attr);
|
||||
|
||||
// Visitors for derived classes to overload.
|
||||
virtual void beginGroup1(LibertyGroup *) {}
|
||||
virtual void beginGroup2(LibertyGroup *) {}
|
||||
|
|
@ -513,7 +528,8 @@ protected:
|
|||
TransRiseFall *tr_;
|
||||
OcvDerate *ocv_derate_;
|
||||
TransRiseFallBoth *rf_type_;
|
||||
EarlyLateAll *early_late_;
|
||||
EarlyLateAll *derate_type_;
|
||||
EarlyLateAll *sigma_type_;
|
||||
PathType path_type_;
|
||||
ScaleFactorType scale_factor_type_;
|
||||
TableAxis *axis_[3];
|
||||
|
|
@ -529,6 +545,7 @@ protected:
|
|||
float volt_scale_;
|
||||
float curr_scale_;
|
||||
float power_scale_;
|
||||
float energy_scale_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(LibertyReader);
|
||||
|
|
@ -688,6 +705,12 @@ public:
|
|||
TableModel *model);
|
||||
void makeTimingModels(LibertyLibrary *library,
|
||||
LibertyReader *visitor);
|
||||
void setDelaySigma(TransRiseFall *tr,
|
||||
EarlyLate *early_late,
|
||||
TableModel *model);
|
||||
void setSlewSigma(TransRiseFall *tr,
|
||||
EarlyLate *early_late,
|
||||
TableModel *model);
|
||||
|
||||
protected:
|
||||
void makeLinearModels(LibertyLibrary *library);
|
||||
|
|
@ -701,6 +724,8 @@ protected:
|
|||
TableModel *cell_[TransRiseFall::index_count];
|
||||
TableModel *constraint_[TransRiseFall::index_count];
|
||||
TableModel *transition_[TransRiseFall::index_count];
|
||||
TableModel *delay_sigma_[TransRiseFall::index_count][EarlyLate::index_count];
|
||||
TableModel *slew_sigma_[TransRiseFall::index_count][EarlyLate::index_count];
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(TimingGroup);
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ GateLinearModel::gateDelay(const LibertyCell *,
|
|||
float load_cap,
|
||||
float,
|
||||
// return values
|
||||
float &gate_delay,
|
||||
float &drvr_slew) const
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) const
|
||||
{
|
||||
gate_delay = intrinsic_ + resistance_ * load_cap;
|
||||
drvr_slew = 0.0;
|
||||
|
|
@ -84,14 +84,15 @@ CheckLinearModel::CheckLinearModel(float intrinsic) :
|
|||
{
|
||||
}
|
||||
|
||||
float
|
||||
void
|
||||
CheckLinearModel::checkDelay(const LibertyCell *,
|
||||
const Pvt *,
|
||||
float,
|
||||
float,
|
||||
float) const
|
||||
float,
|
||||
ArcDelay &margin) const
|
||||
{
|
||||
return intrinsic_;
|
||||
margin = intrinsic_;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ public:
|
|||
float load_cap, float in_slew,
|
||||
float related_out_cap,
|
||||
// return values
|
||||
float &gate_delay, float &drvr_slew) const;
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) const;
|
||||
virtual void reportGateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float load_cap, float in_slew,
|
||||
|
|
@ -56,10 +57,11 @@ class CheckLinearModel : public CheckTimingModel
|
|||
public:
|
||||
explicit CheckLinearModel(float intrinsic);
|
||||
// Timing check margin delay calculation.
|
||||
virtual float checkDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float from_slew, float to_slew,
|
||||
float related_out_cap) const;
|
||||
virtual void checkDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float from_slew, float to_slew,
|
||||
float related_out_cap,
|
||||
ArcDelay &margin) const;
|
||||
virtual void reportCheckDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float from_slew,
|
||||
|
|
|
|||
|
|
@ -23,21 +23,43 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
static void
|
||||
reportPvt(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
int digits,
|
||||
string *result);
|
||||
static void
|
||||
appendSpaces(string *result,
|
||||
int count);
|
||||
|
||||
GateTableModel::GateTableModel(TableModel *delay_model,
|
||||
TableModel *slew_model):
|
||||
TableModel *delay_sigma_models[EarlyLate::index_count],
|
||||
TableModel *slew_model,
|
||||
TableModel *slew_sigma_models[EarlyLate::index_count]) :
|
||||
delay_model_(delay_model),
|
||||
slew_model_(slew_model)
|
||||
{
|
||||
MinMaxIterator el_iter;
|
||||
while (el_iter.hasNext()) {
|
||||
EarlyLate *early_late = el_iter.next();
|
||||
int el_index = early_late->index();
|
||||
slew_sigma_models_[el_index] = slew_sigma_models[el_index];
|
||||
delay_sigma_models_[el_index] = delay_sigma_models[el_index];
|
||||
}
|
||||
}
|
||||
|
||||
GateTableModel::~GateTableModel()
|
||||
{
|
||||
delete delay_model_;
|
||||
delete slew_model_;
|
||||
MinMaxIterator el_iter;
|
||||
while (el_iter.hasNext()) {
|
||||
EarlyLate *early_late = el_iter.next();
|
||||
int el_index = early_late->index();
|
||||
delete slew_sigma_models_[el_index];
|
||||
delete delay_sigma_models_[el_index];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -56,29 +78,40 @@ GateTableModel::gateDelay(const LibertyCell *cell,
|
|||
float load_cap,
|
||||
float related_out_cap,
|
||||
// return values
|
||||
float &gate_delay,
|
||||
float &drvr_slew) const
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) const
|
||||
{
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
gate_delay = findValue(library, cell, pvt, delay_model_, in_slew,
|
||||
load_cap, related_out_cap);
|
||||
drvr_slew = findValue(library, cell, pvt, slew_model_, in_slew,
|
||||
load_cap, related_out_cap);
|
||||
// Clip negative slews to zero.
|
||||
if (drvr_slew < 0.0)
|
||||
drvr_slew = 0.0;
|
||||
}
|
||||
float delay = findValue(library, cell, pvt, delay_model_, in_slew,
|
||||
load_cap, related_out_cap);
|
||||
float sigma_early = 0.0;
|
||||
float sigma_late = 0.0;
|
||||
if (delay_sigma_models_[EarlyLate::earlyIndex()])
|
||||
sigma_early = findValue(library, cell, pvt,
|
||||
delay_sigma_models_[EarlyLate::earlyIndex()],
|
||||
in_slew, load_cap, related_out_cap);
|
||||
if (delay_sigma_models_[EarlyLate::lateIndex()])
|
||||
sigma_late = findValue(library, cell, pvt,
|
||||
delay_sigma_models_[EarlyLate::earlyIndex()],
|
||||
in_slew, load_cap, related_out_cap);
|
||||
gate_delay = makeDelay(delay, sigma_early, sigma_late);
|
||||
|
||||
float
|
||||
GateTableModel::gateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap) const
|
||||
{
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
return findValue(library, cell, pvt, delay_model_, in_slew,
|
||||
load_cap, related_out_cap);
|
||||
float slew = findValue(library, cell, pvt, slew_model_, in_slew,
|
||||
load_cap, related_out_cap);
|
||||
if (slew_sigma_models_[EarlyLate::earlyIndex()])
|
||||
sigma_early = findValue(library, cell, pvt,
|
||||
slew_sigma_models_[EarlyLate::earlyIndex()],
|
||||
in_slew, load_cap, related_out_cap);
|
||||
if (slew_sigma_models_[EarlyLate::lateIndex()])
|
||||
sigma_late = findValue(library, cell, pvt,
|
||||
slew_sigma_models_[EarlyLate::earlyIndex()],
|
||||
in_slew, load_cap, related_out_cap);
|
||||
sigma_early = 0.0;
|
||||
sigma_late = 0.0;
|
||||
// Clip negative slews to zero.
|
||||
if (slew < 0.0)
|
||||
slew = 0.0;
|
||||
drvr_slew = makeDelay(slew, sigma_early, sigma_late);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -91,11 +124,28 @@ GateTableModel::reportGateDelay(const LibertyCell *cell,
|
|||
string *result) const
|
||||
{
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
reportPvt(library, cell, pvt, digits, result);
|
||||
reportTableLookup("Delay", library, cell, pvt, delay_model_, in_slew,
|
||||
load_cap, related_out_cap, digits, result);
|
||||
if (delay_sigma_models_[EarlyLate::earlyIndex()])
|
||||
reportTableLookup("Delay sigma(early)", library, cell, pvt,
|
||||
delay_sigma_models_[EarlyLate::earlyIndex()],
|
||||
in_slew, load_cap, related_out_cap, digits, result);
|
||||
if (delay_sigma_models_[EarlyLate::lateIndex()])
|
||||
reportTableLookup("Delay sigma(late)", library, cell, pvt,
|
||||
delay_sigma_models_[EarlyLate::lateIndex()],
|
||||
in_slew, load_cap, related_out_cap, digits, result);
|
||||
*result += '\n';
|
||||
reportTableLookup("Slew", library, cell, pvt, slew_model_, in_slew,
|
||||
load_cap, related_out_cap, digits, result);
|
||||
if (slew_sigma_models_[EarlyLate::earlyIndex()])
|
||||
reportTableLookup("Slew sigma(early)", library, cell, pvt,
|
||||
slew_sigma_models_[EarlyLate::earlyIndex()],
|
||||
in_slew, load_cap, related_out_cap, digits, result);
|
||||
if (slew_sigma_models_[EarlyLate::lateIndex()])
|
||||
reportTableLookup("Slew sigma(late)", library, cell, pvt,
|
||||
slew_sigma_models_[EarlyLate::lateIndex()],
|
||||
in_slew, load_cap, related_out_cap, digits, result);
|
||||
float drvr_slew = findValue(library, cell, pvt, slew_model_, in_slew,
|
||||
load_cap, related_out_cap);
|
||||
if (drvr_slew < 0.0)
|
||||
|
|
@ -300,23 +350,25 @@ CheckTableModel::setIsScaled(bool is_scaled)
|
|||
model_->setIsScaled(is_scaled);
|
||||
}
|
||||
|
||||
float
|
||||
void
|
||||
CheckTableModel::checkDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float from_slew,
|
||||
float to_slew,
|
||||
float related_out_cap) const
|
||||
float related_out_cap,
|
||||
// Return values.
|
||||
ArcDelay &margin) const
|
||||
{
|
||||
if (model_) {
|
||||
float axis_value1, axis_value2, axis_value3;
|
||||
findAxisValues(from_slew, to_slew, related_out_cap,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
return model_->findValue(library, cell, pvt,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
margin = model_->findValue(library, cell, pvt,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
}
|
||||
else
|
||||
return 0.0;
|
||||
margin = 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -334,6 +386,7 @@ CheckTableModel::reportCheckDelay(const LibertyCell *cell,
|
|||
findAxisValues(from_slew, to_slew, related_out_cap,
|
||||
axis_value1, axis_value2, axis_value3);
|
||||
const LibertyLibrary *library = cell->libertyLibrary();
|
||||
reportPvt(library, cell, pvt, digits, result);
|
||||
model_->reportValue("Check", library, cell, pvt,
|
||||
axis_value1, from_slew_annotation, axis_value2,
|
||||
axis_value3, digits, result);
|
||||
|
|
@ -531,12 +584,12 @@ TableModel::reportValue(const char *result_name,
|
|||
*result += '\n';
|
||||
}
|
||||
|
||||
void
|
||||
TableModel::reportPvtScaleFactor(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
int digits,
|
||||
string *result) const
|
||||
static void
|
||||
reportPvt(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
int digits,
|
||||
string *result)
|
||||
{
|
||||
if (pvt == NULL)
|
||||
pvt = library->defaultOperatingConditions();
|
||||
|
|
@ -550,13 +603,26 @@ TableModel::reportPvtScaleFactor(const LibertyLibrary *library,
|
|||
*result += pvt_str;
|
||||
stringDelete(pvt_str);
|
||||
}
|
||||
const char *scale_str = stringPrint(strlen("PVT scale factor = %.*f\n")
|
||||
+ digits + 10 + 1,
|
||||
"PVT scale factor = %.*f\n",
|
||||
digits,
|
||||
scaleFactor(library, cell, pvt));
|
||||
*result += scale_str;
|
||||
stringDelete(scale_str);
|
||||
}
|
||||
|
||||
void
|
||||
TableModel::reportPvtScaleFactor(const LibertyLibrary *library,
|
||||
const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
int digits,
|
||||
string *result) const
|
||||
{
|
||||
if (pvt == NULL)
|
||||
pvt = library->defaultOperatingConditions();
|
||||
if (pvt) {
|
||||
const char *scale_str = stringPrint(strlen("PVT scale factor = %.*f\n")
|
||||
+ digits + 10 + 1,
|
||||
"PVT scale factor = %.*f\n",
|
||||
digits,
|
||||
scaleFactor(library, cell, pvt));
|
||||
*result += scale_str;
|
||||
stringDelete(scale_str);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <string>
|
||||
#include "DisallowCopyAssign.hh"
|
||||
#include "MinMax.hh"
|
||||
#include "Vector.hh"
|
||||
#include "Transition.hh"
|
||||
#include "LibertyClass.hh"
|
||||
|
|
@ -45,21 +46,18 @@ class GateTableModel : public GateTimingModel
|
|||
{
|
||||
public:
|
||||
GateTableModel(TableModel *delay_model,
|
||||
TableModel *slew_model);
|
||||
TableModel *delay_sigma_models[EarlyLate::index_count],
|
||||
TableModel *slew_model,
|
||||
TableModel *slew_sigma_models[EarlyLate::index_count]);
|
||||
virtual ~GateTableModel();
|
||||
virtual void gateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap,
|
||||
// return values
|
||||
float &gate_delay,
|
||||
float &drvr_slew) const;
|
||||
float gateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float in_slew,
|
||||
float load_cap,
|
||||
float related_out_cap) const;
|
||||
// Return values.
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) const;
|
||||
virtual void reportGateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float in_slew,
|
||||
|
|
@ -115,7 +113,9 @@ protected:
|
|||
static bool checkAxis(TableAxis *axis);
|
||||
|
||||
TableModel *delay_model_;
|
||||
TableModel *delay_sigma_models_[EarlyLate::index_count];
|
||||
TableModel *slew_model_;
|
||||
TableModel *slew_sigma_models_[EarlyLate::index_count];
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(GateTableModel);
|
||||
|
|
@ -126,11 +126,13 @@ class CheckTableModel : public CheckTimingModel
|
|||
public:
|
||||
explicit CheckTableModel(TableModel *model);
|
||||
virtual ~CheckTableModel();
|
||||
virtual float checkDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float from_slew,
|
||||
float to_slew,
|
||||
float related_out_cap) const;
|
||||
virtual void checkDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float from_slew,
|
||||
float to_slew,
|
||||
float related_out_cap,
|
||||
// Return values.
|
||||
ArcDelay &margin) const;
|
||||
virtual void reportCheckDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float from_slew,
|
||||
|
|
|
|||
|
|
@ -40,29 +40,19 @@ TimingArcAttrs::TimingArcAttrs() :
|
|||
sdf_cond_end_(NULL),
|
||||
mode_name_(NULL),
|
||||
mode_value_(NULL),
|
||||
ocv_arc_depth_(0.0)
|
||||
ocv_arc_depth_(0.0),
|
||||
models_{NULL, NULL},
|
||||
model_refs_{false, false}
|
||||
{
|
||||
TransRiseFallIterator tr_iter;
|
||||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *tr = tr_iter.next();
|
||||
int tr_index = tr->index();
|
||||
models_[tr_index] = NULL;
|
||||
model_refs_[tr_index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
TimingArcAttrs::~TimingArcAttrs()
|
||||
{
|
||||
if (sdf_cond_)
|
||||
stringDelete(sdf_cond_);
|
||||
if (sdf_cond_start_)
|
||||
stringDelete(sdf_cond_start_);
|
||||
if (sdf_cond_end_)
|
||||
stringDelete(sdf_cond_end_);
|
||||
if (mode_name_)
|
||||
stringDelete(mode_name_);
|
||||
if (mode_value_)
|
||||
stringDelete(mode_value_);
|
||||
stringDelete(sdf_cond_);
|
||||
stringDelete(sdf_cond_start_);
|
||||
stringDelete(sdf_cond_end_);
|
||||
stringDelete(mode_name_);
|
||||
stringDelete(mode_value_);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -162,8 +152,9 @@ TimingArcSet::TimingArcSet(LibertyCell *cell,
|
|||
is_cond_default_(false),
|
||||
sdf_cond_start_(NULL),
|
||||
sdf_cond_end_(NULL),
|
||||
mode_name_(NULL),
|
||||
mode_value_(NULL),
|
||||
mode_name_(stringCopy(attrs->modeName())),
|
||||
mode_value_(stringCopy(attrs->modeValue())),
|
||||
ocv_arc_depth_(attrs->ocvArcDepth()),
|
||||
index_(0),
|
||||
is_disabled_constraint_(false)
|
||||
{
|
||||
|
|
@ -177,14 +168,6 @@ TimingArcSet::TimingArcSet(LibertyCell *cell,
|
|||
if (sdf_cond_end)
|
||||
sdf_cond_end_ = stringCopy(sdf_cond_end);
|
||||
|
||||
const char *mode_name = attrs->modeName();
|
||||
if (mode_name)
|
||||
mode_name_ = stringCopy(mode_name);
|
||||
const char *mode_value = attrs->modeValue();
|
||||
if (mode_value)
|
||||
mode_value_ = stringCopy(mode_value);
|
||||
ocv_arc_depth_ = attrs->ocvArcDepth();
|
||||
|
||||
init(cell);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,9 +128,9 @@ protected:
|
|||
const char *sdf_cond_end_;
|
||||
const char *mode_name_;
|
||||
const char *mode_value_;
|
||||
float ocv_arc_depth_;
|
||||
TimingModel *models_[TransRiseFall::index_count];
|
||||
bool model_refs_[TransRiseFall::index_count];
|
||||
float ocv_arc_depth_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(TimingArcAttrs);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#define STA_TIMING_MODEL_H
|
||||
|
||||
#include <string>
|
||||
#include "Delay.hh"
|
||||
#include "LibertyClass.hh"
|
||||
|
||||
namespace sta {
|
||||
|
|
@ -47,8 +48,8 @@ public:
|
|||
float load_cap,
|
||||
float related_out_cap,
|
||||
// Return values.
|
||||
float &gate_delay,
|
||||
float &drvr_slew) const = 0;
|
||||
ArcDelay &gate_delay,
|
||||
Slew &drvr_slew) const = 0;
|
||||
virtual void reportGateDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float in_slew,
|
||||
|
|
@ -65,11 +66,13 @@ class CheckTimingModel : public TimingModel
|
|||
{
|
||||
public:
|
||||
// Timing check margin delay calculation.
|
||||
virtual float checkDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float from_slew,
|
||||
float to_slew,
|
||||
float related_out_cap) const = 0;
|
||||
virtual void checkDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float from_slew,
|
||||
float to_slew,
|
||||
float related_out_cap,
|
||||
// Return values.
|
||||
ArcDelay &margin) const = 0;
|
||||
virtual void reportCheckDelay(const LibertyCell *cell,
|
||||
const Pvt *pvt,
|
||||
float from_slew,
|
||||
|
|
|
|||
|
|
@ -76,6 +76,12 @@ Unit::setDigits(int digits)
|
|||
digits_ = digits;
|
||||
}
|
||||
|
||||
int
|
||||
Unit::width() const
|
||||
{
|
||||
return digits_ + (suffix_ ? strlen(suffix_) : 0) + 2;
|
||||
}
|
||||
|
||||
const char *
|
||||
Unit::asString(float value) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ public:
|
|||
void setSuffix(const char *suffix);
|
||||
int digits() const { return digits_; }
|
||||
void setDigits(int digits);
|
||||
int width() const;
|
||||
const char *asString(float value) const;
|
||||
const char *asString(double value) const;
|
||||
const char *asString(float value,
|
||||
|
|
|
|||
|
|
@ -697,8 +697,9 @@ ConcreteCouplingCapExtPin::replaceNode(ConcreteParasiticNode *from_node,
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
ConcreteParasiticNetwork::ConcreteParasiticNetwork() :
|
||||
max_node_id_(0)
|
||||
ConcreteParasiticNetwork::ConcreteParasiticNetwork(bool includes_pin_caps) :
|
||||
max_node_id_(0),
|
||||
includes_pin_caps_(includes_pin_caps)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -783,7 +784,7 @@ ConcreteParasiticNetwork::ensureParasiticNode(Net *net,
|
|||
if (node == NULL) {
|
||||
node = new ConcreteParasiticSubNode(net, id);
|
||||
sub_nodes_[new NetId(net, id)] = node;
|
||||
max_node_id_ = max(max_node_id_, id);
|
||||
max_node_id_ = max((int) max_node_id_, id);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
|
@ -1653,6 +1654,7 @@ ConcreteParasitics::findParasiticNetwork(const Pin *pin,
|
|||
|
||||
Parasitic *
|
||||
ConcreteParasitics::makeParasiticNetwork(Net *net,
|
||||
bool includes_pin_caps,
|
||||
const ParasiticAnalysisPt *ap)
|
||||
{
|
||||
int ap_index = parasiticNetworkAnalysisPtIndex(ap);
|
||||
|
|
@ -1674,7 +1676,7 @@ ConcreteParasitics::makeParasiticNetwork(Net *net,
|
|||
ConcreteParasiticNetwork *parasitic =
|
||||
(*parasitic_network_maps_)[ap_index]->findKey(net);
|
||||
if (parasitic == NULL) {
|
||||
parasitic = new ConcreteParasiticNetwork;
|
||||
parasitic = new ConcreteParasiticNetwork(includes_pin_caps);
|
||||
(*(*parasitic_network_maps_)[ap_index])[net] = parasitic;
|
||||
}
|
||||
lock_.unlock();
|
||||
|
|
@ -1698,6 +1700,14 @@ ConcreteParasitics::deleteParasiticNetwork(const Net *net,
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ConcreteParasitics::includesPinCaps(Parasitic *parasitic) const
|
||||
{
|
||||
ConcreteParasiticNetwork *cparasitic =
|
||||
static_cast<ConcreteParasiticNetwork*>(parasitic);
|
||||
return cparasitic->includesPinCaps();
|
||||
}
|
||||
|
||||
ParasiticNode *
|
||||
ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic,
|
||||
Net *net,
|
||||
|
|
@ -1970,7 +1980,8 @@ ConcreteParasitics::reduceToPiPoleResidue2(Parasitic *parasitic,
|
|||
const MinMax *cnst_min_max,
|
||||
const ParasiticAnalysisPt *ap)
|
||||
{
|
||||
return sta::reduceToPiPoleResidue2(parasitic, drvr_pin,ap->couplingCapFactor(),
|
||||
return sta::reduceToPiPoleResidue2(parasitic, drvr_pin,
|
||||
ap->couplingCapFactor(),
|
||||
tr, op_cond, corner, cnst_min_max,
|
||||
ap, this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,9 +136,11 @@ public:
|
|||
virtual Parasitic *findParasiticNetwork(const Pin *pin,
|
||||
const ParasiticAnalysisPt *ap) const;
|
||||
virtual Parasitic *makeParasiticNetwork(Net *net,
|
||||
bool includes_pin_caps,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
virtual void deleteParasiticNetwork(const Net *net,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
virtual bool includesPinCaps(Parasitic *parasitic) const;
|
||||
virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, Net *net,
|
||||
int id);
|
||||
virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic,
|
||||
|
|
@ -194,7 +196,8 @@ public:
|
|||
const Corner *corner,
|
||||
const MinMax *cnst_min_max,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
virtual void reduceToPiElmore(Parasitic *parasitic, const Net *net,
|
||||
virtual void reduceToPiElmore(Parasitic *parasitic,
|
||||
const Net *net,
|
||||
const TransRiseFall *tr,
|
||||
const OperatingConditions *op_cond,
|
||||
const Corner *corner,
|
||||
|
|
@ -207,7 +210,8 @@ public:
|
|||
const Corner *corner,
|
||||
const MinMax *cnst_min_max,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
virtual void reduceToPiPoleResidue2(Parasitic *parasitic, const Net *net,
|
||||
virtual void reduceToPiPoleResidue2(Parasitic *parasitic,
|
||||
const Net *net,
|
||||
const TransRiseFall *tr,
|
||||
const OperatingConditions *op_cond,
|
||||
const Corner *corner,
|
||||
|
|
|
|||
|
|
@ -403,9 +403,10 @@ class ConcreteParasiticNetwork : public ParasiticNetwork,
|
|||
public ConcreteParasitic
|
||||
{
|
||||
public:
|
||||
ConcreteParasiticNetwork();
|
||||
ConcreteParasiticNetwork(bool includes_pin_caps);
|
||||
virtual ~ConcreteParasiticNetwork();
|
||||
virtual bool isParasiticNetwork() const { return true; }
|
||||
bool includesPinCaps() const { return includes_pin_caps_; }
|
||||
ConcreteParasiticNode *ensureParasiticNode(Net *net,
|
||||
int id);
|
||||
ConcreteParasiticNode *findNode(const Pin *pin);
|
||||
|
|
@ -422,7 +423,8 @@ private:
|
|||
|
||||
ConcreteParasiticSubNodeMap sub_nodes_;
|
||||
ConcreteParasiticPinNodeMap pin_nodes_;
|
||||
int max_node_id_;
|
||||
unsigned max_node_id_:31;
|
||||
bool includes_pin_caps_:1;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ NullParasitics::deleteParasitics()
|
|||
}
|
||||
|
||||
void
|
||||
NullParasitics::deleteParasitics(const Net *, const ParasiticAnalysisPt *)
|
||||
NullParasitics::deleteParasitics(const Net *,
|
||||
const ParasiticAnalysisPt *)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +70,8 @@ NullParasitics::capacitance(Parasitic *) const
|
|||
}
|
||||
|
||||
bool
|
||||
NullParasitics::hasLumpedElmore(const Pin *, const TransRiseFall *,
|
||||
NullParasitics::hasLumpedElmore(const Pin *,
|
||||
const TransRiseFall *,
|
||||
const ParasiticAnalysisPt *) const
|
||||
{
|
||||
return false;
|
||||
|
|
@ -90,7 +92,8 @@ NullParasitics::isLumpedElmore(Parasitic *) const
|
|||
}
|
||||
|
||||
Parasitic *
|
||||
NullParasitics::makeLumpedElmore(const Pin *, float,
|
||||
NullParasitics::makeLumpedElmore(const Pin *,
|
||||
float,
|
||||
const TransRiseFall *,
|
||||
const ParasiticAnalysisPt *)
|
||||
{
|
||||
|
|
@ -124,7 +127,9 @@ Parasitic *
|
|||
NullParasitics::makePiElmore(const Pin *,
|
||||
const TransRiseFall *,
|
||||
const ParasiticAnalysisPt *,
|
||||
float, float, float)
|
||||
float,
|
||||
float,
|
||||
float)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -135,7 +140,8 @@ NullParasitics::deletePiElmore(const Pin *)
|
|||
}
|
||||
|
||||
void
|
||||
NullParasitics::deletePiElmore(const Pin *, const TransRiseFall *,
|
||||
NullParasitics::deletePiElmore(const Pin *,
|
||||
const TransRiseFall *,
|
||||
const ParasiticAnalysisPt *)
|
||||
{
|
||||
}
|
||||
|
|
@ -153,28 +159,39 @@ NullParasitics::isReducedParasiticNetwork(Parasitic *) const
|
|||
}
|
||||
|
||||
void
|
||||
NullParasitics::setIsReducedParasiticNetwork(Parasitic *, bool)
|
||||
NullParasitics::setIsReducedParasiticNetwork(Parasitic *,
|
||||
bool)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NullParasitics::piModel(Parasitic *, float &, float &, float &) const
|
||||
NullParasitics::piModel(Parasitic *,
|
||||
float &,
|
||||
float &,
|
||||
float &) const
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NullParasitics::setPiModel(Parasitic *, float, float, float)
|
||||
NullParasitics::setPiModel(Parasitic *,
|
||||
float,
|
||||
float,
|
||||
float)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NullParasitics::findElmore(Parasitic *, const Pin *,
|
||||
float &, bool &) const
|
||||
NullParasitics::findElmore(Parasitic *,
|
||||
const Pin *,
|
||||
float &,
|
||||
bool &) const
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NullParasitics::setElmore(Parasitic *, const Pin *, float)
|
||||
NullParasitics::setElmore(Parasitic *,
|
||||
const Pin *,
|
||||
float)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +227,9 @@ Parasitic *
|
|||
NullParasitics::makePiPoleResidue(const Pin *,
|
||||
const TransRiseFall *,
|
||||
const ParasiticAnalysisPt *,
|
||||
float, float, float)
|
||||
float,
|
||||
float,
|
||||
float)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -223,8 +242,10 @@ NullParasitics::findPoleResidue(const Parasitic *,
|
|||
}
|
||||
|
||||
void
|
||||
NullParasitics::setPoleResidue(Parasitic *, const Pin *,
|
||||
ComplexFloatSeq *, ComplexFloatSeq *)
|
||||
NullParasitics::setPoleResidue(Parasitic *,
|
||||
const Pin *,
|
||||
ComplexFloatSeq *,
|
||||
ComplexFloatSeq *)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -241,8 +262,10 @@ NullParasitics::poleResidueCount(const Parasitic *) const
|
|||
}
|
||||
|
||||
void
|
||||
NullParasitics::poleResidue(const Parasitic *, int,
|
||||
ComplexFloat &, ComplexFloat &) const
|
||||
NullParasitics::poleResidue(const Parasitic *,
|
||||
int,
|
||||
ComplexFloat &,
|
||||
ComplexFloat &) const
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -267,11 +290,19 @@ NullParasitics::isParasiticNetwork(Parasitic *) const
|
|||
}
|
||||
|
||||
Parasitic *
|
||||
NullParasitics::makeParasiticNetwork(Net *, const ParasiticAnalysisPt *)
|
||||
NullParasitics::makeParasiticNetwork(Net *,
|
||||
bool,
|
||||
const ParasiticAnalysisPt *)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
NullParasitics::includesPinCaps(Parasitic *) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
NullParasitics::deleteParasiticNetwork(const Net *,
|
||||
const ParasiticAnalysisPt *)
|
||||
|
|
@ -279,44 +310,59 @@ NullParasitics::deleteParasiticNetwork(const Net *,
|
|||
}
|
||||
|
||||
ParasiticNode *
|
||||
NullParasitics::ensureParasiticNode(Parasitic *, Net *, int)
|
||||
NullParasitics::ensureParasiticNode(Parasitic *,
|
||||
Net *,
|
||||
int)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ParasiticNode *
|
||||
NullParasitics::ensureParasiticNode(Parasitic *, const Pin *)
|
||||
NullParasitics::ensureParasiticNode(Parasitic *,
|
||||
const Pin *)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
NullParasitics::incrCap(ParasiticNode *, float,
|
||||
NullParasitics::incrCap(ParasiticNode *,
|
||||
float,
|
||||
const ParasiticAnalysisPt *)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NullParasitics::makeCouplingCap(const char *, ParasiticNode *,
|
||||
ParasiticNode *, float,
|
||||
NullParasitics::makeCouplingCap(const char *,
|
||||
ParasiticNode *,
|
||||
ParasiticNode *,
|
||||
float,
|
||||
const ParasiticAnalysisPt *)
|
||||
{
|
||||
}
|
||||
|
||||
void NullParasitics::makeCouplingCap(const char *, ParasiticNode *, Net *,
|
||||
int, float, const ParasiticAnalysisPt *)
|
||||
void NullParasitics::makeCouplingCap(const char *,
|
||||
ParasiticNode *,
|
||||
Net *,
|
||||
int,
|
||||
float,
|
||||
const ParasiticAnalysisPt *)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NullParasitics::makeCouplingCap(const char *, ParasiticNode *, Pin *,
|
||||
float, const ParasiticAnalysisPt *)
|
||||
NullParasitics::makeCouplingCap(const char *,
|
||||
ParasiticNode *,
|
||||
Pin *,
|
||||
float,
|
||||
const ParasiticAnalysisPt *)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
NullParasitics::makeResistor(const char *, ParasiticNode *,
|
||||
ParasiticNode *, float,
|
||||
NullParasitics::makeResistor(const char *,
|
||||
ParasiticNode *,
|
||||
ParasiticNode *,
|
||||
float,
|
||||
const ParasiticAnalysisPt *)
|
||||
{
|
||||
}
|
||||
|
|
@ -334,7 +380,8 @@ NullParasitics::connectionPin(const ParasiticNode *) const
|
|||
}
|
||||
|
||||
ParasiticNode *
|
||||
NullParasitics::findNode(Parasitic *, const Pin *) const
|
||||
NullParasitics::findNode(Parasitic *,
|
||||
const Pin *) const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -378,13 +425,15 @@ NullParasitics::value(const ParasiticDevice *,
|
|||
}
|
||||
|
||||
ParasiticNode *
|
||||
NullParasitics::otherNode(const ParasiticDevice *, ParasiticNode *) const
|
||||
NullParasitics::otherNode(const ParasiticDevice *,
|
||||
ParasiticNode *) const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
NullParasitics::reduceTo(Parasitic *, const Net *,
|
||||
NullParasitics::reduceTo(Parasitic *,
|
||||
const Net *,
|
||||
ReduceParasiticsTo ,
|
||||
const TransRiseFall *,
|
||||
const OperatingConditions *,
|
||||
|
|
@ -395,7 +444,8 @@ NullParasitics::reduceTo(Parasitic *, const Net *,
|
|||
}
|
||||
|
||||
void
|
||||
NullParasitics::reduceToPiElmore(Parasitic *, const Net *,
|
||||
NullParasitics::reduceToPiElmore(Parasitic *,
|
||||
const Net *,
|
||||
const TransRiseFall *,
|
||||
const OperatingConditions *,
|
||||
const Corner *,
|
||||
|
|
@ -418,11 +468,11 @@ NullParasitics::reduceToPiElmore(Parasitic *,
|
|||
|
||||
void
|
||||
NullParasitics::reduceToPiPoleResidue2(Parasitic *, const Net *,
|
||||
const TransRiseFall *,
|
||||
const OperatingConditions *,
|
||||
const TransRiseFall *,
|
||||
const OperatingConditions *,
|
||||
const Corner *,
|
||||
const MinMax *,
|
||||
const ParasiticAnalysisPt *)
|
||||
const MinMax *,
|
||||
const ParasiticAnalysisPt *)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -124,7 +124,9 @@ public:
|
|||
virtual bool isParasiticNetwork(Parasitic *parasitic) const;
|
||||
virtual Parasitic *
|
||||
makeParasiticNetwork(Net *net,
|
||||
bool pin_cap_included,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
virtual bool includesPinCaps(Parasitic *parasitic) const;
|
||||
virtual void deleteParasiticNetwork(const Net *net,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic,
|
||||
|
|
@ -165,14 +167,16 @@ public:
|
|||
virtual ParasiticNode *otherNode(const ParasiticDevice *device,
|
||||
ParasiticNode *node) const;
|
||||
// Reduce parasitic network to reduce_to model.
|
||||
virtual void reduceTo(Parasitic *parasitic, const Net *net,
|
||||
virtual void reduceTo(Parasitic *parasitic,
|
||||
const Net *net,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
const TransRiseFall *tr,
|
||||
const OperatingConditions *op_cond,
|
||||
const Corner *corner,
|
||||
const MinMax *cnst_min_max,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
virtual void reduceToPiElmore(Parasitic *parasitic, const Net *net,
|
||||
virtual void reduceToPiElmore(Parasitic *parasitic,
|
||||
const Net *net,
|
||||
const TransRiseFall *tr,
|
||||
const OperatingConditions *op_cond,
|
||||
const Corner *corner,
|
||||
|
|
@ -186,7 +190,8 @@ public:
|
|||
const Corner *corner,
|
||||
const MinMax *cnst_min_max,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
virtual void reduceToPiPoleResidue2(Parasitic *parasitic, const Net *net,
|
||||
virtual void reduceToPiPoleResidue2(Parasitic *parasitic,
|
||||
const Net *net,
|
||||
const TransRiseFall *tr,
|
||||
const OperatingConditions *op_cond,
|
||||
const Corner *corner,
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin,
|
|||
const ParasiticAnalysisPt *ap)
|
||||
{
|
||||
Net *net = network_->net(drvr_pin);
|
||||
Parasitic *parasitic = makeParasiticNetwork(net, ap);
|
||||
Parasitic *parasitic = makeParasiticNetwork(net, false, ap);
|
||||
float wireload_cap, wireload_res;
|
||||
wireload->findWireload(fanout, op_cond, wireload_cap, wireload_res);
|
||||
|
||||
|
|
|
|||
|
|
@ -182,10 +182,13 @@ public:
|
|||
virtual Parasitic *findParasiticNetwork(const Pin *pin,
|
||||
const ParasiticAnalysisPt *ap) const = 0;
|
||||
virtual Parasitic *makeParasiticNetwork(Net *net,
|
||||
bool pin_cap_included,
|
||||
const ParasiticAnalysisPt *ap) = 0;
|
||||
// Delete parasitic network if it exists.
|
||||
virtual void deleteParasiticNetwork(const Net *net,
|
||||
const ParasiticAnalysisPt *ap) = 0;
|
||||
// True if the parasitic network caps include pin capacitances.
|
||||
virtual bool includesPinCaps(Parasitic *parasitic) const = 0;
|
||||
// Parasitic network component builders.
|
||||
// Make a subnode of the parasitic network net.
|
||||
virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic,
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ read_parasitics_cmd(const char *filename,
|
|||
Instance *instance,
|
||||
MinMaxAll *min_max,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
@ -47,9 +48,9 @@ read_parasitics_cmd(const char *filename,
|
|||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->readParasitics(filename, instance, min_max,
|
||||
increment, keep_coupling_caps,
|
||||
coupling_cap_factor, reduce_to,
|
||||
delete_after_reduce,
|
||||
increment, pin_cap_included,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce,
|
||||
save, quiet);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,16 +17,26 @@
|
|||
namespace eval sta {
|
||||
|
||||
define_cmd_args "read_parasitics" \
|
||||
{[-min] [-max] [-elmore] [-path path] [-increment]\
|
||||
[-keep_capacitive_coupling] [-coupling_reduction_factor factor]\
|
||||
[-reduce_to pi_elmore|pi_pole_residue2] [-delete_after_reduce]\
|
||||
[-quiet] [-save] filenames}
|
||||
{[-min]\
|
||||
[-max]\
|
||||
[-elmore]\
|
||||
[-path path]\
|
||||
[-increment]\
|
||||
[-pin_cap_included]\
|
||||
[-keep_capacitive_coupling]\
|
||||
[-coupling_reduction_factor factor]\
|
||||
[-reduce_to pi_elmore|pi_pole_residue2]\
|
||||
[-delete_after_reduce]\
|
||||
[-quiet]\
|
||||
[-save]\
|
||||
filename}
|
||||
|
||||
proc_redirect read_parasitics {
|
||||
# The -elmore flag is required by dc.
|
||||
parse_key_args "read_parasitics" args \
|
||||
keys {-path -coupling_reduction_factor -reduce_to} \
|
||||
flags {-min -max -elmore -increment -keep_capacitive_coupling \
|
||||
flags {-min -max -elmore -increment -pin_cap_included \
|
||||
-keep_capacitive_coupling \
|
||||
-delete_after_reduce -quiet -save}
|
||||
check_argc_eq1 "report_parasitics" $args
|
||||
|
||||
|
|
@ -46,6 +56,8 @@ proc_redirect read_parasitics {
|
|||
check_positive_float "-coupling_reduction_factor" $coupling_reduction_factor
|
||||
}
|
||||
set keep_coupling_caps [info exists flags(-keep_capacitive_coupling)]
|
||||
set pin_cap_included [info exists flags(-pin_cap_included)]
|
||||
|
||||
set reduce_to "none"
|
||||
if [info exists keys(-reduce_to)] {
|
||||
set reduce_to $keys(-reduce_to)
|
||||
|
|
@ -56,17 +68,11 @@ proc_redirect read_parasitics {
|
|||
set delete_after_reduce [info exists flags(-delete_after_reduce)]
|
||||
set quiet [info exists flags(-quiet)]
|
||||
set save [info exists flags(-save)]
|
||||
set filenames $args
|
||||
set success 1
|
||||
foreach filename $filenames {
|
||||
if { ![read_parasitics_cmd $filename $instance $min_max $increment \
|
||||
$keep_coupling_caps $coupling_reduction_factor \
|
||||
$reduce_to $delete_after_reduce \
|
||||
$save $quiet] } {
|
||||
set success 0
|
||||
}
|
||||
}
|
||||
return $success
|
||||
set filename $args
|
||||
return [read_parasitics_cmd $filename $instance $min_max $increment \
|
||||
$pin_cap_included $keep_coupling_caps $coupling_reduction_factor \
|
||||
$reduce_to $delete_after_reduce \
|
||||
$save $quiet]
|
||||
}
|
||||
|
||||
# set_pi_model [-min] [-max] drvr_pin c2 rpi c1
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ readParasiticsFile(const char *filename,
|
|||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
@ -72,7 +73,7 @@ readParasiticsFile(const char *filename,
|
|||
switch (file_type) {
|
||||
case parasitics_file_spef:
|
||||
success = readSpefFile(filename, stream, line_num,
|
||||
instance, ap, increment,
|
||||
instance, ap, increment, pin_cap_included,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce,
|
||||
op_cond, corner, cnst_min_max,
|
||||
|
|
@ -81,14 +82,16 @@ readParasiticsFile(const char *filename,
|
|||
break;
|
||||
case parasitics_file_rspf:
|
||||
success = readSpfFile(filename, stream, line_num, true, instance, ap,
|
||||
increment, keep_coupling_caps, coupling_cap_factor,
|
||||
increment, pin_cap_included,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce,
|
||||
op_cond, corner, cnst_min_max,
|
||||
save, quiet, report, network, parasitics);
|
||||
break;
|
||||
case parasitics_file_dspf:
|
||||
success = readSpfFile(filename, stream, line_num, false, instance, ap,
|
||||
increment, keep_coupling_caps, coupling_cap_factor,
|
||||
increment, pin_cap_included,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce,
|
||||
op_cond, corner, cnst_min_max,
|
||||
save, quiet, report,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ readParasiticsFile(const char *filename,
|
|||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
|
|||
|
|
@ -34,29 +34,39 @@ class ReduceToPi : public StaState
|
|||
{
|
||||
public:
|
||||
ReduceToPi(StaState *sta);
|
||||
void reduceToPi(const Pin *drvr_pin, ParasiticNode *drvr_node,
|
||||
void reduceToPi(const Pin *drvr_pin,
|
||||
ParasiticNode *drvr_node,
|
||||
bool pin_cap_included,
|
||||
float coupling_cap_factor,
|
||||
const TransRiseFall *tr,
|
||||
const OperatingConditions *op_cond,
|
||||
const Corner *corner,
|
||||
const MinMax *cnst_min_max,
|
||||
const ParasiticAnalysisPt *ap,
|
||||
float &c2, float &rpi, float &c1);
|
||||
float &c2,
|
||||
float &rpi,
|
||||
float &c1);
|
||||
|
||||
protected:
|
||||
void reducePiDfs(const Pin *drvr_pin, ParasiticNode *node,
|
||||
void reducePiDfs(const Pin *drvr_pin,
|
||||
ParasiticNode *node,
|
||||
ParasiticDevice *from_res,
|
||||
const ParasiticAnalysisPt *ap,
|
||||
double &y1, double &y2, double &y3, double &dwn_cap);
|
||||
double &y1,
|
||||
double &y2,
|
||||
double &y3,
|
||||
double &dwn_cap);
|
||||
void visit(ParasiticNode *node);
|
||||
bool isVisited(ParasiticNode *node);
|
||||
void leave(ParasiticNode *node);
|
||||
void setDownstreamCap(ParasiticNode *node, float cap);
|
||||
void setDownstreamCap(ParasiticNode *node,
|
||||
float cap);
|
||||
float downstreamCap(ParasiticNode *node);
|
||||
float pinCapacitance(ParasiticNode *node);
|
||||
bool isLoopResistor(ParasiticDevice *device);
|
||||
void markLoopResistor(ParasiticDevice *device);
|
||||
|
||||
bool pin_cap_included_;
|
||||
float coupling_cap_multiplier_;
|
||||
const TransRiseFall *tr_;
|
||||
const OperatingConditions *op_cond_;
|
||||
|
|
@ -82,15 +92,20 @@ ReduceToPi::ReduceToPi(StaState *sta) :
|
|||
// Thomas Savarino, Proceedings of the 1989 Design Automation
|
||||
// Conference.
|
||||
void
|
||||
ReduceToPi::reduceToPi(const Pin *drvr_pin, ParasiticNode *drvr_node,
|
||||
ReduceToPi::reduceToPi(const Pin *drvr_pin,
|
||||
ParasiticNode *drvr_node,
|
||||
bool pin_cap_included,
|
||||
float coupling_cap_factor,
|
||||
const TransRiseFall *tr,
|
||||
const OperatingConditions *op_cond,
|
||||
const Corner *corner,
|
||||
const MinMax *cnst_min_max,
|
||||
const ParasiticAnalysisPt *ap,
|
||||
float &c2, float &rpi, float &c1)
|
||||
float &c2,
|
||||
float &rpi,
|
||||
float &c1)
|
||||
{
|
||||
pin_cap_included_ = pin_cap_included;
|
||||
coupling_cap_multiplier_ = coupling_cap_factor;
|
||||
tr_ = tr;
|
||||
op_cond_ = op_cond;
|
||||
|
|
@ -190,9 +205,11 @@ ReduceToPi::pinCapacitance(ParasiticNode *node)
|
|||
if (pin) {
|
||||
Port *port = network_->port(pin);
|
||||
LibertyPort *lib_port = network_->libertyPort(port);
|
||||
if (lib_port)
|
||||
pin_cap = sdc_->pinCapacitance(pin,tr_, op_cond_,
|
||||
corner_, cnst_min_max_);
|
||||
if (lib_port) {
|
||||
if (!pin_cap_included_)
|
||||
pin_cap = sdc_->pinCapacitance(pin,tr_, op_cond_, corner_,
|
||||
cnst_min_max_);
|
||||
}
|
||||
else if (network_->isTopLevelPort(pin))
|
||||
pin_cap = sdc_->portExtCap(port, tr_, cnst_min_max_);
|
||||
}
|
||||
|
|
@ -230,7 +247,8 @@ ReduceToPi::markLoopResistor(ParasiticDevice *device)
|
|||
}
|
||||
|
||||
void
|
||||
ReduceToPi::setDownstreamCap(ParasiticNode *node, float cap)
|
||||
ReduceToPi::setDownstreamCap(ParasiticNode *node,
|
||||
float cap)
|
||||
{
|
||||
node_values_[node] = cap;
|
||||
}
|
||||
|
|
@ -261,7 +279,8 @@ ReduceToPiElmore::ReduceToPiElmore(StaState *sta) :
|
|||
}
|
||||
|
||||
Parasitic *
|
||||
reduceToPiElmore(Parasitic *parasitic, const Pin *drvr_pin,
|
||||
reduceToPiElmore(Parasitic *parasitic,
|
||||
const Pin *drvr_pin,
|
||||
float coupling_cap_factor,
|
||||
const TransRiseFall *tr,
|
||||
const OperatingConditions *op_cond,
|
||||
|
|
@ -278,7 +297,9 @@ reduceToPiElmore(Parasitic *parasitic, const Pin *drvr_pin,
|
|||
if (drvr_node) {
|
||||
ReduceToPiElmore reducer(sta);
|
||||
float c2, rpi, c1;
|
||||
reducer.reduceToPi(drvr_pin, drvr_node, coupling_cap_factor,
|
||||
reducer.reduceToPi(drvr_pin, drvr_node,
|
||||
parasitics->includesPinCaps(parasitic),
|
||||
coupling_cap_factor,
|
||||
tr, op_cond, corner, cnst_min_max, ap,
|
||||
c2, rpi, c1);
|
||||
Parasitic *pi_elmore = parasitics->makePiElmore(drvr_pin, tr, ap,
|
||||
|
|
@ -339,25 +360,39 @@ public:
|
|||
ReduceToPiPoleResidue2(StaState *sta);
|
||||
~ReduceToPiPoleResidue2();
|
||||
void findPolesResidues(Parasitic *parasitic_network,
|
||||
Parasitic *pi_pole_residue, const Pin *drvr_pin,
|
||||
Parasitic *pi_pole_residue,
|
||||
const Pin *drvr_pin,
|
||||
ParasiticNode *drvr_node,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
|
||||
private:
|
||||
void findMoments(const Pin *drvr_pin, ParasiticNode *drvr_node,
|
||||
int moment_count, const ParasiticAnalysisPt *ap);
|
||||
void findMoments(const Pin *drvr_pin, ParasiticNode *node, double from_volt,
|
||||
ParasiticDevice *from_res, int moment_index,
|
||||
void findMoments(const Pin *drvr_pin,
|
||||
ParasiticNode *drvr_node,
|
||||
int moment_count,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
double findBranchCurrents(const Pin *drvr_pin, ParasiticNode *node,
|
||||
void findMoments(const Pin *drvr_pin,
|
||||
ParasiticNode *node,
|
||||
double from_volt,
|
||||
ParasiticDevice *from_res,
|
||||
int moment_index,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
double findBranchCurrents(const Pin *drvr_pin,
|
||||
ParasiticNode *node,
|
||||
ParasiticDevice *from_res,
|
||||
int moment_index, const ParasiticAnalysisPt *ap);
|
||||
double moment(ParasiticNode *node, int moment_index);
|
||||
void setMoment(ParasiticNode *node, double moment, int moment_index);
|
||||
int moment_index,
|
||||
const ParasiticAnalysisPt *ap);
|
||||
double moment(ParasiticNode *node,
|
||||
int moment_index);
|
||||
void setMoment(ParasiticNode *node,
|
||||
double moment,
|
||||
int moment_index);
|
||||
double current(ParasiticDevice *res);
|
||||
void setCurrent(ParasiticDevice *res, double i);
|
||||
void findPolesResidues(Parasitic *pi_pole_residue, const Pin *drvr_pin,
|
||||
const Pin *load_pin, ParasiticNode *load_node);
|
||||
void setCurrent(ParasiticDevice *res,
|
||||
double i);
|
||||
void findPolesResidues(Parasitic *pi_pole_residue,
|
||||
const Pin *drvr_pin,
|
||||
const Pin *load_pin,
|
||||
ParasiticNode *load_node);
|
||||
|
||||
// Resistor/capacitor currents.
|
||||
ParasiticDeviceValueMap currents_;
|
||||
|
|
@ -381,7 +416,8 @@ ReduceToPiPoleResidue2::ReduceToPiPoleResidue2(StaState *sta) :
|
|||
// Three Moments of the Impulse Response", Proceedings of the 33rd
|
||||
// Design Automation Conference, 1996, pg 611-616.
|
||||
Parasitic *
|
||||
reduceToPiPoleResidue2(Parasitic *parasitic, const Pin *drvr_pin,
|
||||
reduceToPiPoleResidue2(Parasitic *parasitic,
|
||||
const Pin *drvr_pin,
|
||||
float coupling_cap_factor,
|
||||
const TransRiseFall *tr,
|
||||
const OperatingConditions *op_cond,
|
||||
|
|
@ -398,7 +434,9 @@ reduceToPiPoleResidue2(Parasitic *parasitic, const Pin *drvr_pin,
|
|||
if (drvr_node) {
|
||||
ReduceToPiPoleResidue2 reducer(sta);
|
||||
float c2, rpi, c1;
|
||||
reducer.reduceToPi(drvr_pin, drvr_node, coupling_cap_factor,
|
||||
reducer.reduceToPi(drvr_pin, drvr_node,
|
||||
parasitics->includesPinCaps(parasitic),
|
||||
coupling_cap_factor,
|
||||
tr, op_cond, corner, cnst_min_max, ap,
|
||||
c2, rpi, c1);
|
||||
Parasitic *pi_pole_residue = parasitics->makePiPoleResidue(drvr_pin,
|
||||
|
|
@ -504,7 +542,8 @@ ReduceToPiPoleResidue2::findBranchCurrents(const Pin *drvr_pin,
|
|||
}
|
||||
|
||||
void
|
||||
ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin, ParasiticNode *node,
|
||||
ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin,
|
||||
ParasiticNode *node,
|
||||
double from_volt,
|
||||
ParasiticDevice *from_res,
|
||||
int moment_index,
|
||||
|
|
@ -540,7 +579,8 @@ ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin, ParasiticNode *node,
|
|||
}
|
||||
|
||||
double
|
||||
ReduceToPiPoleResidue2::moment(ParasiticNode *node, int moment_index)
|
||||
ReduceToPiPoleResidue2::moment(ParasiticNode *node,
|
||||
int moment_index)
|
||||
{
|
||||
// Zero'th moments are all 1.
|
||||
if (moment_index == 0)
|
||||
|
|
@ -552,7 +592,8 @@ ReduceToPiPoleResidue2::moment(ParasiticNode *node, int moment_index)
|
|||
}
|
||||
|
||||
void
|
||||
ReduceToPiPoleResidue2::setMoment(ParasiticNode *node, double moment,
|
||||
ReduceToPiPoleResidue2::setMoment(ParasiticNode *node,
|
||||
double moment,
|
||||
int moment_index)
|
||||
{
|
||||
// Zero'th moments are all 1.
|
||||
|
|
@ -569,7 +610,8 @@ ReduceToPiPoleResidue2::current(ParasiticDevice *res)
|
|||
}
|
||||
|
||||
void
|
||||
ReduceToPiPoleResidue2::setCurrent(ParasiticDevice *res, double i)
|
||||
ReduceToPiPoleResidue2::setCurrent(ParasiticDevice *res,
|
||||
double i)
|
||||
{
|
||||
currents_[res] = i;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ class StaState;
|
|||
|
||||
// Reduce parasitic network to pi elmore model for drvr_pin.
|
||||
Parasitic *
|
||||
reduceToPiElmore(Parasitic *parasitic, const Pin *drvr_pin,
|
||||
reduceToPiElmore(Parasitic *parasitic,
|
||||
const Pin *drvr_pin,
|
||||
float coupling_cap_factor,
|
||||
const TransRiseFall *tr,
|
||||
const OperatingConditions *op_cond,
|
||||
|
|
@ -37,7 +38,8 @@ reduceToPiElmore(Parasitic *parasitic, const Pin *drvr_pin,
|
|||
// Reduce parasitic network to pi and 2nd order pole/residue models
|
||||
// for drvr_pin.
|
||||
Parasitic *
|
||||
reduceToPiPoleResidue2(Parasitic *parasitic, const Pin *drvr_pin,
|
||||
reduceToPiPoleResidue2(Parasitic *parasitic,
|
||||
const Pin *drvr_pin,
|
||||
float coupling_cap_factor,
|
||||
const TransRiseFall *tr,
|
||||
const OperatingConditions *op_cond,
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ readSpefFile(const char *filename,
|
|||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
@ -57,7 +58,7 @@ readSpefFile(const char *filename,
|
|||
Parasitics *parasitics)
|
||||
{
|
||||
SpefReader reader(filename, stream, line, instance, ap, increment,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
pin_cap_included, keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce, op_cond, corner,
|
||||
cnst_min_max, quiet, report, network, parasitics);
|
||||
spef_reader = &reader;
|
||||
|
|
@ -75,6 +76,7 @@ SpefReader::SpefReader(const char *filename,
|
|||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
@ -86,7 +88,8 @@ SpefReader::SpefReader(const char *filename,
|
|||
Report *report,
|
||||
Network *network,
|
||||
Parasitics *parasitics) :
|
||||
SpfSpefReader(filename, stream, line, instance, ap, increment,
|
||||
SpfSpefReader(filename, stream, line, instance, ap,
|
||||
increment, pin_cap_included,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce,
|
||||
op_cond, corner, cnst_min_max, quiet,
|
||||
|
|
@ -339,7 +342,9 @@ SpefReader::dspfBegin(Net *net,
|
|||
parasitic_ = 0;
|
||||
else {
|
||||
parasitics_->deleteParasitics(net, ap_);
|
||||
parasitic_ = parasitics_->makeParasiticNetwork(net, ap_);
|
||||
parasitic_ = parasitics_->makeParasiticNetwork(net, pin_cap_included_,
|
||||
ap_);
|
||||
|
||||
}
|
||||
net_ = net;
|
||||
}
|
||||
|
|
@ -361,8 +366,8 @@ SpefReader::dspfFinish()
|
|||
TransRiseFallIterator tr_iter;
|
||||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *tr = tr_iter.next();
|
||||
parasitics_->reduceTo(parasitic_, net_, reduce_to_, tr, op_cond_,
|
||||
corner_, cnst_min_max_, ap_);
|
||||
parasitics_->reduceTo(parasitic_, net_, reduce_to_, tr,
|
||||
op_cond_, corner_, cnst_min_max_, ap_);
|
||||
}
|
||||
if (delete_after_reduce_)
|
||||
parasitics_->deleteParasiticNetwork(net_, ap_);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ readSpefFile(const char *filename,
|
|||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ public:
|
|||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ readSpfFile(const char *filename,
|
|||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
@ -58,9 +59,9 @@ readSpfFile(const char *filename,
|
|||
Parasitics *parasitics)
|
||||
{
|
||||
SpfReader reader(filename, stream, line, rspf, instance, ap,
|
||||
increment, keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce, op_cond,
|
||||
corner, cnst_min_max, quiet,
|
||||
increment, pin_cap_included, keep_coupling_caps,
|
||||
coupling_cap_factor, reduce_to, delete_after_reduce,
|
||||
op_cond, corner, cnst_min_max, quiet,
|
||||
report, network, parasitics);
|
||||
spf_reader = &reader;
|
||||
::spfResetScanner();
|
||||
|
|
@ -78,6 +79,7 @@ SpfReader::SpfReader(const char *filename,
|
|||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
@ -90,7 +92,7 @@ SpfReader::SpfReader(const char *filename,
|
|||
Network *network,
|
||||
Parasitics *parasitics):
|
||||
SpfSpefReader(filename, stream, line, instance, ap, increment,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
pin_cap_included, keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce, op_cond, corner, cnst_min_max,
|
||||
quiet, report, network, parasitics),
|
||||
is_rspf_(rspf),
|
||||
|
|
@ -409,7 +411,7 @@ SpfReader::netBegin(const char *net_name)
|
|||
dspf_ = 0;
|
||||
else {
|
||||
parasitics_->deleteParasitics(net_, ap_);
|
||||
dspf_ = parasitics_->makeParasiticNetwork(net_, ap_);
|
||||
dspf_ = parasitics_->makeParasiticNetwork(net_,pin_cap_included_,ap_);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ readSpfFile(const char *filename,
|
|||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ public:
|
|||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
|
|||
|
|
@ -28,10 +28,13 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
SpfSpefReader::SpfSpefReader(const char *filename, gzFile stream, int line,
|
||||
SpfSpefReader::SpfSpefReader(const char *filename,
|
||||
gzFile stream,
|
||||
int line,
|
||||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
@ -47,6 +50,7 @@ SpfSpefReader::SpfSpefReader(const char *filename, gzFile stream, int line,
|
|||
instance_(instance),
|
||||
ap_(ap),
|
||||
increment_(increment),
|
||||
pin_cap_included_(pin_cap_included),
|
||||
keep_coupling_caps_(keep_coupling_caps),
|
||||
reduce_to_(reduce_to),
|
||||
delete_after_reduce_(delete_after_reduce),
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public:
|
|||
Instance *instance,
|
||||
ParasiticAnalysisPt *ap,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
@ -83,6 +84,7 @@ protected:
|
|||
Instance *instance_;
|
||||
const ParasiticAnalysisPt *ap_;
|
||||
bool increment_;
|
||||
bool pin_cap_included_;
|
||||
bool keep_coupling_caps_;
|
||||
ReduceParasiticsTo reduce_to_;
|
||||
bool delete_after_reduce_;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ ClockInsertion::setDelay(const TransRiseFallBoth *tr,
|
|||
const MinMaxAll *min_max,
|
||||
const EarlyLateAll *early_late, float delay)
|
||||
{
|
||||
MinMaxIterator el_iter(early_late);
|
||||
EarlyLateIterator el_iter(early_late);
|
||||
while (el_iter.hasNext()) {
|
||||
EarlyLate *el = el_iter.next();
|
||||
delays_[el->index()].setValue(tr, min_max, delay);
|
||||
|
|
@ -73,7 +73,7 @@ ClockInsertion::setDelay(const TransRiseFall *tr,
|
|||
void
|
||||
ClockInsertion::setDelays(RiseFallMinMax *delays)
|
||||
{
|
||||
MinMaxIterator el_iter;
|
||||
EarlyLateIterator el_iter;
|
||||
while (el_iter.hasNext()) {
|
||||
EarlyLate *el = el_iter.next();
|
||||
delays_[el->index()].setValues(delays);
|
||||
|
|
|
|||
132
sdc/Sdc.cc
132
sdc/Sdc.cc
|
|
@ -102,6 +102,7 @@ Sdc::Sdc(StaState *sta) :
|
|||
clk_sense_map_(network_),
|
||||
clk_gating_check_(NULL),
|
||||
input_delay_index_(0),
|
||||
port_cap_map_(NULL),
|
||||
net_wire_cap_map_(NULL),
|
||||
drvr_pin_wire_cap_map_(NULL),
|
||||
first_from_pin_exceptions_(NULL),
|
||||
|
|
@ -314,12 +315,6 @@ Sdc::deleteConstraints()
|
|||
}
|
||||
}
|
||||
|
||||
delete net_wire_cap_map_;
|
||||
net_wire_cap_map_ = NULL;
|
||||
|
||||
delete drvr_pin_wire_cap_map_;
|
||||
drvr_pin_wire_cap_map_ = NULL;
|
||||
|
||||
clk_hpin_disables_.deleteContentsClear();
|
||||
clk_hpin_disables_valid_ = false;
|
||||
|
||||
|
|
@ -355,28 +350,22 @@ Sdc::deleteInstancePvts()
|
|||
void
|
||||
Sdc::removeNetLoadCaps()
|
||||
{
|
||||
// set_load net
|
||||
delete net_wire_cap_map_;
|
||||
delete [] net_wire_cap_map_;
|
||||
net_wire_cap_map_ = NULL;
|
||||
|
||||
delete drvr_pin_wire_cap_map_;
|
||||
delete [] drvr_pin_wire_cap_map_;
|
||||
drvr_pin_wire_cap_map_ = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
Sdc::removeLoadCaps()
|
||||
{
|
||||
// set_load port
|
||||
// set_fanout_load port
|
||||
port_cap_map_.deleteContents();
|
||||
port_cap_map_.clear();
|
||||
|
||||
// set_load net
|
||||
delete net_wire_cap_map_;
|
||||
net_wire_cap_map_ = NULL;
|
||||
|
||||
delete drvr_pin_wire_cap_map_;
|
||||
drvr_pin_wire_cap_map_ = NULL;
|
||||
if (port_cap_map_) {
|
||||
port_cap_map_->deleteContents();
|
||||
delete port_cap_map_;
|
||||
port_cap_map_ = NULL;
|
||||
}
|
||||
removeNetLoadCaps();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -470,7 +459,7 @@ Sdc::isConstrained(const Pin *pin) const
|
|||
|| pin_cap_limit_map_.hasKey(pin1)
|
||||
|| port_cap_limit_map_.hasKey(port)
|
||||
|| port_fanout_limit_map_.hasKey(port)
|
||||
|| port_cap_map_.hasKey(port)
|
||||
|| hasPortExtCap(port)
|
||||
|| disabled_pins_.hasKey(pin1)
|
||||
|| disabled_ports_.hasKey(port)
|
||||
|| disabled_clk_gating_checks_pin_.hasKey(pin1)
|
||||
|
|
@ -515,8 +504,7 @@ Sdc::isConstrained(const Net *net) const
|
|||
Net *net1 = const_cast<Net*>(net);
|
||||
return (net_derating_factors_
|
||||
&& net_derating_factors_->hasKey(net))
|
||||
|| (net_wire_cap_map_
|
||||
&& net_wire_cap_map_->hasKey(net1))
|
||||
|| hasNetWireCap(net1)
|
||||
|| net_res_map_.hasKey(net1)
|
||||
|| (first_thru_net_exceptions_
|
||||
&& first_thru_net_exceptions_->hasKey(net));
|
||||
|
|
@ -3256,9 +3244,9 @@ Sdc::deleteOutputDelay(OutputDelay *output_delay)
|
|||
|
||||
void
|
||||
Sdc::setPortExtPinCap(Port *port,
|
||||
const TransRiseFall *tr,
|
||||
const MinMax *min_max,
|
||||
float cap)
|
||||
const TransRiseFall *tr,
|
||||
const MinMax *min_max,
|
||||
float cap)
|
||||
{
|
||||
PortExtCap *port_cap = ensurePortExtPinCap(port);
|
||||
port_cap->setPinCap(cap, tr, min_max);
|
||||
|
|
@ -3286,7 +3274,19 @@ Sdc::setPortExtWireCap(Port *port,
|
|||
PortExtCap *
|
||||
Sdc::portExtCap(Port *port) const
|
||||
{
|
||||
return port_cap_map_.findKey(port);
|
||||
if (port_cap_map_)
|
||||
return port_cap_map_->findKey(port);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
Sdc::hasPortExtCap(Port *port) const
|
||||
{
|
||||
if (port_cap_map_)
|
||||
return port_cap_map_->hasKey(port);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -3301,20 +3301,21 @@ Sdc::portExtCap(Port *port,
|
|||
int &fanout,
|
||||
bool &has_fanout) const
|
||||
{
|
||||
PortExtCap *port_cap = port_cap_map_.findKey(port);
|
||||
if (port_cap) {
|
||||
port_cap->pinCap(tr, min_max, pin_cap, has_pin_cap);
|
||||
port_cap->wireCap(tr, min_max, wire_cap, has_wire_cap);
|
||||
port_cap->fanout(min_max, fanout, has_fanout);
|
||||
}
|
||||
else {
|
||||
pin_cap = 0.0F;
|
||||
has_pin_cap = false;
|
||||
wire_cap = 0.0F;
|
||||
has_wire_cap = false;
|
||||
fanout = 0.0F;
|
||||
has_fanout = false;
|
||||
if (port_cap_map_) {
|
||||
PortExtCap *port_cap = port_cap_map_->findKey(port);
|
||||
if (port_cap) {
|
||||
port_cap->pinCap(tr, min_max, pin_cap, has_pin_cap);
|
||||
port_cap->wireCap(tr, min_max, wire_cap, has_wire_cap);
|
||||
port_cap->fanout(min_max, fanout, has_fanout);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pin_cap = 0.0F;
|
||||
has_pin_cap = false;
|
||||
wire_cap = 0.0F;
|
||||
has_wire_cap = false;
|
||||
fanout = 0.0F;
|
||||
has_fanout = false;
|
||||
}
|
||||
|
||||
float
|
||||
|
|
@ -3346,6 +3347,7 @@ Sdc::drvrPinHasWireCap(const Pin *pin)
|
|||
|
||||
void
|
||||
Sdc::drvrPinWireCap(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &cap,
|
||||
|
|
@ -3353,7 +3355,7 @@ Sdc::drvrPinWireCap(const Pin *pin,
|
|||
{
|
||||
if (drvr_pin_wire_cap_map_) {
|
||||
MinMaxFloatValues *values =
|
||||
drvr_pin_wire_cap_map_->findKey(const_cast<Pin*>(pin));
|
||||
drvr_pin_wire_cap_map_[corner->index()].findKey(const_cast<Pin*>(pin));
|
||||
if (values)
|
||||
return values->value(min_max, cap, exists);
|
||||
}
|
||||
|
|
@ -3386,20 +3388,36 @@ Sdc::setNetWireCap(Net *net,
|
|||
}
|
||||
}
|
||||
if (net_wire_cap_map_ == NULL)
|
||||
net_wire_cap_map_ = new NetWireCapMap;
|
||||
MinMaxFloatValues &values = (*net_wire_cap_map_)[net];
|
||||
net_wire_cap_map_ = new NetWireCapMap[corners_->count()];
|
||||
bool make_drvr_entry = net_wire_cap_map_[corner->index()].hasKey(net);
|
||||
MinMaxFloatValues &values = net_wire_cap_map_[corner->index()][net];
|
||||
values.setValue(min_max, wire_cap);
|
||||
|
||||
NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
if (network_->isDriver(pin)) {
|
||||
if (drvr_pin_wire_cap_map_ == NULL)
|
||||
drvr_pin_wire_cap_map_ = new PinWireCapMap;
|
||||
(*drvr_pin_wire_cap_map_)[pin] = &values;
|
||||
// Only need to do this when there is new net_wire_cap_map_ entry.
|
||||
if (make_drvr_entry) {
|
||||
NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
if (network_->isDriver(pin)) {
|
||||
if (drvr_pin_wire_cap_map_ == NULL)
|
||||
drvr_pin_wire_cap_map_ = new PinWireCapMap[corners_->count()];
|
||||
drvr_pin_wire_cap_map_[corner->index()][pin] = &values;
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Sdc::hasNetWireCap(Net *net) const
|
||||
{
|
||||
if (net_wire_cap_map_) {
|
||||
for (int i = 0; i < corners_->count(); i++) {
|
||||
if (net_wire_cap_map_[i].hasKey(net))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -3420,7 +3438,7 @@ Sdc::connectedCap(const Pin *pin,
|
|||
pin_cap, wire_cap, fanout, has_set_load);
|
||||
float net_wire_cap;
|
||||
bool has_net_wire_cap;
|
||||
drvrPinWireCap(pin, min_max, net_wire_cap, has_net_wire_cap);
|
||||
drvrPinWireCap(pin, corner, min_max, net_wire_cap, has_net_wire_cap);
|
||||
if (has_net_wire_cap) {
|
||||
wire_cap += net_wire_cap;
|
||||
has_set_load = true;
|
||||
|
|
@ -3496,7 +3514,7 @@ void
|
|||
FindNetCaps::operator()(Pin *pin)
|
||||
{
|
||||
sdc_->pinCaps(pin, tr_, op_cond_, corner_, min_max_,
|
||||
pin_cap_, wire_cap_, fanout_, has_set_load_);
|
||||
pin_cap_, wire_cap_, fanout_, has_set_load_);
|
||||
}
|
||||
|
||||
// Capacitances for all pins connected to drvr_pin's net.
|
||||
|
|
@ -3637,7 +3655,7 @@ Sdc::portExtFanout(Port *port,
|
|||
int &fanout,
|
||||
bool &exists)
|
||||
{
|
||||
PortExtCap *port_cap = port_cap_map_.findKey(port);
|
||||
PortExtCap *port_cap = portExtCap(port);
|
||||
if (port_cap)
|
||||
port_cap->fanout(min_max, fanout, exists);
|
||||
else {
|
||||
|
|
@ -3662,10 +3680,12 @@ Sdc::portExtFanout(Port *port,
|
|||
PortExtCap *
|
||||
Sdc::ensurePortExtPinCap(Port *port)
|
||||
{
|
||||
PortExtCap *port_cap = port_cap_map_.findKey(port);
|
||||
if (port_cap_map_ == NULL)
|
||||
port_cap_map_ = new PortExtCapMap;
|
||||
PortExtCap *port_cap = port_cap_map_->findKey(port);
|
||||
if (port_cap == NULL) {
|
||||
port_cap = new PortExtCap(port);
|
||||
port_cap_map_[port] = port_cap;
|
||||
(*port_cap_map_)[port] = port_cap;
|
||||
}
|
||||
return port_cap;
|
||||
}
|
||||
|
|
|
|||
13
sdc/Sdc.hh
13
sdc/Sdc.hh
|
|
@ -582,10 +582,12 @@ public:
|
|||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
float cap);
|
||||
bool hasNetWireCap(Net *net) const;
|
||||
// True if driver pin net has wire capacitance.
|
||||
bool drvrPinHasWireCap(const Pin *pin);
|
||||
// Net wire capacitance (set_load -wire net).
|
||||
void drvrPinWireCap(const Pin *drvr_pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &cap,
|
||||
|
|
@ -907,6 +909,7 @@ public:
|
|||
PinOutputDelayIterator *outputDelayVertexIterator(const Pin *vertex_pin)const;
|
||||
bool hasOutputDelay(const Pin *vertex_pin) const;
|
||||
PortExtCap *portExtCap(Port *port) const;
|
||||
bool hasPortExtCap(Port *port) const;
|
||||
void portExtCap(Port *port,
|
||||
const TransRiseFall *tr,
|
||||
const MinMax *min_max,
|
||||
|
|
@ -1333,9 +1336,15 @@ protected:
|
|||
PinCapLimitMap pin_cap_limit_map_;
|
||||
PortFanoutLimitMap port_fanout_limit_map_;
|
||||
CellFanoutLimitMap cell_fanout_limit_map_;
|
||||
// External parasitics on top level ports (from set_load).
|
||||
PortExtCapMap port_cap_map_;
|
||||
// External parasitics on top level ports.
|
||||
// set_load port
|
||||
// set_fanout_load port
|
||||
// Indexed by corner_index.
|
||||
PortExtCapMap *port_cap_map_;
|
||||
// set_load net
|
||||
// Indexed by corner_index.
|
||||
NetWireCapMap *net_wire_cap_map_;
|
||||
// Indexed by corner_index.
|
||||
PinWireCapMap *drvr_pin_wire_cap_map_;
|
||||
NetResistanceMap net_res_map_;
|
||||
PinSet disabled_pins_;
|
||||
|
|
|
|||
|
|
@ -632,8 +632,8 @@ void
|
|||
WriteSdc::writeClockInsertion(ClockInsertion *insert,
|
||||
WriteSdcObject &write_obj) const
|
||||
{
|
||||
RiseFallMinMax *early_values = insert->delays(EarlyLate::min());
|
||||
RiseFallMinMax *late_values = insert->delays(EarlyLate::max());
|
||||
RiseFallMinMax *early_values = insert->delays(EarlyLate::early());
|
||||
RiseFallMinMax *late_values = insert->delays(EarlyLate::late());
|
||||
if (early_values->equal(late_values))
|
||||
writeRiseFallMinMaxTimeCmd("set_clock_latency -source",
|
||||
late_values, write_obj);
|
||||
|
|
|
|||
|
|
@ -419,10 +419,10 @@ SdfWriter::writeArcDelays(Edge *edge)
|
|||
TimingArc *arc = arc_iter->next();
|
||||
TransRiseFall *tr = arc->toTrans()->asRiseFall();
|
||||
ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_);
|
||||
delays.setValue(tr, MinMax::min(), min_delay);
|
||||
delays.setValue(tr, MinMax::min(), delayAsFloat(min_delay));
|
||||
|
||||
ArcDelay max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_);
|
||||
delays.setValue(tr, MinMax::max(), max_delay);
|
||||
delays.setValue(tr, MinMax::max(), delayAsFloat(max_delay));
|
||||
}
|
||||
delete arc_iter;
|
||||
|
||||
|
|
@ -682,7 +682,7 @@ SdfWriter::writeCheck(Edge *edge,
|
|||
|
||||
ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_);
|
||||
ArcDelay max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_);
|
||||
writeSdfTuple(min_delay, max_delay);
|
||||
writeSdfTuple(delayAsFloat(min_delay), delayAsFloat(max_delay));
|
||||
|
||||
gzprintf(stream_, ")\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,14 +93,14 @@ float
|
|||
ClkSkew::srcLatency(StaState *sta)
|
||||
{
|
||||
Arrival src_arrival = src_path_.arrival(sta);
|
||||
return src_arrival - src_path_.clkEdge(sta)->time();
|
||||
return delayAsFloat(src_arrival) - src_path_.clkEdge(sta)->time();
|
||||
}
|
||||
|
||||
float
|
||||
ClkSkew::tgtLatency(StaState *sta)
|
||||
{
|
||||
Arrival tgt_arrival = tgt_path_.arrival(sta);
|
||||
return tgt_arrival - tgt_path_.clkEdge(sta)->time();
|
||||
return delayAsFloat(tgt_arrival) - tgt_path_.clkEdge(sta)->time();
|
||||
}
|
||||
|
||||
float
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ public:
|
|||
Corners *corners);
|
||||
~Corner();
|
||||
const char *name() const { return name_; }
|
||||
int index() const { return index_; }
|
||||
ParasiticAnalysisPt *findParasiticAnalysisPt(const MinMax *min_max) const;
|
||||
DcalcAnalysisPt *findDcalcAnalysisPt(const MinMax *min_max) const;
|
||||
PathAnalysisPt *findPathAnalysisPt(const MinMax *min_max) const;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ Latches::latchRequired(const Path *data_path,
|
|||
const PathVertex *disable_path,
|
||||
MultiCyclePath *mcp,
|
||||
PathDelay *path_delay,
|
||||
float src_clk_latency,
|
||||
Arrival src_clk_latency,
|
||||
const ArcDelay &margin,
|
||||
// Return values.
|
||||
Required &required,
|
||||
|
|
@ -186,7 +186,8 @@ Latches::latchBorrowInfo(const Path *data_path,
|
|||
if (borrow_limit_exists)
|
||||
max_borrow = borrow_limit;
|
||||
else
|
||||
max_borrow = nom_pulse_width - latency_diff - crpr_diff - margin;
|
||||
max_borrow = nom_pulse_width - delayAsFloat(latency_diff)
|
||||
- crpr_diff - delayAsFloat(margin);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -211,7 +212,7 @@ Latches::latchRequired(const Path *data_path,
|
|||
false);
|
||||
MultiCyclePath *mcp = dynamic_cast<MultiCyclePath*>(excpt);
|
||||
PathDelay *path_delay = dynamic_cast<PathDelay*>(excpt);
|
||||
float src_clk_latency = 0.0;
|
||||
Arrival src_clk_latency = 0.0;
|
||||
if (path_delay && path_delay->ignoreClkLatency())
|
||||
src_clk_latency = search_->pathClkPathArrival(data_path);
|
||||
latchRequired(data_path, enable_path, disable_path, mcp,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public:
|
|||
const PathVertex *disable_path,
|
||||
MultiCyclePath *mcp,
|
||||
PathDelay *path_delay,
|
||||
float src_clk_latency,
|
||||
Arrival src_clk_latency,
|
||||
const ArcDelay &margin,
|
||||
// Return values.
|
||||
Required &required,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ include_HEADERS = \
|
|||
PathGroup.hh \
|
||||
PathVertex.hh \
|
||||
PathVertexRep.hh \
|
||||
Power.hh \
|
||||
ReportPath.hh \
|
||||
Search.hh \
|
||||
SearchClass.hh \
|
||||
|
|
@ -82,6 +83,7 @@ libsearch_la_SOURCES = \
|
|||
PathRef.cc \
|
||||
PathVertex.cc \
|
||||
PathVertexRep.cc \
|
||||
Power.cc \
|
||||
ReportPath.cc \
|
||||
Search.cc \
|
||||
SearchPred.cc \
|
||||
|
|
|
|||
|
|
@ -68,6 +68,18 @@ PathEnd::minMax(const StaState *sta) const
|
|||
return path_.pathAnalysisPt(sta)->pathMinMax();
|
||||
}
|
||||
|
||||
const EarlyLate *
|
||||
PathEnd::pathEarlyLate(const StaState *sta) const
|
||||
{
|
||||
return path_.pathAnalysisPt(sta)->pathMinMax();
|
||||
}
|
||||
|
||||
const EarlyLate *
|
||||
PathEnd::clkEarlyLate(const StaState *sta) const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const TransRiseFall *
|
||||
PathEnd::transition(const StaState *sta) const
|
||||
{
|
||||
|
|
@ -540,6 +552,15 @@ PathEndClkConstrained::setPath(PathEnumed *path,
|
|||
crpr_valid_ = false;
|
||||
}
|
||||
|
||||
const EarlyLate *
|
||||
PathEndClkConstrained::clkEarlyLate(const StaState *sta) const
|
||||
{
|
||||
if (clk_path_.isNull())
|
||||
return NULL;
|
||||
else
|
||||
return clk_path_.pathAnalysisPt(sta)->pathMinMax();
|
||||
}
|
||||
|
||||
float
|
||||
PathEndClkConstrained::sourceClkOffset(const StaState *sta) const
|
||||
{
|
||||
|
|
@ -1565,15 +1586,15 @@ PathEndDataCheck::type() const
|
|||
Arrival
|
||||
PathEndDataCheck::requiredTimeNoCrpr(const StaState *sta) const
|
||||
{
|
||||
float data_clk_arrival = data_clk_path_.arrival(sta);
|
||||
Arrival data_clk_arrival = data_clk_path_.arrival(sta);
|
||||
float data_clk_time = data_clk_path_.clkEdge(sta)->time();
|
||||
float data_clk_delay = data_clk_arrival - data_clk_time;
|
||||
float tgt_clk_arrival = targetClkTime(sta)
|
||||
Arrival data_clk_delay = data_clk_arrival - data_clk_time;
|
||||
Arrival tgt_clk_arrival = targetClkTime(sta)
|
||||
+ data_clk_delay
|
||||
+ targetClkUncertainty(sta)
|
||||
+ targetClkMcpAdjustment(sta);
|
||||
|
||||
float check_margin = margin(sta);
|
||||
ArcDelay check_margin = margin(sta);
|
||||
if (checkGenericRole(sta) == TimingRole::setup())
|
||||
return tgt_clk_arrival - check_margin;
|
||||
else
|
||||
|
|
@ -1773,14 +1794,14 @@ PathEndPathDelay::sourceClkOffset(const StaState *sta) const
|
|||
float
|
||||
PathEnd::pathDelaySrcClkOffset(const PathRef &path,
|
||||
PathDelay *path_delay,
|
||||
float src_clk_arrival,
|
||||
Arrival src_clk_arrival,
|
||||
const StaState *sta)
|
||||
{
|
||||
float offset = 0.0;
|
||||
ClockEdge *clk_edge = path.clkEdge(sta);
|
||||
if (clk_edge) {
|
||||
if (path_delay->ignoreClkLatency())
|
||||
offset = -src_clk_arrival;
|
||||
offset = -delayAsFloat(src_clk_arrival);
|
||||
else
|
||||
// Arrival includes src clock edge time that is not counted in the
|
||||
// path delay.
|
||||
|
|
|
|||
|
|
@ -75,6 +75,9 @@ public:
|
|||
const StaState *sta);
|
||||
Vertex *vertex(const StaState *sta) const;
|
||||
const MinMax *minMax(const StaState *sta) const;
|
||||
// Synonym for minMax().
|
||||
const EarlyLate *pathEarlyLate(const StaState *sta) const;
|
||||
virtual const EarlyLate *clkEarlyLate(const StaState *sta) const;
|
||||
const TransRiseFall *transition(const StaState *sta) const;
|
||||
PathAnalysisPt *pathAnalysisPt(const StaState *sta) const;
|
||||
PathAPIndex pathIndex(const StaState *sta) const;
|
||||
|
|
@ -203,7 +206,7 @@ protected:
|
|||
const StaState *sta);
|
||||
static float pathDelaySrcClkOffset(const PathRef &path,
|
||||
PathDelay *path_delay,
|
||||
float src_clk_arrival,
|
||||
Arrival src_clk_arrival,
|
||||
const StaState *sta);
|
||||
PathRef path_;
|
||||
|
||||
|
|
@ -236,6 +239,7 @@ private:
|
|||
class PathEndClkConstrained : public PathEnd
|
||||
{
|
||||
public:
|
||||
virtual const EarlyLate *clkEarlyLate(const StaState *sta) const;
|
||||
virtual float sourceClkOffset(const StaState *sta) const;
|
||||
virtual Delay sourceClkLatency(const StaState *sta) const;
|
||||
virtual Delay sourceClkInsertionDelay(const StaState *sta) const;
|
||||
|
|
@ -414,7 +418,7 @@ private:
|
|||
PathVertex disable_path_;
|
||||
PathDelay *path_delay_;
|
||||
// Source clk arrival for set_max_delay -ignore_clk_latency.
|
||||
float src_clk_arrival_;
|
||||
Arrival src_clk_arrival_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PathEndLatchCheck);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -69,15 +69,11 @@ Diversion::Diversion(PathEnd *path_end,
|
|||
|
||||
// Default constructor required for DiversionQueue template.
|
||||
DiversionGreater::DiversionGreater() :
|
||||
cmp_slack_(true)
|
||||
sta_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
DiversionGreater::DiversionGreater(bool cmp_slack,
|
||||
const MinMax *min_max,
|
||||
StaState *sta) :
|
||||
cmp_slack_(cmp_slack),
|
||||
min_max_(min_max),
|
||||
DiversionGreater::DiversionGreater(const StaState *sta) :
|
||||
sta_(sta)
|
||||
{
|
||||
}
|
||||
|
|
@ -114,7 +110,7 @@ PathEnum::PathEnum(int group_count,
|
|||
group_count_(group_count),
|
||||
endpoint_count_(endpoint_count),
|
||||
unique_pins_(unique_pins),
|
||||
div_queue_(DiversionGreater(cmp_slack, min_max, sta->network())),
|
||||
div_queue_(DiversionGreater(sta)),
|
||||
div_count_(0),
|
||||
inserts_pruned_(false),
|
||||
next_(NULL)
|
||||
|
|
|
|||
|
|
@ -41,15 +41,11 @@ class DiversionGreater
|
|||
{
|
||||
public:
|
||||
DiversionGreater();
|
||||
DiversionGreater(bool cmp_slack,
|
||||
const MinMax *min_max,
|
||||
StaState *sta);
|
||||
DiversionGreater(const StaState *sta);
|
||||
bool operator()(Diversion *div1,
|
||||
Diversion *div2) const;
|
||||
|
||||
private:
|
||||
bool cmp_slack_;
|
||||
const MinMax *min_max_;
|
||||
const StaState *sta_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,394 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2018, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <algorithm> // max
|
||||
#include "Machine.hh"
|
||||
#include "Debug.hh"
|
||||
#include "Units.hh"
|
||||
#include "Transition.hh"
|
||||
#include "MinMax.hh"
|
||||
#include "Liberty.hh"
|
||||
#include "InternalPower.hh"
|
||||
#include "LeakagePower.hh"
|
||||
#include "InternalPower.hh"
|
||||
#include "TimingArc.hh"
|
||||
#include "FuncExpr.hh"
|
||||
#include "PortDirection.hh"
|
||||
#include "Network.hh"
|
||||
#include "Graph.hh"
|
||||
#include "Sim.hh"
|
||||
#include "Corner.hh"
|
||||
#include "DcalcAnalysisPt.hh"
|
||||
#include "GraphDelayCalc.hh"
|
||||
#include "PathVertex.hh"
|
||||
#include "Clock.hh"
|
||||
#include "Power.hh"
|
||||
|
||||
// Related liberty not supported:
|
||||
// library
|
||||
// default_cell_leakage_power : 0;
|
||||
// output_voltage (default_VDD_VSS_output) {
|
||||
// leakage_power
|
||||
// related_pg_pin : VDD;
|
||||
// internal_power
|
||||
// input_voltage : default_VDD_VSS_input;
|
||||
// pin
|
||||
// output_voltage : default_VDD_VSS_output;
|
||||
|
||||
|
||||
namespace sta {
|
||||
|
||||
Power::Power(Sta *sta) :
|
||||
StaState(sta),
|
||||
sta_(sta),
|
||||
default_signal_toggle_rate_(.1)
|
||||
{
|
||||
}
|
||||
|
||||
float
|
||||
Power::defaultSignalToggleRate()
|
||||
{
|
||||
return default_signal_toggle_rate_;
|
||||
}
|
||||
|
||||
void
|
||||
Power::setDefaultSignalToggleRate(float rate)
|
||||
{
|
||||
default_signal_toggle_rate_ = rate;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Power::power(const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &total,
|
||||
PowerResult &sequential,
|
||||
PowerResult &combinational,
|
||||
PowerResult ¯o,
|
||||
PowerResult &pad)
|
||||
{
|
||||
total.clear();
|
||||
sequential.clear();
|
||||
combinational.clear();
|
||||
macro.clear();
|
||||
pad.clear();
|
||||
LeafInstanceIterator *inst_iter = network_->leafInstanceIterator();
|
||||
while (inst_iter->hasNext()) {
|
||||
Instance *inst = inst_iter->next();
|
||||
LibertyCell *cell = network_->libertyCell(inst);
|
||||
if (cell) {
|
||||
PowerResult inst_power;
|
||||
power(inst, corner, inst_power);
|
||||
if (cell->isMacro())
|
||||
macro.incr(inst_power);
|
||||
else if (cell->isPad())
|
||||
pad.incr(inst_power);
|
||||
else if (cell->hasSequentials())
|
||||
sequential.incr(inst_power);
|
||||
else
|
||||
combinational.incr(inst_power);
|
||||
total.incr(inst_power);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
Power::power(const Instance *inst,
|
||||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
LibertyCell *cell = network_->libertyCell(inst);
|
||||
if (cell)
|
||||
power(inst, cell, corner, result);
|
||||
}
|
||||
|
||||
void
|
||||
Power::power(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
MinMax *mm = MinMax::max();
|
||||
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(mm);
|
||||
InstancePinIterator *pin_iter = network_->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
const Pin *to_pin = pin_iter->next();
|
||||
const LibertyPort *to_port = network_->libertyPort(to_pin);
|
||||
float load_cap = to_port->direction()->isAnyOutput()
|
||||
? loadCap(to_pin, dcalc_ap)
|
||||
: 0.0;
|
||||
float activity1;
|
||||
bool is_clk;
|
||||
activity(to_pin, activity1, is_clk);
|
||||
if (to_port->direction()->isAnyOutput()) {
|
||||
findSwitchingPower(inst, cell, to_pin, to_port, activity1, load_cap,
|
||||
dcalc_ap, result);
|
||||
}
|
||||
findInternalPower(inst, cell, to_pin, to_port, activity1, is_clk,
|
||||
load_cap, dcalc_ap, result);
|
||||
}
|
||||
delete pin_iter;
|
||||
findLeakagePower(inst, cell, result);
|
||||
}
|
||||
|
||||
void
|
||||
Power::findInternalPower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Pin *to_pin,
|
||||
const LibertyPort *to_port,
|
||||
float activity,
|
||||
bool is_clk,
|
||||
float load_cap,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
debugPrint3(debug_, "power", 2, "internal %s/%s %ss\n",
|
||||
network_->pathName(inst),
|
||||
to_port->name(),
|
||||
cell->name());
|
||||
float port_internal = 0.0;
|
||||
const Pvt *pvt = dcalc_ap->operatingConditions();
|
||||
float volt = voltage(cell, to_port, dcalc_ap);
|
||||
const char *pwr_pin = to_port->relatedPowerPin();
|
||||
float duty = is_clk ? 1.0 : .5;
|
||||
debugPrint3(debug_, "power", 2, "cap = %s activity = %.2f/ns duty = %.1f\n",
|
||||
units_->capacitanceUnit()->asString(load_cap),
|
||||
activity * 1e-9,
|
||||
duty);
|
||||
LibertyCellInternalPowerIterator *pwr_iter = cell->internalPowerIterator();
|
||||
while (pwr_iter->hasNext()) {
|
||||
InternalPower *pwr = pwr_iter->next();
|
||||
const char *related_pg_pin = pwr->relatedPgPin();
|
||||
if (pwr->port() == to_port
|
||||
&& ((related_pg_pin == NULL || pwr_pin == NULL)
|
||||
|| stringEqual(related_pg_pin, pwr_pin))) {
|
||||
const LibertyPort *from_port = pwr->relatedPort();
|
||||
if (from_port == NULL)
|
||||
from_port = to_port;
|
||||
const Pin *from_pin = network_->findPin(inst, from_port);
|
||||
Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
|
||||
TransRiseFallIterator tr_iter;
|
||||
while (tr_iter.hasNext()) {
|
||||
TransRiseFall *to_tr = tr_iter.next();
|
||||
// Need unateness to find from_tr.
|
||||
float slew = sta_->vertexSlew(from_vertex, to_tr, dcalc_ap);
|
||||
float energy, tr_internal;
|
||||
if (from_port) {
|
||||
float energy1 = pwr->power(to_tr, pvt, slew, load_cap);
|
||||
// Scale by voltage and rise/fall transition count.
|
||||
energy = energy1 * volt / 2.0;
|
||||
}
|
||||
else {
|
||||
float energy1 = pwr->power(to_tr, pvt, 0.0, 0.0);
|
||||
// Scale by voltage and rise/fall transition count.
|
||||
energy = energy1 * volt / 2.0;
|
||||
}
|
||||
tr_internal = energy * activity * duty;
|
||||
port_internal += tr_internal;
|
||||
debugPrint5(debug_, "power", 2, " %s -> %s %s %s (%s)\n",
|
||||
from_port->name(),
|
||||
to_tr->shortName(),
|
||||
to_port->name(),
|
||||
pwr->when() ? pwr->when()->asString() : "",
|
||||
related_pg_pin ? related_pg_pin : "");
|
||||
debugPrint3(debug_, "power", 2, " slew = %s energy = %.5g pwr = %.5g\n",
|
||||
units_->timeUnit()->asString(slew),
|
||||
energy,
|
||||
tr_internal);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete pwr_iter;
|
||||
debugPrint1(debug_, "power", 2, " internal = %.5g\n", port_internal);
|
||||
result.setInternal(result.internal() + port_internal);
|
||||
}
|
||||
|
||||
float
|
||||
Power::loadCap(const Pin *to_pin,
|
||||
const DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
float ceff_sum = 0.0;
|
||||
int ceff_count = 0;
|
||||
Vertex *to_vertex = graph_->pinDrvrVertex(to_pin);
|
||||
VertexInEdgeIterator edge_iter(to_vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
TimingArcSet *arc_set = edge->timingArcSet();
|
||||
TimingArcSetArcIterator *arc_iter = arc_set->timingArcIterator();
|
||||
while (arc_iter->hasNext()) {
|
||||
TimingArc *arc = arc_iter->next();
|
||||
ceff_sum += graph_delay_calc_->ceff(edge, arc, dcalc_ap);
|
||||
ceff_count++;
|
||||
}
|
||||
delete arc_iter;
|
||||
}
|
||||
return ceff_sum / ceff_count;
|
||||
}
|
||||
|
||||
void
|
||||
Power::findLeakagePower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
float leakage = cell->leakagePower();
|
||||
LibertyCellLeakagePowerIterator *pwr_iter = cell->leakagePowerIterator();
|
||||
while (pwr_iter->hasNext()) {
|
||||
LeakagePower *leak = pwr_iter->next();
|
||||
FuncExpr *when = leak->when();
|
||||
if (when) {
|
||||
LogicValue when_value = sim_->evalExpr(when, inst);
|
||||
switch (when_value) {
|
||||
case logic_zero:
|
||||
case logic_one:
|
||||
leakage = max(leakage, leak->power());
|
||||
break;
|
||||
case logic_unknown:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete pwr_iter;
|
||||
result.setLeakage(leakage);
|
||||
}
|
||||
|
||||
void
|
||||
Power::findSwitchingPower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Pin *to_pin,
|
||||
const LibertyPort *to_port,
|
||||
float activity,
|
||||
float load_cap,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
float volt = voltage(cell, to_port, dcalc_ap);
|
||||
float switching = load_cap * volt * volt * activity / 2.0;
|
||||
result.setSwitching(switching);
|
||||
}
|
||||
|
||||
void
|
||||
Power::activity(const Pin *pin,
|
||||
// Return values.
|
||||
float &activity,
|
||||
bool &is_clk)
|
||||
{
|
||||
const Clock *clk;
|
||||
findClk(pin, clk, is_clk);
|
||||
if (clk) {
|
||||
if (is_clk)
|
||||
activity = 2.0 / clk->period();
|
||||
else
|
||||
activity = default_signal_toggle_rate_ * 2.0 / clk->period();
|
||||
}
|
||||
else
|
||||
activity = 0.0;
|
||||
}
|
||||
|
||||
float
|
||||
Power::voltage(LibertyCell *cell,
|
||||
const LibertyPort *port,
|
||||
const DcalcAnalysisPt *dcalc_ap)
|
||||
{
|
||||
// Should use cell pg_pin voltage name to voltage.
|
||||
const Pvt *pvt = dcalc_ap->operatingConditions();
|
||||
if (pvt == NULL)
|
||||
pvt = cell->libertyLibrary()->defaultOperatingConditions();
|
||||
if (pvt)
|
||||
return pvt->voltage();
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void
|
||||
Power::findClk(const Pin *to_pin,
|
||||
// Return values.
|
||||
const Clock *&clk,
|
||||
bool &is_clk)
|
||||
{
|
||||
clk = NULL;
|
||||
is_clk = false;
|
||||
Vertex *to_vertex = graph_->pinDrvrVertex(to_pin);
|
||||
VertexPathIterator path_iter(to_vertex, this);
|
||||
while (path_iter.hasNext()) {
|
||||
PathVertex *path = path_iter.next();
|
||||
const Clock *path_clk = path->clock(this);
|
||||
if (path_clk
|
||||
&& (clk == NULL
|
||||
|| path_clk->period() < clk->period()))
|
||||
clk = path_clk;
|
||||
if (path->isClock(this))
|
||||
is_clk = true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
PowerResult::PowerResult() :
|
||||
internal_(0.0),
|
||||
switching_(0.0),
|
||||
leakage_(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PowerResult::clear()
|
||||
{
|
||||
internal_ = 0.0;
|
||||
switching_ = 0.0;
|
||||
leakage_ = 0.0;
|
||||
}
|
||||
|
||||
float
|
||||
PowerResult::total() const
|
||||
{
|
||||
return internal_ + switching_ + leakage_;
|
||||
}
|
||||
|
||||
void
|
||||
PowerResult::setInternal(float internal)
|
||||
{
|
||||
internal_ = internal;
|
||||
}
|
||||
|
||||
void
|
||||
PowerResult::setLeakage(float leakage)
|
||||
{
|
||||
leakage_ = leakage;
|
||||
}
|
||||
|
||||
void
|
||||
PowerResult::setSwitching(float switching)
|
||||
{
|
||||
switching_ = switching;
|
||||
}
|
||||
|
||||
void
|
||||
PowerResult::incr(PowerResult &result)
|
||||
{
|
||||
internal_ += result.internal_;
|
||||
switching_ += result.switching_;
|
||||
leakage_ += result.leakage_;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2018, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef STA_POWER_H
|
||||
#define STA_POWER_H
|
||||
|
||||
#include "Sta.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class PowerResult;
|
||||
|
||||
// The Power class has access to Sta components directly for
|
||||
// convenience but also requires access to the Sta class member functions.
|
||||
class Power : public StaState
|
||||
{
|
||||
public:
|
||||
Power(Sta *sta);
|
||||
void power(const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &total,
|
||||
PowerResult &sequential,
|
||||
PowerResult &combinational,
|
||||
PowerResult ¯o,
|
||||
PowerResult &pad);
|
||||
void power(const Instance *inst,
|
||||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
float defaultSignalToggleRate();
|
||||
void setDefaultSignalToggleRate(float rate);
|
||||
|
||||
protected:
|
||||
void power(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
void findInternalPower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Pin *to_pin,
|
||||
const LibertyPort *to_port,
|
||||
float activity,
|
||||
bool is_clk,
|
||||
float load_cap,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
void findLeakagePower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
void findSwitchingPower(const Instance *inst,
|
||||
LibertyCell *cell,
|
||||
const Pin *to_pin,
|
||||
const LibertyPort *to_port,
|
||||
float activity,
|
||||
float load_cap,
|
||||
const DcalcAnalysisPt *dcalc_ap,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
void findClk(const Pin *to_pin,
|
||||
// Return values.
|
||||
const Clock *&clk,
|
||||
bool &is_clk);
|
||||
float loadCap(const Pin *to_pin,
|
||||
const DcalcAnalysisPt *dcalc_ap);;
|
||||
void activity(const Pin *pin,
|
||||
// Return values.
|
||||
float &activity,
|
||||
bool &is_clk);
|
||||
float voltage(LibertyCell *cell,
|
||||
const LibertyPort *port,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
|
||||
private:
|
||||
Sta *sta_;
|
||||
float default_signal_toggle_rate_;
|
||||
};
|
||||
|
||||
class PowerResult
|
||||
{
|
||||
public:
|
||||
PowerResult();
|
||||
void clear();
|
||||
float internal() const { return internal_; }
|
||||
void setInternal(float internal);
|
||||
float switching() const { return switching_; }
|
||||
void setSwitching(float switching);
|
||||
float leakage() const { return leakage_; }
|
||||
void setLeakage(float leakage);
|
||||
float total() const;
|
||||
void incr(PowerResult &result);
|
||||
|
||||
private:
|
||||
float internal_;
|
||||
float switching_;
|
||||
float leakage_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
|
@ -423,7 +423,8 @@ ReportPath::reportFull(const PathEndUnconstrained *end,
|
|||
reportEndOfLine(result);
|
||||
|
||||
reportPath(end, expanded, result);
|
||||
reportLine("data arrival time", end->dataArrivalTimeOffset(this), result);
|
||||
reportLine("data arrival time", end->dataArrivalTimeOffset(this),
|
||||
end->pathEarlyLate(this), result);
|
||||
reportDashLine(result);
|
||||
result += "(Path is unconstrained)\n";
|
||||
}
|
||||
|
|
@ -542,6 +543,7 @@ ReportPath::reportFull(const PathEndLatchCheck *end,
|
|||
string &result)
|
||||
{
|
||||
PathExpanded expanded(end->path(), this);
|
||||
const EarlyLate *early_late = end->pathEarlyLate(this);
|
||||
reportShort(end, expanded, result);
|
||||
PathDelay *path_delay = end->pathDelay();
|
||||
reportEndOfLine(result);
|
||||
|
|
@ -554,7 +556,8 @@ ReportPath::reportFull(const PathEndLatchCheck *end,
|
|||
}
|
||||
else
|
||||
reportSrcPath(end, expanded, result);
|
||||
reportLine("data arrival time", end->dataArrivalTimeOffset(this), result);
|
||||
reportLine("data arrival time", end->dataArrivalTimeOffset(this),
|
||||
early_late, result);
|
||||
reportEndOfLine(result);
|
||||
|
||||
Required req_time;
|
||||
|
|
@ -565,23 +568,27 @@ ReportPath::reportFull(const PathEndLatchCheck *end,
|
|||
req_time += end->sourceClkOffset(this);
|
||||
if (path_delay) {
|
||||
float delay = path_delay->delay();
|
||||
reportLine("max_delay", delay, delay, result);
|
||||
reportLine("max_delay", delay, delay, early_late, result);
|
||||
if (!ignore_clk_latency) {
|
||||
if (reportClkPath()
|
||||
&& isPropagated(end->targetClkPath()))
|
||||
reportTgtClk(end, delay, result);
|
||||
else
|
||||
reportCommonClkPessimism(end, delay, result);
|
||||
else {
|
||||
Delay delay1(delay);
|
||||
reportCommonClkPessimism(end, delay1, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
reportTgtClk(end, result);
|
||||
|
||||
if (borrow >= 0.0)
|
||||
reportLine("time borrowed from endpoint", borrow, req_time, result);
|
||||
reportLine("time borrowed from endpoint", borrow, req_time,
|
||||
early_late, result);
|
||||
else
|
||||
reportLine("time given to endpoint", borrow, req_time, result);
|
||||
reportLine("data required time", req_time, result);
|
||||
reportLine("time given to endpoint", borrow, req_time,
|
||||
early_late, result);
|
||||
reportLine("data required time", req_time, early_late, result);
|
||||
reportDashLine(result);
|
||||
reportSlack(end, result);
|
||||
if (end->checkGenericRole(this) == TimingRole::setup()
|
||||
|
|
@ -629,13 +636,14 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end,
|
|||
Delay open_latency, latency_diff, max_borrow;
|
||||
float nom_pulse_width, open_uncertainty, open_crpr, crpr_diff;
|
||||
bool borrow_limit_exists;
|
||||
const EarlyLate *early_late = EarlyLate::late();
|
||||
end->latchBorrowInfo(this, nom_pulse_width, open_latency, latency_diff,
|
||||
open_uncertainty, open_crpr, crpr_diff,
|
||||
max_borrow, borrow_limit_exists);
|
||||
result += "Time Borrowing Information\n";
|
||||
reportDashLineTotal(result);
|
||||
if (borrow_limit_exists)
|
||||
reportLineTotal("user max time borrow", max_borrow, result);
|
||||
reportLineTotal("user max time borrow", max_borrow, early_late, result);
|
||||
else {
|
||||
const char *tgt_clk_name = tgtClkName(end);
|
||||
Arrival tgt_clk_width = end->targetClkWidth(this);
|
||||
|
|
@ -645,39 +653,41 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end,
|
|||
+ strlen(tgt_clk_name) + 1,
|
||||
"%s nominal pulse width",
|
||||
tgt_clk_name);
|
||||
reportLineTotal(width_msg, nom_pulse_width, result);
|
||||
reportLineTotal(width_msg, nom_pulse_width, early_late, result);
|
||||
if (!delayFuzzyZero(latency_diff))
|
||||
reportLineTotalMinus("clock latency difference", latency_diff, result);
|
||||
reportLineTotalMinus("clock latency difference", latency_diff,
|
||||
early_late, result);
|
||||
}
|
||||
else {
|
||||
const char *width_msg = stringPrintTmp(strlen(" pulse width")
|
||||
+ strlen(tgt_clk_name) + 1,
|
||||
"%s pulse width",
|
||||
tgt_clk_name);
|
||||
reportLineTotal(width_msg, tgt_clk_width, result);
|
||||
reportLineTotal(width_msg, tgt_clk_width, early_late, result);
|
||||
}
|
||||
ArcDelay margin = end->margin(this);
|
||||
reportLineTotalMinus("library setup time", margin, result);
|
||||
reportLineTotalMinus("library setup time", margin, early_late, result);
|
||||
reportDashLineTotal(result);
|
||||
if (!fuzzyZero(crpr_diff))
|
||||
reportLineTotalMinus("CRPR difference", crpr_diff, result);
|
||||
reportLineTotal("max time borrow", max_borrow, result);
|
||||
reportLineTotalMinus("CRPR difference", crpr_diff, early_late, result);
|
||||
reportLineTotal("max time borrow", max_borrow, early_late, result);
|
||||
}
|
||||
if (delayFuzzyGreater(borrow, delay_zero)
|
||||
&& (!fuzzyZero(open_uncertainty)
|
||||
|| !fuzzyZero(open_crpr))) {
|
||||
reportDashLineTotal(result);
|
||||
reportLineTotal("actual time borrow", borrow, result);
|
||||
reportLineTotal("actual time borrow", borrow, early_late, result);
|
||||
if (!fuzzyZero(open_uncertainty))
|
||||
reportLineTotal("open edge uncertainty", open_uncertainty, result);
|
||||
reportLineTotal("open edge uncertainty", open_uncertainty,
|
||||
early_late, result);
|
||||
if (!fuzzyZero(open_crpr))
|
||||
reportLineTotal("open edge CRPR", open_crpr, result);
|
||||
reportLineTotal("open edge CRPR", open_crpr, early_late, result);
|
||||
reportDashLineTotal(result);
|
||||
reportLineTotal("time given to startpoint", time_given_to_startpoint,
|
||||
result);
|
||||
early_late, result);
|
||||
}
|
||||
else
|
||||
reportLineTotal("actual time borrow", borrow, result);
|
||||
reportLineTotal("actual time borrow", borrow, early_late, result);
|
||||
reportDashLineTotal(result);
|
||||
}
|
||||
|
||||
|
|
@ -727,6 +737,7 @@ ReportPath::reportFull(const PathEndPathDelay *end,
|
|||
{
|
||||
PathExpanded expanded(end->path(), this);
|
||||
reportShort(end, expanded, result);
|
||||
const EarlyLate *early_late = end->pathEarlyLate(this);
|
||||
|
||||
// Based on reportSrcPathArrival.
|
||||
reportEndOfLine(result);
|
||||
|
|
@ -739,7 +750,8 @@ ReportPath::reportFull(const PathEndPathDelay *end,
|
|||
}
|
||||
else
|
||||
reportSrcPath(end, expanded, result);
|
||||
reportLine("data arrival time", end->dataArrivalTimeOffset(this), result);
|
||||
reportLine("data arrival time", end->dataArrivalTimeOffset(this),
|
||||
early_late, result);
|
||||
reportEndOfLine(result);
|
||||
|
||||
ArcDelay margin = end->margin(this);
|
||||
|
|
@ -758,7 +770,7 @@ ReportPath::reportFull(const PathEndPathDelay *end,
|
|||
"%s_delay",
|
||||
min_max_str);
|
||||
float delay = path_delay->delay();
|
||||
reportLine(delay_msg, delay, delay, result);
|
||||
reportLine(delay_msg, delay, delay, early_late, result);
|
||||
if (!path_delay->ignoreClkLatency()) {
|
||||
const Path *tgt_clk_path = end->targetClkPath();
|
||||
if (tgt_clk_path) {
|
||||
|
|
@ -773,7 +785,7 @@ ReportPath::reportFull(const PathEndPathDelay *end,
|
|||
Arrival tgt_clk_arrival = delay + tgt_clk_delay;
|
||||
if (!delayFuzzyZero(tgt_clk_delay))
|
||||
reportLine(clkNetworkDelayIdealProp(isPropagated(tgt_clk_path)),
|
||||
tgt_clk_delay, tgt_clk_arrival, result);
|
||||
tgt_clk_delay, tgt_clk_arrival, early_late, result);
|
||||
reportClkUncertainty(end, tgt_clk_arrival, result);
|
||||
reportCommonClkPessimism(end, tgt_clk_arrival, result);
|
||||
}
|
||||
|
|
@ -968,9 +980,9 @@ ReportPath::reportFull(const PathEndDataCheck *end,
|
|||
// Report the path from the clk network to the data check.
|
||||
PathExpanded clk_expanded(data_clk_path, this);
|
||||
float src_offset = end->sourceClkOffset(this);
|
||||
float clk_delay = end->targetClkDelay(this);
|
||||
float clk_arrival = end->targetClkArrival(this);
|
||||
float offset = clk_arrival - clk_delay + src_offset;
|
||||
Delay clk_delay = end->targetClkDelay(this);
|
||||
Arrival clk_arrival = end->targetClkArrival(this);
|
||||
float offset = delayAsFloat(clk_arrival - clk_delay + src_offset);
|
||||
reportPath5(data_clk_path, clk_expanded, clk_expanded.startIndex(),
|
||||
clk_expanded.size() - 1,
|
||||
data_clk_path->clkInfo(search_)->isPropagated(), false,
|
||||
|
|
@ -1030,11 +1042,12 @@ void
|
|||
ReportPath::reportEndLine(PathEnd *end,
|
||||
string &result)
|
||||
{
|
||||
const EarlyLate *early_late = end->pathEarlyLate(this);
|
||||
reportDescription(pathEndpoint(end), result);
|
||||
reportSpaceFieldTime(end->requiredTimeOffset(this), result);
|
||||
reportSpaceFieldTime(end->dataArrivalTimeOffset(this), result);
|
||||
reportSpaceFieldDelay(end->requiredTimeOffset(this), early_late, result);
|
||||
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, result);
|
||||
Slack slack = end->slack(this);
|
||||
reportSpaceFieldTime(slack, result);
|
||||
reportSpaceFieldDelay(slack, early_late, result);
|
||||
result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)";
|
||||
reportEndOfLine(result);
|
||||
}
|
||||
|
|
@ -1059,12 +1072,13 @@ ReportPath::reportSummaryLine(PathEnd *end,
|
|||
string &result)
|
||||
{
|
||||
PathExpanded expanded(end->path(), this);
|
||||
const EarlyLate *early_late = end->pathEarlyLate(this);
|
||||
reportDescription(pathStartpoint(end, expanded), result);
|
||||
reportDescription(pathEndpoint(end), result);
|
||||
if (end->isUnconstrained())
|
||||
reportSpaceFieldTime(end->dataArrivalTimeOffset(this), result);
|
||||
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, result);
|
||||
else
|
||||
reportSpaceFieldTime(end->slack(this), result);
|
||||
reportSpaceFieldDelay(end->slack(this), early_late, result);
|
||||
reportEndOfLine(result);
|
||||
}
|
||||
|
||||
|
|
@ -1131,11 +1145,12 @@ void
|
|||
ReportPath::reportSlackOnly(PathEnd *end,
|
||||
string &result)
|
||||
{
|
||||
const EarlyLate *early_late = end->pathEarlyLate(this);
|
||||
reportDescription(search_->pathGroup(end)->name(), result);
|
||||
if (end->isUnconstrained())
|
||||
reportSpaceFieldTime(end->dataArrivalTimeOffset(this), result);
|
||||
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, result);
|
||||
else
|
||||
reportSpaceFieldTime(end->slack(this), result);
|
||||
reportSpaceFieldDelay(end->slack(this), early_late, result);
|
||||
reportEndOfLine(result);
|
||||
}
|
||||
|
||||
|
|
@ -1229,9 +1244,9 @@ ReportPath::reportShort(MinPulseWidthCheck *check,
|
|||
hi_low);
|
||||
reportDescription(what, result);
|
||||
reportSpaceFieldTime(check->minWidth(this), result);
|
||||
reportSpaceFieldTime(check->width(this), result);
|
||||
reportSpaceFieldDelay(check->width(this), EarlyLate::late(), result);
|
||||
Slack slack = check->slack(this);
|
||||
reportSpaceFieldTime(slack, result);
|
||||
reportSpaceFieldDelay(slack, EarlyLate::early(), result);
|
||||
result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)";
|
||||
reportEndOfLine(result);
|
||||
}
|
||||
|
|
@ -1249,6 +1264,7 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check,
|
|||
reportEndOfLine(result);
|
||||
|
||||
reportPathHeader(result);
|
||||
const EarlyLate *open_el = EarlyLate::late();
|
||||
ClockEdge *open_clk_edge = check->openClkEdge(this);
|
||||
Clock *open_clk = open_clk_edge->clock();
|
||||
const char *open_clk_name = open_clk->name();
|
||||
|
|
@ -1260,15 +1276,18 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check,
|
|||
"clock %s (%s edge)",
|
||||
open_clk_name,
|
||||
open_rise_fall);
|
||||
reportLine(open_clk_msg, open_clk_time, open_clk_time, result);
|
||||
reportLine(open_clk_msg, open_clk_time, open_clk_time,
|
||||
open_el, result);
|
||||
Arrival open_arrival = check->openArrival(this);
|
||||
bool is_prop = isPropagated(check->openPath());
|
||||
const char *clk_ideal_prop = clkNetworkDelayIdealProp(is_prop);
|
||||
reportLine(clk_ideal_prop, check->openDelay(this), open_arrival, result);
|
||||
reportLine(pin_name, delay_zero, open_arrival, result);
|
||||
reportLine("open edge arrival time", open_arrival, result);
|
||||
reportLine(clk_ideal_prop, check->openDelay(this), open_arrival,
|
||||
open_el, result);
|
||||
reportLine(pin_name, delay_zero, open_arrival, open_el, result);
|
||||
reportLine("open edge arrival time", open_arrival, open_el, result);
|
||||
reportEndOfLine(result);
|
||||
|
||||
const EarlyLate *close_el = EarlyLate::late();
|
||||
ClockEdge *close_clk_edge = check->closeClkEdge(this);
|
||||
Clock *close_clk = close_clk_edge->clock();
|
||||
const char *close_clk_name = close_clk->name();
|
||||
|
|
@ -1281,18 +1300,20 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check,
|
|||
"clock %s (%s edge)",
|
||||
close_clk_name,
|
||||
close_rise_fall);
|
||||
reportLine(close_clk_msg, close_clk_time, close_clk_time, result);
|
||||
reportLine(close_clk_msg, close_clk_time, close_clk_time, close_el, result);
|
||||
Arrival close_arrival = check->closeArrival(this) + close_offset;
|
||||
reportLine(clk_ideal_prop, check->closeDelay(this), close_arrival, result);
|
||||
reportLine(pin_name, delay_zero, close_arrival, result);
|
||||
reportLine(clk_ideal_prop, check->closeDelay(this), close_arrival,
|
||||
close_el, result);
|
||||
reportLine(pin_name, delay_zero, close_arrival, close_el, result);
|
||||
|
||||
if (sdc_->crprEnabled()) {
|
||||
float pessimism = check->commonClkPessimism(this);
|
||||
close_arrival += pessimism;
|
||||
reportLine("clock reconvergence pessimism", pessimism, close_arrival,
|
||||
result);
|
||||
close_el, result);
|
||||
}
|
||||
reportLine("close edge arrival time", close_arrival, result);
|
||||
reportLine("close edge arrival time", close_arrival, close_el, result);
|
||||
|
||||
reportDashLine(result);
|
||||
float min_width = check->minWidth(this);
|
||||
const char *hi_low = mpwCheckHiLow(check);
|
||||
|
|
@ -1300,8 +1321,9 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check,
|
|||
+ strlen(hi_low) + 1,
|
||||
"required pulse width (%s)",
|
||||
hi_low);
|
||||
reportLine(rpw_msg, min_width, result);
|
||||
reportLine("actual pulse width", check->width(this), result);
|
||||
reportLine(rpw_msg, min_width, EarlyLate::early(), result);
|
||||
reportLine("actual pulse width", check->width(this),
|
||||
EarlyLate::early(), result);
|
||||
reportDashLine(result);
|
||||
reportSlack(check->slack(this), result);
|
||||
}
|
||||
|
|
@ -1399,10 +1421,10 @@ ReportPath::reportShort(MinPeriodCheck *check,
|
|||
{
|
||||
const char *pin_name = cmd_network_->pathName(check->pin());
|
||||
reportDescription(pin_name, result);
|
||||
reportSpaceFieldTime(check->period(), result);
|
||||
reportSpaceFieldTime(check->minPeriod(this), result);
|
||||
reportSpaceFieldDelay(check->period(), EarlyLate::early(), result);
|
||||
reportSpaceFieldDelay(check->minPeriod(this), EarlyLate::early(), result);
|
||||
Slack slack = check->slack(this);
|
||||
reportSpaceFieldTime(slack, result);
|
||||
reportSpaceFieldDelay(slack, EarlyLate::early(), result);
|
||||
result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)";
|
||||
reportEndOfLine(result);
|
||||
}
|
||||
|
|
@ -1415,8 +1437,9 @@ ReportPath::reportVerbose(MinPeriodCheck *check, string &result)
|
|||
result += pin_name;
|
||||
reportEndOfLine(result);
|
||||
|
||||
reportLine("Period", check->period(), result);
|
||||
reportLine("min_period", -check->minPeriod(this), result);
|
||||
reportLine("Period", check->period(), EarlyLate::early(), result);
|
||||
reportLine("min_period", -check->minPeriod(this),
|
||||
EarlyLate::early(), result);
|
||||
reportDashLine(result);
|
||||
reportSlack(check->slack(this), result);
|
||||
}
|
||||
|
|
@ -1513,10 +1536,10 @@ ReportPath::reportShort(MaxSkewCheck *check,
|
|||
check_arc->fromTrans()->asString(),
|
||||
check_arc->toTrans()->asString());
|
||||
reportDescription(what, result);
|
||||
reportSpaceFieldTime(check->maxSkew(this), result);
|
||||
reportSpaceFieldTime(check->skew(this), result);
|
||||
reportSpaceFieldDelay(check->maxSkew(this), EarlyLate::early(), result);
|
||||
reportSpaceFieldDelay(check->skew(this), EarlyLate::early(), result);
|
||||
Slack slack = check->slack(this);
|
||||
reportSpaceFieldTime(slack, result);
|
||||
reportSpaceFieldDelay(slack, EarlyLate::early(), result);
|
||||
result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)";
|
||||
reportEndOfLine(result);
|
||||
}
|
||||
|
|
@ -1544,8 +1567,9 @@ ReportPath::reportVerbose(MaxSkewCheck *check,
|
|||
reportSkewClkPath("constrained pin arrival time", check->clkPath(), result);
|
||||
|
||||
reportDashLine(result);
|
||||
reportLine("allowable skew", check->maxSkew(this), result);
|
||||
reportLine("actual skew", check->skew(this), result);
|
||||
reportLine("allowable skew", check->maxSkew(this),
|
||||
EarlyLate::early(), result);
|
||||
reportLine("actual skew", check->skew(this), EarlyLate::late(), result);
|
||||
reportDashLine(result);
|
||||
reportSlack(check->slack(this), result);
|
||||
}
|
||||
|
|
@ -1558,6 +1582,7 @@ ReportPath::reportSkewClkPath(const char *arrival_msg,
|
|||
{
|
||||
ClockEdge *clk_edge = clk_path->clkEdge(this);
|
||||
Clock *clk = clk_edge->clock();
|
||||
const EarlyLate *early_late = clk_path->minMax(this);
|
||||
const TransRiseFall *clk_tr = clk_edge->transition();
|
||||
const TransRiseFall *clk_end_tr = clk_path->transition(this);
|
||||
const char *clk_name = (clk_end_tr == clk_tr)
|
||||
|
|
@ -1580,17 +1605,19 @@ ReportPath::reportSkewClkPath(const char *arrival_msg,
|
|||
Arrival insertion, latency;
|
||||
PathEnd::checkTgtClkDelay(clk_path, clk_edge, TimingRole::skew(), this,
|
||||
insertion, latency);
|
||||
reportClkSrcLatency(insertion, clk_time, result);
|
||||
reportClkSrcLatency(insertion, clk_time, early_late, result);
|
||||
PathExpanded clk_expanded(clk_path, this);
|
||||
reportPath2(clk_path, clk_expanded, false, 0.0, result);
|
||||
}
|
||||
}
|
||||
else {
|
||||
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay, clk_arrival,
|
||||
result);
|
||||
reportLine(descriptionField(clk_vertex), clk_arrival, clk_end_tr, result);
|
||||
early_late, result);
|
||||
reportLine(descriptionField(clk_vertex), clk_arrival, early_late,
|
||||
clk_end_tr, result);
|
||||
}
|
||||
reportLine(arrival_msg, search_->clkPathArrival(clk_path), result);
|
||||
reportLine(arrival_msg, search_->clkPathArrival(clk_path),
|
||||
early_late, result);
|
||||
reportEndOfLine(result);
|
||||
}
|
||||
|
||||
|
|
@ -1642,7 +1669,7 @@ ReportPath::reportSlewLimitShort(Pin *pin,
|
|||
const char *pin_name = cmd_network_->pathName(pin);
|
||||
reportDescription(pin_name, result);
|
||||
reportSpaceFieldTime(limit, result);
|
||||
reportSpaceFieldTime(slew, result);
|
||||
reportSpaceFieldDelay(slew, EarlyLate::late(), result);
|
||||
reportSpaceFieldTime(slack, result);
|
||||
result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)";
|
||||
reportEndOfLine(result);
|
||||
|
|
@ -1977,7 +2004,8 @@ ReportPath::reportSrcPathArrival(const PathEnd *end,
|
|||
{
|
||||
reportEndOfLine(result);
|
||||
reportSrcPath(end, expanded, result);
|
||||
reportLine("data arrival time", end->dataArrivalTimeOffset(this), result);
|
||||
reportLine("data arrival time", end->dataArrivalTimeOffset(this),
|
||||
end->pathEarlyLate(this), result);
|
||||
reportEndOfLine(result);
|
||||
}
|
||||
|
||||
|
|
@ -2077,33 +2105,33 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
|||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result);
|
||||
ClkInfo *clk_info = path->tag(search_)->clkInfo();
|
||||
if (clk_info->isPropagated())
|
||||
reportClkSrcLatency(clk_insertion, clk_time, result);
|
||||
reportClkSrcLatency(clk_insertion, clk_time, early_late, result);
|
||||
reportPath1(path, expanded, true, time_offset, result);
|
||||
}
|
||||
else if (is_prop
|
||||
&& reportClkPath()
|
||||
&& !(path_from_input && !input_has_ref_path)) {
|
||||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result);
|
||||
reportClkSrcLatency(clk_insertion, clk_time, result);
|
||||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, early_late, result);
|
||||
reportClkSrcLatency(clk_insertion, clk_time, early_late, result);
|
||||
reportPath1(path, expanded, false, time_offset, result);
|
||||
}
|
||||
else if (clk_used_as_data) {
|
||||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result);
|
||||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, early_late, result);
|
||||
if (clk_insertion > 0.0)
|
||||
reportClkSrcLatency(clk_insertion, clk_time, result);
|
||||
reportClkSrcLatency(clk_insertion, clk_time, early_late, result);
|
||||
reportPath1(path, expanded, true, time_offset, result);
|
||||
}
|
||||
else {
|
||||
if (is_path_delay) {
|
||||
if (clk_delay > 0.0)
|
||||
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
|
||||
clk_end_time, result);
|
||||
clk_end_time, early_late, result);
|
||||
}
|
||||
else {
|
||||
reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result);
|
||||
float clk_arrival = clk_end_time;
|
||||
Arrival clk_arrival = clk_end_time;
|
||||
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
|
||||
clk_arrival, result);
|
||||
clk_arrival, early_late, result);
|
||||
}
|
||||
reportPath1(path, expanded, false, time_offset, result);
|
||||
}
|
||||
|
|
@ -2170,7 +2198,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
|
|||
else {
|
||||
Arrival insertion = end->targetClkInsertionDelay(this);
|
||||
if (clk_path) {
|
||||
reportClkSrcLatency(insertion, clk_time, result);
|
||||
reportClkSrcLatency(insertion, clk_time, early_late, result);
|
||||
PathExpanded clk_expanded(clk_path, this);
|
||||
float insertion_offset = tgtClkInsertionOffet(clk_path, early_late,
|
||||
path_ap);
|
||||
|
|
@ -2182,7 +2210,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
|
|||
// Output departure.
|
||||
Arrival clk_arrival = clk_time + clk_delay;
|
||||
reportLine(clkNetworkDelayIdealProp(clk->isPropagated()),
|
||||
clk_delay, clk_arrival, result);
|
||||
clk_delay, clk_arrival, min_max, result);
|
||||
}
|
||||
}
|
||||
reportClkUncertainty(end, clk_arrival, result);
|
||||
|
|
@ -2190,7 +2218,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
|
|||
}
|
||||
else {
|
||||
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay, clk_arrival,
|
||||
result);
|
||||
min_max, result);
|
||||
reportClkUncertainty(end, clk_arrival, result);
|
||||
reportCommonClkPessimism(end, clk_arrival, result);
|
||||
if (clk_path) {
|
||||
|
|
@ -2199,7 +2227,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
|
|||
prev_time
|
||||
+ end->targetClkArrival(this)
|
||||
+ end->sourceClkOffset(this),
|
||||
clk_end_tr, result);
|
||||
min_max, clk_end_tr, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2289,11 +2317,12 @@ ReportPath::reportClkLine(const Clock *clk,
|
|||
clk_name,
|
||||
rise_fall);
|
||||
if (clk->isPropagated())
|
||||
reportLine(clk_msg, clk_time - prev_time, clk_time, result);
|
||||
reportLine(clk_msg, clk_time - prev_time, clk_time, min_max, result);
|
||||
else {
|
||||
// Report ideal clock slew.
|
||||
float clk_slew = clk->slew(clk_tr, min_max);
|
||||
reportLine(clk_msg, clk_slew, clk_time - prev_time, clk_time, result);
|
||||
reportLine(clk_msg, clk_slew, clk_time - prev_time, clk_time,
|
||||
min_max, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2350,6 +2379,7 @@ ReportPath::reportGenClkSrcPath1(Clock *clk,
|
|||
{
|
||||
PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late);
|
||||
PathVertex src_path;
|
||||
const MinMax *min_max = path_ap->pathMinMax();
|
||||
search_->genclks()->srcPath(clk, clk_pin, clk_tr, insert_ap, src_path);
|
||||
if (!src_path.isNull()) {
|
||||
ClkInfo *src_clk_info = src_path.clkInfo(search_);
|
||||
|
|
@ -2370,13 +2400,12 @@ ReportPath::reportGenClkSrcPath1(Clock *clk,
|
|||
src_clk_tr,
|
||||
path_ap->pathMinMax(),
|
||||
early_late, path_ap);
|
||||
reportClkSrcLatency(insertion, gclk_time, result);
|
||||
reportClkSrcLatency(insertion, gclk_time, early_late, result);
|
||||
}
|
||||
PathExpanded src_expanded(&src_path, this);
|
||||
if (clk->pllOut()) {
|
||||
reportPath4(&src_path, src_expanded, skip_first_path, true,
|
||||
clk_used_as_data, gclk_time, result);
|
||||
const MinMax *min_max = path_ap->pathMinMax();
|
||||
PathAnalysisPt *pll_ap=path_ap->insertionAnalysisPt(min_max->opposite());
|
||||
Arrival pll_delay = search_->genclks()->pllDelay(clk, clk_tr, pll_ap);
|
||||
size_t path_length = src_expanded.size();
|
||||
|
|
@ -2392,13 +2421,14 @@ ReportPath::reportGenClkSrcPath1(Clock *clk,
|
|||
clk_used_as_data, gclk_time, result);
|
||||
if (!clk->isPropagated())
|
||||
reportLine("clock network delay (ideal)", 0.0, src_path.arrival(this),
|
||||
result);
|
||||
min_max, result);
|
||||
}
|
||||
else {
|
||||
if (clk->isPropagated())
|
||||
reportClkSrcLatency(0.0, gclk_time, result);
|
||||
reportClkSrcLatency(0.0, gclk_time, early_late, result);
|
||||
else if (!clk_used_as_data)
|
||||
reportLine("clock network delay (ideal)", 0.0, gclk_time, result);
|
||||
reportLine("clock network delay (ideal)", 0.0, gclk_time,
|
||||
min_max, result);
|
||||
}
|
||||
return !src_path.isNull();
|
||||
}
|
||||
|
|
@ -2406,9 +2436,11 @@ ReportPath::reportGenClkSrcPath1(Clock *clk,
|
|||
void
|
||||
ReportPath::reportClkSrcLatency(Arrival insertion,
|
||||
float clk_time,
|
||||
const EarlyLate *early_late,
|
||||
string &result)
|
||||
{
|
||||
reportLine("clock source latency", insertion, clk_time + insertion, result);
|
||||
reportLine("clock source latency", insertion, clk_time + insertion,
|
||||
early_late, result);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2423,7 +2455,9 @@ ReportPath::reportPathLine(const Path *path,
|
|||
const char *what = descriptionField(vertex);
|
||||
const TransRiseFall *tr = path->transition(this);
|
||||
bool is_driver = network_->isDriver(pin);
|
||||
DcalcAnalysisPt *dcalc_ap = path->pathAnalysisPt(this)->dcalcAnalysisPt();
|
||||
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
||||
const EarlyLate *early_late = path_ap->pathMinMax();
|
||||
DcalcAnalysisPt *dcalc_ap = path_ap->dcalcAnalysisPt();
|
||||
DcalcAPIndex ap_index = dcalc_ap->index();
|
||||
Slew slew = graph_->slew(vertex, tr, ap_index);
|
||||
float cap = field_blank_;
|
||||
|
|
@ -2431,7 +2465,7 @@ ReportPath::reportPathLine(const Path *path,
|
|||
if (is_driver && field_capacitance_->enabled())
|
||||
cap = loadCap(pin, tr, dcalc_ap);
|
||||
reportLine(what, cap, slew, field_blank_,
|
||||
incr, time, false, tr, line_case, result);
|
||||
incr, time, false, early_late, tr, line_case, result);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2440,11 +2474,12 @@ ReportPath::reportRequired(const PathEnd *end,
|
|||
string &result)
|
||||
{
|
||||
Required req_time = end->requiredTimeOffset(this);
|
||||
const EarlyLate *early_late = end->clkEarlyLate(this);
|
||||
ArcDelay margin = end->margin(this);
|
||||
if (end->minMax(this) == MinMax::max())
|
||||
margin = -margin;
|
||||
reportLine(margin_msg, margin, req_time, result);
|
||||
reportLine("data required time", req_time, result);
|
||||
reportLine(margin_msg, margin, req_time, early_late, result);
|
||||
reportLine("data required time", req_time, early_late, result);
|
||||
reportDashLine(result);
|
||||
}
|
||||
|
||||
|
|
@ -2452,9 +2487,11 @@ void
|
|||
ReportPath::reportSlack(const PathEnd *end,
|
||||
string &result)
|
||||
{
|
||||
reportLine("data required time", end->requiredTimeOffset(this), result);
|
||||
const EarlyLate *early_late = end->pathEarlyLate(this);
|
||||
reportLine("data required time", end->requiredTimeOffset(this),
|
||||
early_late->opposite(), result);
|
||||
reportLineNegative("data arrival time", end->dataArrivalTimeOffset(this),
|
||||
result);
|
||||
early_late, result);
|
||||
reportDashLine(result);
|
||||
reportSlack(end->slack(this), result);
|
||||
}
|
||||
|
|
@ -2463,10 +2500,10 @@ void
|
|||
ReportPath::reportSlack(Slack slack,
|
||||
string &result)
|
||||
{
|
||||
if (slack < 0.0)
|
||||
reportLine("slack (VIOLATED)", slack, result);
|
||||
else
|
||||
reportLine("slack (MET)", slack, result);
|
||||
const char *msg = (slack < 0.0)
|
||||
? "slack (VIOLATED)"
|
||||
: "slack (MET)";
|
||||
reportLine(msg, slack, EarlyLate::early(), result);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2477,7 +2514,8 @@ ReportPath::reportCommonClkPessimism(const PathEnd *end,
|
|||
if (sdc_->crprEnabled()) {
|
||||
float pessimism = end->commonClkPessimism(this);
|
||||
clk_arrival += pessimism;
|
||||
reportLine("clock reconvergence pessimism", pessimism, clk_arrival, result);
|
||||
reportLine("clock reconvergence pessimism", pessimism, clk_arrival,
|
||||
end->clkEarlyLate(this), result);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2486,15 +2524,17 @@ ReportPath::reportClkUncertainty(const PathEnd *end,
|
|||
Arrival &clk_arrival,
|
||||
string &result)
|
||||
{
|
||||
const EarlyLate *early_late = end->clkEarlyLate(this);
|
||||
float uncertainty = end->targetNonInterClkUncertainty(this);
|
||||
clk_arrival += uncertainty;
|
||||
if (uncertainty != 0.0)
|
||||
reportLine("clock uncertainty", uncertainty, clk_arrival, result);
|
||||
reportLine("clock uncertainty", uncertainty, clk_arrival,
|
||||
early_late, result);
|
||||
float inter_uncertainty = end->interClkUncertainty(this);
|
||||
clk_arrival += inter_uncertainty;
|
||||
if (inter_uncertainty != 0.0)
|
||||
reportLine("inter-clock uncertainty", inter_uncertainty, clk_arrival,
|
||||
result);
|
||||
early_late, result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -2538,6 +2578,7 @@ ReportPath::reportPath1(const Path *path,
|
|||
latch_time_given,
|
||||
latch_enable_path);
|
||||
if (!latch_enable_path.isNull()) {
|
||||
const EarlyLate *early_late = latch_enable_path.minMax(this);
|
||||
latch_enable_time = search_->clkPathArrival(&latch_enable_path);
|
||||
if (reportClkPath()) {
|
||||
PathExpanded enable_expanded(&latch_enable_path, this);
|
||||
|
|
@ -2548,9 +2589,10 @@ ReportPath::reportPath1(const Path *path,
|
|||
Arrival time = latch_enable_time + latch_time_given;
|
||||
Arrival incr = latch_time_given;
|
||||
if (incr >= 0.0)
|
||||
reportLine("time given to startpoint", incr, time, result);
|
||||
reportLine("time given to startpoint", incr, time, early_late, result);
|
||||
else
|
||||
reportLine("time borrowed from startpoint", incr, time, result);
|
||||
reportLine("time borrowed from startpoint", incr, time,
|
||||
early_late, result);
|
||||
// Override latch D arrival with enable + given.
|
||||
reportPathLine(expanded.path(0), delay_zero, time, "latch_D", result);
|
||||
bool propagated_clk = path->clkInfo(search_)->isPropagated();
|
||||
|
|
@ -2646,7 +2688,7 @@ ReportPath::reportPath5(const Path *path,
|
|||
Vertex *vertex = path1->vertex(this);
|
||||
Pin *pin = vertex->pin();
|
||||
Arrival time = path1->arrival(this) + time_offset;
|
||||
Arrival incr(0.0);
|
||||
float incr = 0.0;
|
||||
const char *line_case = NULL;
|
||||
bool is_clk_start = network_->isRegClkPin(pin);
|
||||
bool is_clk = path1->isClock(search_);
|
||||
|
|
@ -2671,7 +2713,8 @@ ReportPath::reportPath5(const Path *path,
|
|||
// from the input to the loads. Report the wire delay on the
|
||||
// input pin instead.
|
||||
Arrival next_time = next_path->arrival(this) + time_offset;
|
||||
incr = next_time - time;
|
||||
incr = delayMeanSigma(next_time, min_max)
|
||||
- delayMeanSigma(time, min_max);
|
||||
time = next_time;
|
||||
line_case = "input_drive";
|
||||
}
|
||||
|
|
@ -2718,11 +2761,13 @@ ReportPath::reportPath5(const Path *path,
|
|||
line_case = "clk_ideal";
|
||||
}
|
||||
else if (is_clk && !is_clk_start) {
|
||||
incr = time - prev_time;
|
||||
incr = delayMeanSigma(time, min_max)
|
||||
- delayMeanSigma(prev_time, min_max);
|
||||
line_case = "clk_prop";
|
||||
}
|
||||
else {
|
||||
incr = time - prev_time;
|
||||
incr = delayMeanSigma(time, min_max)
|
||||
- delayMeanSigma(prev_time, min_max);
|
||||
line_case = "normal";
|
||||
}
|
||||
if (report_input_pin_
|
||||
|
|
@ -2742,7 +2787,7 @@ ReportPath::reportPath5(const Path *path,
|
|||
if (report_net_ && is_driver) {
|
||||
// Capacitance field is reported on the net line.
|
||||
reportLine(what, field_blank_, slew, field_blank_,
|
||||
incr, time, false, tr, line_case, result);
|
||||
incr, time, false, min_max, tr, line_case, result);
|
||||
if (network_->isTopLevelPort(pin)) {
|
||||
const char *pin_name = cmd_network_->pathName(pin);
|
||||
what = stringPrintTmp(strlen(" (net)")
|
||||
|
|
@ -2763,12 +2808,12 @@ ReportPath::reportPath5(const Path *path,
|
|||
}
|
||||
float fanout = drvrFanout(vertex, min_max);
|
||||
reportLine(what, cap, field_blank_, fanout,
|
||||
field_blank_, field_blank_, false, NULL,
|
||||
field_blank_, field_blank_, false, min_max, NULL,
|
||||
line_case, result);
|
||||
}
|
||||
else
|
||||
reportLine(what, cap, slew, field_blank_,
|
||||
incr, time, false, tr, line_case, result);
|
||||
incr, time, false, min_max, tr, line_case, result);
|
||||
prev_time = time;
|
||||
}
|
||||
}
|
||||
|
|
@ -2870,6 +2915,7 @@ ReportPath::reportInputExternalDelay(const Path *first_path,
|
|||
if (!pathFromClkPin(first_path, first_pin)) {
|
||||
const TransRiseFall *tr = first_path->transition(this);
|
||||
Arrival time = first_path->arrival(this) + time_offset;
|
||||
const EarlyLate *early_late = first_path->minMax(this);
|
||||
InputDelay *input_delay = pathInputDelay(first_path);
|
||||
if (input_delay) {
|
||||
const Pin *ref_pin = input_delay->refPin();
|
||||
|
|
@ -2890,10 +2936,11 @@ ReportPath::reportInputExternalDelay(const Path *first_path,
|
|||
}
|
||||
float input_arrival =
|
||||
input_delay->delays()->value(tr, first_path->minMax(this));
|
||||
reportLine("input external delay", input_arrival, time, tr, result);
|
||||
reportLine("input external delay", input_arrival, time,
|
||||
early_late, tr, result);
|
||||
}
|
||||
else if (network_->isTopLevelPort(first_pin))
|
||||
reportLine("input external delay", 0.0, time, tr, result);
|
||||
reportLine("input external delay", 0.0, time, early_late, tr, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2970,42 +3017,56 @@ ReportPath::reportPathHeader(string &result)
|
|||
void
|
||||
ReportPath::reportLine(const char *what,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
string &result)
|
||||
{
|
||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
||||
field_blank_, total, false, NULL, NULL, result);
|
||||
field_blank_, total, false, early_late, NULL, NULL, result);
|
||||
}
|
||||
|
||||
// Report negative total.
|
||||
void
|
||||
ReportPath::reportLineNegative(const char *what,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
string &result)
|
||||
{
|
||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
||||
field_blank_, total, true, NULL, NULL, result);
|
||||
field_blank_, total, true, early_late, NULL, NULL, result);
|
||||
}
|
||||
|
||||
// Report total, and transition suffix.
|
||||
void
|
||||
ReportPath::reportLine(const char *what,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
const TransRiseFall *tr,
|
||||
string &result)
|
||||
{
|
||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
||||
field_blank_, total, false, tr, NULL, result);
|
||||
field_blank_, total, false, early_late, tr, NULL, result);
|
||||
}
|
||||
|
||||
// Report increment, and total.
|
||||
void
|
||||
ReportPath::reportLine(const char *what,
|
||||
Delay incr,
|
||||
Delay total,
|
||||
float incr,
|
||||
float total,
|
||||
string &result)
|
||||
{
|
||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
||||
incr, total, false, NULL, NULL, result);
|
||||
incr, total, false, NULL, NULL, NULL, result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportLine(const char *what,
|
||||
Delay incr,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
string &result)
|
||||
{
|
||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
||||
incr, total, false, early_late, NULL, NULL, result);
|
||||
}
|
||||
|
||||
// Report increment, total, and transition suffix.
|
||||
|
|
@ -3013,11 +3074,12 @@ void
|
|||
ReportPath::reportLine(const char *what,
|
||||
Delay incr,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
const TransRiseFall *tr,
|
||||
string &result)
|
||||
{
|
||||
reportLine(what, field_blank_, field_blank_, field_blank_,
|
||||
incr, total, false, tr, NULL, result);
|
||||
incr, total, false, early_late, tr, NULL, result);
|
||||
}
|
||||
|
||||
// Report slew, increment, and total.
|
||||
|
|
@ -3026,10 +3088,11 @@ ReportPath::reportLine(const char *what,
|
|||
Slew slew,
|
||||
Delay incr,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
string &result)
|
||||
{
|
||||
reportLine(what, field_blank_, slew, field_blank_,
|
||||
incr, total, false, NULL, NULL, result);
|
||||
incr, total, false, early_late, NULL, NULL, result);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -3040,6 +3103,7 @@ ReportPath::reportLine(const char *what,
|
|||
Delay incr,
|
||||
Delay total,
|
||||
bool total_with_minus,
|
||||
const EarlyLate *early_late,
|
||||
const TransRiseFall *tr,
|
||||
const char *line_case,
|
||||
string &result)
|
||||
|
|
@ -3070,16 +3134,14 @@ ReportPath::reportLine(const char *what,
|
|||
else if (field == field_capacitance_)
|
||||
reportField(cap, field, result);
|
||||
else if (field == field_slew_)
|
||||
reportField(slew, field, result);
|
||||
reportFieldDelay(slew, early_late, field, result);
|
||||
else if (field == field_incr_)
|
||||
reportField(incr, field, result);
|
||||
reportFieldDelay(incr, early_late, field, result);
|
||||
else if (field == field_total_) {
|
||||
if (total == field_blank_)
|
||||
reportFieldBlank(field, result);
|
||||
else if (total_with_minus)
|
||||
reportFieldTimeMinus(total, result);
|
||||
if (total_with_minus)
|
||||
reportFieldDelayMinus(total, early_late, field, result);
|
||||
else
|
||||
reportFieldTime(total, result);
|
||||
reportFieldDelay(total, early_late, field, result);
|
||||
}
|
||||
else if (field == field_edge_) {
|
||||
if (tr) {
|
||||
|
|
@ -3105,32 +3167,35 @@ ReportPath::reportLine(const char *what,
|
|||
void
|
||||
ReportPath::reportLineTotal(const char *what,
|
||||
Delay incr,
|
||||
const EarlyLate *early_late,
|
||||
string &result)
|
||||
{
|
||||
reportLineTotal1(what, incr, false, result);
|
||||
reportLineTotal1(what, incr, false, early_late, result);
|
||||
}
|
||||
|
||||
// Only the total field and always with leading minus sign.
|
||||
void
|
||||
ReportPath::reportLineTotalMinus(const char *what,
|
||||
Delay decr,
|
||||
const EarlyLate *early_late,
|
||||
string &result)
|
||||
{
|
||||
reportLineTotal1(what, decr, true, result);
|
||||
reportLineTotal1(what, decr, true, early_late, result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportLineTotal1(const char *what,
|
||||
Delay incr,
|
||||
bool incr_with_minus,
|
||||
const EarlyLate *early_late,
|
||||
string &result)
|
||||
{
|
||||
reportDescription(what, result);
|
||||
result += ' ';
|
||||
if (incr_with_minus)
|
||||
reportFieldTimeMinus(incr, result);
|
||||
reportFieldDelayMinus(incr, early_late, field_total_, result);
|
||||
else
|
||||
reportFieldTime(incr, result);
|
||||
reportFieldDelay(incr, early_late, field_total_, result);
|
||||
|
||||
reportEndOfLine(result);
|
||||
}
|
||||
|
|
@ -3162,35 +3227,84 @@ ReportPath::reportDescription(const char *what,
|
|||
}
|
||||
|
||||
void
|
||||
ReportPath::reportSpaceFieldTime(Delay value,
|
||||
string &result)
|
||||
ReportPath::reportFieldTime(float value,
|
||||
ReportField *field,
|
||||
string &result)
|
||||
{
|
||||
result += ' ';
|
||||
reportFieldTime(value, result);
|
||||
if (delayAsFloat(value) == field_blank_)
|
||||
reportFieldBlank(field, result);
|
||||
else {
|
||||
const char *str = units_->timeUnit()->asString(value, digits_);
|
||||
if (stringEq(str, minus_zero_))
|
||||
// Filter "-0.00" fields.
|
||||
str = plus_zero_;
|
||||
reportField(str, field, result);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportFieldTime(Delay value,
|
||||
string &result)
|
||||
ReportPath::reportSpaceFieldTime(float value,
|
||||
string &result)
|
||||
{
|
||||
const char *field = units_->timeUnit()->asString(delayAsFloat(value),
|
||||
digits_);
|
||||
if (stringEq(field, minus_zero_))
|
||||
result += ' ';
|
||||
reportFieldTime(value, field_total_, result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportSpaceFieldDelay(Delay value,
|
||||
const EarlyLate *early_late,
|
||||
string &result)
|
||||
{
|
||||
result += ' ';
|
||||
reportTotalDelay(value, early_late, result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportTotalDelay(Delay value,
|
||||
const EarlyLate *early_late,
|
||||
string &result)
|
||||
{
|
||||
const char *str = delayMeanSigmaString(value, early_late, units_, digits_);
|
||||
if (stringEq(str, minus_zero_))
|
||||
// Filter "-0.00" fields.
|
||||
field = plus_zero_;
|
||||
reportField(field, field_total_, result);
|
||||
str = plus_zero_;
|
||||
reportField(str, field_total_, result);
|
||||
}
|
||||
|
||||
// Total time always with leading minus sign.
|
||||
void
|
||||
ReportPath::reportFieldTimeMinus(Delay value,
|
||||
string &result)
|
||||
ReportPath::reportFieldDelayMinus(Delay value,
|
||||
const EarlyLate *early_late,
|
||||
ReportField *field,
|
||||
string &result)
|
||||
{
|
||||
const char *field=units_->timeUnit()->asString(-delayAsFloat(value),digits_);
|
||||
if (stringEq(field, plus_zero_))
|
||||
// Force leading minus sign.
|
||||
field = minus_zero_;
|
||||
reportField(field, field_total_, result);
|
||||
if (delayAsFloat(value) == field_blank_)
|
||||
reportFieldBlank(field, result);
|
||||
else {
|
||||
float mean_sigma = delayMeanSigma(value, early_late);
|
||||
const char *str = units_->timeUnit()->asString(-mean_sigma, digits_);
|
||||
if (stringEq(str, plus_zero_))
|
||||
// Force leading minus sign.
|
||||
str = minus_zero_;
|
||||
reportField(str, field, result);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportFieldDelay(Delay value,
|
||||
const EarlyLate *early_late,
|
||||
ReportField *field,
|
||||
string &result)
|
||||
{
|
||||
if (delayAsFloat(value) == field_blank_)
|
||||
reportFieldBlank(field, result);
|
||||
else {
|
||||
const char *str = delayMeanSigmaString(value, early_late, units_, digits_);
|
||||
if (stringEq(str, minus_zero_))
|
||||
// Filter "-0.00" fields.
|
||||
str = plus_zero_;
|
||||
reportField(str, field, result);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -307,9 +307,10 @@ protected:
|
|||
string &result);
|
||||
void reportClkSrcLatency(Arrival insertion,
|
||||
float clk_time,
|
||||
const EarlyLate *early_late,
|
||||
string &result);
|
||||
void reportPathLine(const Path *path,
|
||||
Arrival incr,
|
||||
Delay incr,
|
||||
Arrival time,
|
||||
const char *line_case,
|
||||
string &result);
|
||||
|
|
@ -385,27 +386,37 @@ protected:
|
|||
string &result);
|
||||
void reportLine(const char *what,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
string &result);
|
||||
void reportLineNegative(const char *what,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
string &result);
|
||||
void reportLine(const char *what,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
const TransRiseFall *tr,
|
||||
string &result);
|
||||
void reportLine(const char *what,
|
||||
Delay incr,
|
||||
Delay total,
|
||||
float incr,
|
||||
float total,
|
||||
string &result);
|
||||
void reportLine(const char *what,
|
||||
Delay incr,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
string &result);
|
||||
void reportLine(const char *what,
|
||||
Delay incr,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
const TransRiseFall *tr,
|
||||
string &result);
|
||||
void reportLine(const char *what,
|
||||
Slew slew,
|
||||
Delay incr,
|
||||
Delay total,
|
||||
const EarlyLate *early_late,
|
||||
string &result);
|
||||
void reportLine(const char *what,
|
||||
float cap,
|
||||
|
|
@ -414,28 +425,45 @@ protected:
|
|||
Delay incr,
|
||||
Delay total,
|
||||
bool total_with_minus,
|
||||
const EarlyLate *early_late,
|
||||
const TransRiseFall *tr,
|
||||
const char *line_case,
|
||||
string &result);
|
||||
void reportLineTotal(const char *what,
|
||||
Delay incr,
|
||||
const EarlyLate *early_late,
|
||||
string &result);
|
||||
void reportLineTotalMinus(const char *what,
|
||||
Delay decr,
|
||||
const EarlyLate *early_late,
|
||||
string &result);
|
||||
void reportLineTotal1(const char *what,
|
||||
Delay incr,
|
||||
bool incr_with_minus,
|
||||
const EarlyLate *early_late,
|
||||
string &result);
|
||||
void reportDashLineTotal(string &result);
|
||||
void reportDescription(const char *what,
|
||||
string &result);
|
||||
void reportSpaceFieldTime(Delay value,
|
||||
string &result);
|
||||
void reportFieldTime(Delay value,
|
||||
void reportFieldTime(float value,
|
||||
ReportField *field,
|
||||
string &result);
|
||||
void reportFieldTimeMinus(Delay value,
|
||||
void reportSpaceFieldTime(float value,
|
||||
string &result);
|
||||
void reportSpaceFieldDelay(Delay value,
|
||||
const EarlyLate *early_late,
|
||||
string &result);
|
||||
void reportFieldDelayMinus(Delay value,
|
||||
const EarlyLate *early_late,
|
||||
ReportField *field,
|
||||
string &result);
|
||||
void reportTotalDelay(Delay value,
|
||||
const EarlyLate *early_late,
|
||||
string &result);
|
||||
void reportFieldDelay(Delay value,
|
||||
const EarlyLate *early_late,
|
||||
ReportField *field,
|
||||
string &result);
|
||||
void reportField(float value,
|
||||
ReportField *field,
|
||||
string &result);
|
||||
|
|
@ -520,8 +548,8 @@ protected:
|
|||
const char *plus_zero_;
|
||||
const char *minus_zero_;
|
||||
|
||||
static const Delay field_blank_;
|
||||
static const Delay field_skip_;
|
||||
static const float field_blank_;
|
||||
static const float field_skip_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(ReportPath);
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ Search::Search(StaState *sta) :
|
|||
void
|
||||
Search::init(StaState *sta)
|
||||
{
|
||||
crpr_path_pruning_enabled_ = true;
|
||||
report_unconstrained_paths_ = false;
|
||||
search_adj_ = new SearchThru(NULL, sta);
|
||||
eval_pred_ = new EvalPred(sta);
|
||||
|
|
@ -292,6 +293,7 @@ Search::~Search()
|
|||
void
|
||||
Search::clear()
|
||||
{
|
||||
crpr_path_pruning_enabled_ = true;
|
||||
clk_arrivals_valid_ = false;
|
||||
arrivals_exist_ = false;
|
||||
arrivals_at_endpoints_exist_ = false;
|
||||
|
|
@ -315,6 +317,18 @@ Search::clear()
|
|||
found_downstream_clk_pins_ = false;
|
||||
}
|
||||
|
||||
bool
|
||||
Search::crprPathPruningEnabled() const
|
||||
{
|
||||
return crpr_path_pruning_enabled_;
|
||||
}
|
||||
|
||||
void
|
||||
Search::setCrprpathPruningEnabled(bool enabled)
|
||||
{
|
||||
crpr_path_pruning_enabled_ = enabled;
|
||||
}
|
||||
|
||||
void
|
||||
Search::setReportUnconstrainedPaths(bool report)
|
||||
{
|
||||
|
|
@ -1086,9 +1100,9 @@ ArrivalVisitor::visit(Vertex *vertex)
|
|||
|
||||
visitFaninPaths(vertex);
|
||||
if (crpr_active_
|
||||
&& search->crprPathPruningEnabled()
|
||||
&& !has_fanin_one_)
|
||||
pruneCrprArrivals();
|
||||
|
||||
// Insert paths that originate here but
|
||||
if (!network->isTopLevelPort(pin)
|
||||
&& sdc->hasInputDelay(pin))
|
||||
|
|
@ -1538,11 +1552,11 @@ Search::seedClkArrival(const Pin *pin,
|
|||
bool latency_exists;
|
||||
// Check for clk pin latency.
|
||||
sdc_->clockLatency(clk, pin, tr, min_max,
|
||||
latency, latency_exists);
|
||||
latency, latency_exists);
|
||||
if (!latency_exists) {
|
||||
// Check for clk latency (lower priority).
|
||||
sdc_->clockLatency(clk, tr, min_max,
|
||||
latency, latency_exists);
|
||||
latency, latency_exists);
|
||||
if (latency_exists) {
|
||||
// Propagated pin overrides latency on clk.
|
||||
if (sdc_->isPropagatedClock(pin)) {
|
||||
|
|
@ -1712,8 +1726,7 @@ Search::seedInputArrival(const Pin *pin,
|
|||
{
|
||||
bool has_arrival = false;
|
||||
// There can be multiple arrivals for a pin with wrt different clocks.
|
||||
PinInputDelayIterator *arrival_iter =
|
||||
sdc_->inputDelayVertexIterator(pin);
|
||||
PinInputDelayIterator *arrival_iter = sdc_->inputDelayVertexIterator(pin);
|
||||
TagGroupBldr tag_bldr(true, this);
|
||||
tag_bldr.init(vertex);
|
||||
while (arrival_iter->hasNext()) {
|
||||
|
|
@ -1762,8 +1775,7 @@ Search::seedInputArrival1(const Pin *pin,
|
|||
TagGroupBldr *tag_bldr)
|
||||
{
|
||||
// There can be multiple arrivals for a pin with wrt different clocks.
|
||||
PinInputDelayIterator *arrival_iter=
|
||||
sdc_->inputDelayVertexIterator(pin);
|
||||
PinInputDelayIterator *arrival_iter = sdc_->inputDelayVertexIterator(pin);
|
||||
while (arrival_iter->hasNext()) {
|
||||
InputDelay *input_delay = arrival_iter->next();
|
||||
Clock *input_clk = input_delay->clock();
|
||||
|
|
@ -1864,8 +1876,7 @@ Search::inputDelayRefPinArrival(Path *ref_path,
|
|||
const EarlyLate *early_late = min_max;
|
||||
// Input delays from ideal clk reference pins include clock
|
||||
// insertion delay but not latency.
|
||||
ref_insertion = sdc_->clockInsertion(clk, clk_tr, min_max,
|
||||
early_late);
|
||||
ref_insertion = sdc_->clockInsertion(clk, clk_tr, min_max, early_late);
|
||||
ref_arrival = clk_edge->time() + ref_insertion;
|
||||
ref_latency = 0.0;
|
||||
}
|
||||
|
|
@ -2311,7 +2322,7 @@ Search::clkPathArrival(const Path *clk_path,
|
|||
return clk_path->arrival(this);
|
||||
}
|
||||
|
||||
float
|
||||
Arrival
|
||||
Search::pathClkPathArrival(const Path *path) const
|
||||
{
|
||||
PathRef src_clk_path;
|
||||
|
|
@ -2392,7 +2403,7 @@ Search::fromRegClkTag(const Pin *from_pin,
|
|||
{
|
||||
ExceptionStateSet *states = NULL;
|
||||
if (sdc_->exceptionFromStates(from_pin, from_tr, clk, clk_tr,
|
||||
min_max, states)) {
|
||||
min_max, states)) {
|
||||
// Hack for filter -from reg/Q.
|
||||
sdc_->filterRegQStates(to_pin, to_tr, min_max, states);
|
||||
return findTag(to_tr, path_ap, clk_info, false, NULL, false, states, true);
|
||||
|
|
@ -2535,7 +2546,7 @@ Search::thruClkInfo(PathVertex *from_path,
|
|||
float latency;
|
||||
bool exists;
|
||||
sdc_->clockLatency(from_clk, to_pin, clk_tr, min_max,
|
||||
latency, exists);
|
||||
latency, exists);
|
||||
if (exists) {
|
||||
// Latency on pin has precidence over fanin or hierarchical
|
||||
// pin latency.
|
||||
|
|
@ -2546,7 +2557,7 @@ Search::thruClkInfo(PathVertex *from_path,
|
|||
else {
|
||||
// Check for hierarchical pin latency thru edge.
|
||||
sdc_->clockLatency(edge, clk_tr, min_max,
|
||||
latency, exists);
|
||||
latency, exists);
|
||||
if (exists) {
|
||||
to_latency = latency;
|
||||
to_clk_prop = false;
|
||||
|
|
@ -2618,8 +2629,7 @@ Search::mutateTag(Tag *from_tag,
|
|||
}
|
||||
}
|
||||
// Get the set of -thru exceptions starting at to_pin/edge.
|
||||
sdc_->exceptionThruStates(from_pin, to_pin, to_tr, min_max,
|
||||
new_states);
|
||||
sdc_->exceptionThruStates(from_pin, to_pin, to_tr, min_max, new_states);
|
||||
if (new_states || state_change) {
|
||||
// Second pass to apply state changes and add updated existing
|
||||
// states to new states.
|
||||
|
|
@ -2659,8 +2669,7 @@ Search::mutateTag(Tag *from_tag,
|
|||
}
|
||||
else
|
||||
// Get the set of -thru exceptions starting at to_pin/edge.
|
||||
sdc_->exceptionThruStates(from_pin, to_pin, to_tr, min_max,
|
||||
new_states);
|
||||
sdc_->exceptionThruStates(from_pin, to_pin, to_tr, min_max, new_states);
|
||||
|
||||
if (new_states)
|
||||
return findTag(to_tr, path_ap, to_clk_info, to_is_clk,
|
||||
|
|
@ -3058,8 +3067,8 @@ Search::timingDerate(Vertex *from_vertex,
|
|||
const Pin *pin = from_vertex->pin();
|
||||
if (role->isWire()) {
|
||||
const TransRiseFall *tr = arc->toTrans()->asRiseFall();
|
||||
return sdc_->timingDerateNet(pin, derate_clk_data,
|
||||
tr, path_ap->pathMinMax());
|
||||
return sdc_->timingDerateNet(pin, derate_clk_data, tr,
|
||||
path_ap->pathMinMax());
|
||||
}
|
||||
else {
|
||||
TimingDerateType derate_type;
|
||||
|
|
@ -3072,9 +3081,8 @@ Search::timingDerate(Vertex *from_vertex,
|
|||
derate_type = timing_derate_cell_delay;
|
||||
tr = arc->fromTrans()->asRiseFall();
|
||||
}
|
||||
return sdc_->timingDerateInstance(pin, derate_type,
|
||||
derate_clk_data, tr,
|
||||
path_ap->pathMinMax());
|
||||
return sdc_->timingDerateInstance(pin, derate_type, derate_clk_data, tr,
|
||||
path_ap->pathMinMax());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3536,12 +3544,13 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
|||
VertexPathIterator to_iter(to_vertex, to_tr, path_ap, sta_);
|
||||
while (to_iter.hasNext()) {
|
||||
PathVertex *to_path = to_iter.next();
|
||||
if (tagMatchNoCrpr(to_path->tag(sta_), to_tag)) {
|
||||
Tag *to_path_tag = to_path->tag(sta_);
|
||||
if (tagMatchNoCrpr(to_path_tag, to_tag)) {
|
||||
Required to_required = to_path->required(sta_);
|
||||
Required from_required = to_required - arc_delay;
|
||||
debugPrint2(debug, "search", 3, " to tag %2u: %s\n",
|
||||
to_tag->index(),
|
||||
to_tag->asString(sta_));
|
||||
to_path_tag->index(),
|
||||
to_path_tag->asString(sta_));
|
||||
debugPrint5(debug, "search", 3, " %s - %s = %s %s %s\n",
|
||||
delayAsString(to_required, sta_),
|
||||
delayAsString(arc_delay, sta_),
|
||||
|
|
@ -3676,7 +3685,7 @@ Search::exceptionTo(ExceptionPathType type,
|
|||
if ((type == exception_type_any
|
||||
|| exception->type() == type)
|
||||
&& sdc_->isCompleteTo(state, pin, tr, clk_edge, min_max,
|
||||
match_min_max_exactly, require_to_pin)
|
||||
match_min_max_exactly, require_to_pin)
|
||||
&& (hi_priority_exception == NULL
|
||||
|| priority > hi_priority
|
||||
|| (priority == hi_priority
|
||||
|
|
|
|||
|
|
@ -68,6 +68,11 @@ public:
|
|||
virtual void copyState(const StaState *sta);
|
||||
// Reset to virgin state.
|
||||
void clear();
|
||||
// When enabled, non-critical path arrivals are pruned to improve
|
||||
// run time and reduce memory. The side-effect is that slacks for
|
||||
// non-critical paths on intermediate pins may be incorrect.
|
||||
bool crprPathPruningEnabled() const;
|
||||
void setCrprpathPruningEnabled(bool enabled);
|
||||
// Report unconstrained paths.
|
||||
bool reportUnconstrainedPaths() const { return report_unconstrained_paths_; }
|
||||
void setReportUnconstrainedPaths(bool report);
|
||||
|
|
@ -132,7 +137,7 @@ public:
|
|||
const MinMax *min_max,
|
||||
const PathAnalysisPt *path_ap) const;
|
||||
// Clock arrival at the path source/launch point.
|
||||
float pathClkPathArrival(const Path *path) const;
|
||||
Arrival pathClkPathArrival(const Path *path) const;
|
||||
|
||||
PathGroup *pathGroup(const PathEnd *path_end) const;
|
||||
void deletePathGroups();
|
||||
|
|
@ -571,6 +576,7 @@ protected:
|
|||
VisitPathEnds *visit_path_ends_;
|
||||
GatedClk *gated_clk_;
|
||||
Crpr *crpr_;
|
||||
bool crpr_path_pruning_enabled_;
|
||||
Genclks *genclks_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@
|
|||
#include "VisitPathGroupVertices.hh"
|
||||
#include "SdfWriter.hh"
|
||||
#include "Genclks.hh"
|
||||
#include "Power.hh"
|
||||
#include "Sta.hh"
|
||||
|
||||
namespace sta {
|
||||
|
|
@ -272,6 +273,7 @@ Sta::Sta() :
|
|||
check_max_skews_(NULL),
|
||||
clk_skews_(NULL),
|
||||
report_path_(NULL),
|
||||
power_(NULL),
|
||||
link_make_black_boxes_(true),
|
||||
update_genclks_(false)
|
||||
{
|
||||
|
|
@ -348,6 +350,8 @@ Sta::updateComponentsState()
|
|||
report_path_->copyState(this);
|
||||
if (check_timing_)
|
||||
check_timing_->copyState(this);
|
||||
if (power_)
|
||||
power_->copyState(this);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -466,6 +470,12 @@ Sta::makeReportPath()
|
|||
report_path_ = new ReportPath(this);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::makePower()
|
||||
{
|
||||
power_ = new Power(this);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::setSta(Sta *sta)
|
||||
{
|
||||
|
|
@ -3185,9 +3195,9 @@ Sta::portExtPinCap(Port *port,
|
|||
int fanout;
|
||||
bool pin_exists, wire_exists, fanout_exists;
|
||||
sdc_->portExtCap(port, tr, min_max,
|
||||
pin_cap, pin_exists,
|
||||
wire_cap, wire_exists,
|
||||
fanout, fanout_exists);
|
||||
pin_cap, pin_exists,
|
||||
wire_cap, wire_exists,
|
||||
fanout, fanout_exists);
|
||||
if (pin_exists)
|
||||
return pin_cap;
|
||||
else
|
||||
|
|
@ -3221,9 +3231,9 @@ Sta::portExtWireCap(Port *port,
|
|||
int fanout;
|
||||
bool pin_exists, wire_exists, fanout_exists;
|
||||
sdc_->portExtCap(port, tr, min_max,
|
||||
pin_cap, pin_exists,
|
||||
wire_cap, wire_exists,
|
||||
fanout, fanout_exists);
|
||||
pin_cap, pin_exists,
|
||||
wire_cap, wire_exists,
|
||||
fanout, fanout_exists);
|
||||
if (wire_exists)
|
||||
return wire_cap;
|
||||
else
|
||||
|
|
@ -3244,8 +3254,7 @@ Sta::setPortExtWireCap(Port *port,
|
|||
MinMaxIterator mm_iter(min_max);
|
||||
while (mm_iter.hasNext()) {
|
||||
MinMax *mm = mm_iter.next();
|
||||
sdc_->setPortExtWireCap(port, subtract_pin_cap, tr1,
|
||||
corner, mm, cap);
|
||||
sdc_->setPortExtWireCap(port, subtract_pin_cap, tr1, corner, mm, cap);
|
||||
}
|
||||
}
|
||||
delaysInvalidFromFanin(port);
|
||||
|
|
@ -3375,6 +3384,7 @@ Sta::readParasitics(const char *filename,
|
|||
Instance *instance,
|
||||
const MinMaxAll *min_max,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
@ -3398,6 +3408,7 @@ Sta::readParasitics(const char *filename,
|
|||
const OperatingConditions *op_cond =
|
||||
sdc_->operatingConditions(cnst_min_max);
|
||||
bool success = readParasiticsFile(filename, instance, ap, increment,
|
||||
pin_cap_included,
|
||||
keep_coupling_caps, coupling_cap_factor,
|
||||
reduce_to, delete_after_reduce,
|
||||
op_cond, corner, cnst_min_max, save, quiet,
|
||||
|
|
@ -4860,4 +4871,39 @@ Sta::reportCheck(MaxSkewCheck *check,
|
|||
report_path_->reportCheck(check, verbose);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
Sta::powerPreamble()
|
||||
{
|
||||
// Use arrivals to find clocking info.
|
||||
searchPreamble();
|
||||
search_->findAllArrivals();
|
||||
if (power_ == NULL)
|
||||
makePower();
|
||||
}
|
||||
|
||||
void
|
||||
Sta::power(const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &total,
|
||||
PowerResult &sequential,
|
||||
PowerResult &combinational,
|
||||
PowerResult ¯o,
|
||||
PowerResult &pad)
|
||||
{
|
||||
powerPreamble();
|
||||
power_->power(corner, total, sequential, combinational, macro, pad);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::power(const Instance *inst,
|
||||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result)
|
||||
{
|
||||
powerPreamble();
|
||||
power_->power(inst, corner, result);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ class SearchPred;
|
|||
class Corner;
|
||||
class ClkSkews;
|
||||
class ReportField;
|
||||
class Power;
|
||||
class PowerResult;
|
||||
|
||||
typedef InstanceSeq::Iterator SlowDrvrIterator;
|
||||
typedef Vector<const char*> CheckError;
|
||||
|
|
@ -669,6 +671,7 @@ public:
|
|||
void reportCheck(MaxSkewCheck *check,
|
||||
bool verbose);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// User visible but non SDC commands.
|
||||
|
||||
|
|
@ -974,9 +977,11 @@ public:
|
|||
Slack vertexSlack(Vertex *vertex,
|
||||
const TransRiseFall *tr,
|
||||
const PathAnalysisPt *path_ap);
|
||||
// Slew for one delay calc analysis pt(corner).
|
||||
Slew vertexSlew(Vertex *vertex,
|
||||
const TransRiseFall *tr,
|
||||
const DcalcAnalysisPt *dcalc_ap);
|
||||
// Slew across all corners.
|
||||
Slew vertexSlew(Vertex *vertex,
|
||||
const TransRiseFall *tr,
|
||||
const MinMax *min_max);
|
||||
|
|
@ -1021,6 +1026,7 @@ public:
|
|||
Instance *instance,
|
||||
const MinMaxAll *min_max,
|
||||
bool increment,
|
||||
bool pin_cap_included,
|
||||
bool keep_coupling_caps,
|
||||
float coupling_cap_factor,
|
||||
ReduceParasiticsTo reduce_to,
|
||||
|
|
@ -1143,6 +1149,21 @@ public:
|
|||
Vertex *vertex,
|
||||
LibertyCell *to_cell);
|
||||
|
||||
// Power API.
|
||||
Power *power() { return power_; }
|
||||
const Power *power() const { return power_; }
|
||||
void power(const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &total,
|
||||
PowerResult &sequential,
|
||||
PowerResult &combinational,
|
||||
PowerResult ¯o,
|
||||
PowerResult &pad);
|
||||
void power(const Instance *inst,
|
||||
const Corner *corner,
|
||||
// Return values.
|
||||
PowerResult &result);
|
||||
|
||||
protected:
|
||||
// Default constructors that are called by makeComponents in the Sta
|
||||
// constructor. These can be redefined by a derived class to
|
||||
|
|
@ -1168,6 +1189,7 @@ protected:
|
|||
virtual void makeCheckMinPeriods();
|
||||
virtual void makeCheckMaxSkews();
|
||||
virtual void makeReportPath();
|
||||
virtual void makePower();
|
||||
virtual void makeObservers();
|
||||
NetworkEdit *networkCmdEdit();
|
||||
|
||||
|
|
@ -1254,6 +1276,7 @@ protected:
|
|||
Corner *corner,
|
||||
const MinMax *min_max);
|
||||
void parasiticsChangedAfter();
|
||||
void powerPreamble();
|
||||
|
||||
CmdNamespace cmd_namespace_;
|
||||
Instance *current_instance_;
|
||||
|
|
@ -1264,6 +1287,7 @@ protected:
|
|||
CheckMaxSkews *check_max_skews_;
|
||||
ClkSkews *clk_skews_;
|
||||
ReportPath *report_path_;
|
||||
Power *power_;
|
||||
Tcl_Interp *tcl_interp_;
|
||||
bool link_make_black_boxes_;
|
||||
bool update_genclks_;
|
||||
|
|
|
|||
16
tcl/Cmds.tcl
16
tcl/Cmds.tcl
|
|
@ -1246,6 +1246,22 @@ proc parse_corner { keys_var } {
|
|||
}
|
||||
}
|
||||
|
||||
proc parse_corner_or_default { keys_var } {
|
||||
upvar 1 $keys_var keys
|
||||
|
||||
if { [info exists keys(-corner)] } {
|
||||
set corner_name $keys(-corner)
|
||||
set corner [find_corner $corner_name]
|
||||
if { $corner == "NULL" } {
|
||||
sta_error "$corner_name is not the name of process corner."
|
||||
} else {
|
||||
return $corner
|
||||
}
|
||||
} else {
|
||||
return [default_corner]
|
||||
}
|
||||
}
|
||||
|
||||
proc parse_corner_or_all { keys_var } {
|
||||
upvar 1 $keys_var keys
|
||||
|
||||
|
|
|
|||
|
|
@ -121,8 +121,8 @@ proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc } {
|
|||
set iter [$edge timing_arc_iterator]
|
||||
while {[$iter has_next]} {
|
||||
set arc [$iter next]
|
||||
set delays [$edge arc_delays $arc]
|
||||
set delays_fmt [format_times $delays $sta_report_default_digits]
|
||||
set delays [$edge arc_delay_strings $arc $sta_report_default_digits]
|
||||
set delays_fmt [format_delays $delays]
|
||||
set disable_reason ""
|
||||
if { [timing_arc_disabled $edge $arc] } {
|
||||
set disable_reason " disabled"
|
||||
|
|
@ -144,6 +144,18 @@ proc format_times { values digits } {
|
|||
return $result
|
||||
}
|
||||
|
||||
# Separate delay list elements with colons.
|
||||
proc format_delays { values } {
|
||||
set result ""
|
||||
foreach value $values {
|
||||
if { $result != "" } {
|
||||
append result ":"
|
||||
}
|
||||
append result $value
|
||||
}
|
||||
return $result
|
||||
}
|
||||
|
||||
proc edge_disable_reason { edge } {
|
||||
set disables ""
|
||||
if [$edge is_disabled_constraint] {
|
||||
|
|
|
|||
|
|
@ -33,46 +33,5 @@ proc read_liberty { args } {
|
|||
read_liberty_cmd $filename $corner $min_max $infer_latches
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
define_hidden_cmd_args "report_lib_cell_power" {lib_cell}
|
||||
|
||||
proc report_lib_cell_power { args } {
|
||||
global sta_report_default_digits
|
||||
|
||||
check_argc_eq3 "report_internal_power" $args
|
||||
set cells [get_lib_cells [lindex $args 0]]
|
||||
set slew [time_ui_sta [lindex $args 1]]
|
||||
set cap [capacitance_ui_sta [lindex $args 2]]
|
||||
|
||||
foreach cell $cells {
|
||||
puts "[$cell name] Leakage Power"
|
||||
set leakage_iter [$cell leakage_power_iterator]
|
||||
while {[$leakage_iter has_next]} {
|
||||
set leakage [$leakage_iter next]
|
||||
puts "[format_power [$leakage power] 5] [$leakage when]"
|
||||
}
|
||||
$leakage_iter finish
|
||||
|
||||
puts "[$cell name] Internal Power"
|
||||
set internal_iter [$cell internal_power_iterator]
|
||||
while {[$internal_iter has_next]} {
|
||||
set internal [$internal_iter next]
|
||||
set port_name [[$internal port] name]
|
||||
set related_port [$internal related_port]
|
||||
if { $related_port != "NULL" } {
|
||||
set related_port_name [$related_port name]
|
||||
} else {
|
||||
set related_port_name ""
|
||||
}
|
||||
set digits $sta_report_default_digits
|
||||
set rise [format_power [$internal power rise $slew $cap] $digits]
|
||||
set fall [format_power [$internal power fall $slew $cap] $digits]
|
||||
puts "$port_name $related_port_name [rise_short_name] $rise [fall_short_name] $fall [$internal when]"
|
||||
}
|
||||
$internal_iter finish
|
||||
}
|
||||
}
|
||||
|
||||
# sta namespace end
|
||||
}
|
||||
|
|
|
|||
|
|
@ -251,10 +251,11 @@ define_cmd_args "report_net" \
|
|||
proc_redirect report_net {
|
||||
global sta_report_default_digits
|
||||
|
||||
parse_key_args "report_net" args keys {-digits -significant_digits} \
|
||||
parse_key_args "report_net" args keys {-corner -digits -significant_digits} \
|
||||
flags {-connections -verbose -hier_pins}
|
||||
check_argc_eq1 "report_net" $args
|
||||
|
||||
set corner [parse_corner keys]
|
||||
set digits $sta_report_default_digits
|
||||
if { [info exists keys(-digits)] } {
|
||||
set digits $keys(-digits)
|
||||
|
|
@ -269,13 +270,13 @@ proc_redirect report_net {
|
|||
set net_path [lindex $args 0]
|
||||
set net [find_net $net_path]
|
||||
if { $net != "NULL" } {
|
||||
report_net1 $net $connections $verbose $hier_pins $digits
|
||||
report_net1 $net $connections $verbose $hier_pins $corner $digits
|
||||
} else {
|
||||
set pin [find_pin $net_path]
|
||||
if { $pin != "NULL" } {
|
||||
set net [$pin net]
|
||||
if { $net != "NULL" } {
|
||||
report_net1 $net $connections $verbose $hier_pins $digits
|
||||
report_net1 $net $connections $verbose $hier_pins $corner $digits
|
||||
} else {
|
||||
sta_error "net $net_path not found."
|
||||
}
|
||||
|
|
@ -287,27 +288,27 @@ proc_redirect report_net {
|
|||
|
||||
proc report_net_ { net } {
|
||||
global sta_report_default_digits
|
||||
report_net1 $net 1 1 1 $sta_report_default_digits
|
||||
report_net1 $net 1 1 1 $corner $sta_report_default_digits
|
||||
}
|
||||
|
||||
proc report_net1 { net connections verbose hier_pins digits } {
|
||||
proc report_net1 { net connections verbose hier_pins corner digits } {
|
||||
puts "Net [$net path_name]"
|
||||
if {$connections} {
|
||||
set pins [net_connected_pins_sorted $net]
|
||||
if {$verbose} {
|
||||
report_net_caps $net $pins $digits
|
||||
report_net_caps $net $pins $corner $digits
|
||||
}
|
||||
puts "Driver pins"
|
||||
report_net_pins $pins "is_driver" $verbose $digits
|
||||
report_net_pins $pins "is_driver" $verbose $corner $digits
|
||||
puts ""
|
||||
puts "Load pins"
|
||||
report_net_pins $pins "is_load" $verbose $digits
|
||||
report_net_pins $pins "is_load" $verbose $corner $digits
|
||||
if {$hier_pins} {
|
||||
puts ""
|
||||
puts "Hierarchical pins"
|
||||
report_net_pins $pins "is_hierarchical" $verbose $digits
|
||||
report_net_pins $pins "is_hierarchical" $verbose $corner $digits
|
||||
}
|
||||
report_net_other_pins $pins $verbose $digits
|
||||
report_net_other_pins $pins $verbose $corner $digits
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -323,8 +324,7 @@ proc net_connected_pins_sorted { net } {
|
|||
return $pins
|
||||
}
|
||||
|
||||
proc report_net_caps { net pins digits } {
|
||||
set corner [default_corner]
|
||||
proc report_net_caps { net pins corner digits } {
|
||||
report_net_cap $net "Pin" "pin_capacitance" $corner $digits
|
||||
report_net_cap $net "Wire" "wire_capacitance" $corner $digits
|
||||
report_net_cap $net "Total" "capacitance" $corner $digits
|
||||
|
|
@ -356,15 +356,15 @@ proc report_net_cap { net caption cap_msg corner digits } {
|
|||
puts " $caption capacitance: [capacitances_str $cap_r_min $cap_r_max $cap_f_min $cap_f_max $digits]"
|
||||
}
|
||||
|
||||
proc report_net_pins { pins pin_pred verbose digits } {
|
||||
proc report_net_pins { pins pin_pred verbose corner digits } {
|
||||
foreach pin $pins {
|
||||
if {[$pin $pin_pred]} {
|
||||
report_net_pin $pin $verbose $digits
|
||||
report_net_pin $pin $verbose $corner $digits
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc report_net_other_pins { pins verbose digits } {
|
||||
proc report_net_other_pins { pins verbose corner digits } {
|
||||
set header 0
|
||||
foreach pin $pins {
|
||||
if { !([$pin is_driver] || [$pin is_load] || [$pin is_hierarchical]) } {
|
||||
|
|
@ -373,12 +373,12 @@ proc report_net_other_pins { pins verbose digits } {
|
|||
puts "Other pins"
|
||||
set header 1
|
||||
}
|
||||
report_net_pin $pin $verbose $digits
|
||||
report_net_pin $pin $verbose $corner $digits
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc report_net_pin { pin verbose digits } {
|
||||
proc report_net_pin { pin verbose corner digits } {
|
||||
if [$pin is_leaf] {
|
||||
set cell_name [[[$pin instance] cell] name]
|
||||
puts -nonewline " [$pin path_name] [$pin direction] ($cell_name)"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
# OpenSTA, Static Timing Analyzer
|
||||
# Copyright (c) 2018, Parallax Software, Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
################################################################
|
||||
#
|
||||
# Power commands.
|
||||
#
|
||||
################################################################
|
||||
|
||||
namespace eval sta {
|
||||
|
||||
define_cmd_args "report_power" \
|
||||
{ [-instances instances]\
|
||||
[-corner corner_name]]\
|
||||
[-digits digits]\
|
||||
[> filename] [>> filename] }
|
||||
|
||||
proc_redirect report_power {
|
||||
global sta_report_default_digits
|
||||
|
||||
parse_key_args "report_power" args keys {-instances -corner -digits} flags {} 1
|
||||
|
||||
if [info exists keys(-digits)] {
|
||||
set digits $keys(-digits)
|
||||
check_positive_integer "-digits" $digits
|
||||
} else {
|
||||
set digits $sta_report_default_digits
|
||||
}
|
||||
set corner [parse_corner keys]
|
||||
|
||||
if { [info exists keys(-instances)] } {
|
||||
set insts [get_instance_error "-cell" $keys(-instances)]
|
||||
foreach inst $insts {
|
||||
report_power_inst $inst $corner $digits
|
||||
}
|
||||
} else {
|
||||
report_power_design $corner $digits
|
||||
}
|
||||
}
|
||||
|
||||
proc report_power_design { corner digits } {
|
||||
set power_result [design_power $corner]
|
||||
puts "Group Internal Switching Leakage Total"
|
||||
puts " Power Power Power Power (mW)"
|
||||
puts "-------------------------------------------------------------------"
|
||||
set design_total [lindex $power_result 3]
|
||||
report_power_row "Sequential" $power_result 4 $design_total $digits
|
||||
report_power_row "Combinational" $power_result 8 $design_total $digits
|
||||
report_power_row "Macro" $power_result 12 $design_total $digits
|
||||
report_power_row "Pad" $power_result 16 $design_total $digits
|
||||
puts "-------------------------------------------------------------------"
|
||||
report_power_row "Total" $power_result 0 $design_total $digits
|
||||
|
||||
puts -nonewline " "
|
||||
report_power_col_percent $power_result 0
|
||||
report_power_col_percent $power_result 1
|
||||
report_power_col_percent $power_result 2
|
||||
puts ""
|
||||
}
|
||||
|
||||
proc report_power_row { type power_result index design_total digits } {
|
||||
set internal [lindex $power_result [expr $index + 0]]
|
||||
set switching [lindex $power_result [expr $index + 1]]
|
||||
set leakage [lindex $power_result [expr $index + 2]]
|
||||
set total [lindex $power_result [expr $index + 3]]
|
||||
set percent [expr $total / $design_total * 100]
|
||||
puts -nonewline [format "%-20s" $type]
|
||||
report_power_col $internal $digits
|
||||
report_power_col $switching $digits
|
||||
report_power_col $leakage $digits
|
||||
report_power_col $total $digits
|
||||
puts [format " %5.1f%%" $percent]
|
||||
}
|
||||
|
||||
proc report_power_col { pwr digits } {
|
||||
puts -nonewline [format "%10.${digits}f" [expr $pwr * 1e+3]]
|
||||
}
|
||||
|
||||
proc report_power_col_percent { power_result index } {
|
||||
set total [lindex $power_result 3]
|
||||
set col [lindex $power_result $index]
|
||||
puts -nonewline [format "%9.1f%%" [expr $col / $total * 100]]
|
||||
}
|
||||
|
||||
proc report_power_inst { inst corner digits } {
|
||||
puts "Instance: [$inst path_name]"
|
||||
puts "Cell: [[$inst liberty_cell] name]"
|
||||
puts "Liberty file: [[[$inst liberty_cell] liberty_library] filename]"
|
||||
set power_result [instance_power $inst $corner]
|
||||
set switching [lindex $power_result 0]
|
||||
set internal [lindex $power_result 1]
|
||||
set leakage [lindex $power_result 2]
|
||||
set total [lindex $power_result 3]
|
||||
report_power_line "Switching power" $switching $digits
|
||||
report_power_line "Internal power" $internal $digits
|
||||
report_power_line "Leakage power" $leakage $digits
|
||||
report_power_line "Total power" $total $digits
|
||||
}
|
||||
|
||||
proc report_power_line { type pwr digits } {
|
||||
puts [format "%-16s %.${digits}fmW" $type [expr $pwr * 1e+3]]
|
||||
}
|
||||
|
||||
set ::power_default_signal_toggle_rate 0.1
|
||||
|
||||
trace variable ::power_default_signal_toggle_rate "rw" \
|
||||
sta::trace_power_default_signal_toggle_rate
|
||||
|
||||
proc trace_power_default_signal_toggle_rate { name1 name2 op } {
|
||||
global power_default_signal_toggle_rate
|
||||
|
||||
if { $op == "r" } {
|
||||
set power_default_signal_toggle_rate [power_default_signal_toggle_rate]
|
||||
} elseif { $op == "w" } {
|
||||
if { [string is double $power_default_signal_toggle_rate] \
|
||||
&& $power_default_signal_toggle_rate >= 0.0 } {
|
||||
set_power_default_signal_toggle_rate $power_default_signal_toggle_rate
|
||||
} else {
|
||||
sta_error "power_default_signal_toggle_rate must be a positive float."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# sta namespace end.
|
||||
}
|
||||
|
|
@ -2356,20 +2356,19 @@ proc set_input_transition { args } {
|
|||
################################################################
|
||||
|
||||
define_cmd_args "set_load" \
|
||||
{[-rise] [-fall] [-max] [-min] [-corner corner] [-subtract_pin_load]\
|
||||
{[-rise] [-fall] [-max] [-min] [-subtract_pin_load]\
|
||||
[-pin_load] [-wire_load] capacitance objects}
|
||||
|
||||
proc set_load { args } {
|
||||
parse_key_args "set_load" args keys {} \
|
||||
flags {-rise -fall -min -max -corner -subtract_pin_load \
|
||||
-pin_load -wire_load}
|
||||
parse_key_args "set_load" args keys {-corner} \
|
||||
flags {-rise -fall -min -max -subtract_pin_load -pin_load -wire_load}\
|
||||
|
||||
check_argc_eq2 "set_load" $args
|
||||
|
||||
set pin_load [info exists flags(-pin_load)]
|
||||
set wire_load [info exists flags(-wire_load)]
|
||||
set subtract_pin_load [info exists flags(-subtract_pin_load)]
|
||||
set corner [parse_corner keys]
|
||||
set corner [parse_corner_or_default keys]
|
||||
set min_max [parse_min_max_all_check_flags flags]
|
||||
set tr [parse_rise_fall_flags flags]
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,42 @@ namespace eval sta {
|
|||
define_cmd_args "report_arrival" {pin}
|
||||
|
||||
proc report_arrival { pin } {
|
||||
report_wrt_clks $pin "arrivals_clk"
|
||||
report_delays_wrt_clks $pin "arrivals_clk_delays"
|
||||
}
|
||||
|
||||
proc report_delays_wrt_clks { pin_arg what } {
|
||||
set pin [get_port_pin_error "pin" $pin_arg]
|
||||
foreach vertex [$pin vertices] {
|
||||
if { $vertex != "NULL" } {
|
||||
report_delays_wrt_clk $vertex $what "NULL" "rise"
|
||||
report_delays_wrt_clk $vertex $what [default_arrival_clock] "rise"
|
||||
set clk_iter [clock_iterator]
|
||||
while {[$clk_iter has_next]} {
|
||||
set clk [$clk_iter next]
|
||||
report_delays_wrt_clk $vertex $what $clk "rise"
|
||||
report_delays_wrt_clk $vertex $what $clk "fall"
|
||||
}
|
||||
$clk_iter finish
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc report_delays_wrt_clk { vertex what clk clk_tr } {
|
||||
global sta_report_default_digits
|
||||
|
||||
set rise [$vertex $what rise $clk $clk_tr $sta_report_default_digits]
|
||||
set fall [$vertex $what fall $clk $clk_tr $sta_report_default_digits]
|
||||
# Filter INF/-INF arrivals.
|
||||
if { !([delays_are_inf $rise] && [delays_are_inf $fall]) } {
|
||||
set rise_fmt [format_delays $rise]
|
||||
set fall_fmt [format_delays $fall]
|
||||
if {$clk != "NULL"} {
|
||||
set clk_str " ([$clk name] [rise_fall_short_name $clk_tr])"
|
||||
} else {
|
||||
set clk_str ""
|
||||
}
|
||||
puts "$clk_str r $rise_fmt f $fall_fmt"
|
||||
}
|
||||
}
|
||||
|
||||
proc report_wrt_clks { pin_arg what } {
|
||||
|
|
@ -82,6 +117,16 @@ proc times_are_inf { times } {
|
|||
return 1
|
||||
}
|
||||
|
||||
proc delays_are_inf { delays } {
|
||||
foreach delay $delays {
|
||||
if { !([string match "INF*" $delay] \
|
||||
|| [string match "-INF*" $delay]) } {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
# Note that -all and -tags are intentionally "hidden".
|
||||
|
|
@ -221,7 +266,7 @@ proc parse_report_path_options { cmd args_var default_format
|
|||
define_cmd_args "report_required" {pin}
|
||||
|
||||
proc report_required { pin } {
|
||||
report_wrt_clks $pin "requireds_clk"
|
||||
report_delays_wrt_clks $pin "requireds_clk_delays"
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
|
@ -229,7 +274,7 @@ proc report_required { pin } {
|
|||
define_cmd_args "report_slack" {pin}
|
||||
|
||||
proc report_slack { pin } {
|
||||
report_wrt_clks $pin "slacks_clk"
|
||||
report_delays_wrt_clks $pin "slacks_clk_delays"
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
|
|
|||
277
tcl/StaTcl.i
277
tcl/StaTcl.i
|
|
@ -49,8 +49,6 @@
|
|||
#include "Transition.hh"
|
||||
#include "TimingRole.hh"
|
||||
#include "TimingArc.hh"
|
||||
#include "InternalPower.hh"
|
||||
#include "LeakagePower.hh"
|
||||
#include "EquivCells.hh"
|
||||
#include "Liberty.hh"
|
||||
#include "Network.hh"
|
||||
|
|
@ -77,6 +75,7 @@
|
|||
#include "SearchPred.hh"
|
||||
#include "PathAnalysisPt.hh"
|
||||
#include "ReportPath.hh"
|
||||
#include "Power.hh"
|
||||
#include "Sta.hh"
|
||||
|
||||
namespace sta {
|
||||
|
|
@ -693,7 +692,10 @@ edgeDelayProperty(Edge *edge,
|
|||
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
|
||||
ArcDelay arc_delay = sta->arcDelay(edge, arc, dcalc_ap);
|
||||
if (!delay_exists
|
||||
|| min_max->compare(arc_delay, delay))
|
||||
|| ((min_max == MinMax::max()
|
||||
&& arc_delay > delay)
|
||||
|| (min_max == MinMax::min()
|
||||
&& arc_delay < delay)))
|
||||
delay = arc_delay;
|
||||
}
|
||||
}
|
||||
|
|
@ -822,6 +824,16 @@ findEndpoints()
|
|||
return pins;
|
||||
}
|
||||
|
||||
void
|
||||
pushPowerResultFloats(PowerResult &power,
|
||||
TmpFloatSeq *floats)
|
||||
{
|
||||
floats->push_back(power.internal());
|
||||
floats->push_back(power.switching());
|
||||
floats->push_back(power.leakage());
|
||||
floats->push_back(power.total());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
|
|
@ -1510,11 +1522,11 @@ using namespace sta;
|
|||
%typemap(in) EarlyLate* {
|
||||
int length;
|
||||
char *arg = Tcl_GetStringFromObj($input, &length);
|
||||
MinMax *min_max = MinMax::find(arg);
|
||||
if (min_max)
|
||||
$1 = min_max;
|
||||
EarlyLate *early_late = EarlyLate::find(arg);
|
||||
if (early_late)
|
||||
$1 = early_late;
|
||||
else {
|
||||
tclError(interp, "Error: %s not min or max.", arg);
|
||||
tclError(interp, "Error: %s not early/min or late/max.", arg);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
|
|
@ -1523,11 +1535,11 @@ using namespace sta;
|
|||
%typemap(in) EarlyLateAll* {
|
||||
int length;
|
||||
char *arg = Tcl_GetStringFromObj($input, &length);
|
||||
MinMaxAll *min_max = MinMaxAll::find(arg);
|
||||
if (min_max)
|
||||
$1 = min_max;
|
||||
EarlyLateAll *early_late = EarlyLateAll::find(arg);
|
||||
if (early_late)
|
||||
$1 = early_late;
|
||||
else {
|
||||
tclError(interp, "Error: %s not min, max or min_max.", arg);
|
||||
tclError(interp, "Error: %s not early/min, late/max or early_late/min_max.", arg);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
|
|
@ -1735,26 +1747,6 @@ using namespace sta;
|
|||
Tcl_SetObjResult(interp, obj);
|
||||
}
|
||||
|
||||
%typemap(out) InternalPower* {
|
||||
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
|
||||
Tcl_SetObjResult(interp, obj);
|
||||
}
|
||||
|
||||
%typemap(out) LibertyCellInternalPowerIterator* {
|
||||
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
|
||||
Tcl_SetObjResult(interp, obj);
|
||||
}
|
||||
|
||||
%typemap(out) LeakagePower* {
|
||||
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
|
||||
Tcl_SetObjResult(interp, obj);
|
||||
}
|
||||
|
||||
%typemap(out) LibertyCellLeakagePowerIterator* {
|
||||
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
|
||||
Tcl_SetObjResult(interp, obj);
|
||||
}
|
||||
|
||||
%typemap(out) CellTimingArcSetIterator* {
|
||||
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
|
||||
Tcl_SetObjResult(interp, obj);
|
||||
|
|
@ -2009,34 +2001,6 @@ private:
|
|||
~CellTimingArcSetIterator();
|
||||
};
|
||||
|
||||
class InternalPower
|
||||
{
|
||||
private:
|
||||
InternalPower();
|
||||
~InternalPower();
|
||||
};
|
||||
|
||||
class LibertyCellInternalPowerIterator
|
||||
{
|
||||
private:
|
||||
LibertyCellInternalPowerIterator();
|
||||
~LibertyCellInternalPowerIterator();
|
||||
};
|
||||
|
||||
class LeakagePower
|
||||
{
|
||||
private:
|
||||
LeakagePower();
|
||||
~LeakagePower();
|
||||
};
|
||||
|
||||
class LibertyCellLeakagePowerIterator
|
||||
{
|
||||
private:
|
||||
LibertyCellLeakagePowerIterator();
|
||||
~LibertyCellLeakagePowerIterator();
|
||||
};
|
||||
|
||||
class TimingArcSetArcIterator
|
||||
{
|
||||
private:
|
||||
|
|
@ -4814,6 +4778,50 @@ report_slew_limit_verbose(Pin *pin,
|
|||
Sta::sta()->reportSlewLimitVerbose(pin, corner, min_max);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
TmpFloatSeq *
|
||||
design_power(const Corner *corner)
|
||||
{
|
||||
PowerResult total, sequential, combinational, macro, pad;
|
||||
Sta::sta()->power(corner, total, sequential, combinational, macro, pad);
|
||||
FloatSeq *floats = new FloatSeq;
|
||||
pushPowerResultFloats(total, floats);
|
||||
pushPowerResultFloats(sequential, floats);
|
||||
pushPowerResultFloats(combinational, floats);
|
||||
pushPowerResultFloats(macro, floats);
|
||||
pushPowerResultFloats(pad, floats);
|
||||
return floats;
|
||||
}
|
||||
|
||||
TmpFloatSeq *
|
||||
instance_power(Instance *inst,
|
||||
const Corner *corner)
|
||||
{
|
||||
PowerResult power;
|
||||
Sta::sta()->power(inst, corner, power);
|
||||
FloatSeq *floats = new FloatSeq;
|
||||
floats->push_back(power.switching());
|
||||
floats->push_back(power.internal());
|
||||
floats->push_back(power.leakage());
|
||||
floats->push_back(power.total());
|
||||
return floats;
|
||||
}
|
||||
|
||||
float
|
||||
power_default_signal_toggle_rate()
|
||||
{
|
||||
return Sta::sta()->power()->defaultSignalToggleRate();
|
||||
}
|
||||
|
||||
void
|
||||
set_power_default_signal_toggle_rate(float rate)
|
||||
{
|
||||
return Sta::sta()->power()->setDefaultSignalToggleRate(rate);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
EdgeSeq *
|
||||
disabled_edges_sorted()
|
||||
{
|
||||
|
|
@ -5339,6 +5347,7 @@ find_cells_matching(const char *pattern,
|
|||
%extend LibertyLibrary {
|
||||
|
||||
const char *name() { return self->name(); }
|
||||
const char *filename() { return self->filename(); }
|
||||
const char *object_name() { return self->name(); }
|
||||
|
||||
LibertyCell *
|
||||
|
|
@ -5456,12 +5465,6 @@ liberty_port_iterator() { return self->libertyPortIterator(); }
|
|||
CellTimingArcSetIterator *
|
||||
timing_arc_set_iterator() { return self->timingArcSetIterator(); }
|
||||
|
||||
LibertyCellInternalPowerIterator *
|
||||
internal_power_iterator() { return self->internalPowerIterator(); }
|
||||
|
||||
LibertyCellLeakagePowerIterator *
|
||||
leakage_power_iterator() { return self->leakagePowerIterator(); }
|
||||
|
||||
} // LibertyCell methods
|
||||
|
||||
%extend CellPortIterator {
|
||||
|
|
@ -5594,61 +5597,6 @@ TimingArc *next() { return self->next(); }
|
|||
void finish() { delete self; }
|
||||
}
|
||||
|
||||
%extend InternalPower {
|
||||
LibertyPort *port() { return self->port(); }
|
||||
LibertyPort *related_port() { return self->relatedPort(); }
|
||||
|
||||
const char *
|
||||
when()
|
||||
{
|
||||
FuncExpr *when = self->when();
|
||||
if (when)
|
||||
return when->asString();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
float
|
||||
power(TransRiseFall *tr,
|
||||
float in_slew,
|
||||
float load_cap)
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
Corner *corner = sta->corners()->defaultCorner();
|
||||
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max());
|
||||
const Pvt *pvt = dcalc_ap->operatingConditions();
|
||||
return self->power(tr, pvt, in_slew, load_cap);
|
||||
}
|
||||
|
||||
} // InternalPower methods
|
||||
|
||||
%extend LibertyCellInternalPowerIterator {
|
||||
bool has_next() { return self->hasNext(); }
|
||||
InternalPower *next() { return self->next(); }
|
||||
void finish() { delete self; }
|
||||
}
|
||||
|
||||
%extend LeakagePower {
|
||||
float power() { return self->power(); }
|
||||
|
||||
const char *
|
||||
when()
|
||||
{
|
||||
FuncExpr *when = self->when();
|
||||
if (when)
|
||||
return when->asString();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
} // LeakagePower methods
|
||||
|
||||
%extend LibertyCellLeakagePowerIterator {
|
||||
bool has_next() { return self->hasNext(); }
|
||||
LeakagePower *next() { return self->next(); }
|
||||
void finish() { delete self; }
|
||||
}
|
||||
|
||||
%extend Instance {
|
||||
const char *name() { return cmdLinkedNetwork()->name(self); }
|
||||
const char *object_name() { return cmdLinkedNetwork()->pathName(self); }
|
||||
|
|
@ -5954,11 +5902,33 @@ arrivals_clk(const TransRiseFall *tr,
|
|||
PathAnalysisPtIterator ap_iter(sta);
|
||||
while (ap_iter.hasNext()) {
|
||||
PathAnalysisPt *path_ap = ap_iter.next();
|
||||
floats->push_back(delayAsFloat(sta->vertexArrival(self, tr, clk_edge, path_ap)));
|
||||
floats->push_back(delayAsFloat(sta->vertexArrival(self, tr, clk_edge,
|
||||
path_ap)));
|
||||
}
|
||||
return floats;
|
||||
}
|
||||
|
||||
StringSeq *
|
||||
arrivals_clk_delays(const TransRiseFall *tr,
|
||||
Clock *clk,
|
||||
const TransRiseFall *clk_tr,
|
||||
int digits)
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
StringSeq *arrivals = new StringSeq;
|
||||
const ClockEdge *clk_edge = NULL;
|
||||
if (clk)
|
||||
clk_edge = clk->edge(clk_tr);
|
||||
PathAnalysisPtIterator ap_iter(sta);
|
||||
while (ap_iter.hasNext()) {
|
||||
PathAnalysisPt *path_ap = ap_iter.next();
|
||||
arrivals->push_back(delayAsString(sta->vertexArrival(self, tr, clk_edge,
|
||||
path_ap),
|
||||
sta->units(), digits));
|
||||
}
|
||||
return arrivals;
|
||||
}
|
||||
|
||||
TmpFloatSeq *
|
||||
requireds_clk(const TransRiseFall *tr,
|
||||
Clock *clk,
|
||||
|
|
@ -5972,11 +5942,33 @@ requireds_clk(const TransRiseFall *tr,
|
|||
PathAnalysisPtIterator ap_iter(sta);
|
||||
while (ap_iter.hasNext()) {
|
||||
PathAnalysisPt *path_ap = ap_iter.next();
|
||||
floats->push_back(delayAsFloat(sta->vertexRequired(self,tr,clk_edge,path_ap)));
|
||||
floats->push_back(delayAsFloat(sta->vertexRequired(self, tr, clk_edge,
|
||||
path_ap)));
|
||||
}
|
||||
return floats;
|
||||
}
|
||||
|
||||
StringSeq *
|
||||
requireds_clk_delays(const TransRiseFall *tr,
|
||||
Clock *clk,
|
||||
const TransRiseFall *clk_tr,
|
||||
int digits)
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
StringSeq *requireds = new StringSeq;
|
||||
const ClockEdge *clk_edge = NULL;
|
||||
if (clk)
|
||||
clk_edge = clk->edge(clk_tr);
|
||||
PathAnalysisPtIterator ap_iter(sta);
|
||||
while (ap_iter.hasNext()) {
|
||||
PathAnalysisPt *path_ap = ap_iter.next();
|
||||
requireds->push_back(delayAsString(sta->vertexRequired(self, tr, clk_edge,
|
||||
path_ap),
|
||||
sta->units(), digits));
|
||||
}
|
||||
return requireds;
|
||||
}
|
||||
|
||||
TmpFloatSeq *
|
||||
slacks(TransRiseFall *tr)
|
||||
{
|
||||
|
|
@ -6004,11 +5996,33 @@ slacks_clk(const TransRiseFall *tr,
|
|||
PathAnalysisPtIterator ap_iter(sta);
|
||||
while (ap_iter.hasNext()) {
|
||||
PathAnalysisPt *path_ap = ap_iter.next();
|
||||
floats->push_back(delayAsFloat(sta->vertexSlack(self, tr, clk_edge, path_ap)));
|
||||
floats->push_back(delayAsFloat(sta->vertexSlack(self, tr, clk_edge,
|
||||
path_ap)));
|
||||
}
|
||||
return floats;
|
||||
}
|
||||
|
||||
StringSeq *
|
||||
slacks_clk_delays(const TransRiseFall *tr,
|
||||
Clock *clk,
|
||||
const TransRiseFall *clk_tr,
|
||||
int digits)
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
StringSeq *slacks = new StringSeq;
|
||||
const ClockEdge *clk_edge = NULL;
|
||||
if (clk)
|
||||
clk_edge = clk->edge(clk_tr);
|
||||
PathAnalysisPtIterator ap_iter(sta);
|
||||
while (ap_iter.hasNext()) {
|
||||
PathAnalysisPt *path_ap = ap_iter.next();
|
||||
slacks->push_back(delayAsString(sta->vertexSlack(self, tr, clk_edge,
|
||||
path_ap),
|
||||
sta->units(), digits));
|
||||
}
|
||||
return slacks;
|
||||
}
|
||||
|
||||
VertexPathIterator *
|
||||
path_iterator(const TransRiseFall *tr,
|
||||
const MinMax *min_max)
|
||||
|
|
@ -6070,6 +6084,21 @@ arc_delays(TimingArc *arc)
|
|||
return floats;
|
||||
}
|
||||
|
||||
StringSeq *
|
||||
arc_delay_strings(TimingArc *arc,
|
||||
int digits)
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
StringSeq *delays = new StringSeq;
|
||||
DcalcAnalysisPtIterator ap_iter(sta);
|
||||
while (ap_iter.hasNext()) {
|
||||
DcalcAnalysisPt *dcalc_ap = ap_iter.next();
|
||||
delays->push_back(delayAsString(sta->arcDelay(self, arc, dcalc_ap),
|
||||
sta->units(), digits));
|
||||
}
|
||||
return delays;
|
||||
}
|
||||
|
||||
bool
|
||||
delay_annotated(TimingArc *arc,
|
||||
const Corner *corner,
|
||||
|
|
@ -6085,7 +6114,7 @@ arc_delay(TimingArc *arc,
|
|||
const MinMax *min_max)
|
||||
{
|
||||
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
|
||||
return Sta::sta()->arcDelay(self, arc, dcalc_ap);
|
||||
return delayAsFloat(Sta::sta()->arcDelay(self, arc, dcalc_ap));
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
|
|||
|
|
@ -90,9 +90,11 @@ MinMax::opposite() const
|
|||
MinMax *
|
||||
MinMax::find(const char *min_max)
|
||||
{
|
||||
if (stringEq(min_max, "min"))
|
||||
if (stringEq(min_max, "min")
|
||||
|| stringEq(min_max, "early"))
|
||||
return min();
|
||||
else if (stringEq(min_max, "max"))
|
||||
else if (stringEq(min_max, "max")
|
||||
|| stringEq(min_max, "late"))
|
||||
return max();
|
||||
else
|
||||
return NULL;
|
||||
|
|
@ -172,9 +174,11 @@ MinMaxAll::matches(const MinMaxAll *min_max) const
|
|||
MinMaxAll *
|
||||
MinMaxAll::find(const char *min_max)
|
||||
{
|
||||
if (stringEq(min_max, "min"))
|
||||
if (stringEq(min_max, "min")
|
||||
|| stringEq(min_max, "early"))
|
||||
return min();
|
||||
else if (stringEq(min_max, "max"))
|
||||
else if (stringEq(min_max, "max")
|
||||
|| stringEq(min_max, "late"))
|
||||
return max();
|
||||
else if (stringEq(min_max, "all")
|
||||
|| stringEq(min_max, "min_max")
|
||||
|
|
|
|||
|
|
@ -24,9 +24,12 @@ namespace sta {
|
|||
|
||||
class MinMax;
|
||||
class MinMaxAll;
|
||||
class MinMaxIterator;
|
||||
|
||||
// Use typedefs to make early/late functional equivalents to min/max.
|
||||
typedef MinMax EarlyLate;
|
||||
typedef MinMaxAll EarlyLateAll;
|
||||
typedef MinMaxIterator EarlyLateIterator;
|
||||
|
||||
// Large value used for min/max initial values.
|
||||
extern const float INF;
|
||||
|
|
@ -39,8 +42,12 @@ public:
|
|||
// Singleton accessors.
|
||||
static MinMax *min() { return min_; }
|
||||
static MinMax *max() { return max_; }
|
||||
static EarlyLate *early() { return min_; }
|
||||
static EarlyLate *late() { return max_; }
|
||||
static int minIndex() { return min_->index_; }
|
||||
static int earlyIndex() { return min_->index_; }
|
||||
static int maxIndex() { return max_->index_; }
|
||||
static int lateIndex() { return min_->index_; }
|
||||
const char *asString() const { return name_; }
|
||||
int index() const { return index_; }
|
||||
float initValue() const { return init_value_; }
|
||||
|
|
@ -98,7 +105,9 @@ public:
|
|||
static void destroy();
|
||||
// Singleton accessors.
|
||||
static MinMaxAll *min() { return min_; }
|
||||
static MinMaxAll *early() { return min_; }
|
||||
static MinMaxAll *max() { return max_; }
|
||||
static MinMaxAll *late() { return max_; }
|
||||
static MinMaxAll *all() { return all_; }
|
||||
const char *asString() const { return name_; }
|
||||
int index() const { return index_; }
|
||||
|
|
|
|||
Loading…
Reference in New Issue