report_power, pocv support

This commit is contained in:
James Cherry 2018-11-26 09:15:52 -08:00
parent 9071a01306
commit ddf897d4e6
93 changed files with 3147 additions and 929 deletions

View File

@ -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" 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 if test "$TCL_INCLUDE"; then
STA_INCLUDE="$STA_INCLUDE -I$TCL_INCLUDE" STA_INCLUDE="$STA_INCLUDE -I$TCL_INCLUDE"

View File

@ -86,7 +86,8 @@ public:
float related_out_cap, float related_out_cap,
const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap,
// Return values. // 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. // Find the wire delay and load slew of a load pin.
// Called after inputPortDelay or gateDelay. // Called after inputPortDelay or gateDelay.
virtual void loadDelay(const Pin *load_pin, virtual void loadDelay(const Pin *load_pin,
@ -94,16 +95,27 @@ public:
ArcDelay &wire_delay, ArcDelay &wire_delay,
Slew &load_slew) = 0; Slew &load_slew) = 0;
virtual void setMultiDrvrSlewFactor(float factor) = 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 // Find the delay for a timing check arc given the arc's
// from/clock, to/data slews and related output pin parasitic. // from/clock, to/data slews and related output pin parasitic.
virtual ArcDelay checkDelay(const LibertyCell *drvr_cell, virtual void checkDelay(const LibertyCell *drvr_cell,
TimingArc *arc, TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const Slew &to_slew, const Slew &to_slew,
float related_out_cap, float related_out_cap,
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap) = 0; const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin) = 0;
// Report delay and slew calculation. // Report delay and slew calculation.
virtual void reportGateDelay(const LibertyCell *drvr_cell, virtual void reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc, TimingArc *arc,

View File

@ -418,7 +418,7 @@ ArnoldiDelayCalc::gateDelaySlew(const LibertyCell *drvr_cell,
tab.table = table_model; tab.table = table_model;
tab.cell = drvr_cell; tab.cell = drvr_cell;
tab.pvt = pvt; tab.pvt = pvt;
tab.in_slew = in_slew; tab.in_slew = delayAsFloat(in_slew);
tab.relcap = related_out_cap; tab.relcap = related_out_cap;
ar1_ceff_delay(delay_work_, &tab, rcmodel_, ar1_ceff_delay(delay_work_, &tab, rcmodel_,
_delayV, _slewV); _delayV, _slewV);
@ -1303,12 +1303,14 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D,
delay_c *c = D->c; delay_c *c = D->c;
double slew_derate = c->slew_derate; double slew_derate = c->slew_derate;
double c_log = c->vlg; double c_log = c->vlg;
float c1,d1,s1; float c1;
double tlohi,r; double tlohi,r;
c1 = ctot; c1 = ctot;
ArcDelay d1;
Slew s1;
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
c1, tab->relcap, d1, s1); c1, tab->relcap, d1, s1);
tlohi = slew_derate*s1; tlohi = slew_derate*delayAsFloat(s1);
r = tlohi/(c_log*c1); r = tlohi/(c_log*c1);
if (rdelay>0.0 && r > rdelay) if (rdelay>0.0 && r > rdelay)
r = rdelay; r = rdelay;
@ -1327,10 +1329,11 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
double c_log = con->vlg; double c_log = con->vlg;
double c_smin = con->smin; double c_smin = con->smin;
double tlohi,smin,s; double tlohi,smin,s;
float d1,s1; ArcDelay d1;
Slew s1;
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
c, tab->relcap, d1, s1); 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); smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
if (c_log*r*c >= tlohi) { if (c_log*r*c >= tlohi) {
// printf("hit smin\n"); // printf("hit smin\n");
@ -1360,13 +1363,13 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab,
float c2 = 0.5*c1; float c2 = 0.5*c1;
if (c1==c2) if (c1==c2)
return 0.0; return 0.0;
float d1, s1; ArcDelay d1, d2;
Slew s1, s2;
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
c1, tab->relcap, d1, s1); c1, tab->relcap, d1, s1);
float d2, s2;
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
c2, tab->relcap, d2, s2); c2, tab->relcap, d2, s2);
double dt50 = d1-d2; double dt50 = delayAsFloat(d1)-delayAsFloat(d2);
if (dt50 <= 0.0) if (dt50 <= 0.0)
return 0.0; return 0.0;
double rdelay = dt50/(c1-c2); double rdelay = dt50/(c1-c2);
@ -1386,7 +1389,8 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
double vlo = con->vlo; double vlo = con->vlo;
double ctot = mod->ctot; double ctot = mod->ctot;
double ceff,tlohi,t50_sy,r,s,t50_sr,rdelay; double ceff,tlohi,t50_sy,r,s,t50_sr,rdelay;
float df,sf; ArcDelay df;
Slew sf;
debugPrint1(debug_, "arnoldi", 1, "\nctot=%s\n", debugPrint1(debug_, "arnoldi", 1, "\nctot=%s\n",
units_->capacitanceUnit()->asString(ctot)); units_->capacitanceUnit()->asString(ctot));
@ -1422,8 +1426,8 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
"table slew (in_slew %s ctot %s) = %s\n", "table slew (in_slew %s ctot %s) = %s\n",
units_->timeUnit()->asString(tab->in_slew), units_->timeUnit()->asString(tab->in_slew),
units_->capacitanceUnit()->asString(ctot), units_->capacitanceUnit()->asString(ctot),
units_->timeUnit()->asString(sf)); delayAsString(sf, units_));
tlohi = slew_derate*sf; tlohi = slew_derate*delayAsFloat(sf);
debugPrint2(debug_, "arnoldi", 1, "tlohi %s %s\n", debugPrint2(debug_, "arnoldi", 1, "tlohi %s %s\n",
units_->timeUnit()->asString(tlohi), units_->timeUnit()->asString(tlohi),
units_->timeUnit()->asString(tlox-thix)); units_->timeUnit()->asString(tlox-thix));
@ -1431,7 +1435,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
ceff = ctot; ceff = ctot;
tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew,
ceff, tab->relcap, df, sf); 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); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
// calculate s,r,mod -> t50_srmod, // 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->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, ceff,
tab->relcap, df, sf); tab->relcap, df, sf);
t50_sy = df; t50_sy = delayAsFloat(df);
t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5);
for (j=0;j<mod->n;j++) { for (j=0;j<mod->n;j++) {
rr = delay_work_get_residues(D,j); rr = delay_work_get_residues(D,j);

View File

@ -372,14 +372,15 @@ DmpAlg::gateCapDelaySlew(double ceff,
double &delay, double &delay,
double &slew) double &slew)
{ {
float model_delay, model_slew; ArcDelay model_delay;
Slew model_slew;
gate_model_->gateDelay(drvr_cell_, pvt_, gate_model_->gateDelay(drvr_cell_, pvt_,
static_cast<float>(in_slew_), static_cast<float>(in_slew_),
static_cast<float>(ceff), static_cast<float>(ceff),
related_out_cap_, related_out_cap_,
model_delay, model_slew); model_delay, model_slew);
delay = model_delay; delay = delayAsFloat(model_delay);
slew = model_slew; slew = delayAsFloat(model_slew);
} }
void void
@ -1665,6 +1666,24 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library,
dmp_alg_->name()); 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 void
DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell, DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc, TimingArc *arc,
@ -1723,9 +1742,11 @@ gateModelRd(const LibertyCell *cell,
float cap1 = static_cast<float>((c1 + c2) * .75); float cap1 = static_cast<float>((c1 + c2) * .75);
float cap2 = cap1 * 1.1F; float cap2 = cap1 * 1.1F;
float in_slew1 = static_cast<float>(in_slew); float in_slew1 = static_cast<float>(in_slew);
float d1 = gate_model->gateDelay(cell, pvt, in_slew1, cap1, related_out_cap); ArcDelay d1, d2;
float d2 = gate_model->gateDelay(cell, pvt, in_slew1, cap2, related_out_cap); Slew s1, s2;
return abs(d1 - d2) / (cap2 - cap1); 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 void

View File

@ -50,6 +50,14 @@ public:
// return values // return values
ArcDelay &gate_delay, ArcDelay &gate_delay,
Slew &drvr_slew); 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, virtual void reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc, TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,

View File

@ -70,6 +70,14 @@ GraphDelayCalc::loadCap(const Pin *,
pin_cap = wire_cap = 0.0F; pin_cap = wire_cap = 0.0F;
} }
float
GraphDelayCalc::loadCap(const Pin *,
const TransRiseFall *,
const DcalcAnalysisPt *) const
{
return 0.0F;
}
float float
GraphDelayCalc::loadCap(const Pin *, GraphDelayCalc::loadCap(const Pin *,
Parasitic *, Parasitic *,

View File

@ -80,6 +80,10 @@ public:
float &pin_cap, float &pin_cap,
float &wire_cap) const; float &wire_cap) const;
// Load pin_cap + wire_cap. // 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, virtual float loadCap(const Pin *drvr_pin,
Parasitic *drvr_parasitic, Parasitic *drvr_parasitic,
const TransRiseFall *tr, const TransRiseFall *tr,
@ -92,6 +96,9 @@ public:
float &wire_cap, float &wire_cap,
float &fanout, float &fanout,
bool &has_set_load) const; bool &has_set_load) const;
virtual float ceff(Edge *edge,
TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap) = 0;
// Precedence: // Precedence:
// SDF annotation // SDF annotation
// Liberty library // Liberty library

View File

@ -394,7 +394,7 @@ FindVertexDelays::copy()
{ {
// Copy StaState::arc_delay_calc_ because it needs separate state // Copy StaState::arc_delay_calc_ because it needs separate state
// for each thread. // 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 void
@ -1023,8 +1023,7 @@ GraphDelayCalc1::findDriverEdgeDelays(LibertyCell *drvr_cell,
DcalcAnalysisPtIterator ap_iter(this); DcalcAnalysisPtIterator ap_iter(this);
while (ap_iter.hasNext()) { while (ap_iter.hasNext()) {
DcalcAnalysisPt *dcalc_ap = ap_iter.next(); DcalcAnalysisPt *dcalc_ap = ap_iter.next();
const Pvt *pvt = sdc_->pvt(drvr_inst, const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
dcalc_ap->constraintMinMax());
if (pvt == NULL) if (pvt == NULL)
pvt = dcalc_ap->operatingConditions(); pvt = dcalc_ap->operatingConditions();
TimingArcSetArcIterator *arc_iter = arc_set->timingArcIterator(); TimingArcSetArcIterator *arc_iter = arc_set->timingArcIterator();
@ -1065,13 +1064,28 @@ GraphDelayCalc1::findDriverEdgeDelays(LibertyCell *drvr_cell,
return delay_changed; 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 float
GraphDelayCalc1::loadCap(const Pin *drvr_pin, GraphDelayCalc1::loadCap(const Pin *drvr_pin,
Parasitic *drvr_parasitic, Parasitic *drvr_parasitic,
const TransRiseFall *tr, const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap) const 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 float
@ -1160,7 +1174,7 @@ GraphDelayCalc1::netCaps(const Pin *drvr_pin,
const MinMax *min_max = dcalc_ap->constraintMinMax(); const MinMax *min_max = dcalc_ap->constraintMinMax();
// Find pin and external pin/wire capacitance. // Find pin and external pin/wire capacitance.
sdc_->connectedCap(drvr_pin, tr, op_cond, corner, min_max, 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, arc_delay_calc->finish(related_out_pin, to_tr, dcalc_ap,
related_out_parasitic, delete_related); related_out_parasitic, delete_related);
} }
ArcDelay check_delay = arc_delay_calc->checkDelay(cell, arc, ArcDelay check_delay;
from_slew, to_slew, arc_delay_calc->checkDelay(cell, arc,
related_out_cap, from_slew, to_slew,
pvt, dcalc_ap); related_out_cap,
pvt, dcalc_ap,
check_delay);
debugPrint1(debug_, "delay_calc", 3, debugPrint1(debug_, "delay_calc", 3,
" check_delay = %s\n", " check_delay = %s\n",
delayAsString(check_delay, units_)); delayAsString(check_delay, units_));
@ -1727,6 +1743,54 @@ GraphDelayCalc1::isIdealClk(const Vertex *vertex) const
&& clks->size() > 0; && 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 * string *

View File

@ -51,6 +51,10 @@ public:
virtual float incrementalDelayTolerance(); virtual float incrementalDelayTolerance();
virtual void setIncrementalDelayTolerance(float tol); virtual void setIncrementalDelayTolerance(float tol);
virtual void setObserver(DelayCalcObserver *observer); 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, virtual void loadCap(const Pin *drvr_pin,
Parasitic *drvr_parasitic, Parasitic *drvr_parasitic,
const TransRiseFall *tr, const TransRiseFall *tr,
@ -70,6 +74,9 @@ public:
float &wire_cap, float &wire_cap,
float &fanout, float &fanout,
bool &has_set_load) const; bool &has_set_load) const;
float ceff(Edge *edge,
TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap);
protected: protected:
void seedInvalidDelays(); void seedInvalidDelays();

View File

@ -122,6 +122,19 @@ LumpedCapDelayCalc::inputPortDelay(const Pin *, float in_slew,
multi_drvr_slew_factor_ = 1.0F; 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 void
LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell, LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
TimingArc *arc, TimingArc *arc,
@ -142,7 +155,8 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell,
units()->capacitanceUnit()->asString(load_cap), units()->capacitanceUnit()->asString(load_cap),
units()->capacitanceUnit()->asString(related_out_cap)); units()->capacitanceUnit()->asString(related_out_cap));
if (model) { if (model) {
float gate_delay1, drvr_slew1; ArcDelay gate_delay1;
Slew drvr_slew1;
float in_slew1 = delayAsFloat(in_slew); float in_slew1 = delayAsFloat(in_slew);
model->gateDelay(drvr_cell, pvt, in_slew1, load_cap, related_out_cap, model->gateDelay(drvr_cell, pvt, in_slew1, load_cap, related_out_cap,
gate_delay1, drvr_slew1); gate_delay1, drvr_slew1);
@ -235,23 +249,25 @@ LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell,
} }
} }
ArcDelay void
LumpedCapDelayCalc::checkDelay(const LibertyCell *cell, LumpedCapDelayCalc::checkDelay(const LibertyCell *cell,
TimingArc *arc, TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const Slew &to_slew, const Slew &to_slew,
float related_out_cap, float related_out_cap,
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap) const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin)
{ {
CheckTimingModel *model = checkModel(arc, dcalc_ap); CheckTimingModel *model = checkModel(arc, dcalc_ap);
if (model) { if (model) {
float from_slew1 = delayAsFloat(from_slew); float from_slew1 = delayAsFloat(from_slew);
float to_slew1 = delayAsFloat(to_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 else
return delay_zero; margin = delay_zero;
} }
void void

View File

@ -60,13 +60,23 @@ public:
// Return values. // Return values.
ArcDelay &wire_delay, ArcDelay &wire_delay,
Slew &load_slew); Slew &load_slew);
virtual ArcDelay checkDelay(const LibertyCell *cell, virtual void checkDelay(const LibertyCell *cell,
TimingArc *arc, TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const Slew &to_slew, const Slew &to_slew,
float related_out_cap, float related_out_cap,
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap); 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, virtual void reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc, TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,

View File

@ -92,6 +92,19 @@ UnitDelayCalc::loadDelay(const Pin *,
load_slew = 0.0; load_slew = 0.0;
} }
float
UnitDelayCalc::ceff(const LibertyCell *,
TimingArc *,
const Slew &,
float,
Parasitic *,
float,
const Pvt *,
const DcalcAnalysisPt *)
{
return 0.0;
}
void void
UnitDelayCalc::reportGateDelay(const LibertyCell *, UnitDelayCalc::reportGateDelay(const LibertyCell *,
TimingArc *, TimingArc *,
@ -108,16 +121,18 @@ UnitDelayCalc::reportGateDelay(const LibertyCell *,
*result += "Slew = 0.0\n"; *result += "Slew = 0.0\n";
} }
ArcDelay void
UnitDelayCalc::checkDelay(const LibertyCell *, UnitDelayCalc::checkDelay(const LibertyCell *,
TimingArc *, TimingArc *,
const Slew &, const Slew &,
const Slew &, const Slew &,
float, float,
const Pvt *, const Pvt *,
const DcalcAnalysisPt *) const DcalcAnalysisPt *,
// Return values.
ArcDelay &margin)
{ {
return units_->timeUnit()->scale(); margin = units_->timeUnit()->scale();
} }
void void

View File

@ -54,18 +54,28 @@ public:
ArcDelay &wire_delay, ArcDelay &wire_delay,
Slew &load_slew); Slew &load_slew);
virtual void setMultiDrvrSlewFactor(float) {} 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, virtual void inputPortDelay(const Pin *port_pin,
float in_slew, float in_slew,
const TransRiseFall *tr, const TransRiseFall *tr,
Parasitic *parasitic, Parasitic *parasitic,
const DcalcAnalysisPt *dcalc_ap); const DcalcAnalysisPt *dcalc_ap);
virtual ArcDelay checkDelay(const LibertyCell *cell, virtual void checkDelay(const LibertyCell *cell,
TimingArc *arc, TimingArc *arc,
const Slew &from_slew, const Slew &from_slew,
const Slew &to_slew, const Slew &to_slew,
float related_out_cap, float related_out_cap,
const Pvt *pvt, const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap); const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin);
virtual void reportGateDelay(const LibertyCell *drvr_cell, virtual void reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc, TimingArc *arc,
const Slew &in_slew, const Slew &in_slew,

Binary file not shown.

39
graph/Delay.cc Normal file
View File

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

View File

@ -14,12 +14,20 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // 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 to use the float definitions.
#define DELAY_FLOAT #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_FLOAT_CLASS
// Define DELAY_NORMAL2 to use the DelayNormal2 definitions.
//#define DELAY_NORMAL2
#ifdef DELAY_FLOAT #ifdef DELAY_FLOAT
#include "DelayFloat.hh" #include "DelayFloat.hh"
#endif #endif
@ -27,3 +35,91 @@
#ifdef DELAY_FLOAT_CLASS #ifdef DELAY_FLOAT_CLASS
#include "DelayFloatClass.hh" #include "DelayFloatClass.hh"
#endif #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

View File

@ -47,6 +47,12 @@ delayIsInitValue(const Delay &delay,
return fuzzyEqual(delay, min_max->initValue()); return fuzzyEqual(delay, min_max->initValue());
} }
float
delayAsFloat(const Delay &delay)
{
return delay;
}
bool bool
delayFuzzyZero(const Delay &delay) delayFuzzyZero(const Delay &delay)
{ {
@ -141,16 +147,27 @@ delayRatio(const Delay &delay1,
const char * const char *
delayAsString(const Delay &delay, 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 * const char *
delayAsString(const Delay &delay, delayMeanSigmaString(const Delay &delay,
const StaState *sta) const EarlyLate *,
const Units *units,
int digits)
{ {
return delayAsString(delay, sta->units()); const Unit *unit = units->timeUnit();
return unit->asString(delay, digits);
} }
} // namespace } // namespace

View File

@ -18,75 +18,22 @@
#define STA_DELAY_FLOAT_H #define STA_DELAY_FLOAT_H
#include "MinMax.hh" #include "MinMax.hh"
#include "Pool.hh"
// Delay values defined as floats. // Delay values defined as floats.
namespace sta { namespace sta {
class Units;
class StaState;
typedef float Delay; 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; const Delay delay_zero = 0.0;
void initDelayConstants(); inline Delay
makeDelay(float delay,
inline float delayAsFloat(const Delay &delay) { return delay; } float,
const char * float)
delayAsString(const Delay &delay, {
Units *units); return delay;
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);
} // namespace } // namespace
#endif #endif

View File

@ -50,12 +50,6 @@ Delay::Delay(float delay) :
{ {
} }
float
Delay::asFloat() const
{
return delay_;
}
void void
Delay::operator=(const Delay &delay) Delay::operator=(const Delay &delay)
{ {
@ -273,6 +267,13 @@ operator+(float delay1,
return Delay(delay1 + delayAsFloat(delay2)); return Delay(delay1 + delayAsFloat(delay2));
} }
Delay
operator-(float delay1,
const Delay &delay2)
{
return Delay(delay1 - delayAsFloat(delay2));
}
Delay Delay
operator/(float delay1, operator/(float delay1,
const Delay &delay2) const Delay &delay2)
@ -280,13 +281,6 @@ operator/(float delay1,
return Delay(delay1 / delayAsFloat(delay2)); return Delay(delay1 / delayAsFloat(delay2));
} }
Delay
operator*(float delay1,
const Delay &delay2)
{
return Delay(delay1 * delayAsFloat(delay2));
}
Delay Delay
operator*(const Delay &delay1, operator*(const Delay &delay1,
float delay2) float delay2)
@ -303,16 +297,26 @@ delayRatio(const Delay &delay1,
const char * const char *
delayAsString(const Delay &delay, 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 * const char *
delayAsString(const Delay &delay, delayMeanSigmaString(const Delay &delay,
const StaState *sta) const EarlyLate *,
const Units *units,
int digits)
{ {
return delayAsString(delay, sta->units()); return units->timeUnit()->asString(delay.delay(), digits);
} }
} // namespace } // namespace

View File

@ -18,29 +18,19 @@
#define STA_DELAY_FLOAT_CLASS_H #define STA_DELAY_FLOAT_CLASS_H
#include "MinMax.hh" #include "MinMax.hh"
#include "Pool.hh"
namespace sta { namespace sta {
// Delay values defined as objects that hold a float value. // Delay values defined as class objects that hold a float value.
// This is really a trial balloon for delay values as objects
class Units; // instead of simple floats.
class Delay;
class StaState;
typedef Delay ArcDelay;
typedef Delay Slew;
typedef Delay Arrival;
typedef Delay Required;
typedef Delay Slack;
typedef Pool<Delay> DelayPool;
class Delay class Delay
{ {
public: public:
Delay(); Delay();
Delay(float delay); Delay(float delay);
float asFloat() const; float delay() const { return delay_; }
void operator=(const Delay &delay); void operator=(const Delay &delay);
void operator=(float delay); void operator=(float delay);
void operator+=(const Delay &delay); void operator+=(const Delay &delay);
@ -63,8 +53,16 @@ private:
const Delay delay_zero(0.0); const Delay delay_zero(0.0);
void inline Delay
initDelayConstants(); 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 // Most non-operator functions on Delay are not defined as member
// functions so they can be defined on floats, where there is no class // functions so they can be defined on floats, where there is no class
@ -72,70 +70,29 @@ initDelayConstants();
Delay operator+(float delay1, Delay operator+(float delay1,
const Delay &delay2); const Delay &delay2);
Delay operator-(float delay1,
const Delay &delay2);
// Used for parallel gate delay calc.
Delay operator/(float delay1, Delay operator/(float delay1,
const Delay &delay2); const Delay &delay2);
Delay operator*(float delay1, // Used for parallel gate delay calc.
const Delay &delay2); Delay operator*(const Delay &delay2,
float delay1);
Delay operator*(const Delay &delay1, Delay operator*(const Delay &delay1,
float delay2); 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 bool
delayFuzzyLess(const Delay &delay1, delayFuzzyLess(const Delay &delay1,
float delay2); float delay2);
bool 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, delayFuzzyLessEqual(const Delay &delay1,
float delay2); float delay2);
bool bool
delayFuzzyGreater(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyGreater(const Delay &delay1, delayFuzzyGreater(const Delay &delay1,
float delay2); float delay2);
bool bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyGreaterEqual(const Delay &delay1, delayFuzzyGreaterEqual(const Delay &delay1,
float delay2); 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 } // namespace
#endif #endif

389
graph/DelayNormal2.cc Normal file
View File

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

93
graph/DelayNormal2.hh Normal file
View File

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

View File

@ -715,6 +715,7 @@ Graph::makeArcDelayPools(ArcIndex arc_count,
arc_delays_[i] = pool; arc_delays_[i] = pool;
} }
// Leave some room for edits.
unsigned annot_size = arc_count * 1.2; unsigned annot_size = arc_count * 1.2;
arc_delay_annotated_.resize(annot_size * ap_count); arc_delay_annotated_.resize(annot_size * ap_count);
} }
@ -747,7 +748,7 @@ Graph::makeEdgeArcDelays(Edge *edge)
} }
edge->setArcDelays(arc_index); edge->setArcDelays(arc_index);
// Make sure there is room for delay_annotated flags. // 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()) { if (max_annot_index >= arc_delay_annotated_.size()) {
unsigned size = max_annot_index * 1.2; unsigned size = max_annot_index * 1.2;
arc_delay_annotated_.resize(size); arc_delay_annotated_.resize(size);
@ -832,7 +833,9 @@ Graph::arcDelayAnnotated(Edge *edge,
TimingArc *arc, TimingArc *arc,
DcalcAPIndex ap_index) const 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]; return arc_delay_annotated_[index];
} }
@ -842,7 +845,9 @@ Graph::setArcDelayAnnotated(Edge *edge,
DcalcAPIndex ap_index, DcalcAPIndex ap_index,
bool annotated) 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; arc_delay_annotated_[index] = annotated;
} }
@ -851,8 +856,10 @@ Graph::wireDelayAnnotated(Edge *edge,
const TransRiseFall *tr, const TransRiseFall *tr,
DcalcAPIndex ap_index) const DcalcAPIndex ap_index) const
{ {
int index = (edge->arcDelays() + TimingArcSet::wireArcIndex(tr)) * ap_count_ unsigned index = (edge->arcDelays() + TimingArcSet::wireArcIndex(tr)) * ap_count_
+ ap_index; + ap_index;
if (index >= arc_delay_annotated_.size())
internalError("arc_delay_annotated array bounds exceeded");
return arc_delay_annotated_[index]; return arc_delay_annotated_[index];
} }
@ -862,8 +869,10 @@ Graph::setWireDelayAnnotated(Edge *edge,
DcalcAPIndex ap_index, DcalcAPIndex ap_index,
bool annotated) bool annotated)
{ {
int index = (edge->arcDelays() + TimingArcSet::wireArcIndex(tr)) * ap_count_ unsigned index = (edge->arcDelays() + TimingArcSet::wireArcIndex(tr)) * ap_count_
+ ap_index; + ap_index;
if (index >= arc_delay_annotated_.size())
internalError("arc_delay_annotated array bounds exceeded");
arc_delay_annotated_[index] = annotated; arc_delay_annotated_[index] = annotated;
} }

View File

@ -40,6 +40,7 @@ enum VertexColor {
vertex_color_black vertex_color_black
}; };
typedef Pool<Delay> DelayPool;
typedef Pool<Vertex> VertexPool; typedef Pool<Vertex> VertexPool;
typedef Pool<Edge> EdgePool; typedef Pool<Edge> EdgePool;
typedef Map<const Pin*, Vertex*> PinVertexMap; typedef Map<const Pin*, Vertex*> PinVertexMap;

View File

@ -20,13 +20,16 @@ include_HEADERS = \
Delay.hh \ Delay.hh \
DelayFloat.hh \ DelayFloat.hh \
DelayFloatClass.hh \ DelayFloatClass.hh \
DelayNormal2.hh \
Graph.hh \ Graph.hh \
GraphClass.hh \ GraphClass.hh \
GraphCmp.hh GraphCmp.hh
libgraph_la_SOURCES = \ libgraph_la_SOURCES = \
Delay.cc \
DelayFloat.cc \ DelayFloat.cc \
DelayFloatClass.cc \ DelayFloatClass.cc \
DelayNormal2.cc \
Graph.cc \ Graph.cc \
GraphCmp.cc GraphCmp.cc

View File

@ -23,14 +23,15 @@
namespace sta { namespace sta {
InternalPowerAttrs::InternalPowerAttrs() : 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(); InternalPowerAttrs::~InternalPowerAttrs()
int tr_index = tr->index(); {
models_[tr_index] = NULL; stringDelete(related_pg_pin_);
}
} }
InternalPowerModel * InternalPowerModel *
@ -46,6 +47,13 @@ InternalPowerAttrs::setModel(TransRiseFall *tr,
models_[tr->index()] = model; 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, InternalPower::InternalPower(LibertyCell *cell,
@ -54,7 +62,8 @@ InternalPower::InternalPower(LibertyCell *cell,
InternalPowerAttrs *attrs) : InternalPowerAttrs *attrs) :
port_(port), port_(port),
related_port_(related_port), related_port_(related_port),
when_(attrs->when()) when_(attrs->when()),
related_pg_pin_(stringCopy(attrs->relatedPgPin()))
{ {
TransRiseFallIterator tr_iter; TransRiseFallIterator tr_iter;
while (tr_iter.hasNext()) { while (tr_iter.hasNext()) {
@ -77,6 +86,7 @@ InternalPower::~InternalPower()
} }
if (when_) if (when_)
when_->deleteSubexprs(); when_->deleteSubexprs();
stringDelete(related_pg_pin_);
} }
LibertyCell * LibertyCell *

View File

@ -30,15 +30,19 @@ class InternalPowerAttrs
{ {
public: public:
InternalPowerAttrs(); InternalPowerAttrs();
~InternalPowerAttrs();
FuncExpr *when() const { return when_; } FuncExpr *when() const { return when_; }
FuncExpr *&whenRef() { return when_; } FuncExpr *&whenRef() { return when_; }
void setModel(TransRiseFall *tr, void setModel(TransRiseFall *tr,
InternalPowerModel *model); InternalPowerModel *model);
InternalPowerModel *model(TransRiseFall *tr) const; InternalPowerModel *model(TransRiseFall *tr) const;
const char *relatedPgPin() const { return related_pg_pin_; }
void setRelatedPgPin(const char *related_pg_pin);
protected: protected:
FuncExpr *when_; FuncExpr *when_;
InternalPowerModel *models_[TransRiseFall::index_count]; InternalPowerModel *models_[TransRiseFall::index_count];
const char *related_pg_pin_;
private: private:
DISALLOW_COPY_AND_ASSIGN(InternalPowerAttrs); DISALLOW_COPY_AND_ASSIGN(InternalPowerAttrs);
@ -56,6 +60,7 @@ public:
LibertyPort *port() const { return port_; } LibertyPort *port() const { return port_; }
LibertyPort *relatedPort() const { return related_port_; } LibertyPort *relatedPort() const { return related_port_; }
FuncExpr *when() const { return when_; } FuncExpr *when() const { return when_; }
const char *relatedPgPin() const { return related_pg_pin_; }
float power(TransRiseFall *tr, float power(TransRiseFall *tr,
const Pvt *pvt, const Pvt *pvt,
float in_slew, float in_slew,
@ -65,6 +70,7 @@ protected:
LibertyPort *port_; LibertyPort *port_;
LibertyPort *related_port_; LibertyPort *related_port_;
FuncExpr *when_; FuncExpr *when_;
const char *related_pg_pin_;
InternalPowerModel *models_[TransRiseFall::index_count]; InternalPowerModel *models_[TransRiseFall::index_count];
private: private:

View File

@ -815,6 +815,8 @@ LibertyCell::LibertyCell(LibertyLibrary *library,
liberty_library_(library), liberty_library_(library),
area_(0.0), area_(0.0),
dont_use_(false), dont_use_(false),
is_macro_(false),
is_pad_(false),
has_internal_ports_(false), has_internal_ports_(false),
interface_timing_(false), interface_timing_(false),
clock_gate_type_(clock_gate_none), clock_gate_type_(clock_gate_none),
@ -833,7 +835,8 @@ LibertyCell::LibertyCell(LibertyLibrary *library,
test_cell_(NULL), test_cell_(NULL),
ocv_arc_depth_(0.0), ocv_arc_depth_(0.0),
ocv_derate_(NULL), 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; 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 void
LibertyCell::setInterfaceTiming(bool value) LibertyCell::setInterfaceTiming(bool value)
{ {
@ -1155,6 +1170,18 @@ LibertyCell::leakagePowerIterator()
return new LibertyCellLeakagePowerIterator(leakage_powers_); return new LibertyCellLeakagePowerIterator(leakage_powers_);
} }
float
LibertyCell::leakagePower() const
{
return leakage_power_;
}
void
LibertyCell::setLeakagePower(float leakage)
{
leakage_power_ = leakage;
}
void void
LibertyCell::finish(bool infer_latches, LibertyCell::finish(bool infer_latches,
Report *report, Report *report,
@ -1808,6 +1835,7 @@ LibertyPort::LibertyPort(LibertyCell *cell,
min_period_(0.0), min_period_(0.0),
pulse_clk_trigger_(NULL), pulse_clk_trigger_(NULL),
pulse_clk_sense_(NULL), pulse_clk_sense_(NULL),
related_power_pin_(NULL),
min_pulse_width_exists_(false), min_pulse_width_exists_(false),
min_period_exists_(false), min_period_exists_(false),
is_clk_(false), is_clk_(false),
@ -1830,6 +1858,7 @@ LibertyPort::~LibertyPort()
if (tristate_enable_) if (tristate_enable_)
tristate_enable_->deleteSubexprs(); tristate_enable_->deleteSubexprs();
delete scaled_ports_; delete scaled_ports_;
stringDelete(related_power_pin_);
} }
void void
@ -2197,6 +2226,12 @@ LibertyPort::setCornerPort(LibertyPort *corner_port,
corner_ports_[ap_index] = corner_port; corner_ports_[ap_index] = corner_port;
} }
void
LibertyPort::setRelatedPowerPin(const char *related_power_pin)
{
related_power_pin_ = stringCopy(related_power_pin);
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
void void
@ -2686,7 +2721,7 @@ TestCell::setScanOutInv(LibertyPort *port)
OcvDerate::OcvDerate(const char *name) : OcvDerate::OcvDerate(const char *name) :
name_(name) name_(name)
{ {
MinMaxIterator el_iter; EarlyLateIterator el_iter;
while (el_iter.hasNext()) { while (el_iter.hasNext()) {
EarlyLate *early_late = el_iter.next(); EarlyLate *early_late = el_iter.next();
int el_index = early_late->index(); int el_index = early_late->index();
@ -2706,7 +2741,7 @@ OcvDerate::~OcvDerate()
// Derating table models can be shared in multiple places in derate_; // Derating table models can be shared in multiple places in derate_;
// Collect them in a set to avoid duplicate deletes. // Collect them in a set to avoid duplicate deletes.
Set<Table*> models; Set<Table*> models;
MinMaxIterator el_iter; EarlyLateIterator el_iter;
while (el_iter.hasNext()) { while (el_iter.hasNext()) {
EarlyLate *early_late = el_iter.next(); EarlyLate *early_late = el_iter.next();
int el_index = early_late->index(); int el_index = early_late->index();

View File

@ -383,6 +383,10 @@ public:
void setArea(float area); void setArea(float area);
bool dontUse() const { return dont_use_; } bool dontUse() const { return dont_use_; }
void setDontUse(bool 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_; } bool interfaceTiming() const { return interface_timing_; }
void setInterfaceTiming(bool value); void setInterfaceTiming(bool value);
bool isClockGateLatchPosedge() const; bool isClockGateLatchPosedge() const;
@ -409,6 +413,7 @@ public:
bool hasTimingArcs(LibertyPort *port) const; bool hasTimingArcs(LibertyPort *port) const;
LibertyCellInternalPowerIterator *internalPowerIterator(); LibertyCellInternalPowerIterator *internalPowerIterator();
LibertyCellLeakagePowerIterator *leakagePowerIterator(); LibertyCellLeakagePowerIterator *leakagePowerIterator();
float leakagePower() const;
bool hasSequentials() const; bool hasSequentials() const;
CellSequentialIterator *sequentialIterator() const; CellSequentialIterator *sequentialIterator() const;
void makeSequential(int size, void makeSequential(int size,
@ -444,6 +449,7 @@ public:
LibertyCell *cornerCell(int ap_index); LibertyCell *cornerCell(int ap_index);
void setCornerCell(LibertyCell *corner_cell, void setCornerCell(LibertyCell *corner_cell,
int ap_index); int ap_index);
void setLeakagePower(float leakage);
// AOCV // AOCV
float ocvArcDepth() const; float ocvArcDepth() const;
@ -476,6 +482,8 @@ protected:
LibertyLibrary *liberty_library_; LibertyLibrary *liberty_library_;
float area_; float area_;
bool dont_use_; bool dont_use_;
bool is_macro_;
bool is_pad_;
bool has_internal_ports_; bool has_internal_ports_;
bool interface_timing_; bool interface_timing_;
ClockGateType clock_gate_type_; ClockGateType clock_gate_type_;
@ -505,6 +513,7 @@ protected:
OcvDerateMap ocv_derate_map_; OcvDerateMap ocv_derate_map_;
bool is_disabled_constraint_; bool is_disabled_constraint_;
Vector<LibertyCell*> corner_cells_; Vector<LibertyCell*> corner_cells_;
float leakage_power_;
private: private:
DISALLOW_COPY_AND_ASSIGN(LibertyCell); DISALLOW_COPY_AND_ASSIGN(LibertyCell);
@ -637,6 +646,8 @@ public:
LibertyPort *cornerPort(int ap_index); LibertyPort *cornerPort(int ap_index);
void setCornerPort(LibertyPort *corner_port, void setCornerPort(LibertyPort *corner_port,
int ap_index); int ap_index);
const char *relatedPowerPin() const { return related_power_pin_; }
void setRelatedPowerPin(const char *related_power_pin);
static bool equiv(const LibertyPort *port1, static bool equiv(const LibertyPort *port1,
const LibertyPort *port2); const LibertyPort *port2);
@ -670,6 +681,7 @@ protected:
float min_pulse_width_[TransRiseFall::index_count]; float min_pulse_width_[TransRiseFall::index_count];
TransRiseFall *pulse_clk_trigger_; TransRiseFall *pulse_clk_trigger_;
TransRiseFall *pulse_clk_sense_; TransRiseFall *pulse_clk_sense_;
const char *related_power_pin_;
Vector<LibertyPort*> corner_ports_; Vector<LibertyPort*> corner_ports_;
unsigned int min_pulse_width_exists_:TransRiseFall::index_count; unsigned int min_pulse_width_exists_:TransRiseFall::index_count;

View File

@ -287,6 +287,8 @@ LibertyReader::defineVisitors()
&LibertyReader::visitClockGatingIntegratedCell); &LibertyReader::visitClockGatingIntegratedCell);
defineAttrVisitor("area", &LibertyReader::visitArea); defineAttrVisitor("area", &LibertyReader::visitArea);
defineAttrVisitor("dont_use", &LibertyReader::visitDontUse); defineAttrVisitor("dont_use", &LibertyReader::visitDontUse);
defineAttrVisitor("is_macro", &LibertyReader::visitIsMacro);
defineAttrVisitor("is_pad", &LibertyReader::visitIsPad);
defineAttrVisitor("interface_timing", &LibertyReader::visitInterfaceTiming); defineAttrVisitor("interface_timing", &LibertyReader::visitInterfaceTiming);
defineAttrVisitor("scaling_factors", &LibertyReader::visitScalingFactors); defineAttrVisitor("scaling_factors", &LibertyReader::visitScalingFactors);
@ -399,6 +401,8 @@ LibertyReader::defineVisitors()
&LibertyReader::endRiseFallPower); &LibertyReader::endRiseFallPower);
defineGroupVisitor("rise_power", &LibertyReader::beginRisePower, defineGroupVisitor("rise_power", &LibertyReader::beginRisePower,
&LibertyReader::endRiseFallPower); &LibertyReader::endRiseFallPower);
defineAttrVisitor("related_power_pin", &LibertyReader::visitRelatedPowerPin);
defineAttrVisitor("related_pg_pin", &LibertyReader::visitRelatedPgPin);
// AOCV attributes. // AOCV attributes.
defineAttrVisitor("ocv_arc_depth", &LibertyReader::visitOcvArcDepth); defineAttrVisitor("ocv_arc_depth", &LibertyReader::visitOcvArcDepth);
@ -417,6 +421,20 @@ LibertyReader::defineVisitors()
defineAttrVisitor("rf_type", &LibertyReader::visitRfType); defineAttrVisitor("rf_type", &LibertyReader::visitRfType);
defineAttrVisitor("derate_type", &LibertyReader::visitDerateType); defineAttrVisitor("derate_type", &LibertyReader::visitDerateType);
defineAttrVisitor("path_type", &LibertyReader::visitPathType); 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 void
@ -535,6 +553,8 @@ LibertyReader::beginLibrary(LibertyGroup *group)
curr_scale_ = 1E-3F; curr_scale_ = 1E-3F;
// Default is 1; // Default is 1;
power_scale_ = 1; power_scale_ = 1;
// Default is fJ.
energy_scale_ = 1e-15;
library_->units()->timeUnit()->setScale(time_scale_); library_->units()->timeUnit()->setScale(time_scale_);
library_->units()->capacitanceUnit()->setScale(cap_scale_); library_->units()->capacitanceUnit()->setScale(cap_scale_);
@ -1720,7 +1740,11 @@ void
LibertyReader::endCell(LibertyGroup *group) LibertyReader::endCell(LibertyGroup *group)
{ {
if (cell_) { if (cell_) {
// Sequentials and leakage powers reference expressions outside of port definitions
// so they do not require LibertyFunc's.
makeCellSequentials(); makeCellSequentials();
// Parse functions defined inside of port groups that reference other ports
// and replace the references with the parsed expressions.
parseCellFuncs(); parseCellFuncs();
makeLeakagePowers(); makeLeakagePowers();
finishPortGroups(); finishPortGroups();
@ -2128,7 +2152,8 @@ TimingGroup::makeTableModels(LibertyReader *visitor)
TableModel *constraint = constraint_[tr_index]; TableModel *constraint = constraint_[tr_index];
TableModel *transition = transition_[tr_index]; TableModel *transition = transition_[tr_index];
if (cell || transition) { 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 if (timing_type_ == timing_type_clear
|| timing_type_ == timing_type_combinational || timing_type_ == timing_type_combinational
|| timing_type_ == timing_type_combinational_fall || 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
|| timing_type_ == timing_type_three_state_enable_fall || timing_type_ == timing_type_three_state_enable_fall
|| timing_type_ == timing_type_three_state_enable_rise) { || timing_type_ == timing_type_three_state_enable_rise) {
const char *tr_name = tr == TransRiseFall::rise() ? "rise" : "fall";
if (transition == NULL) if (transition == NULL)
visitor->libWarn(line_, "missing %s_transition.\n", tr_name); visitor->libWarn(line_, "missing %s_transition.\n", tr->name());
if (cell == NULL) if (cell == NULL)
visitor->libWarn(line_, "missing cell_%s.\n", tr_name); visitor->libWarn(line_, "missing cell_%s.\n", tr->name());
} }
} }
if (constraint) 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 void
LibertyReader::visitInterfaceTiming(LibertyAttr *attr) LibertyReader::visitInterfaceTiming(LibertyAttr *attr)
{ {
@ -3705,6 +3751,7 @@ LibertyReader::beginTableModel(LibertyGroup *group,
beginTable(group, scale); beginTable(group, scale);
tr_ = tr; tr_ = tr;
scale_factor_type_ = scale_factor_type; scale_factor_type_ = scale_factor_type;
sigma_type_ = EarlyLateAll::all();
} }
void void
@ -4248,6 +4295,20 @@ LibertyReader::parseFunc(const char *func,
return parseFuncExpr(func, cell_, error_msg, report_); 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 void
@ -4356,7 +4417,7 @@ void
LibertyReader::beginFallPower(LibertyGroup *group) LibertyReader::beginFallPower(LibertyGroup *group)
{ {
if (internal_power_) if (internal_power_)
beginTableModel(group, TransRiseFall::fall(), power_scale_, beginTableModel(group, TransRiseFall::fall(), energy_scale_,
scale_factor_internal_power); scale_factor_internal_power);
} }
@ -4364,7 +4425,7 @@ void
LibertyReader::beginRisePower(LibertyGroup *group) LibertyReader::beginRisePower(LibertyGroup *group)
{ {
if (internal_power_) if (internal_power_)
beginTableModel(group, TransRiseFall::rise(), power_scale_, beginTableModel(group, TransRiseFall::rise(), energy_scale_,
scale_factor_internal_power); scale_factor_internal_power);
} }
@ -4378,6 +4439,26 @@ LibertyReader::endRiseFallPower(LibertyGroup *)
endTableModel(); 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 void
@ -4438,7 +4519,7 @@ LibertyReader::beginOcvDerateFactors(LibertyGroup *group)
{ {
if (ocv_derate_) { if (ocv_derate_) {
rf_type_ = TransRiseFallBoth::riseFall(); rf_type_ = TransRiseFallBoth::riseFall();
early_late_ = EarlyLateAll::all(); derate_type_ = EarlyLateAll::all();
path_type_ = path_type_clk_and_data; path_type_ = path_type_clk_and_data;
beginTable(group, 1.0); beginTable(group, 1.0);
} }
@ -4448,7 +4529,7 @@ void
LibertyReader::endOcvDerateFactors(LibertyGroup *) LibertyReader::endOcvDerateFactors(LibertyGroup *)
{ {
if (ocv_derate_) { if (ocv_derate_) {
MinMaxIterator el_iter(early_late_); EarlyLateIterator el_iter(derate_type_);
while (el_iter.hasNext()) { while (el_iter.hasNext()) {
EarlyLate *early_late = el_iter.next(); EarlyLate *early_late = el_iter.next();
TransRiseFallIterator tr_iter(rf_type_); TransRiseFallIterator tr_iter(rf_type_);
@ -4483,13 +4564,7 @@ LibertyReader::visitRfType(LibertyAttr *attr)
void void
LibertyReader::visitDerateType(LibertyAttr *attr) LibertyReader::visitDerateType(LibertyAttr *attr)
{ {
const char *derate_type = getAttrString(attr); derate_type_ = getAttrEarlyLate(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");
} }
void 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, LibertyFunc::LibertyFunc(const char *expr,
FuncExpr *&func_ref, FuncExpr *&func_ref,
bool invert, bool invert,
@ -4672,6 +4833,14 @@ TimingGroup::TimingGroup(int line) :
intrinsic_exists_[tr_index] = false; intrinsic_exists_[tr_index] = false;
resistance_[tr_index] = 0.0F; resistance_[tr_index] = 0.0F;
resistance_exists_[tr_index] = false; 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; 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) : InternalPowerGroup::InternalPowerGroup(int line) :
InternalPowerAttrs(), InternalPowerAttrs(),

View File

@ -175,8 +175,11 @@ public:
virtual void visitClockGatingIntegratedCell(LibertyAttr *attr); virtual void visitClockGatingIntegratedCell(LibertyAttr *attr);
virtual void visitArea(LibertyAttr *attr); virtual void visitArea(LibertyAttr *attr);
virtual void visitDontUse(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 visitScalingFactors(LibertyAttr *attr);
virtual void visitCellLeakagePower(LibertyAttr *attr);
virtual void beginPin(LibertyGroup *group); virtual void beginPin(LibertyGroup *group);
virtual void endPin(LibertyGroup *group); virtual void endPin(LibertyGroup *group);
@ -222,6 +225,7 @@ public:
virtual void visitClockGateOutPin(LibertyAttr *attr); virtual void visitClockGateOutPin(LibertyAttr *attr);
void visitIsPllFeedbackPin(LibertyAttr *attr); void visitIsPllFeedbackPin(LibertyAttr *attr);
virtual void visitSignalType(LibertyAttr *attr); virtual void visitSignalType(LibertyAttr *attr);
EarlyLateAll *getAttrEarlyLate(LibertyAttr *attr);
virtual void visitClock(LibertyAttr *attr); virtual void visitClock(LibertyAttr *attr);
virtual void beginScalingFactors(LibertyGroup *group); virtual void beginScalingFactors(LibertyGroup *group);
@ -353,6 +357,8 @@ public:
virtual void beginFallPower(LibertyGroup *group); virtual void beginFallPower(LibertyGroup *group);
virtual void beginRisePower(LibertyGroup *group); virtual void beginRisePower(LibertyGroup *group);
virtual void endRiseFallPower(LibertyGroup *group); virtual void endRiseFallPower(LibertyGroup *group);
virtual void visitRelatedPowerPin(LibertyAttr *attr);
virtual void visitRelatedPgPin(LibertyAttr *attr);
virtual void makeInternalPowers(LibertyPort *port, virtual void makeInternalPowers(LibertyPort *port,
InternalPowerGroup *power_group); InternalPowerGroup *power_group);
virtual void makeInternalPowers(LibertyPort *port, virtual void makeInternalPowers(LibertyPort *port,
@ -372,6 +378,15 @@ public:
virtual void visitDerateType(LibertyAttr *attr); virtual void visitDerateType(LibertyAttr *attr);
virtual void visitPathType(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. // Visitors for derived classes to overload.
virtual void beginGroup1(LibertyGroup *) {} virtual void beginGroup1(LibertyGroup *) {}
virtual void beginGroup2(LibertyGroup *) {} virtual void beginGroup2(LibertyGroup *) {}
@ -513,7 +528,8 @@ protected:
TransRiseFall *tr_; TransRiseFall *tr_;
OcvDerate *ocv_derate_; OcvDerate *ocv_derate_;
TransRiseFallBoth *rf_type_; TransRiseFallBoth *rf_type_;
EarlyLateAll *early_late_; EarlyLateAll *derate_type_;
EarlyLateAll *sigma_type_;
PathType path_type_; PathType path_type_;
ScaleFactorType scale_factor_type_; ScaleFactorType scale_factor_type_;
TableAxis *axis_[3]; TableAxis *axis_[3];
@ -529,6 +545,7 @@ protected:
float volt_scale_; float volt_scale_;
float curr_scale_; float curr_scale_;
float power_scale_; float power_scale_;
float energy_scale_;
private: private:
DISALLOW_COPY_AND_ASSIGN(LibertyReader); DISALLOW_COPY_AND_ASSIGN(LibertyReader);
@ -688,6 +705,12 @@ public:
TableModel *model); TableModel *model);
void makeTimingModels(LibertyLibrary *library, void makeTimingModels(LibertyLibrary *library,
LibertyReader *visitor); LibertyReader *visitor);
void setDelaySigma(TransRiseFall *tr,
EarlyLate *early_late,
TableModel *model);
void setSlewSigma(TransRiseFall *tr,
EarlyLate *early_late,
TableModel *model);
protected: protected:
void makeLinearModels(LibertyLibrary *library); void makeLinearModels(LibertyLibrary *library);
@ -701,6 +724,8 @@ protected:
TableModel *cell_[TransRiseFall::index_count]; TableModel *cell_[TransRiseFall::index_count];
TableModel *constraint_[TransRiseFall::index_count]; TableModel *constraint_[TransRiseFall::index_count];
TableModel *transition_[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: private:
DISALLOW_COPY_AND_ASSIGN(TimingGroup); DISALLOW_COPY_AND_ASSIGN(TimingGroup);

View File

@ -35,8 +35,8 @@ GateLinearModel::gateDelay(const LibertyCell *,
float load_cap, float load_cap,
float, float,
// return values // return values
float &gate_delay, ArcDelay &gate_delay,
float &drvr_slew) const Slew &drvr_slew) const
{ {
gate_delay = intrinsic_ + resistance_ * load_cap; gate_delay = intrinsic_ + resistance_ * load_cap;
drvr_slew = 0.0; drvr_slew = 0.0;
@ -84,14 +84,15 @@ CheckLinearModel::CheckLinearModel(float intrinsic) :
{ {
} }
float void
CheckLinearModel::checkDelay(const LibertyCell *, CheckLinearModel::checkDelay(const LibertyCell *,
const Pvt *, const Pvt *,
float, float,
float, float,
float) const float,
ArcDelay &margin) const
{ {
return intrinsic_; margin = intrinsic_;
} }
void void

View File

@ -32,7 +32,8 @@ public:
float load_cap, float in_slew, float load_cap, float in_slew,
float related_out_cap, float related_out_cap,
// return values // return values
float &gate_delay, float &drvr_slew) const; ArcDelay &gate_delay,
Slew &drvr_slew) const;
virtual void reportGateDelay(const LibertyCell *cell, virtual void reportGateDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float load_cap, float in_slew, float load_cap, float in_slew,
@ -56,10 +57,11 @@ class CheckLinearModel : public CheckTimingModel
public: public:
explicit CheckLinearModel(float intrinsic); explicit CheckLinearModel(float intrinsic);
// Timing check margin delay calculation. // Timing check margin delay calculation.
virtual float checkDelay(const LibertyCell *cell, virtual void checkDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float from_slew, float to_slew, float from_slew, float to_slew,
float related_out_cap) const; float related_out_cap,
ArcDelay &margin) const;
virtual void reportCheckDelay(const LibertyCell *cell, virtual void reportCheckDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float from_slew, float from_slew,

View File

@ -23,21 +23,43 @@
namespace sta { namespace sta {
static void
reportPvt(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
int digits,
string *result);
static void static void
appendSpaces(string *result, appendSpaces(string *result,
int count); int count);
GateTableModel::GateTableModel(TableModel *delay_model, 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), delay_model_(delay_model),
slew_model_(slew_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() GateTableModel::~GateTableModel()
{ {
delete delay_model_; delete delay_model_;
delete slew_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 void
@ -56,29 +78,40 @@ GateTableModel::gateDelay(const LibertyCell *cell,
float load_cap, float load_cap,
float related_out_cap, float related_out_cap,
// return values // return values
float &gate_delay, ArcDelay &gate_delay,
float &drvr_slew) const Slew &drvr_slew) const
{ {
const LibertyLibrary *library = cell->libertyLibrary(); const LibertyLibrary *library = cell->libertyLibrary();
gate_delay = findValue(library, cell, pvt, delay_model_, in_slew, float delay = findValue(library, cell, pvt, delay_model_, in_slew,
load_cap, related_out_cap); load_cap, related_out_cap);
drvr_slew = findValue(library, cell, pvt, slew_model_, in_slew, float sigma_early = 0.0;
load_cap, related_out_cap); float sigma_late = 0.0;
// Clip negative slews to zero. if (delay_sigma_models_[EarlyLate::earlyIndex()])
if (drvr_slew < 0.0) sigma_early = findValue(library, cell, pvt,
drvr_slew = 0.0; 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 float slew = findValue(library, cell, pvt, slew_model_, in_slew,
GateTableModel::gateDelay(const LibertyCell *cell, load_cap, related_out_cap);
const Pvt *pvt, if (slew_sigma_models_[EarlyLate::earlyIndex()])
float in_slew, sigma_early = findValue(library, cell, pvt,
float load_cap, slew_sigma_models_[EarlyLate::earlyIndex()],
float related_out_cap) const in_slew, load_cap, related_out_cap);
{ if (slew_sigma_models_[EarlyLate::lateIndex()])
const LibertyLibrary *library = cell->libertyLibrary(); sigma_late = findValue(library, cell, pvt,
return findValue(library, cell, pvt, delay_model_, in_slew, slew_sigma_models_[EarlyLate::earlyIndex()],
load_cap, related_out_cap); 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 void
@ -91,11 +124,28 @@ GateTableModel::reportGateDelay(const LibertyCell *cell,
string *result) const string *result) const
{ {
const LibertyLibrary *library = cell->libertyLibrary(); const LibertyLibrary *library = cell->libertyLibrary();
reportPvt(library, cell, pvt, digits, result);
reportTableLookup("Delay", library, cell, pvt, delay_model_, in_slew, reportTableLookup("Delay", library, cell, pvt, delay_model_, in_slew,
load_cap, related_out_cap, digits, result); 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'; *result += '\n';
reportTableLookup("Slew", library, cell, pvt, slew_model_, in_slew, reportTableLookup("Slew", library, cell, pvt, slew_model_, in_slew,
load_cap, related_out_cap, digits, result); 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, float drvr_slew = findValue(library, cell, pvt, slew_model_, in_slew,
load_cap, related_out_cap); load_cap, related_out_cap);
if (drvr_slew < 0.0) if (drvr_slew < 0.0)
@ -300,23 +350,25 @@ CheckTableModel::setIsScaled(bool is_scaled)
model_->setIsScaled(is_scaled); model_->setIsScaled(is_scaled);
} }
float void
CheckTableModel::checkDelay(const LibertyCell *cell, CheckTableModel::checkDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float from_slew, float from_slew,
float to_slew, float to_slew,
float related_out_cap) const float related_out_cap,
// Return values.
ArcDelay &margin) const
{ {
if (model_) { if (model_) {
float axis_value1, axis_value2, axis_value3; float axis_value1, axis_value2, axis_value3;
findAxisValues(from_slew, to_slew, related_out_cap, findAxisValues(from_slew, to_slew, related_out_cap,
axis_value1, axis_value2, axis_value3); axis_value1, axis_value2, axis_value3);
const LibertyLibrary *library = cell->libertyLibrary(); const LibertyLibrary *library = cell->libertyLibrary();
return model_->findValue(library, cell, pvt, margin = model_->findValue(library, cell, pvt,
axis_value1, axis_value2, axis_value3); axis_value1, axis_value2, axis_value3);
} }
else else
return 0.0; margin = 0.0;
} }
void void
@ -334,6 +386,7 @@ CheckTableModel::reportCheckDelay(const LibertyCell *cell,
findAxisValues(from_slew, to_slew, related_out_cap, findAxisValues(from_slew, to_slew, related_out_cap,
axis_value1, axis_value2, axis_value3); axis_value1, axis_value2, axis_value3);
const LibertyLibrary *library = cell->libertyLibrary(); const LibertyLibrary *library = cell->libertyLibrary();
reportPvt(library, cell, pvt, digits, result);
model_->reportValue("Check", library, cell, pvt, model_->reportValue("Check", library, cell, pvt,
axis_value1, from_slew_annotation, axis_value2, axis_value1, from_slew_annotation, axis_value2,
axis_value3, digits, result); axis_value3, digits, result);
@ -531,12 +584,12 @@ TableModel::reportValue(const char *result_name,
*result += '\n'; *result += '\n';
} }
void static void
TableModel::reportPvtScaleFactor(const LibertyLibrary *library, reportPvt(const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
int digits, int digits,
string *result) const string *result)
{ {
if (pvt == NULL) if (pvt == NULL)
pvt = library->defaultOperatingConditions(); pvt = library->defaultOperatingConditions();
@ -550,13 +603,26 @@ TableModel::reportPvtScaleFactor(const LibertyLibrary *library,
*result += pvt_str; *result += pvt_str;
stringDelete(pvt_str); stringDelete(pvt_str);
} }
const char *scale_str = stringPrint(strlen("PVT scale factor = %.*f\n") }
+ digits + 10 + 1,
"PVT scale factor = %.*f\n", void
digits, TableModel::reportPvtScaleFactor(const LibertyLibrary *library,
scaleFactor(library, cell, pvt)); const LibertyCell *cell,
*result += scale_str; const Pvt *pvt,
stringDelete(scale_str); 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);
}
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////

View File

@ -19,6 +19,7 @@
#include <string> #include <string>
#include "DisallowCopyAssign.hh" #include "DisallowCopyAssign.hh"
#include "MinMax.hh"
#include "Vector.hh" #include "Vector.hh"
#include "Transition.hh" #include "Transition.hh"
#include "LibertyClass.hh" #include "LibertyClass.hh"
@ -45,21 +46,18 @@ class GateTableModel : public GateTimingModel
{ {
public: public:
GateTableModel(TableModel *delay_model, 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 ~GateTableModel();
virtual void gateDelay(const LibertyCell *cell, virtual void gateDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float in_slew, float in_slew,
float load_cap, float load_cap,
float related_out_cap, float related_out_cap,
// return values // Return values.
float &gate_delay, ArcDelay &gate_delay,
float &drvr_slew) const; Slew &drvr_slew) const;
float gateDelay(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
float related_out_cap) const;
virtual void reportGateDelay(const LibertyCell *cell, virtual void reportGateDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float in_slew, float in_slew,
@ -115,7 +113,9 @@ protected:
static bool checkAxis(TableAxis *axis); static bool checkAxis(TableAxis *axis);
TableModel *delay_model_; TableModel *delay_model_;
TableModel *delay_sigma_models_[EarlyLate::index_count];
TableModel *slew_model_; TableModel *slew_model_;
TableModel *slew_sigma_models_[EarlyLate::index_count];
private: private:
DISALLOW_COPY_AND_ASSIGN(GateTableModel); DISALLOW_COPY_AND_ASSIGN(GateTableModel);
@ -126,11 +126,13 @@ class CheckTableModel : public CheckTimingModel
public: public:
explicit CheckTableModel(TableModel *model); explicit CheckTableModel(TableModel *model);
virtual ~CheckTableModel(); virtual ~CheckTableModel();
virtual float checkDelay(const LibertyCell *cell, virtual void checkDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float from_slew, float from_slew,
float to_slew, float to_slew,
float related_out_cap) const; float related_out_cap,
// Return values.
ArcDelay &margin) const;
virtual void reportCheckDelay(const LibertyCell *cell, virtual void reportCheckDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float from_slew, float from_slew,

View File

@ -40,29 +40,19 @@ TimingArcAttrs::TimingArcAttrs() :
sdf_cond_end_(NULL), sdf_cond_end_(NULL),
mode_name_(NULL), mode_name_(NULL),
mode_value_(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() TimingArcAttrs::~TimingArcAttrs()
{ {
if (sdf_cond_) stringDelete(sdf_cond_);
stringDelete(sdf_cond_); stringDelete(sdf_cond_start_);
if (sdf_cond_start_) stringDelete(sdf_cond_end_);
stringDelete(sdf_cond_start_); stringDelete(mode_name_);
if (sdf_cond_end_) stringDelete(mode_value_);
stringDelete(sdf_cond_end_);
if (mode_name_)
stringDelete(mode_name_);
if (mode_value_)
stringDelete(mode_value_);
} }
void void
@ -162,8 +152,9 @@ TimingArcSet::TimingArcSet(LibertyCell *cell,
is_cond_default_(false), is_cond_default_(false),
sdf_cond_start_(NULL), sdf_cond_start_(NULL),
sdf_cond_end_(NULL), sdf_cond_end_(NULL),
mode_name_(NULL), mode_name_(stringCopy(attrs->modeName())),
mode_value_(NULL), mode_value_(stringCopy(attrs->modeValue())),
ocv_arc_depth_(attrs->ocvArcDepth()),
index_(0), index_(0),
is_disabled_constraint_(false) is_disabled_constraint_(false)
{ {
@ -177,14 +168,6 @@ TimingArcSet::TimingArcSet(LibertyCell *cell,
if (sdf_cond_end) if (sdf_cond_end)
sdf_cond_end_ = stringCopy(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); init(cell);
} }

View File

@ -128,9 +128,9 @@ protected:
const char *sdf_cond_end_; const char *sdf_cond_end_;
const char *mode_name_; const char *mode_name_;
const char *mode_value_; const char *mode_value_;
float ocv_arc_depth_;
TimingModel *models_[TransRiseFall::index_count]; TimingModel *models_[TransRiseFall::index_count];
bool model_refs_[TransRiseFall::index_count]; bool model_refs_[TransRiseFall::index_count];
float ocv_arc_depth_;
private: private:
DISALLOW_COPY_AND_ASSIGN(TimingArcAttrs); DISALLOW_COPY_AND_ASSIGN(TimingArcAttrs);

View File

@ -18,6 +18,7 @@
#define STA_TIMING_MODEL_H #define STA_TIMING_MODEL_H
#include <string> #include <string>
#include "Delay.hh"
#include "LibertyClass.hh" #include "LibertyClass.hh"
namespace sta { namespace sta {
@ -47,8 +48,8 @@ public:
float load_cap, float load_cap,
float related_out_cap, float related_out_cap,
// Return values. // Return values.
float &gate_delay, ArcDelay &gate_delay,
float &drvr_slew) const = 0; Slew &drvr_slew) const = 0;
virtual void reportGateDelay(const LibertyCell *cell, virtual void reportGateDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float in_slew, float in_slew,
@ -65,11 +66,13 @@ class CheckTimingModel : public TimingModel
{ {
public: public:
// Timing check margin delay calculation. // Timing check margin delay calculation.
virtual float checkDelay(const LibertyCell *cell, virtual void checkDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float from_slew, float from_slew,
float to_slew, float to_slew,
float related_out_cap) const = 0; float related_out_cap,
// Return values.
ArcDelay &margin) const = 0;
virtual void reportCheckDelay(const LibertyCell *cell, virtual void reportCheckDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float from_slew, float from_slew,

View File

@ -76,6 +76,12 @@ Unit::setDigits(int digits)
digits_ = digits; digits_ = digits;
} }
int
Unit::width() const
{
return digits_ + (suffix_ ? strlen(suffix_) : 0) + 2;
}
const char * const char *
Unit::asString(float value) const Unit::asString(float value) const
{ {

View File

@ -36,6 +36,7 @@ public:
void setSuffix(const char *suffix); void setSuffix(const char *suffix);
int digits() const { return digits_; } int digits() const { return digits_; }
void setDigits(int digits); void setDigits(int digits);
int width() const;
const char *asString(float value) const; const char *asString(float value) const;
const char *asString(double value) const; const char *asString(double value) const;
const char *asString(float value, const char *asString(float value,

View File

@ -697,8 +697,9 @@ ConcreteCouplingCapExtPin::replaceNode(ConcreteParasiticNode *from_node,
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
ConcreteParasiticNetwork::ConcreteParasiticNetwork() : ConcreteParasiticNetwork::ConcreteParasiticNetwork(bool includes_pin_caps) :
max_node_id_(0) max_node_id_(0),
includes_pin_caps_(includes_pin_caps)
{ {
} }
@ -783,7 +784,7 @@ ConcreteParasiticNetwork::ensureParasiticNode(Net *net,
if (node == NULL) { if (node == NULL) {
node = new ConcreteParasiticSubNode(net, id); node = new ConcreteParasiticSubNode(net, id);
sub_nodes_[new NetId(net, id)] = node; 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; return node;
} }
@ -1653,6 +1654,7 @@ ConcreteParasitics::findParasiticNetwork(const Pin *pin,
Parasitic * Parasitic *
ConcreteParasitics::makeParasiticNetwork(Net *net, ConcreteParasitics::makeParasiticNetwork(Net *net,
bool includes_pin_caps,
const ParasiticAnalysisPt *ap) const ParasiticAnalysisPt *ap)
{ {
int ap_index = parasiticNetworkAnalysisPtIndex(ap); int ap_index = parasiticNetworkAnalysisPtIndex(ap);
@ -1674,7 +1676,7 @@ ConcreteParasitics::makeParasiticNetwork(Net *net,
ConcreteParasiticNetwork *parasitic = ConcreteParasiticNetwork *parasitic =
(*parasitic_network_maps_)[ap_index]->findKey(net); (*parasitic_network_maps_)[ap_index]->findKey(net);
if (parasitic == NULL) { if (parasitic == NULL) {
parasitic = new ConcreteParasiticNetwork; parasitic = new ConcreteParasiticNetwork(includes_pin_caps);
(*(*parasitic_network_maps_)[ap_index])[net] = parasitic; (*(*parasitic_network_maps_)[ap_index])[net] = parasitic;
} }
lock_.unlock(); 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 * ParasiticNode *
ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic, ConcreteParasitics::ensureParasiticNode(Parasitic *parasitic,
Net *net, Net *net,
@ -1970,7 +1980,8 @@ ConcreteParasitics::reduceToPiPoleResidue2(Parasitic *parasitic,
const MinMax *cnst_min_max, const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap) 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, tr, op_cond, corner, cnst_min_max,
ap, this); ap, this);
} }

View File

@ -136,9 +136,11 @@ public:
virtual Parasitic *findParasiticNetwork(const Pin *pin, virtual Parasitic *findParasiticNetwork(const Pin *pin,
const ParasiticAnalysisPt *ap) const; const ParasiticAnalysisPt *ap) const;
virtual Parasitic *makeParasiticNetwork(Net *net, virtual Parasitic *makeParasiticNetwork(Net *net,
bool includes_pin_caps,
const ParasiticAnalysisPt *ap); const ParasiticAnalysisPt *ap);
virtual void deleteParasiticNetwork(const Net *net, virtual void deleteParasiticNetwork(const Net *net,
const ParasiticAnalysisPt *ap); const ParasiticAnalysisPt *ap);
virtual bool includesPinCaps(Parasitic *parasitic) const;
virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, Net *net, virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, Net *net,
int id); int id);
virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic,
@ -194,7 +196,8 @@ public:
const Corner *corner, const Corner *corner,
const MinMax *cnst_min_max, const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap); const ParasiticAnalysisPt *ap);
virtual void reduceToPiElmore(Parasitic *parasitic, const Net *net, virtual void reduceToPiElmore(Parasitic *parasitic,
const Net *net,
const TransRiseFall *tr, const TransRiseFall *tr,
const OperatingConditions *op_cond, const OperatingConditions *op_cond,
const Corner *corner, const Corner *corner,
@ -207,7 +210,8 @@ public:
const Corner *corner, const Corner *corner,
const MinMax *cnst_min_max, const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap); const ParasiticAnalysisPt *ap);
virtual void reduceToPiPoleResidue2(Parasitic *parasitic, const Net *net, virtual void reduceToPiPoleResidue2(Parasitic *parasitic,
const Net *net,
const TransRiseFall *tr, const TransRiseFall *tr,
const OperatingConditions *op_cond, const OperatingConditions *op_cond,
const Corner *corner, const Corner *corner,

View File

@ -403,9 +403,10 @@ class ConcreteParasiticNetwork : public ParasiticNetwork,
public ConcreteParasitic public ConcreteParasitic
{ {
public: public:
ConcreteParasiticNetwork(); ConcreteParasiticNetwork(bool includes_pin_caps);
virtual ~ConcreteParasiticNetwork(); virtual ~ConcreteParasiticNetwork();
virtual bool isParasiticNetwork() const { return true; } virtual bool isParasiticNetwork() const { return true; }
bool includesPinCaps() const { return includes_pin_caps_; }
ConcreteParasiticNode *ensureParasiticNode(Net *net, ConcreteParasiticNode *ensureParasiticNode(Net *net,
int id); int id);
ConcreteParasiticNode *findNode(const Pin *pin); ConcreteParasiticNode *findNode(const Pin *pin);
@ -422,7 +423,8 @@ private:
ConcreteParasiticSubNodeMap sub_nodes_; ConcreteParasiticSubNodeMap sub_nodes_;
ConcreteParasiticPinNodeMap pin_nodes_; ConcreteParasiticPinNodeMap pin_nodes_;
int max_node_id_; unsigned max_node_id_:31;
bool includes_pin_caps_:1;
}; };
} // namespace } // namespace

View File

@ -45,7 +45,8 @@ NullParasitics::deleteParasitics()
} }
void void
NullParasitics::deleteParasitics(const Net *, const ParasiticAnalysisPt *) NullParasitics::deleteParasitics(const Net *,
const ParasiticAnalysisPt *)
{ {
} }
@ -69,7 +70,8 @@ NullParasitics::capacitance(Parasitic *) const
} }
bool bool
NullParasitics::hasLumpedElmore(const Pin *, const TransRiseFall *, NullParasitics::hasLumpedElmore(const Pin *,
const TransRiseFall *,
const ParasiticAnalysisPt *) const const ParasiticAnalysisPt *) const
{ {
return false; return false;
@ -90,7 +92,8 @@ NullParasitics::isLumpedElmore(Parasitic *) const
} }
Parasitic * Parasitic *
NullParasitics::makeLumpedElmore(const Pin *, float, NullParasitics::makeLumpedElmore(const Pin *,
float,
const TransRiseFall *, const TransRiseFall *,
const ParasiticAnalysisPt *) const ParasiticAnalysisPt *)
{ {
@ -124,7 +127,9 @@ Parasitic *
NullParasitics::makePiElmore(const Pin *, NullParasitics::makePiElmore(const Pin *,
const TransRiseFall *, const TransRiseFall *,
const ParasiticAnalysisPt *, const ParasiticAnalysisPt *,
float, float, float) float,
float,
float)
{ {
return NULL; return NULL;
} }
@ -135,7 +140,8 @@ NullParasitics::deletePiElmore(const Pin *)
} }
void void
NullParasitics::deletePiElmore(const Pin *, const TransRiseFall *, NullParasitics::deletePiElmore(const Pin *,
const TransRiseFall *,
const ParasiticAnalysisPt *) const ParasiticAnalysisPt *)
{ {
} }
@ -153,28 +159,39 @@ NullParasitics::isReducedParasiticNetwork(Parasitic *) const
} }
void void
NullParasitics::setIsReducedParasiticNetwork(Parasitic *, bool) NullParasitics::setIsReducedParasiticNetwork(Parasitic *,
bool)
{ {
} }
void void
NullParasitics::piModel(Parasitic *, float &, float &, float &) const NullParasitics::piModel(Parasitic *,
float &,
float &,
float &) const
{ {
} }
void void
NullParasitics::setPiModel(Parasitic *, float, float, float) NullParasitics::setPiModel(Parasitic *,
float,
float,
float)
{ {
} }
void void
NullParasitics::findElmore(Parasitic *, const Pin *, NullParasitics::findElmore(Parasitic *,
float &, bool &) const const Pin *,
float &,
bool &) const
{ {
} }
void void
NullParasitics::setElmore(Parasitic *, const Pin *, float) NullParasitics::setElmore(Parasitic *,
const Pin *,
float)
{ {
} }
@ -210,7 +227,9 @@ Parasitic *
NullParasitics::makePiPoleResidue(const Pin *, NullParasitics::makePiPoleResidue(const Pin *,
const TransRiseFall *, const TransRiseFall *,
const ParasiticAnalysisPt *, const ParasiticAnalysisPt *,
float, float, float) float,
float,
float)
{ {
return NULL; return NULL;
} }
@ -223,8 +242,10 @@ NullParasitics::findPoleResidue(const Parasitic *,
} }
void void
NullParasitics::setPoleResidue(Parasitic *, const Pin *, NullParasitics::setPoleResidue(Parasitic *,
ComplexFloatSeq *, ComplexFloatSeq *) const Pin *,
ComplexFloatSeq *,
ComplexFloatSeq *)
{ {
} }
@ -241,8 +262,10 @@ NullParasitics::poleResidueCount(const Parasitic *) const
} }
void void
NullParasitics::poleResidue(const Parasitic *, int, NullParasitics::poleResidue(const Parasitic *,
ComplexFloat &, ComplexFloat &) const int,
ComplexFloat &,
ComplexFloat &) const
{ {
} }
@ -267,11 +290,19 @@ NullParasitics::isParasiticNetwork(Parasitic *) const
} }
Parasitic * Parasitic *
NullParasitics::makeParasiticNetwork(Net *, const ParasiticAnalysisPt *) NullParasitics::makeParasiticNetwork(Net *,
bool,
const ParasiticAnalysisPt *)
{ {
return NULL; return NULL;
} }
bool
NullParasitics::includesPinCaps(Parasitic *) const
{
return false;
}
void void
NullParasitics::deleteParasiticNetwork(const Net *, NullParasitics::deleteParasiticNetwork(const Net *,
const ParasiticAnalysisPt *) const ParasiticAnalysisPt *)
@ -279,44 +310,59 @@ NullParasitics::deleteParasiticNetwork(const Net *,
} }
ParasiticNode * ParasiticNode *
NullParasitics::ensureParasiticNode(Parasitic *, Net *, int) NullParasitics::ensureParasiticNode(Parasitic *,
Net *,
int)
{ {
return NULL; return NULL;
} }
ParasiticNode * ParasiticNode *
NullParasitics::ensureParasiticNode(Parasitic *, const Pin *) NullParasitics::ensureParasiticNode(Parasitic *,
const Pin *)
{ {
return NULL; return NULL;
} }
void void
NullParasitics::incrCap(ParasiticNode *, float, NullParasitics::incrCap(ParasiticNode *,
float,
const ParasiticAnalysisPt *) const ParasiticAnalysisPt *)
{ {
} }
void void
NullParasitics::makeCouplingCap(const char *, ParasiticNode *, NullParasitics::makeCouplingCap(const char *,
ParasiticNode *, float, ParasiticNode *,
ParasiticNode *,
float,
const ParasiticAnalysisPt *) const ParasiticAnalysisPt *)
{ {
} }
void NullParasitics::makeCouplingCap(const char *, ParasiticNode *, Net *, void NullParasitics::makeCouplingCap(const char *,
int, float, const ParasiticAnalysisPt *) ParasiticNode *,
Net *,
int,
float,
const ParasiticAnalysisPt *)
{ {
} }
void void
NullParasitics::makeCouplingCap(const char *, ParasiticNode *, Pin *, NullParasitics::makeCouplingCap(const char *,
float, const ParasiticAnalysisPt *) ParasiticNode *,
Pin *,
float,
const ParasiticAnalysisPt *)
{ {
} }
void void
NullParasitics::makeResistor(const char *, ParasiticNode *, NullParasitics::makeResistor(const char *,
ParasiticNode *, float, ParasiticNode *,
ParasiticNode *,
float,
const ParasiticAnalysisPt *) const ParasiticAnalysisPt *)
{ {
} }
@ -334,7 +380,8 @@ NullParasitics::connectionPin(const ParasiticNode *) const
} }
ParasiticNode * ParasiticNode *
NullParasitics::findNode(Parasitic *, const Pin *) const NullParasitics::findNode(Parasitic *,
const Pin *) const
{ {
return NULL; return NULL;
} }
@ -378,13 +425,15 @@ NullParasitics::value(const ParasiticDevice *,
} }
ParasiticNode * ParasiticNode *
NullParasitics::otherNode(const ParasiticDevice *, ParasiticNode *) const NullParasitics::otherNode(const ParasiticDevice *,
ParasiticNode *) const
{ {
return NULL; return NULL;
} }
void void
NullParasitics::reduceTo(Parasitic *, const Net *, NullParasitics::reduceTo(Parasitic *,
const Net *,
ReduceParasiticsTo , ReduceParasiticsTo ,
const TransRiseFall *, const TransRiseFall *,
const OperatingConditions *, const OperatingConditions *,
@ -395,7 +444,8 @@ NullParasitics::reduceTo(Parasitic *, const Net *,
} }
void void
NullParasitics::reduceToPiElmore(Parasitic *, const Net *, NullParasitics::reduceToPiElmore(Parasitic *,
const Net *,
const TransRiseFall *, const TransRiseFall *,
const OperatingConditions *, const OperatingConditions *,
const Corner *, const Corner *,
@ -418,11 +468,11 @@ NullParasitics::reduceToPiElmore(Parasitic *,
void void
NullParasitics::reduceToPiPoleResidue2(Parasitic *, const Net *, NullParasitics::reduceToPiPoleResidue2(Parasitic *, const Net *,
const TransRiseFall *, const TransRiseFall *,
const OperatingConditions *, const OperatingConditions *,
const Corner *, const Corner *,
const MinMax *, const MinMax *,
const ParasiticAnalysisPt *) const ParasiticAnalysisPt *)
{ {
} }

View File

@ -124,7 +124,9 @@ public:
virtual bool isParasiticNetwork(Parasitic *parasitic) const; virtual bool isParasiticNetwork(Parasitic *parasitic) const;
virtual Parasitic * virtual Parasitic *
makeParasiticNetwork(Net *net, makeParasiticNetwork(Net *net,
bool pin_cap_included,
const ParasiticAnalysisPt *ap); const ParasiticAnalysisPt *ap);
virtual bool includesPinCaps(Parasitic *parasitic) const;
virtual void deleteParasiticNetwork(const Net *net, virtual void deleteParasiticNetwork(const Net *net,
const ParasiticAnalysisPt *ap); const ParasiticAnalysisPt *ap);
virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic,
@ -165,14 +167,16 @@ public:
virtual ParasiticNode *otherNode(const ParasiticDevice *device, virtual ParasiticNode *otherNode(const ParasiticDevice *device,
ParasiticNode *node) const; ParasiticNode *node) const;
// Reduce parasitic network to reduce_to model. // 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, ReduceParasiticsTo reduce_to,
const TransRiseFall *tr, const TransRiseFall *tr,
const OperatingConditions *op_cond, const OperatingConditions *op_cond,
const Corner *corner, const Corner *corner,
const MinMax *cnst_min_max, const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap); const ParasiticAnalysisPt *ap);
virtual void reduceToPiElmore(Parasitic *parasitic, const Net *net, virtual void reduceToPiElmore(Parasitic *parasitic,
const Net *net,
const TransRiseFall *tr, const TransRiseFall *tr,
const OperatingConditions *op_cond, const OperatingConditions *op_cond,
const Corner *corner, const Corner *corner,
@ -186,7 +190,8 @@ public:
const Corner *corner, const Corner *corner,
const MinMax *cnst_min_max, const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap); const ParasiticAnalysisPt *ap);
virtual void reduceToPiPoleResidue2(Parasitic *parasitic, const Net *net, virtual void reduceToPiPoleResidue2(Parasitic *parasitic,
const Net *net,
const TransRiseFall *tr, const TransRiseFall *tr,
const OperatingConditions *op_cond, const OperatingConditions *op_cond,
const Corner *corner, const Corner *corner,

View File

@ -93,7 +93,7 @@ Parasitics::makeWireloadNetwork(const Pin *drvr_pin,
const ParasiticAnalysisPt *ap) const ParasiticAnalysisPt *ap)
{ {
Net *net = network_->net(drvr_pin); Net *net = network_->net(drvr_pin);
Parasitic *parasitic = makeParasiticNetwork(net, ap); Parasitic *parasitic = makeParasiticNetwork(net, false, ap);
float wireload_cap, wireload_res; float wireload_cap, wireload_res;
wireload->findWireload(fanout, op_cond, wireload_cap, wireload_res); wireload->findWireload(fanout, op_cond, wireload_cap, wireload_res);

View File

@ -182,10 +182,13 @@ public:
virtual Parasitic *findParasiticNetwork(const Pin *pin, virtual Parasitic *findParasiticNetwork(const Pin *pin,
const ParasiticAnalysisPt *ap) const = 0; const ParasiticAnalysisPt *ap) const = 0;
virtual Parasitic *makeParasiticNetwork(Net *net, virtual Parasitic *makeParasiticNetwork(Net *net,
bool pin_cap_included,
const ParasiticAnalysisPt *ap) = 0; const ParasiticAnalysisPt *ap) = 0;
// Delete parasitic network if it exists. // Delete parasitic network if it exists.
virtual void deleteParasiticNetwork(const Net *net, virtual void deleteParasiticNetwork(const Net *net,
const ParasiticAnalysisPt *ap) = 0; const ParasiticAnalysisPt *ap) = 0;
// True if the parasitic network caps include pin capacitances.
virtual bool includesPinCaps(Parasitic *parasitic) const = 0;
// Parasitic network component builders. // Parasitic network component builders.
// Make a subnode of the parasitic network net. // Make a subnode of the parasitic network net.
virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic, virtual ParasiticNode *ensureParasiticNode(Parasitic *parasitic,

View File

@ -38,6 +38,7 @@ read_parasitics_cmd(const char *filename,
Instance *instance, Instance *instance,
MinMaxAll *min_max, MinMaxAll *min_max,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,
@ -47,9 +48,9 @@ read_parasitics_cmd(const char *filename,
{ {
cmdLinkedNetwork(); cmdLinkedNetwork();
return Sta::sta()->readParasitics(filename, instance, min_max, return Sta::sta()->readParasitics(filename, instance, min_max,
increment, keep_coupling_caps, increment, pin_cap_included,
coupling_cap_factor, reduce_to, keep_coupling_caps, coupling_cap_factor,
delete_after_reduce, reduce_to, delete_after_reduce,
save, quiet); save, quiet);
} }

View File

@ -17,16 +17,26 @@
namespace eval sta { namespace eval sta {
define_cmd_args "read_parasitics" \ define_cmd_args "read_parasitics" \
{[-min] [-max] [-elmore] [-path path] [-increment]\ {[-min]\
[-keep_capacitive_coupling] [-coupling_reduction_factor factor]\ [-max]\
[-reduce_to pi_elmore|pi_pole_residue2] [-delete_after_reduce]\ [-elmore]\
[-quiet] [-save] filenames} [-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 { proc_redirect read_parasitics {
# The -elmore flag is required by dc. # The -elmore flag is required by dc.
parse_key_args "read_parasitics" args \ parse_key_args "read_parasitics" args \
keys {-path -coupling_reduction_factor -reduce_to} \ 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} -delete_after_reduce -quiet -save}
check_argc_eq1 "report_parasitics" $args check_argc_eq1 "report_parasitics" $args
@ -46,6 +56,8 @@ proc_redirect read_parasitics {
check_positive_float "-coupling_reduction_factor" $coupling_reduction_factor check_positive_float "-coupling_reduction_factor" $coupling_reduction_factor
} }
set keep_coupling_caps [info exists flags(-keep_capacitive_coupling)] set keep_coupling_caps [info exists flags(-keep_capacitive_coupling)]
set pin_cap_included [info exists flags(-pin_cap_included)]
set reduce_to "none" set reduce_to "none"
if [info exists keys(-reduce_to)] { if [info exists keys(-reduce_to)] {
set reduce_to $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 delete_after_reduce [info exists flags(-delete_after_reduce)]
set quiet [info exists flags(-quiet)] set quiet [info exists flags(-quiet)]
set save [info exists flags(-save)] set save [info exists flags(-save)]
set filenames $args set filename $args
set success 1 return [read_parasitics_cmd $filename $instance $min_max $increment \
foreach filename $filenames { $pin_cap_included $keep_coupling_caps $coupling_reduction_factor \
if { ![read_parasitics_cmd $filename $instance $min_max $increment \ $reduce_to $delete_after_reduce \
$keep_coupling_caps $coupling_reduction_factor \ $save $quiet]
$reduce_to $delete_after_reduce \
$save $quiet] } {
set success 0
}
}
return $success
} }
# set_pi_model [-min] [-max] drvr_pin c2 rpi c1 # set_pi_model [-min] [-max] drvr_pin c2 rpi c1

View File

@ -50,6 +50,7 @@ readParasiticsFile(const char *filename,
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,
@ -72,7 +73,7 @@ readParasiticsFile(const char *filename,
switch (file_type) { switch (file_type) {
case parasitics_file_spef: case parasitics_file_spef:
success = readSpefFile(filename, stream, line_num, success = readSpefFile(filename, stream, line_num,
instance, ap, increment, instance, ap, increment, pin_cap_included,
keep_coupling_caps, coupling_cap_factor, keep_coupling_caps, coupling_cap_factor,
reduce_to, delete_after_reduce, reduce_to, delete_after_reduce,
op_cond, corner, cnst_min_max, op_cond, corner, cnst_min_max,
@ -81,14 +82,16 @@ readParasiticsFile(const char *filename,
break; break;
case parasitics_file_rspf: case parasitics_file_rspf:
success = readSpfFile(filename, stream, line_num, true, instance, ap, 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, reduce_to, delete_after_reduce,
op_cond, corner, cnst_min_max, op_cond, corner, cnst_min_max,
save, quiet, report, network, parasitics); save, quiet, report, network, parasitics);
break; break;
case parasitics_file_dspf: case parasitics_file_dspf:
success = readSpfFile(filename, stream, line_num, false, instance, ap, 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, reduce_to, delete_after_reduce,
op_cond, corner, cnst_min_max, op_cond, corner, cnst_min_max,
save, quiet, report, save, quiet, report,

View File

@ -34,6 +34,7 @@ readParasiticsFile(const char *filename,
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,

View File

@ -34,29 +34,39 @@ class ReduceToPi : public StaState
{ {
public: public:
ReduceToPi(StaState *sta); 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, float coupling_cap_factor,
const TransRiseFall *tr, const TransRiseFall *tr,
const OperatingConditions *op_cond, const OperatingConditions *op_cond,
const Corner *corner, const Corner *corner,
const MinMax *cnst_min_max, const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap, const ParasiticAnalysisPt *ap,
float &c2, float &rpi, float &c1); float &c2,
float &rpi,
float &c1);
protected: protected:
void reducePiDfs(const Pin *drvr_pin, ParasiticNode *node, void reducePiDfs(const Pin *drvr_pin,
ParasiticNode *node,
ParasiticDevice *from_res, ParasiticDevice *from_res,
const ParasiticAnalysisPt *ap, 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); void visit(ParasiticNode *node);
bool isVisited(ParasiticNode *node); bool isVisited(ParasiticNode *node);
void leave(ParasiticNode *node); void leave(ParasiticNode *node);
void setDownstreamCap(ParasiticNode *node, float cap); void setDownstreamCap(ParasiticNode *node,
float cap);
float downstreamCap(ParasiticNode *node); float downstreamCap(ParasiticNode *node);
float pinCapacitance(ParasiticNode *node); float pinCapacitance(ParasiticNode *node);
bool isLoopResistor(ParasiticDevice *device); bool isLoopResistor(ParasiticDevice *device);
void markLoopResistor(ParasiticDevice *device); void markLoopResistor(ParasiticDevice *device);
bool pin_cap_included_;
float coupling_cap_multiplier_; float coupling_cap_multiplier_;
const TransRiseFall *tr_; const TransRiseFall *tr_;
const OperatingConditions *op_cond_; const OperatingConditions *op_cond_;
@ -82,15 +92,20 @@ ReduceToPi::ReduceToPi(StaState *sta) :
// Thomas Savarino, Proceedings of the 1989 Design Automation // Thomas Savarino, Proceedings of the 1989 Design Automation
// Conference. // Conference.
void 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, float coupling_cap_factor,
const TransRiseFall *tr, const TransRiseFall *tr,
const OperatingConditions *op_cond, const OperatingConditions *op_cond,
const Corner *corner, const Corner *corner,
const MinMax *cnst_min_max, const MinMax *cnst_min_max,
const ParasiticAnalysisPt *ap, 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; coupling_cap_multiplier_ = coupling_cap_factor;
tr_ = tr; tr_ = tr;
op_cond_ = op_cond; op_cond_ = op_cond;
@ -190,9 +205,11 @@ ReduceToPi::pinCapacitance(ParasiticNode *node)
if (pin) { if (pin) {
Port *port = network_->port(pin); Port *port = network_->port(pin);
LibertyPort *lib_port = network_->libertyPort(port); LibertyPort *lib_port = network_->libertyPort(port);
if (lib_port) if (lib_port) {
pin_cap = sdc_->pinCapacitance(pin,tr_, op_cond_, if (!pin_cap_included_)
corner_, cnst_min_max_); pin_cap = sdc_->pinCapacitance(pin,tr_, op_cond_, corner_,
cnst_min_max_);
}
else if (network_->isTopLevelPort(pin)) else if (network_->isTopLevelPort(pin))
pin_cap = sdc_->portExtCap(port, tr_, cnst_min_max_); pin_cap = sdc_->portExtCap(port, tr_, cnst_min_max_);
} }
@ -230,7 +247,8 @@ ReduceToPi::markLoopResistor(ParasiticDevice *device)
} }
void void
ReduceToPi::setDownstreamCap(ParasiticNode *node, float cap) ReduceToPi::setDownstreamCap(ParasiticNode *node,
float cap)
{ {
node_values_[node] = cap; node_values_[node] = cap;
} }
@ -261,7 +279,8 @@ ReduceToPiElmore::ReduceToPiElmore(StaState *sta) :
} }
Parasitic * Parasitic *
reduceToPiElmore(Parasitic *parasitic, const Pin *drvr_pin, reduceToPiElmore(Parasitic *parasitic,
const Pin *drvr_pin,
float coupling_cap_factor, float coupling_cap_factor,
const TransRiseFall *tr, const TransRiseFall *tr,
const OperatingConditions *op_cond, const OperatingConditions *op_cond,
@ -278,7 +297,9 @@ reduceToPiElmore(Parasitic *parasitic, const Pin *drvr_pin,
if (drvr_node) { if (drvr_node) {
ReduceToPiElmore reducer(sta); ReduceToPiElmore reducer(sta);
float c2, rpi, c1; 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, tr, op_cond, corner, cnst_min_max, ap,
c2, rpi, c1); c2, rpi, c1);
Parasitic *pi_elmore = parasitics->makePiElmore(drvr_pin, tr, ap, Parasitic *pi_elmore = parasitics->makePiElmore(drvr_pin, tr, ap,
@ -339,25 +360,39 @@ public:
ReduceToPiPoleResidue2(StaState *sta); ReduceToPiPoleResidue2(StaState *sta);
~ReduceToPiPoleResidue2(); ~ReduceToPiPoleResidue2();
void findPolesResidues(Parasitic *parasitic_network, void findPolesResidues(Parasitic *parasitic_network,
Parasitic *pi_pole_residue, const Pin *drvr_pin, Parasitic *pi_pole_residue,
const Pin *drvr_pin,
ParasiticNode *drvr_node, ParasiticNode *drvr_node,
const ParasiticAnalysisPt *ap); const ParasiticAnalysisPt *ap);
private: private:
void findMoments(const Pin *drvr_pin, ParasiticNode *drvr_node, void findMoments(const Pin *drvr_pin,
int moment_count, const ParasiticAnalysisPt *ap); ParasiticNode *drvr_node,
void findMoments(const Pin *drvr_pin, ParasiticNode *node, double from_volt, int moment_count,
ParasiticDevice *from_res, int moment_index,
const ParasiticAnalysisPt *ap); 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, ParasiticDevice *from_res,
int moment_index, const ParasiticAnalysisPt *ap); int moment_index,
double moment(ParasiticNode *node, int moment_index); const ParasiticAnalysisPt *ap);
void setMoment(ParasiticNode *node, double moment, int moment_index); double moment(ParasiticNode *node,
int moment_index);
void setMoment(ParasiticNode *node,
double moment,
int moment_index);
double current(ParasiticDevice *res); double current(ParasiticDevice *res);
void setCurrent(ParasiticDevice *res, double i); void setCurrent(ParasiticDevice *res,
void findPolesResidues(Parasitic *pi_pole_residue, const Pin *drvr_pin, double i);
const Pin *load_pin, ParasiticNode *load_node); void findPolesResidues(Parasitic *pi_pole_residue,
const Pin *drvr_pin,
const Pin *load_pin,
ParasiticNode *load_node);
// Resistor/capacitor currents. // Resistor/capacitor currents.
ParasiticDeviceValueMap currents_; ParasiticDeviceValueMap currents_;
@ -381,7 +416,8 @@ ReduceToPiPoleResidue2::ReduceToPiPoleResidue2(StaState *sta) :
// Three Moments of the Impulse Response", Proceedings of the 33rd // Three Moments of the Impulse Response", Proceedings of the 33rd
// Design Automation Conference, 1996, pg 611-616. // Design Automation Conference, 1996, pg 611-616.
Parasitic * Parasitic *
reduceToPiPoleResidue2(Parasitic *parasitic, const Pin *drvr_pin, reduceToPiPoleResidue2(Parasitic *parasitic,
const Pin *drvr_pin,
float coupling_cap_factor, float coupling_cap_factor,
const TransRiseFall *tr, const TransRiseFall *tr,
const OperatingConditions *op_cond, const OperatingConditions *op_cond,
@ -398,7 +434,9 @@ reduceToPiPoleResidue2(Parasitic *parasitic, const Pin *drvr_pin,
if (drvr_node) { if (drvr_node) {
ReduceToPiPoleResidue2 reducer(sta); ReduceToPiPoleResidue2 reducer(sta);
float c2, rpi, c1; 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, tr, op_cond, corner, cnst_min_max, ap,
c2, rpi, c1); c2, rpi, c1);
Parasitic *pi_pole_residue = parasitics->makePiPoleResidue(drvr_pin, Parasitic *pi_pole_residue = parasitics->makePiPoleResidue(drvr_pin,
@ -504,7 +542,8 @@ ReduceToPiPoleResidue2::findBranchCurrents(const Pin *drvr_pin,
} }
void void
ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin, ParasiticNode *node, ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin,
ParasiticNode *node,
double from_volt, double from_volt,
ParasiticDevice *from_res, ParasiticDevice *from_res,
int moment_index, int moment_index,
@ -540,7 +579,8 @@ ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin, ParasiticNode *node,
} }
double double
ReduceToPiPoleResidue2::moment(ParasiticNode *node, int moment_index) ReduceToPiPoleResidue2::moment(ParasiticNode *node,
int moment_index)
{ {
// Zero'th moments are all 1. // Zero'th moments are all 1.
if (moment_index == 0) if (moment_index == 0)
@ -552,7 +592,8 @@ ReduceToPiPoleResidue2::moment(ParasiticNode *node, int moment_index)
} }
void void
ReduceToPiPoleResidue2::setMoment(ParasiticNode *node, double moment, ReduceToPiPoleResidue2::setMoment(ParasiticNode *node,
double moment,
int moment_index) int moment_index)
{ {
// Zero'th moments are all 1. // Zero'th moments are all 1.
@ -569,7 +610,8 @@ ReduceToPiPoleResidue2::current(ParasiticDevice *res)
} }
void void
ReduceToPiPoleResidue2::setCurrent(ParasiticDevice *res, double i) ReduceToPiPoleResidue2::setCurrent(ParasiticDevice *res,
double i)
{ {
currents_[res] = i; currents_[res] = i;
} }

View File

@ -25,7 +25,8 @@ class StaState;
// Reduce parasitic network to pi elmore model for drvr_pin. // Reduce parasitic network to pi elmore model for drvr_pin.
Parasitic * Parasitic *
reduceToPiElmore(Parasitic *parasitic, const Pin *drvr_pin, reduceToPiElmore(Parasitic *parasitic,
const Pin *drvr_pin,
float coupling_cap_factor, float coupling_cap_factor,
const TransRiseFall *tr, const TransRiseFall *tr,
const OperatingConditions *op_cond, 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 // Reduce parasitic network to pi and 2nd order pole/residue models
// for drvr_pin. // for drvr_pin.
Parasitic * Parasitic *
reduceToPiPoleResidue2(Parasitic *parasitic, const Pin *drvr_pin, reduceToPiPoleResidue2(Parasitic *parasitic,
const Pin *drvr_pin,
float coupling_cap_factor, float coupling_cap_factor,
const TransRiseFall *tr, const TransRiseFall *tr,
const OperatingConditions *op_cond, const OperatingConditions *op_cond,

View File

@ -43,6 +43,7 @@ readSpefFile(const char *filename,
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,
@ -57,7 +58,7 @@ readSpefFile(const char *filename,
Parasitics *parasitics) Parasitics *parasitics)
{ {
SpefReader reader(filename, stream, line, instance, ap, increment, 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, reduce_to, delete_after_reduce, op_cond, corner,
cnst_min_max, quiet, report, network, parasitics); cnst_min_max, quiet, report, network, parasitics);
spef_reader = &reader; spef_reader = &reader;
@ -75,6 +76,7 @@ SpefReader::SpefReader(const char *filename,
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,
@ -86,7 +88,8 @@ SpefReader::SpefReader(const char *filename,
Report *report, Report *report,
Network *network, Network *network,
Parasitics *parasitics) : 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, keep_coupling_caps, coupling_cap_factor,
reduce_to, delete_after_reduce, reduce_to, delete_after_reduce,
op_cond, corner, cnst_min_max, quiet, op_cond, corner, cnst_min_max, quiet,
@ -339,7 +342,9 @@ SpefReader::dspfBegin(Net *net,
parasitic_ = 0; parasitic_ = 0;
else { else {
parasitics_->deleteParasitics(net, ap_); parasitics_->deleteParasitics(net, ap_);
parasitic_ = parasitics_->makeParasiticNetwork(net, ap_); parasitic_ = parasitics_->makeParasiticNetwork(net, pin_cap_included_,
ap_);
} }
net_ = net; net_ = net;
} }
@ -361,8 +366,8 @@ SpefReader::dspfFinish()
TransRiseFallIterator tr_iter; TransRiseFallIterator tr_iter;
while (tr_iter.hasNext()) { while (tr_iter.hasNext()) {
TransRiseFall *tr = tr_iter.next(); TransRiseFall *tr = tr_iter.next();
parasitics_->reduceTo(parasitic_, net_, reduce_to_, tr, op_cond_, parasitics_->reduceTo(parasitic_, net_, reduce_to_, tr,
corner_, cnst_min_max_, ap_); op_cond_, corner_, cnst_min_max_, ap_);
} }
if (delete_after_reduce_) if (delete_after_reduce_)
parasitics_->deleteParasiticNetwork(net_, ap_); parasitics_->deleteParasiticNetwork(net_, ap_);

View File

@ -38,6 +38,7 @@ readSpefFile(const char *filename,
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,

View File

@ -52,6 +52,7 @@ public:
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,

View File

@ -44,6 +44,7 @@ readSpfFile(const char *filename,
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,
@ -58,9 +59,9 @@ readSpfFile(const char *filename,
Parasitics *parasitics) Parasitics *parasitics)
{ {
SpfReader reader(filename, stream, line, rspf, instance, ap, SpfReader reader(filename, stream, line, rspf, instance, ap,
increment, keep_coupling_caps, coupling_cap_factor, increment, pin_cap_included, keep_coupling_caps,
reduce_to, delete_after_reduce, op_cond, coupling_cap_factor, reduce_to, delete_after_reduce,
corner, cnst_min_max, quiet, op_cond, corner, cnst_min_max, quiet,
report, network, parasitics); report, network, parasitics);
spf_reader = &reader; spf_reader = &reader;
::spfResetScanner(); ::spfResetScanner();
@ -78,6 +79,7 @@ SpfReader::SpfReader(const char *filename,
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,
@ -90,7 +92,7 @@ SpfReader::SpfReader(const char *filename,
Network *network, Network *network,
Parasitics *parasitics): Parasitics *parasitics):
SpfSpefReader(filename, stream, line, instance, ap, increment, 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, reduce_to, delete_after_reduce, op_cond, corner, cnst_min_max,
quiet, report, network, parasitics), quiet, report, network, parasitics),
is_rspf_(rspf), is_rspf_(rspf),
@ -409,7 +411,7 @@ SpfReader::netBegin(const char *net_name)
dspf_ = 0; dspf_ = 0;
else { else {
parasitics_->deleteParasitics(net_, ap_); parasitics_->deleteParasitics(net_, ap_);
dspf_ = parasitics_->makeParasiticNetwork(net_, ap_); dspf_ = parasitics_->makeParasiticNetwork(net_,pin_cap_included_,ap_);
} }
} }
else { else {

View File

@ -37,6 +37,7 @@ readSpfFile(const char *filename,
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,

View File

@ -46,6 +46,7 @@ public:
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,

View File

@ -28,10 +28,13 @@
namespace sta { namespace sta {
SpfSpefReader::SpfSpefReader(const char *filename, gzFile stream, int line, SpfSpefReader::SpfSpefReader(const char *filename,
gzFile stream,
int line,
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,
@ -47,6 +50,7 @@ SpfSpefReader::SpfSpefReader(const char *filename, gzFile stream, int line,
instance_(instance), instance_(instance),
ap_(ap), ap_(ap),
increment_(increment), increment_(increment),
pin_cap_included_(pin_cap_included),
keep_coupling_caps_(keep_coupling_caps), keep_coupling_caps_(keep_coupling_caps),
reduce_to_(reduce_to), reduce_to_(reduce_to),
delete_after_reduce_(delete_after_reduce), delete_after_reduce_(delete_after_reduce),

View File

@ -40,6 +40,7 @@ public:
Instance *instance, Instance *instance,
ParasiticAnalysisPt *ap, ParasiticAnalysisPt *ap,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,
@ -83,6 +84,7 @@ protected:
Instance *instance_; Instance *instance_;
const ParasiticAnalysisPt *ap_; const ParasiticAnalysisPt *ap_;
bool increment_; bool increment_;
bool pin_cap_included_;
bool keep_coupling_caps_; bool keep_coupling_caps_;
ReduceParasiticsTo reduce_to_; ReduceParasiticsTo reduce_to_;
bool delete_after_reduce_; bool delete_after_reduce_;

View File

@ -30,7 +30,7 @@ ClockInsertion::setDelay(const TransRiseFallBoth *tr,
const MinMaxAll *min_max, const MinMaxAll *min_max,
const EarlyLateAll *early_late, float delay) const EarlyLateAll *early_late, float delay)
{ {
MinMaxIterator el_iter(early_late); EarlyLateIterator el_iter(early_late);
while (el_iter.hasNext()) { while (el_iter.hasNext()) {
EarlyLate *el = el_iter.next(); EarlyLate *el = el_iter.next();
delays_[el->index()].setValue(tr, min_max, delay); delays_[el->index()].setValue(tr, min_max, delay);
@ -73,7 +73,7 @@ ClockInsertion::setDelay(const TransRiseFall *tr,
void void
ClockInsertion::setDelays(RiseFallMinMax *delays) ClockInsertion::setDelays(RiseFallMinMax *delays)
{ {
MinMaxIterator el_iter; EarlyLateIterator el_iter;
while (el_iter.hasNext()) { while (el_iter.hasNext()) {
EarlyLate *el = el_iter.next(); EarlyLate *el = el_iter.next();
delays_[el->index()].setValues(delays); delays_[el->index()].setValues(delays);

View File

@ -102,6 +102,7 @@ Sdc::Sdc(StaState *sta) :
clk_sense_map_(network_), clk_sense_map_(network_),
clk_gating_check_(NULL), clk_gating_check_(NULL),
input_delay_index_(0), input_delay_index_(0),
port_cap_map_(NULL),
net_wire_cap_map_(NULL), net_wire_cap_map_(NULL),
drvr_pin_wire_cap_map_(NULL), drvr_pin_wire_cap_map_(NULL),
first_from_pin_exceptions_(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_.deleteContentsClear();
clk_hpin_disables_valid_ = false; clk_hpin_disables_valid_ = false;
@ -355,28 +350,22 @@ Sdc::deleteInstancePvts()
void void
Sdc::removeNetLoadCaps() Sdc::removeNetLoadCaps()
{ {
// set_load net delete [] net_wire_cap_map_;
delete net_wire_cap_map_;
net_wire_cap_map_ = NULL; net_wire_cap_map_ = NULL;
delete drvr_pin_wire_cap_map_; delete [] drvr_pin_wire_cap_map_;
drvr_pin_wire_cap_map_ = NULL; drvr_pin_wire_cap_map_ = NULL;
} }
void void
Sdc::removeLoadCaps() Sdc::removeLoadCaps()
{ {
// set_load port if (port_cap_map_) {
// set_fanout_load port port_cap_map_->deleteContents();
port_cap_map_.deleteContents(); delete port_cap_map_;
port_cap_map_.clear(); port_cap_map_ = NULL;
}
// set_load net removeNetLoadCaps();
delete net_wire_cap_map_;
net_wire_cap_map_ = NULL;
delete drvr_pin_wire_cap_map_;
drvr_pin_wire_cap_map_ = NULL;
} }
void void
@ -470,7 +459,7 @@ Sdc::isConstrained(const Pin *pin) const
|| pin_cap_limit_map_.hasKey(pin1) || pin_cap_limit_map_.hasKey(pin1)
|| port_cap_limit_map_.hasKey(port) || port_cap_limit_map_.hasKey(port)
|| port_fanout_limit_map_.hasKey(port) || port_fanout_limit_map_.hasKey(port)
|| port_cap_map_.hasKey(port) || hasPortExtCap(port)
|| disabled_pins_.hasKey(pin1) || disabled_pins_.hasKey(pin1)
|| disabled_ports_.hasKey(port) || disabled_ports_.hasKey(port)
|| disabled_clk_gating_checks_pin_.hasKey(pin1) || disabled_clk_gating_checks_pin_.hasKey(pin1)
@ -515,8 +504,7 @@ Sdc::isConstrained(const Net *net) const
Net *net1 = const_cast<Net*>(net); Net *net1 = const_cast<Net*>(net);
return (net_derating_factors_ return (net_derating_factors_
&& net_derating_factors_->hasKey(net)) && net_derating_factors_->hasKey(net))
|| (net_wire_cap_map_ || hasNetWireCap(net1)
&& net_wire_cap_map_->hasKey(net1))
|| net_res_map_.hasKey(net1) || net_res_map_.hasKey(net1)
|| (first_thru_net_exceptions_ || (first_thru_net_exceptions_
&& first_thru_net_exceptions_->hasKey(net)); && first_thru_net_exceptions_->hasKey(net));
@ -3256,9 +3244,9 @@ Sdc::deleteOutputDelay(OutputDelay *output_delay)
void void
Sdc::setPortExtPinCap(Port *port, Sdc::setPortExtPinCap(Port *port,
const TransRiseFall *tr, const TransRiseFall *tr,
const MinMax *min_max, const MinMax *min_max,
float cap) float cap)
{ {
PortExtCap *port_cap = ensurePortExtPinCap(port); PortExtCap *port_cap = ensurePortExtPinCap(port);
port_cap->setPinCap(cap, tr, min_max); port_cap->setPinCap(cap, tr, min_max);
@ -3286,7 +3274,19 @@ Sdc::setPortExtWireCap(Port *port,
PortExtCap * PortExtCap *
Sdc::portExtCap(Port *port) const 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 void
@ -3301,20 +3301,21 @@ Sdc::portExtCap(Port *port,
int &fanout, int &fanout,
bool &has_fanout) const bool &has_fanout) const
{ {
PortExtCap *port_cap = port_cap_map_.findKey(port); if (port_cap_map_) {
if (port_cap) { PortExtCap *port_cap = port_cap_map_->findKey(port);
port_cap->pinCap(tr, min_max, pin_cap, has_pin_cap); if (port_cap) {
port_cap->wireCap(tr, min_max, wire_cap, has_wire_cap); port_cap->pinCap(tr, min_max, pin_cap, has_pin_cap);
port_cap->fanout(min_max, fanout, has_fanout); port_cap->wireCap(tr, min_max, wire_cap, has_wire_cap);
} port_cap->fanout(min_max, fanout, has_fanout);
else { return;
pin_cap = 0.0F; }
has_pin_cap = false;
wire_cap = 0.0F;
has_wire_cap = false;
fanout = 0.0F;
has_fanout = false;
} }
pin_cap = 0.0F;
has_pin_cap = false;
wire_cap = 0.0F;
has_wire_cap = false;
fanout = 0.0F;
has_fanout = false;
} }
float float
@ -3346,6 +3347,7 @@ Sdc::drvrPinHasWireCap(const Pin *pin)
void void
Sdc::drvrPinWireCap(const Pin *pin, Sdc::drvrPinWireCap(const Pin *pin,
const Corner *corner,
const MinMax *min_max, const MinMax *min_max,
// Return values. // Return values.
float &cap, float &cap,
@ -3353,7 +3355,7 @@ Sdc::drvrPinWireCap(const Pin *pin,
{ {
if (drvr_pin_wire_cap_map_) { if (drvr_pin_wire_cap_map_) {
MinMaxFloatValues *values = 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) if (values)
return values->value(min_max, cap, exists); return values->value(min_max, cap, exists);
} }
@ -3386,20 +3388,36 @@ Sdc::setNetWireCap(Net *net,
} }
} }
if (net_wire_cap_map_ == NULL) if (net_wire_cap_map_ == NULL)
net_wire_cap_map_ = new NetWireCapMap; net_wire_cap_map_ = new NetWireCapMap[corners_->count()];
MinMaxFloatValues &values = (*net_wire_cap_map_)[net]; 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); values.setValue(min_max, wire_cap);
NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net); // Only need to do this when there is new net_wire_cap_map_ entry.
while (pin_iter->hasNext()) { if (make_drvr_entry) {
Pin *pin = pin_iter->next(); NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net);
if (network_->isDriver(pin)) { while (pin_iter->hasNext()) {
if (drvr_pin_wire_cap_map_ == NULL) Pin *pin = pin_iter->next();
drvr_pin_wire_cap_map_ = new PinWireCapMap; if (network_->isDriver(pin)) {
(*drvr_pin_wire_cap_map_)[pin] = &values; 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); pin_cap, wire_cap, fanout, has_set_load);
float net_wire_cap; float net_wire_cap;
bool has_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) { if (has_net_wire_cap) {
wire_cap += net_wire_cap; wire_cap += net_wire_cap;
has_set_load = true; has_set_load = true;
@ -3496,7 +3514,7 @@ void
FindNetCaps::operator()(Pin *pin) FindNetCaps::operator()(Pin *pin)
{ {
sdc_->pinCaps(pin, tr_, op_cond_, corner_, min_max_, 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. // Capacitances for all pins connected to drvr_pin's net.
@ -3637,7 +3655,7 @@ Sdc::portExtFanout(Port *port,
int &fanout, int &fanout,
bool &exists) bool &exists)
{ {
PortExtCap *port_cap = port_cap_map_.findKey(port); PortExtCap *port_cap = portExtCap(port);
if (port_cap) if (port_cap)
port_cap->fanout(min_max, fanout, exists); port_cap->fanout(min_max, fanout, exists);
else { else {
@ -3662,10 +3680,12 @@ Sdc::portExtFanout(Port *port,
PortExtCap * PortExtCap *
Sdc::ensurePortExtPinCap(Port *port) 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) { if (port_cap == NULL) {
port_cap = new PortExtCap(port); port_cap = new PortExtCap(port);
port_cap_map_[port] = port_cap; (*port_cap_map_)[port] = port_cap;
} }
return port_cap; return port_cap;
} }

View File

@ -582,10 +582,12 @@ public:
const Corner *corner, const Corner *corner,
const MinMax *min_max, const MinMax *min_max,
float cap); float cap);
bool hasNetWireCap(Net *net) const;
// True if driver pin net has wire capacitance. // True if driver pin net has wire capacitance.
bool drvrPinHasWireCap(const Pin *pin); bool drvrPinHasWireCap(const Pin *pin);
// Net wire capacitance (set_load -wire net). // Net wire capacitance (set_load -wire net).
void drvrPinWireCap(const Pin *drvr_pin, void drvrPinWireCap(const Pin *drvr_pin,
const Corner *corner,
const MinMax *min_max, const MinMax *min_max,
// Return values. // Return values.
float &cap, float &cap,
@ -907,6 +909,7 @@ public:
PinOutputDelayIterator *outputDelayVertexIterator(const Pin *vertex_pin)const; PinOutputDelayIterator *outputDelayVertexIterator(const Pin *vertex_pin)const;
bool hasOutputDelay(const Pin *vertex_pin) const; bool hasOutputDelay(const Pin *vertex_pin) const;
PortExtCap *portExtCap(Port *port) const; PortExtCap *portExtCap(Port *port) const;
bool hasPortExtCap(Port *port) const;
void portExtCap(Port *port, void portExtCap(Port *port,
const TransRiseFall *tr, const TransRiseFall *tr,
const MinMax *min_max, const MinMax *min_max,
@ -1333,9 +1336,15 @@ protected:
PinCapLimitMap pin_cap_limit_map_; PinCapLimitMap pin_cap_limit_map_;
PortFanoutLimitMap port_fanout_limit_map_; PortFanoutLimitMap port_fanout_limit_map_;
CellFanoutLimitMap cell_fanout_limit_map_; CellFanoutLimitMap cell_fanout_limit_map_;
// External parasitics on top level ports (from set_load). // External parasitics on top level ports.
PortExtCapMap port_cap_map_; // 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_; NetWireCapMap *net_wire_cap_map_;
// Indexed by corner_index.
PinWireCapMap *drvr_pin_wire_cap_map_; PinWireCapMap *drvr_pin_wire_cap_map_;
NetResistanceMap net_res_map_; NetResistanceMap net_res_map_;
PinSet disabled_pins_; PinSet disabled_pins_;

View File

@ -632,8 +632,8 @@ void
WriteSdc::writeClockInsertion(ClockInsertion *insert, WriteSdc::writeClockInsertion(ClockInsertion *insert,
WriteSdcObject &write_obj) const WriteSdcObject &write_obj) const
{ {
RiseFallMinMax *early_values = insert->delays(EarlyLate::min()); RiseFallMinMax *early_values = insert->delays(EarlyLate::early());
RiseFallMinMax *late_values = insert->delays(EarlyLate::max()); RiseFallMinMax *late_values = insert->delays(EarlyLate::late());
if (early_values->equal(late_values)) if (early_values->equal(late_values))
writeRiseFallMinMaxTimeCmd("set_clock_latency -source", writeRiseFallMinMaxTimeCmd("set_clock_latency -source",
late_values, write_obj); late_values, write_obj);

View File

@ -419,10 +419,10 @@ SdfWriter::writeArcDelays(Edge *edge)
TimingArc *arc = arc_iter->next(); TimingArc *arc = arc_iter->next();
TransRiseFall *tr = arc->toTrans()->asRiseFall(); TransRiseFall *tr = arc->toTrans()->asRiseFall();
ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_); 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_); 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; delete arc_iter;
@ -682,7 +682,7 @@ SdfWriter::writeCheck(Edge *edge,
ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_); ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_);
ArcDelay max_delay = graph_->arcDelay(edge, arc, arc_delay_max_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"); gzprintf(stream_, ")\n");
} }

View File

@ -93,14 +93,14 @@ float
ClkSkew::srcLatency(StaState *sta) ClkSkew::srcLatency(StaState *sta)
{ {
Arrival src_arrival = src_path_.arrival(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 float
ClkSkew::tgtLatency(StaState *sta) ClkSkew::tgtLatency(StaState *sta)
{ {
Arrival tgt_arrival = tgt_path_.arrival(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 float

View File

@ -101,6 +101,7 @@ public:
Corners *corners); Corners *corners);
~Corner(); ~Corner();
const char *name() const { return name_; } const char *name() const { return name_; }
int index() const { return index_; }
ParasiticAnalysisPt *findParasiticAnalysisPt(const MinMax *min_max) const; ParasiticAnalysisPt *findParasiticAnalysisPt(const MinMax *min_max) const;
DcalcAnalysisPt *findDcalcAnalysisPt(const MinMax *min_max) const; DcalcAnalysisPt *findDcalcAnalysisPt(const MinMax *min_max) const;
PathAnalysisPt *findPathAnalysisPt(const MinMax *min_max) const; PathAnalysisPt *findPathAnalysisPt(const MinMax *min_max) const;

View File

@ -45,7 +45,7 @@ Latches::latchRequired(const Path *data_path,
const PathVertex *disable_path, const PathVertex *disable_path,
MultiCyclePath *mcp, MultiCyclePath *mcp,
PathDelay *path_delay, PathDelay *path_delay,
float src_clk_latency, Arrival src_clk_latency,
const ArcDelay &margin, const ArcDelay &margin,
// Return values. // Return values.
Required &required, Required &required,
@ -186,7 +186,8 @@ Latches::latchBorrowInfo(const Path *data_path,
if (borrow_limit_exists) if (borrow_limit_exists)
max_borrow = borrow_limit; max_borrow = borrow_limit;
else else
max_borrow = nom_pulse_width - latency_diff - crpr_diff - margin; max_borrow = nom_pulse_width - delayAsFloat(latency_diff)
- crpr_diff - delayAsFloat(margin);
} }
void void
@ -211,7 +212,7 @@ Latches::latchRequired(const Path *data_path,
false); false);
MultiCyclePath *mcp = dynamic_cast<MultiCyclePath*>(excpt); MultiCyclePath *mcp = dynamic_cast<MultiCyclePath*>(excpt);
PathDelay *path_delay = dynamic_cast<PathDelay*>(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()) if (path_delay && path_delay->ignoreClkLatency())
src_clk_latency = search_->pathClkPathArrival(data_path); src_clk_latency = search_->pathClkPathArrival(data_path);
latchRequired(data_path, enable_path, disable_path, mcp, latchRequired(data_path, enable_path, disable_path, mcp,

View File

@ -44,7 +44,7 @@ public:
const PathVertex *disable_path, const PathVertex *disable_path,
MultiCyclePath *mcp, MultiCyclePath *mcp,
PathDelay *path_delay, PathDelay *path_delay,
float src_clk_latency, Arrival src_clk_latency,
const ArcDelay &margin, const ArcDelay &margin,
// Return values. // Return values.
Required &required, Required &required,

View File

@ -42,6 +42,7 @@ include_HEADERS = \
PathGroup.hh \ PathGroup.hh \
PathVertex.hh \ PathVertex.hh \
PathVertexRep.hh \ PathVertexRep.hh \
Power.hh \
ReportPath.hh \ ReportPath.hh \
Search.hh \ Search.hh \
SearchClass.hh \ SearchClass.hh \
@ -82,6 +83,7 @@ libsearch_la_SOURCES = \
PathRef.cc \ PathRef.cc \
PathVertex.cc \ PathVertex.cc \
PathVertexRep.cc \ PathVertexRep.cc \
Power.cc \
ReportPath.cc \ ReportPath.cc \
Search.cc \ Search.cc \
SearchPred.cc \ SearchPred.cc \

View File

@ -68,6 +68,18 @@ PathEnd::minMax(const StaState *sta) const
return path_.pathAnalysisPt(sta)->pathMinMax(); 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 * const TransRiseFall *
PathEnd::transition(const StaState *sta) const PathEnd::transition(const StaState *sta) const
{ {
@ -540,6 +552,15 @@ PathEndClkConstrained::setPath(PathEnumed *path,
crpr_valid_ = false; 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 float
PathEndClkConstrained::sourceClkOffset(const StaState *sta) const PathEndClkConstrained::sourceClkOffset(const StaState *sta) const
{ {
@ -1565,15 +1586,15 @@ PathEndDataCheck::type() const
Arrival Arrival
PathEndDataCheck::requiredTimeNoCrpr(const StaState *sta) const 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_time = data_clk_path_.clkEdge(sta)->time();
float data_clk_delay = data_clk_arrival - data_clk_time; Arrival data_clk_delay = data_clk_arrival - data_clk_time;
float tgt_clk_arrival = targetClkTime(sta) Arrival tgt_clk_arrival = targetClkTime(sta)
+ data_clk_delay + data_clk_delay
+ targetClkUncertainty(sta) + targetClkUncertainty(sta)
+ targetClkMcpAdjustment(sta); + targetClkMcpAdjustment(sta);
float check_margin = margin(sta); ArcDelay check_margin = margin(sta);
if (checkGenericRole(sta) == TimingRole::setup()) if (checkGenericRole(sta) == TimingRole::setup())
return tgt_clk_arrival - check_margin; return tgt_clk_arrival - check_margin;
else else
@ -1773,14 +1794,14 @@ PathEndPathDelay::sourceClkOffset(const StaState *sta) const
float float
PathEnd::pathDelaySrcClkOffset(const PathRef &path, PathEnd::pathDelaySrcClkOffset(const PathRef &path,
PathDelay *path_delay, PathDelay *path_delay,
float src_clk_arrival, Arrival src_clk_arrival,
const StaState *sta) const StaState *sta)
{ {
float offset = 0.0; float offset = 0.0;
ClockEdge *clk_edge = path.clkEdge(sta); ClockEdge *clk_edge = path.clkEdge(sta);
if (clk_edge) { if (clk_edge) {
if (path_delay->ignoreClkLatency()) if (path_delay->ignoreClkLatency())
offset = -src_clk_arrival; offset = -delayAsFloat(src_clk_arrival);
else else
// Arrival includes src clock edge time that is not counted in the // Arrival includes src clock edge time that is not counted in the
// path delay. // path delay.

View File

@ -75,6 +75,9 @@ public:
const StaState *sta); const StaState *sta);
Vertex *vertex(const StaState *sta) const; Vertex *vertex(const StaState *sta) const;
const MinMax *minMax(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; const TransRiseFall *transition(const StaState *sta) const;
PathAnalysisPt *pathAnalysisPt(const StaState *sta) const; PathAnalysisPt *pathAnalysisPt(const StaState *sta) const;
PathAPIndex pathIndex(const StaState *sta) const; PathAPIndex pathIndex(const StaState *sta) const;
@ -203,7 +206,7 @@ protected:
const StaState *sta); const StaState *sta);
static float pathDelaySrcClkOffset(const PathRef &path, static float pathDelaySrcClkOffset(const PathRef &path,
PathDelay *path_delay, PathDelay *path_delay,
float src_clk_arrival, Arrival src_clk_arrival,
const StaState *sta); const StaState *sta);
PathRef path_; PathRef path_;
@ -236,6 +239,7 @@ private:
class PathEndClkConstrained : public PathEnd class PathEndClkConstrained : public PathEnd
{ {
public: public:
virtual const EarlyLate *clkEarlyLate(const StaState *sta) const;
virtual float sourceClkOffset(const StaState *sta) const; virtual float sourceClkOffset(const StaState *sta) const;
virtual Delay sourceClkLatency(const StaState *sta) const; virtual Delay sourceClkLatency(const StaState *sta) const;
virtual Delay sourceClkInsertionDelay(const StaState *sta) const; virtual Delay sourceClkInsertionDelay(const StaState *sta) const;
@ -414,7 +418,7 @@ private:
PathVertex disable_path_; PathVertex disable_path_;
PathDelay *path_delay_; PathDelay *path_delay_;
// Source clk arrival for set_max_delay -ignore_clk_latency. // Source clk arrival for set_max_delay -ignore_clk_latency.
float src_clk_arrival_; Arrival src_clk_arrival_;
DISALLOW_COPY_AND_ASSIGN(PathEndLatchCheck); DISALLOW_COPY_AND_ASSIGN(PathEndLatchCheck);
}; };

View File

@ -69,15 +69,11 @@ Diversion::Diversion(PathEnd *path_end,
// Default constructor required for DiversionQueue template. // Default constructor required for DiversionQueue template.
DiversionGreater::DiversionGreater() : DiversionGreater::DiversionGreater() :
cmp_slack_(true) sta_(NULL)
{ {
} }
DiversionGreater::DiversionGreater(bool cmp_slack, DiversionGreater::DiversionGreater(const StaState *sta) :
const MinMax *min_max,
StaState *sta) :
cmp_slack_(cmp_slack),
min_max_(min_max),
sta_(sta) sta_(sta)
{ {
} }
@ -114,7 +110,7 @@ PathEnum::PathEnum(int group_count,
group_count_(group_count), group_count_(group_count),
endpoint_count_(endpoint_count), endpoint_count_(endpoint_count),
unique_pins_(unique_pins), unique_pins_(unique_pins),
div_queue_(DiversionGreater(cmp_slack, min_max, sta->network())), div_queue_(DiversionGreater(sta)),
div_count_(0), div_count_(0),
inserts_pruned_(false), inserts_pruned_(false),
next_(NULL) next_(NULL)

View File

@ -41,15 +41,11 @@ class DiversionGreater
{ {
public: public:
DiversionGreater(); DiversionGreater();
DiversionGreater(bool cmp_slack, DiversionGreater(const StaState *sta);
const MinMax *min_max,
StaState *sta);
bool operator()(Diversion *div1, bool operator()(Diversion *div1,
Diversion *div2) const; Diversion *div2) const;
private: private:
bool cmp_slack_;
const MinMax *min_max_;
const StaState *sta_; const StaState *sta_;
}; };

394
search/Power.cc Normal file
View File

@ -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 &macro,
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

115
search/Power.hh Normal file
View File

@ -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 &macro,
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

View File

@ -423,7 +423,8 @@ ReportPath::reportFull(const PathEndUnconstrained *end,
reportEndOfLine(result); reportEndOfLine(result);
reportPath(end, expanded, 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); reportDashLine(result);
result += "(Path is unconstrained)\n"; result += "(Path is unconstrained)\n";
} }
@ -542,6 +543,7 @@ ReportPath::reportFull(const PathEndLatchCheck *end,
string &result) string &result)
{ {
PathExpanded expanded(end->path(), this); PathExpanded expanded(end->path(), this);
const EarlyLate *early_late = end->pathEarlyLate(this);
reportShort(end, expanded, result); reportShort(end, expanded, result);
PathDelay *path_delay = end->pathDelay(); PathDelay *path_delay = end->pathDelay();
reportEndOfLine(result); reportEndOfLine(result);
@ -554,7 +556,8 @@ ReportPath::reportFull(const PathEndLatchCheck *end,
} }
else else
reportSrcPath(end, expanded, result); reportSrcPath(end, expanded, result);
reportLine("data arrival time", end->dataArrivalTimeOffset(this), result); reportLine("data arrival time", end->dataArrivalTimeOffset(this),
early_late, result);
reportEndOfLine(result); reportEndOfLine(result);
Required req_time; Required req_time;
@ -565,23 +568,27 @@ ReportPath::reportFull(const PathEndLatchCheck *end,
req_time += end->sourceClkOffset(this); req_time += end->sourceClkOffset(this);
if (path_delay) { if (path_delay) {
float delay = path_delay->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 (!ignore_clk_latency) {
if (reportClkPath() if (reportClkPath()
&& isPropagated(end->targetClkPath())) && isPropagated(end->targetClkPath()))
reportTgtClk(end, delay, result); reportTgtClk(end, delay, result);
else else {
reportCommonClkPessimism(end, delay, result); Delay delay1(delay);
reportCommonClkPessimism(end, delay1, result);
}
} }
} }
else else
reportTgtClk(end, result); reportTgtClk(end, result);
if (borrow >= 0.0) 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 else
reportLine("time given to endpoint", borrow, req_time, result); reportLine("time given to endpoint", borrow, req_time,
reportLine("data required time", req_time, result); early_late, result);
reportLine("data required time", req_time, early_late, result);
reportDashLine(result); reportDashLine(result);
reportSlack(end, result); reportSlack(end, result);
if (end->checkGenericRole(this) == TimingRole::setup() if (end->checkGenericRole(this) == TimingRole::setup()
@ -629,13 +636,14 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end,
Delay open_latency, latency_diff, max_borrow; Delay open_latency, latency_diff, max_borrow;
float nom_pulse_width, open_uncertainty, open_crpr, crpr_diff; float nom_pulse_width, open_uncertainty, open_crpr, crpr_diff;
bool borrow_limit_exists; bool borrow_limit_exists;
const EarlyLate *early_late = EarlyLate::late();
end->latchBorrowInfo(this, nom_pulse_width, open_latency, latency_diff, end->latchBorrowInfo(this, nom_pulse_width, open_latency, latency_diff,
open_uncertainty, open_crpr, crpr_diff, open_uncertainty, open_crpr, crpr_diff,
max_borrow, borrow_limit_exists); max_borrow, borrow_limit_exists);
result += "Time Borrowing Information\n"; result += "Time Borrowing Information\n";
reportDashLineTotal(result); reportDashLineTotal(result);
if (borrow_limit_exists) if (borrow_limit_exists)
reportLineTotal("user max time borrow", max_borrow, result); reportLineTotal("user max time borrow", max_borrow, early_late, result);
else { else {
const char *tgt_clk_name = tgtClkName(end); const char *tgt_clk_name = tgtClkName(end);
Arrival tgt_clk_width = end->targetClkWidth(this); Arrival tgt_clk_width = end->targetClkWidth(this);
@ -645,39 +653,41 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end,
+ strlen(tgt_clk_name) + 1, + strlen(tgt_clk_name) + 1,
"%s nominal pulse width", "%s nominal pulse width",
tgt_clk_name); tgt_clk_name);
reportLineTotal(width_msg, nom_pulse_width, result); reportLineTotal(width_msg, nom_pulse_width, early_late, result);
if (!delayFuzzyZero(latency_diff)) if (!delayFuzzyZero(latency_diff))
reportLineTotalMinus("clock latency difference", latency_diff, result); reportLineTotalMinus("clock latency difference", latency_diff,
early_late, result);
} }
else { else {
const char *width_msg = stringPrintTmp(strlen(" pulse width") const char *width_msg = stringPrintTmp(strlen(" pulse width")
+ strlen(tgt_clk_name) + 1, + strlen(tgt_clk_name) + 1,
"%s pulse width", "%s pulse width",
tgt_clk_name); tgt_clk_name);
reportLineTotal(width_msg, tgt_clk_width, result); reportLineTotal(width_msg, tgt_clk_width, early_late, result);
} }
ArcDelay margin = end->margin(this); ArcDelay margin = end->margin(this);
reportLineTotalMinus("library setup time", margin, result); reportLineTotalMinus("library setup time", margin, early_late, result);
reportDashLineTotal(result); reportDashLineTotal(result);
if (!fuzzyZero(crpr_diff)) if (!fuzzyZero(crpr_diff))
reportLineTotalMinus("CRPR difference", crpr_diff, result); reportLineTotalMinus("CRPR difference", crpr_diff, early_late, result);
reportLineTotal("max time borrow", max_borrow, result); reportLineTotal("max time borrow", max_borrow, early_late, result);
} }
if (delayFuzzyGreater(borrow, delay_zero) if (delayFuzzyGreater(borrow, delay_zero)
&& (!fuzzyZero(open_uncertainty) && (!fuzzyZero(open_uncertainty)
|| !fuzzyZero(open_crpr))) { || !fuzzyZero(open_crpr))) {
reportDashLineTotal(result); reportDashLineTotal(result);
reportLineTotal("actual time borrow", borrow, result); reportLineTotal("actual time borrow", borrow, early_late, result);
if (!fuzzyZero(open_uncertainty)) if (!fuzzyZero(open_uncertainty))
reportLineTotal("open edge uncertainty", open_uncertainty, result); reportLineTotal("open edge uncertainty", open_uncertainty,
early_late, result);
if (!fuzzyZero(open_crpr)) if (!fuzzyZero(open_crpr))
reportLineTotal("open edge CRPR", open_crpr, result); reportLineTotal("open edge CRPR", open_crpr, early_late, result);
reportDashLineTotal(result); reportDashLineTotal(result);
reportLineTotal("time given to startpoint", time_given_to_startpoint, reportLineTotal("time given to startpoint", time_given_to_startpoint,
result); early_late, result);
} }
else else
reportLineTotal("actual time borrow", borrow, result); reportLineTotal("actual time borrow", borrow, early_late, result);
reportDashLineTotal(result); reportDashLineTotal(result);
} }
@ -727,6 +737,7 @@ ReportPath::reportFull(const PathEndPathDelay *end,
{ {
PathExpanded expanded(end->path(), this); PathExpanded expanded(end->path(), this);
reportShort(end, expanded, result); reportShort(end, expanded, result);
const EarlyLate *early_late = end->pathEarlyLate(this);
// Based on reportSrcPathArrival. // Based on reportSrcPathArrival.
reportEndOfLine(result); reportEndOfLine(result);
@ -739,7 +750,8 @@ ReportPath::reportFull(const PathEndPathDelay *end,
} }
else else
reportSrcPath(end, expanded, result); reportSrcPath(end, expanded, result);
reportLine("data arrival time", end->dataArrivalTimeOffset(this), result); reportLine("data arrival time", end->dataArrivalTimeOffset(this),
early_late, result);
reportEndOfLine(result); reportEndOfLine(result);
ArcDelay margin = end->margin(this); ArcDelay margin = end->margin(this);
@ -758,7 +770,7 @@ ReportPath::reportFull(const PathEndPathDelay *end,
"%s_delay", "%s_delay",
min_max_str); min_max_str);
float delay = path_delay->delay(); float delay = path_delay->delay();
reportLine(delay_msg, delay, delay, result); reportLine(delay_msg, delay, delay, early_late, result);
if (!path_delay->ignoreClkLatency()) { if (!path_delay->ignoreClkLatency()) {
const Path *tgt_clk_path = end->targetClkPath(); const Path *tgt_clk_path = end->targetClkPath();
if (tgt_clk_path) { if (tgt_clk_path) {
@ -773,7 +785,7 @@ ReportPath::reportFull(const PathEndPathDelay *end,
Arrival tgt_clk_arrival = delay + tgt_clk_delay; Arrival tgt_clk_arrival = delay + tgt_clk_delay;
if (!delayFuzzyZero(tgt_clk_delay)) if (!delayFuzzyZero(tgt_clk_delay))
reportLine(clkNetworkDelayIdealProp(isPropagated(tgt_clk_path)), 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); reportClkUncertainty(end, tgt_clk_arrival, result);
reportCommonClkPessimism(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. // Report the path from the clk network to the data check.
PathExpanded clk_expanded(data_clk_path, this); PathExpanded clk_expanded(data_clk_path, this);
float src_offset = end->sourceClkOffset(this); float src_offset = end->sourceClkOffset(this);
float clk_delay = end->targetClkDelay(this); Delay clk_delay = end->targetClkDelay(this);
float clk_arrival = end->targetClkArrival(this); Arrival clk_arrival = end->targetClkArrival(this);
float offset = clk_arrival - clk_delay + src_offset; float offset = delayAsFloat(clk_arrival - clk_delay + src_offset);
reportPath5(data_clk_path, clk_expanded, clk_expanded.startIndex(), reportPath5(data_clk_path, clk_expanded, clk_expanded.startIndex(),
clk_expanded.size() - 1, clk_expanded.size() - 1,
data_clk_path->clkInfo(search_)->isPropagated(), false, data_clk_path->clkInfo(search_)->isPropagated(), false,
@ -1030,11 +1042,12 @@ void
ReportPath::reportEndLine(PathEnd *end, ReportPath::reportEndLine(PathEnd *end,
string &result) string &result)
{ {
const EarlyLate *early_late = end->pathEarlyLate(this);
reportDescription(pathEndpoint(end), result); reportDescription(pathEndpoint(end), result);
reportSpaceFieldTime(end->requiredTimeOffset(this), result); reportSpaceFieldDelay(end->requiredTimeOffset(this), early_late, result);
reportSpaceFieldTime(end->dataArrivalTimeOffset(this), result); reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, result);
Slack slack = end->slack(this); Slack slack = end->slack(this);
reportSpaceFieldTime(slack, result); reportSpaceFieldDelay(slack, early_late, result);
result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)"; result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)";
reportEndOfLine(result); reportEndOfLine(result);
} }
@ -1059,12 +1072,13 @@ ReportPath::reportSummaryLine(PathEnd *end,
string &result) string &result)
{ {
PathExpanded expanded(end->path(), this); PathExpanded expanded(end->path(), this);
const EarlyLate *early_late = end->pathEarlyLate(this);
reportDescription(pathStartpoint(end, expanded), result); reportDescription(pathStartpoint(end, expanded), result);
reportDescription(pathEndpoint(end), result); reportDescription(pathEndpoint(end), result);
if (end->isUnconstrained()) if (end->isUnconstrained())
reportSpaceFieldTime(end->dataArrivalTimeOffset(this), result); reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, result);
else else
reportSpaceFieldTime(end->slack(this), result); reportSpaceFieldDelay(end->slack(this), early_late, result);
reportEndOfLine(result); reportEndOfLine(result);
} }
@ -1131,11 +1145,12 @@ void
ReportPath::reportSlackOnly(PathEnd *end, ReportPath::reportSlackOnly(PathEnd *end,
string &result) string &result)
{ {
const EarlyLate *early_late = end->pathEarlyLate(this);
reportDescription(search_->pathGroup(end)->name(), result); reportDescription(search_->pathGroup(end)->name(), result);
if (end->isUnconstrained()) if (end->isUnconstrained())
reportSpaceFieldTime(end->dataArrivalTimeOffset(this), result); reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, result);
else else
reportSpaceFieldTime(end->slack(this), result); reportSpaceFieldDelay(end->slack(this), early_late, result);
reportEndOfLine(result); reportEndOfLine(result);
} }
@ -1229,9 +1244,9 @@ ReportPath::reportShort(MinPulseWidthCheck *check,
hi_low); hi_low);
reportDescription(what, result); reportDescription(what, result);
reportSpaceFieldTime(check->minWidth(this), result); reportSpaceFieldTime(check->minWidth(this), result);
reportSpaceFieldTime(check->width(this), result); reportSpaceFieldDelay(check->width(this), EarlyLate::late(), result);
Slack slack = check->slack(this); Slack slack = check->slack(this);
reportSpaceFieldTime(slack, result); reportSpaceFieldDelay(slack, EarlyLate::early(), result);
result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)"; result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)";
reportEndOfLine(result); reportEndOfLine(result);
} }
@ -1249,6 +1264,7 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check,
reportEndOfLine(result); reportEndOfLine(result);
reportPathHeader(result); reportPathHeader(result);
const EarlyLate *open_el = EarlyLate::late();
ClockEdge *open_clk_edge = check->openClkEdge(this); ClockEdge *open_clk_edge = check->openClkEdge(this);
Clock *open_clk = open_clk_edge->clock(); Clock *open_clk = open_clk_edge->clock();
const char *open_clk_name = open_clk->name(); const char *open_clk_name = open_clk->name();
@ -1260,15 +1276,18 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check,
"clock %s (%s edge)", "clock %s (%s edge)",
open_clk_name, open_clk_name,
open_rise_fall); 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); Arrival open_arrival = check->openArrival(this);
bool is_prop = isPropagated(check->openPath()); bool is_prop = isPropagated(check->openPath());
const char *clk_ideal_prop = clkNetworkDelayIdealProp(is_prop); const char *clk_ideal_prop = clkNetworkDelayIdealProp(is_prop);
reportLine(clk_ideal_prop, check->openDelay(this), open_arrival, result); reportLine(clk_ideal_prop, check->openDelay(this), open_arrival,
reportLine(pin_name, delay_zero, open_arrival, result); open_el, result);
reportLine("open edge arrival time", open_arrival, result); reportLine(pin_name, delay_zero, open_arrival, open_el, result);
reportLine("open edge arrival time", open_arrival, open_el, result);
reportEndOfLine(result); reportEndOfLine(result);
const EarlyLate *close_el = EarlyLate::late();
ClockEdge *close_clk_edge = check->closeClkEdge(this); ClockEdge *close_clk_edge = check->closeClkEdge(this);
Clock *close_clk = close_clk_edge->clock(); Clock *close_clk = close_clk_edge->clock();
const char *close_clk_name = close_clk->name(); const char *close_clk_name = close_clk->name();
@ -1281,18 +1300,20 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check,
"clock %s (%s edge)", "clock %s (%s edge)",
close_clk_name, close_clk_name,
close_rise_fall); 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; Arrival close_arrival = check->closeArrival(this) + close_offset;
reportLine(clk_ideal_prop, check->closeDelay(this), close_arrival, result); reportLine(clk_ideal_prop, check->closeDelay(this), close_arrival,
reportLine(pin_name, delay_zero, close_arrival, result); close_el, result);
reportLine(pin_name, delay_zero, close_arrival, close_el, result);
if (sdc_->crprEnabled()) { if (sdc_->crprEnabled()) {
float pessimism = check->commonClkPessimism(this); float pessimism = check->commonClkPessimism(this);
close_arrival += pessimism; close_arrival += pessimism;
reportLine("clock reconvergence pessimism", pessimism, close_arrival, 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); reportDashLine(result);
float min_width = check->minWidth(this); float min_width = check->minWidth(this);
const char *hi_low = mpwCheckHiLow(check); const char *hi_low = mpwCheckHiLow(check);
@ -1300,8 +1321,9 @@ ReportPath::reportVerbose(MinPulseWidthCheck *check,
+ strlen(hi_low) + 1, + strlen(hi_low) + 1,
"required pulse width (%s)", "required pulse width (%s)",
hi_low); hi_low);
reportLine(rpw_msg, min_width, result); reportLine(rpw_msg, min_width, EarlyLate::early(), result);
reportLine("actual pulse width", check->width(this), result); reportLine("actual pulse width", check->width(this),
EarlyLate::early(), result);
reportDashLine(result); reportDashLine(result);
reportSlack(check->slack(this), result); reportSlack(check->slack(this), result);
} }
@ -1399,10 +1421,10 @@ ReportPath::reportShort(MinPeriodCheck *check,
{ {
const char *pin_name = cmd_network_->pathName(check->pin()); const char *pin_name = cmd_network_->pathName(check->pin());
reportDescription(pin_name, result); reportDescription(pin_name, result);
reportSpaceFieldTime(check->period(), result); reportSpaceFieldDelay(check->period(), EarlyLate::early(), result);
reportSpaceFieldTime(check->minPeriod(this), result); reportSpaceFieldDelay(check->minPeriod(this), EarlyLate::early(), result);
Slack slack = check->slack(this); Slack slack = check->slack(this);
reportSpaceFieldTime(slack, result); reportSpaceFieldDelay(slack, EarlyLate::early(), result);
result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)"; result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)";
reportEndOfLine(result); reportEndOfLine(result);
} }
@ -1415,8 +1437,9 @@ ReportPath::reportVerbose(MinPeriodCheck *check, string &result)
result += pin_name; result += pin_name;
reportEndOfLine(result); reportEndOfLine(result);
reportLine("Period", check->period(), result); reportLine("Period", check->period(), EarlyLate::early(), result);
reportLine("min_period", -check->minPeriod(this), result); reportLine("min_period", -check->minPeriod(this),
EarlyLate::early(), result);
reportDashLine(result); reportDashLine(result);
reportSlack(check->slack(this), result); reportSlack(check->slack(this), result);
} }
@ -1513,10 +1536,10 @@ ReportPath::reportShort(MaxSkewCheck *check,
check_arc->fromTrans()->asString(), check_arc->fromTrans()->asString(),
check_arc->toTrans()->asString()); check_arc->toTrans()->asString());
reportDescription(what, result); reportDescription(what, result);
reportSpaceFieldTime(check->maxSkew(this), result); reportSpaceFieldDelay(check->maxSkew(this), EarlyLate::early(), result);
reportSpaceFieldTime(check->skew(this), result); reportSpaceFieldDelay(check->skew(this), EarlyLate::early(), result);
Slack slack = check->slack(this); Slack slack = check->slack(this);
reportSpaceFieldTime(slack, result); reportSpaceFieldDelay(slack, EarlyLate::early(), result);
result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)"; result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)";
reportEndOfLine(result); reportEndOfLine(result);
} }
@ -1544,8 +1567,9 @@ ReportPath::reportVerbose(MaxSkewCheck *check,
reportSkewClkPath("constrained pin arrival time", check->clkPath(), result); reportSkewClkPath("constrained pin arrival time", check->clkPath(), result);
reportDashLine(result); reportDashLine(result);
reportLine("allowable skew", check->maxSkew(this), result); reportLine("allowable skew", check->maxSkew(this),
reportLine("actual skew", check->skew(this), result); EarlyLate::early(), result);
reportLine("actual skew", check->skew(this), EarlyLate::late(), result);
reportDashLine(result); reportDashLine(result);
reportSlack(check->slack(this), result); reportSlack(check->slack(this), result);
} }
@ -1558,6 +1582,7 @@ ReportPath::reportSkewClkPath(const char *arrival_msg,
{ {
ClockEdge *clk_edge = clk_path->clkEdge(this); ClockEdge *clk_edge = clk_path->clkEdge(this);
Clock *clk = clk_edge->clock(); Clock *clk = clk_edge->clock();
const EarlyLate *early_late = clk_path->minMax(this);
const TransRiseFall *clk_tr = clk_edge->transition(); const TransRiseFall *clk_tr = clk_edge->transition();
const TransRiseFall *clk_end_tr = clk_path->transition(this); const TransRiseFall *clk_end_tr = clk_path->transition(this);
const char *clk_name = (clk_end_tr == clk_tr) const char *clk_name = (clk_end_tr == clk_tr)
@ -1580,17 +1605,19 @@ ReportPath::reportSkewClkPath(const char *arrival_msg,
Arrival insertion, latency; Arrival insertion, latency;
PathEnd::checkTgtClkDelay(clk_path, clk_edge, TimingRole::skew(), this, PathEnd::checkTgtClkDelay(clk_path, clk_edge, TimingRole::skew(), this,
insertion, latency); insertion, latency);
reportClkSrcLatency(insertion, clk_time, result); reportClkSrcLatency(insertion, clk_time, early_late, result);
PathExpanded clk_expanded(clk_path, this); PathExpanded clk_expanded(clk_path, this);
reportPath2(clk_path, clk_expanded, false, 0.0, result); reportPath2(clk_path, clk_expanded, false, 0.0, result);
} }
} }
else { else {
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay, clk_arrival, reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay, clk_arrival,
result); early_late, result);
reportLine(descriptionField(clk_vertex), clk_arrival, clk_end_tr, 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); reportEndOfLine(result);
} }
@ -1642,7 +1669,7 @@ ReportPath::reportSlewLimitShort(Pin *pin,
const char *pin_name = cmd_network_->pathName(pin); const char *pin_name = cmd_network_->pathName(pin);
reportDescription(pin_name, result); reportDescription(pin_name, result);
reportSpaceFieldTime(limit, result); reportSpaceFieldTime(limit, result);
reportSpaceFieldTime(slew, result); reportSpaceFieldDelay(slew, EarlyLate::late(), result);
reportSpaceFieldTime(slack, result); reportSpaceFieldTime(slack, result);
result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)"; result += (slack >= 0.0) ? " (MET)" : " (VIOLATED)";
reportEndOfLine(result); reportEndOfLine(result);
@ -1977,7 +2004,8 @@ ReportPath::reportSrcPathArrival(const PathEnd *end,
{ {
reportEndOfLine(result); reportEndOfLine(result);
reportSrcPath(end, expanded, 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); reportEndOfLine(result);
} }
@ -2077,33 +2105,33 @@ ReportPath::reportSrcClkAndPath(const Path *path,
reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result); reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result);
ClkInfo *clk_info = path->tag(search_)->clkInfo(); ClkInfo *clk_info = path->tag(search_)->clkInfo();
if (clk_info->isPropagated()) 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); reportPath1(path, expanded, true, time_offset, result);
} }
else if (is_prop else if (is_prop
&& reportClkPath() && reportClkPath()
&& !(path_from_input && !input_has_ref_path)) { && !(path_from_input && !input_has_ref_path)) {
reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result); reportClkLine(clk, clk_name, clk_end_tr, clk_time, early_late, result);
reportClkSrcLatency(clk_insertion, clk_time, result); reportClkSrcLatency(clk_insertion, clk_time, early_late, result);
reportPath1(path, expanded, false, time_offset, result); reportPath1(path, expanded, false, time_offset, result);
} }
else if (clk_used_as_data) { 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) 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); reportPath1(path, expanded, true, time_offset, result);
} }
else { else {
if (is_path_delay) { if (is_path_delay) {
if (clk_delay > 0.0) if (clk_delay > 0.0)
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay, reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
clk_end_time, result); clk_end_time, early_late, result);
} }
else { else {
reportClkLine(clk, clk_name, clk_end_tr, clk_time, min_max, result); 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, reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
clk_arrival, result); clk_arrival, early_late, result);
} }
reportPath1(path, expanded, false, time_offset, result); reportPath1(path, expanded, false, time_offset, result);
} }
@ -2170,7 +2198,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
else { else {
Arrival insertion = end->targetClkInsertionDelay(this); Arrival insertion = end->targetClkInsertionDelay(this);
if (clk_path) { if (clk_path) {
reportClkSrcLatency(insertion, clk_time, result); reportClkSrcLatency(insertion, clk_time, early_late, result);
PathExpanded clk_expanded(clk_path, this); PathExpanded clk_expanded(clk_path, this);
float insertion_offset = tgtClkInsertionOffet(clk_path, early_late, float insertion_offset = tgtClkInsertionOffet(clk_path, early_late,
path_ap); path_ap);
@ -2182,7 +2210,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
// Output departure. // Output departure.
Arrival clk_arrival = clk_time + clk_delay; Arrival clk_arrival = clk_time + clk_delay;
reportLine(clkNetworkDelayIdealProp(clk->isPropagated()), reportLine(clkNetworkDelayIdealProp(clk->isPropagated()),
clk_delay, clk_arrival, result); clk_delay, clk_arrival, min_max, result);
} }
} }
reportClkUncertainty(end, clk_arrival, result); reportClkUncertainty(end, clk_arrival, result);
@ -2190,7 +2218,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
} }
else { else {
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay, clk_arrival, reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay, clk_arrival,
result); min_max, result);
reportClkUncertainty(end, clk_arrival, result); reportClkUncertainty(end, clk_arrival, result);
reportCommonClkPessimism(end, clk_arrival, result); reportCommonClkPessimism(end, clk_arrival, result);
if (clk_path) { if (clk_path) {
@ -2199,7 +2227,7 @@ ReportPath::reportTgtClk(const PathEnd *end,
prev_time prev_time
+ end->targetClkArrival(this) + end->targetClkArrival(this)
+ end->sourceClkOffset(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, clk_name,
rise_fall); rise_fall);
if (clk->isPropagated()) 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 { else {
// Report ideal clock slew. // Report ideal clock slew.
float clk_slew = clk->slew(clk_tr, min_max); 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); PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late);
PathVertex src_path; PathVertex src_path;
const MinMax *min_max = path_ap->pathMinMax();
search_->genclks()->srcPath(clk, clk_pin, clk_tr, insert_ap, src_path); search_->genclks()->srcPath(clk, clk_pin, clk_tr, insert_ap, src_path);
if (!src_path.isNull()) { if (!src_path.isNull()) {
ClkInfo *src_clk_info = src_path.clkInfo(search_); ClkInfo *src_clk_info = src_path.clkInfo(search_);
@ -2370,13 +2400,12 @@ ReportPath::reportGenClkSrcPath1(Clock *clk,
src_clk_tr, src_clk_tr,
path_ap->pathMinMax(), path_ap->pathMinMax(),
early_late, path_ap); early_late, path_ap);
reportClkSrcLatency(insertion, gclk_time, result); reportClkSrcLatency(insertion, gclk_time, early_late, result);
} }
PathExpanded src_expanded(&src_path, this); PathExpanded src_expanded(&src_path, this);
if (clk->pllOut()) { if (clk->pllOut()) {
reportPath4(&src_path, src_expanded, skip_first_path, true, reportPath4(&src_path, src_expanded, skip_first_path, true,
clk_used_as_data, gclk_time, result); clk_used_as_data, gclk_time, result);
const MinMax *min_max = path_ap->pathMinMax();
PathAnalysisPt *pll_ap=path_ap->insertionAnalysisPt(min_max->opposite()); PathAnalysisPt *pll_ap=path_ap->insertionAnalysisPt(min_max->opposite());
Arrival pll_delay = search_->genclks()->pllDelay(clk, clk_tr, pll_ap); Arrival pll_delay = search_->genclks()->pllDelay(clk, clk_tr, pll_ap);
size_t path_length = src_expanded.size(); size_t path_length = src_expanded.size();
@ -2392,13 +2421,14 @@ ReportPath::reportGenClkSrcPath1(Clock *clk,
clk_used_as_data, gclk_time, result); clk_used_as_data, gclk_time, result);
if (!clk->isPropagated()) if (!clk->isPropagated())
reportLine("clock network delay (ideal)", 0.0, src_path.arrival(this), reportLine("clock network delay (ideal)", 0.0, src_path.arrival(this),
result); min_max, result);
} }
else { else {
if (clk->isPropagated()) if (clk->isPropagated())
reportClkSrcLatency(0.0, gclk_time, result); reportClkSrcLatency(0.0, gclk_time, early_late, result);
else if (!clk_used_as_data) 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(); return !src_path.isNull();
} }
@ -2406,9 +2436,11 @@ ReportPath::reportGenClkSrcPath1(Clock *clk,
void void
ReportPath::reportClkSrcLatency(Arrival insertion, ReportPath::reportClkSrcLatency(Arrival insertion,
float clk_time, float clk_time,
const EarlyLate *early_late,
string &result) string &result)
{ {
reportLine("clock source latency", insertion, clk_time + insertion, result); reportLine("clock source latency", insertion, clk_time + insertion,
early_late, result);
} }
void void
@ -2423,7 +2455,9 @@ ReportPath::reportPathLine(const Path *path,
const char *what = descriptionField(vertex); const char *what = descriptionField(vertex);
const TransRiseFall *tr = path->transition(this); const TransRiseFall *tr = path->transition(this);
bool is_driver = network_->isDriver(pin); 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(); DcalcAPIndex ap_index = dcalc_ap->index();
Slew slew = graph_->slew(vertex, tr, ap_index); Slew slew = graph_->slew(vertex, tr, ap_index);
float cap = field_blank_; float cap = field_blank_;
@ -2431,7 +2465,7 @@ ReportPath::reportPathLine(const Path *path,
if (is_driver && field_capacitance_->enabled()) if (is_driver && field_capacitance_->enabled())
cap = loadCap(pin, tr, dcalc_ap); cap = loadCap(pin, tr, dcalc_ap);
reportLine(what, cap, slew, field_blank_, reportLine(what, cap, slew, field_blank_,
incr, time, false, tr, line_case, result); incr, time, false, early_late, tr, line_case, result);
} }
void void
@ -2440,11 +2474,12 @@ ReportPath::reportRequired(const PathEnd *end,
string &result) string &result)
{ {
Required req_time = end->requiredTimeOffset(this); Required req_time = end->requiredTimeOffset(this);
const EarlyLate *early_late = end->clkEarlyLate(this);
ArcDelay margin = end->margin(this); ArcDelay margin = end->margin(this);
if (end->minMax(this) == MinMax::max()) if (end->minMax(this) == MinMax::max())
margin = -margin; margin = -margin;
reportLine(margin_msg, margin, req_time, result); reportLine(margin_msg, margin, req_time, early_late, result);
reportLine("data required time", req_time, result); reportLine("data required time", req_time, early_late, result);
reportDashLine(result); reportDashLine(result);
} }
@ -2452,9 +2487,11 @@ void
ReportPath::reportSlack(const PathEnd *end, ReportPath::reportSlack(const PathEnd *end,
string &result) 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), reportLineNegative("data arrival time", end->dataArrivalTimeOffset(this),
result); early_late, result);
reportDashLine(result); reportDashLine(result);
reportSlack(end->slack(this), result); reportSlack(end->slack(this), result);
} }
@ -2463,10 +2500,10 @@ void
ReportPath::reportSlack(Slack slack, ReportPath::reportSlack(Slack slack,
string &result) string &result)
{ {
if (slack < 0.0) const char *msg = (slack < 0.0)
reportLine("slack (VIOLATED)", slack, result); ? "slack (VIOLATED)"
else : "slack (MET)";
reportLine("slack (MET)", slack, result); reportLine(msg, slack, EarlyLate::early(), result);
} }
void void
@ -2477,7 +2514,8 @@ ReportPath::reportCommonClkPessimism(const PathEnd *end,
if (sdc_->crprEnabled()) { if (sdc_->crprEnabled()) {
float pessimism = end->commonClkPessimism(this); float pessimism = end->commonClkPessimism(this);
clk_arrival += pessimism; 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, Arrival &clk_arrival,
string &result) string &result)
{ {
const EarlyLate *early_late = end->clkEarlyLate(this);
float uncertainty = end->targetNonInterClkUncertainty(this); float uncertainty = end->targetNonInterClkUncertainty(this);
clk_arrival += uncertainty; clk_arrival += uncertainty;
if (uncertainty != 0.0) 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); float inter_uncertainty = end->interClkUncertainty(this);
clk_arrival += inter_uncertainty; clk_arrival += inter_uncertainty;
if (inter_uncertainty != 0.0) if (inter_uncertainty != 0.0)
reportLine("inter-clock uncertainty", inter_uncertainty, clk_arrival, 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_time_given,
latch_enable_path); latch_enable_path);
if (!latch_enable_path.isNull()) { if (!latch_enable_path.isNull()) {
const EarlyLate *early_late = latch_enable_path.minMax(this);
latch_enable_time = search_->clkPathArrival(&latch_enable_path); latch_enable_time = search_->clkPathArrival(&latch_enable_path);
if (reportClkPath()) { if (reportClkPath()) {
PathExpanded enable_expanded(&latch_enable_path, this); 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 time = latch_enable_time + latch_time_given;
Arrival incr = latch_time_given; Arrival incr = latch_time_given;
if (incr >= 0.0) if (incr >= 0.0)
reportLine("time given to startpoint", incr, time, result); reportLine("time given to startpoint", incr, time, early_late, result);
else 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. // Override latch D arrival with enable + given.
reportPathLine(expanded.path(0), delay_zero, time, "latch_D", result); reportPathLine(expanded.path(0), delay_zero, time, "latch_D", result);
bool propagated_clk = path->clkInfo(search_)->isPropagated(); bool propagated_clk = path->clkInfo(search_)->isPropagated();
@ -2646,7 +2688,7 @@ ReportPath::reportPath5(const Path *path,
Vertex *vertex = path1->vertex(this); Vertex *vertex = path1->vertex(this);
Pin *pin = vertex->pin(); Pin *pin = vertex->pin();
Arrival time = path1->arrival(this) + time_offset; Arrival time = path1->arrival(this) + time_offset;
Arrival incr(0.0); float incr = 0.0;
const char *line_case = NULL; const char *line_case = NULL;
bool is_clk_start = network_->isRegClkPin(pin); bool is_clk_start = network_->isRegClkPin(pin);
bool is_clk = path1->isClock(search_); 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 // from the input to the loads. Report the wire delay on the
// input pin instead. // input pin instead.
Arrival next_time = next_path->arrival(this) + time_offset; 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; time = next_time;
line_case = "input_drive"; line_case = "input_drive";
} }
@ -2718,11 +2761,13 @@ ReportPath::reportPath5(const Path *path,
line_case = "clk_ideal"; line_case = "clk_ideal";
} }
else if (is_clk && !is_clk_start) { 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"; line_case = "clk_prop";
} }
else { else {
incr = time - prev_time; incr = delayMeanSigma(time, min_max)
- delayMeanSigma(prev_time, min_max);
line_case = "normal"; line_case = "normal";
} }
if (report_input_pin_ if (report_input_pin_
@ -2742,7 +2787,7 @@ ReportPath::reportPath5(const Path *path,
if (report_net_ && is_driver) { if (report_net_ && is_driver) {
// Capacitance field is reported on the net line. // Capacitance field is reported on the net line.
reportLine(what, field_blank_, slew, field_blank_, 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)) { if (network_->isTopLevelPort(pin)) {
const char *pin_name = cmd_network_->pathName(pin); const char *pin_name = cmd_network_->pathName(pin);
what = stringPrintTmp(strlen(" (net)") what = stringPrintTmp(strlen(" (net)")
@ -2763,12 +2808,12 @@ ReportPath::reportPath5(const Path *path,
} }
float fanout = drvrFanout(vertex, min_max); float fanout = drvrFanout(vertex, min_max);
reportLine(what, cap, field_blank_, fanout, reportLine(what, cap, field_blank_, fanout,
field_blank_, field_blank_, false, NULL, field_blank_, field_blank_, false, min_max, NULL,
line_case, result); line_case, result);
} }
else else
reportLine(what, cap, slew, field_blank_, 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; prev_time = time;
} }
} }
@ -2870,6 +2915,7 @@ ReportPath::reportInputExternalDelay(const Path *first_path,
if (!pathFromClkPin(first_path, first_pin)) { if (!pathFromClkPin(first_path, first_pin)) {
const TransRiseFall *tr = first_path->transition(this); const TransRiseFall *tr = first_path->transition(this);
Arrival time = first_path->arrival(this) + time_offset; Arrival time = first_path->arrival(this) + time_offset;
const EarlyLate *early_late = first_path->minMax(this);
InputDelay *input_delay = pathInputDelay(first_path); InputDelay *input_delay = pathInputDelay(first_path);
if (input_delay) { if (input_delay) {
const Pin *ref_pin = input_delay->refPin(); const Pin *ref_pin = input_delay->refPin();
@ -2890,10 +2936,11 @@ ReportPath::reportInputExternalDelay(const Path *first_path,
} }
float input_arrival = float input_arrival =
input_delay->delays()->value(tr, first_path->minMax(this)); 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)) 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 void
ReportPath::reportLine(const char *what, ReportPath::reportLine(const char *what,
Delay total, Delay total,
const EarlyLate *early_late,
string &result) string &result)
{ {
reportLine(what, field_blank_, field_blank_, field_blank_, 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. // Report negative total.
void void
ReportPath::reportLineNegative(const char *what, ReportPath::reportLineNegative(const char *what,
Delay total, Delay total,
const EarlyLate *early_late,
string &result) string &result)
{ {
reportLine(what, field_blank_, field_blank_, field_blank_, 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. // Report total, and transition suffix.
void void
ReportPath::reportLine(const char *what, ReportPath::reportLine(const char *what,
Delay total, Delay total,
const EarlyLate *early_late,
const TransRiseFall *tr, const TransRiseFall *tr,
string &result) string &result)
{ {
reportLine(what, field_blank_, field_blank_, field_blank_, 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. // Report increment, and total.
void void
ReportPath::reportLine(const char *what, ReportPath::reportLine(const char *what,
Delay incr, float incr,
Delay total, float total,
string &result) string &result)
{ {
reportLine(what, field_blank_, field_blank_, field_blank_, 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. // Report increment, total, and transition suffix.
@ -3013,11 +3074,12 @@ void
ReportPath::reportLine(const char *what, ReportPath::reportLine(const char *what,
Delay incr, Delay incr,
Delay total, Delay total,
const EarlyLate *early_late,
const TransRiseFall *tr, const TransRiseFall *tr,
string &result) string &result)
{ {
reportLine(what, field_blank_, field_blank_, field_blank_, 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. // Report slew, increment, and total.
@ -3026,10 +3088,11 @@ ReportPath::reportLine(const char *what,
Slew slew, Slew slew,
Delay incr, Delay incr,
Delay total, Delay total,
const EarlyLate *early_late,
string &result) string &result)
{ {
reportLine(what, field_blank_, slew, field_blank_, reportLine(what, field_blank_, slew, field_blank_,
incr, total, false, NULL, NULL, result); incr, total, false, early_late, NULL, NULL, result);
} }
void void
@ -3040,6 +3103,7 @@ ReportPath::reportLine(const char *what,
Delay incr, Delay incr,
Delay total, Delay total,
bool total_with_minus, bool total_with_minus,
const EarlyLate *early_late,
const TransRiseFall *tr, const TransRiseFall *tr,
const char *line_case, const char *line_case,
string &result) string &result)
@ -3070,16 +3134,14 @@ ReportPath::reportLine(const char *what,
else if (field == field_capacitance_) else if (field == field_capacitance_)
reportField(cap, field, result); reportField(cap, field, result);
else if (field == field_slew_) else if (field == field_slew_)
reportField(slew, field, result); reportFieldDelay(slew, early_late, field, result);
else if (field == field_incr_) else if (field == field_incr_)
reportField(incr, field, result); reportFieldDelay(incr, early_late, field, result);
else if (field == field_total_) { else if (field == field_total_) {
if (total == field_blank_) if (total_with_minus)
reportFieldBlank(field, result); reportFieldDelayMinus(total, early_late, field, result);
else if (total_with_minus)
reportFieldTimeMinus(total, result);
else else
reportFieldTime(total, result); reportFieldDelay(total, early_late, field, result);
} }
else if (field == field_edge_) { else if (field == field_edge_) {
if (tr) { if (tr) {
@ -3105,32 +3167,35 @@ ReportPath::reportLine(const char *what,
void void
ReportPath::reportLineTotal(const char *what, ReportPath::reportLineTotal(const char *what,
Delay incr, Delay incr,
const EarlyLate *early_late,
string &result) string &result)
{ {
reportLineTotal1(what, incr, false, result); reportLineTotal1(what, incr, false, early_late, result);
} }
// Only the total field and always with leading minus sign. // Only the total field and always with leading minus sign.
void void
ReportPath::reportLineTotalMinus(const char *what, ReportPath::reportLineTotalMinus(const char *what,
Delay decr, Delay decr,
const EarlyLate *early_late,
string &result) string &result)
{ {
reportLineTotal1(what, decr, true, result); reportLineTotal1(what, decr, true, early_late, result);
} }
void void
ReportPath::reportLineTotal1(const char *what, ReportPath::reportLineTotal1(const char *what,
Delay incr, Delay incr,
bool incr_with_minus, bool incr_with_minus,
const EarlyLate *early_late,
string &result) string &result)
{ {
reportDescription(what, result); reportDescription(what, result);
result += ' '; result += ' ';
if (incr_with_minus) if (incr_with_minus)
reportFieldTimeMinus(incr, result); reportFieldDelayMinus(incr, early_late, field_total_, result);
else else
reportFieldTime(incr, result); reportFieldDelay(incr, early_late, field_total_, result);
reportEndOfLine(result); reportEndOfLine(result);
} }
@ -3162,35 +3227,84 @@ ReportPath::reportDescription(const char *what,
} }
void void
ReportPath::reportSpaceFieldTime(Delay value, ReportPath::reportFieldTime(float value,
string &result) ReportField *field,
string &result)
{ {
result += ' '; if (delayAsFloat(value) == field_blank_)
reportFieldTime(value, result); 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 void
ReportPath::reportFieldTime(Delay value, ReportPath::reportSpaceFieldTime(float value,
string &result) string &result)
{ {
const char *field = units_->timeUnit()->asString(delayAsFloat(value), result += ' ';
digits_); reportFieldTime(value, field_total_, result);
if (stringEq(field, minus_zero_)) }
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. // Filter "-0.00" fields.
field = plus_zero_; str = plus_zero_;
reportField(field, field_total_, result); reportField(str, field_total_, result);
} }
// Total time always with leading minus sign. // Total time always with leading minus sign.
void void
ReportPath::reportFieldTimeMinus(Delay value, ReportPath::reportFieldDelayMinus(Delay value,
string &result) const EarlyLate *early_late,
ReportField *field,
string &result)
{ {
const char *field=units_->timeUnit()->asString(-delayAsFloat(value),digits_); if (delayAsFloat(value) == field_blank_)
if (stringEq(field, plus_zero_)) reportFieldBlank(field, result);
// Force leading minus sign. else {
field = minus_zero_; float mean_sigma = delayMeanSigma(value, early_late);
reportField(field, field_total_, result); 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 void

View File

@ -307,9 +307,10 @@ protected:
string &result); string &result);
void reportClkSrcLatency(Arrival insertion, void reportClkSrcLatency(Arrival insertion,
float clk_time, float clk_time,
const EarlyLate *early_late,
string &result); string &result);
void reportPathLine(const Path *path, void reportPathLine(const Path *path,
Arrival incr, Delay incr,
Arrival time, Arrival time,
const char *line_case, const char *line_case,
string &result); string &result);
@ -385,27 +386,37 @@ protected:
string &result); string &result);
void reportLine(const char *what, void reportLine(const char *what,
Delay total, Delay total,
const EarlyLate *early_late,
string &result); string &result);
void reportLineNegative(const char *what, void reportLineNegative(const char *what,
Delay total, Delay total,
const EarlyLate *early_late,
string &result); string &result);
void reportLine(const char *what, void reportLine(const char *what,
Delay total, Delay total,
const EarlyLate *early_late,
const TransRiseFall *tr, const TransRiseFall *tr,
string &result); string &result);
void reportLine(const char *what, void reportLine(const char *what,
Delay incr, float incr,
Delay total, float total,
string &result); string &result);
void reportLine(const char *what, void reportLine(const char *what,
Delay incr, Delay incr,
Delay total, Delay total,
const EarlyLate *early_late,
string &result);
void reportLine(const char *what,
Delay incr,
Delay total,
const EarlyLate *early_late,
const TransRiseFall *tr, const TransRiseFall *tr,
string &result); string &result);
void reportLine(const char *what, void reportLine(const char *what,
Slew slew, Slew slew,
Delay incr, Delay incr,
Delay total, Delay total,
const EarlyLate *early_late,
string &result); string &result);
void reportLine(const char *what, void reportLine(const char *what,
float cap, float cap,
@ -414,28 +425,45 @@ protected:
Delay incr, Delay incr,
Delay total, Delay total,
bool total_with_minus, bool total_with_minus,
const EarlyLate *early_late,
const TransRiseFall *tr, const TransRiseFall *tr,
const char *line_case, const char *line_case,
string &result); string &result);
void reportLineTotal(const char *what, void reportLineTotal(const char *what,
Delay incr, Delay incr,
const EarlyLate *early_late,
string &result); string &result);
void reportLineTotalMinus(const char *what, void reportLineTotalMinus(const char *what,
Delay decr, Delay decr,
const EarlyLate *early_late,
string &result); string &result);
void reportLineTotal1(const char *what, void reportLineTotal1(const char *what,
Delay incr, Delay incr,
bool incr_with_minus, bool incr_with_minus,
const EarlyLate *early_late,
string &result); string &result);
void reportDashLineTotal(string &result); void reportDashLineTotal(string &result);
void reportDescription(const char *what, void reportDescription(const char *what,
string &result); string &result);
void reportSpaceFieldTime(Delay value, void reportFieldTime(float value,
string &result); ReportField *field,
void reportFieldTime(Delay value,
string &result); string &result);
void reportFieldTimeMinus(Delay value, void reportSpaceFieldTime(float value,
string &result); 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, void reportField(float value,
ReportField *field, ReportField *field,
string &result); string &result);
@ -520,8 +548,8 @@ protected:
const char *plus_zero_; const char *plus_zero_;
const char *minus_zero_; const char *minus_zero_;
static const Delay field_blank_; static const float field_blank_;
static const Delay field_skip_; static const float field_skip_;
private: private:
DISALLOW_COPY_AND_ASSIGN(ReportPath); DISALLOW_COPY_AND_ASSIGN(ReportPath);

View File

@ -227,6 +227,7 @@ Search::Search(StaState *sta) :
void void
Search::init(StaState *sta) Search::init(StaState *sta)
{ {
crpr_path_pruning_enabled_ = true;
report_unconstrained_paths_ = false; report_unconstrained_paths_ = false;
search_adj_ = new SearchThru(NULL, sta); search_adj_ = new SearchThru(NULL, sta);
eval_pred_ = new EvalPred(sta); eval_pred_ = new EvalPred(sta);
@ -292,6 +293,7 @@ Search::~Search()
void void
Search::clear() Search::clear()
{ {
crpr_path_pruning_enabled_ = true;
clk_arrivals_valid_ = false; clk_arrivals_valid_ = false;
arrivals_exist_ = false; arrivals_exist_ = false;
arrivals_at_endpoints_exist_ = false; arrivals_at_endpoints_exist_ = false;
@ -315,6 +317,18 @@ Search::clear()
found_downstream_clk_pins_ = false; 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 void
Search::setReportUnconstrainedPaths(bool report) Search::setReportUnconstrainedPaths(bool report)
{ {
@ -1086,9 +1100,9 @@ ArrivalVisitor::visit(Vertex *vertex)
visitFaninPaths(vertex); visitFaninPaths(vertex);
if (crpr_active_ if (crpr_active_
&& search->crprPathPruningEnabled()
&& !has_fanin_one_) && !has_fanin_one_)
pruneCrprArrivals(); pruneCrprArrivals();
// Insert paths that originate here but // Insert paths that originate here but
if (!network->isTopLevelPort(pin) if (!network->isTopLevelPort(pin)
&& sdc->hasInputDelay(pin)) && sdc->hasInputDelay(pin))
@ -1538,11 +1552,11 @@ Search::seedClkArrival(const Pin *pin,
bool latency_exists; bool latency_exists;
// Check for clk pin latency. // Check for clk pin latency.
sdc_->clockLatency(clk, pin, tr, min_max, sdc_->clockLatency(clk, pin, tr, min_max,
latency, latency_exists); latency, latency_exists);
if (!latency_exists) { if (!latency_exists) {
// Check for clk latency (lower priority). // Check for clk latency (lower priority).
sdc_->clockLatency(clk, tr, min_max, sdc_->clockLatency(clk, tr, min_max,
latency, latency_exists); latency, latency_exists);
if (latency_exists) { if (latency_exists) {
// Propagated pin overrides latency on clk. // Propagated pin overrides latency on clk.
if (sdc_->isPropagatedClock(pin)) { if (sdc_->isPropagatedClock(pin)) {
@ -1712,8 +1726,7 @@ Search::seedInputArrival(const Pin *pin,
{ {
bool has_arrival = false; bool has_arrival = false;
// There can be multiple arrivals for a pin with wrt different clocks. // There can be multiple arrivals for a pin with wrt different clocks.
PinInputDelayIterator *arrival_iter = PinInputDelayIterator *arrival_iter = sdc_->inputDelayVertexIterator(pin);
sdc_->inputDelayVertexIterator(pin);
TagGroupBldr tag_bldr(true, this); TagGroupBldr tag_bldr(true, this);
tag_bldr.init(vertex); tag_bldr.init(vertex);
while (arrival_iter->hasNext()) { while (arrival_iter->hasNext()) {
@ -1762,8 +1775,7 @@ Search::seedInputArrival1(const Pin *pin,
TagGroupBldr *tag_bldr) TagGroupBldr *tag_bldr)
{ {
// There can be multiple arrivals for a pin with wrt different clocks. // There can be multiple arrivals for a pin with wrt different clocks.
PinInputDelayIterator *arrival_iter= PinInputDelayIterator *arrival_iter = sdc_->inputDelayVertexIterator(pin);
sdc_->inputDelayVertexIterator(pin);
while (arrival_iter->hasNext()) { while (arrival_iter->hasNext()) {
InputDelay *input_delay = arrival_iter->next(); InputDelay *input_delay = arrival_iter->next();
Clock *input_clk = input_delay->clock(); Clock *input_clk = input_delay->clock();
@ -1864,8 +1876,7 @@ Search::inputDelayRefPinArrival(Path *ref_path,
const EarlyLate *early_late = min_max; const EarlyLate *early_late = min_max;
// Input delays from ideal clk reference pins include clock // Input delays from ideal clk reference pins include clock
// insertion delay but not latency. // insertion delay but not latency.
ref_insertion = sdc_->clockInsertion(clk, clk_tr, min_max, ref_insertion = sdc_->clockInsertion(clk, clk_tr, min_max, early_late);
early_late);
ref_arrival = clk_edge->time() + ref_insertion; ref_arrival = clk_edge->time() + ref_insertion;
ref_latency = 0.0; ref_latency = 0.0;
} }
@ -2311,7 +2322,7 @@ Search::clkPathArrival(const Path *clk_path,
return clk_path->arrival(this); return clk_path->arrival(this);
} }
float Arrival
Search::pathClkPathArrival(const Path *path) const Search::pathClkPathArrival(const Path *path) const
{ {
PathRef src_clk_path; PathRef src_clk_path;
@ -2392,7 +2403,7 @@ Search::fromRegClkTag(const Pin *from_pin,
{ {
ExceptionStateSet *states = NULL; ExceptionStateSet *states = NULL;
if (sdc_->exceptionFromStates(from_pin, from_tr, clk, clk_tr, if (sdc_->exceptionFromStates(from_pin, from_tr, clk, clk_tr,
min_max, states)) { min_max, states)) {
// Hack for filter -from reg/Q. // Hack for filter -from reg/Q.
sdc_->filterRegQStates(to_pin, to_tr, min_max, states); sdc_->filterRegQStates(to_pin, to_tr, min_max, states);
return findTag(to_tr, path_ap, clk_info, false, NULL, false, states, true); return findTag(to_tr, path_ap, clk_info, false, NULL, false, states, true);
@ -2535,7 +2546,7 @@ Search::thruClkInfo(PathVertex *from_path,
float latency; float latency;
bool exists; bool exists;
sdc_->clockLatency(from_clk, to_pin, clk_tr, min_max, sdc_->clockLatency(from_clk, to_pin, clk_tr, min_max,
latency, exists); latency, exists);
if (exists) { if (exists) {
// Latency on pin has precidence over fanin or hierarchical // Latency on pin has precidence over fanin or hierarchical
// pin latency. // pin latency.
@ -2546,7 +2557,7 @@ Search::thruClkInfo(PathVertex *from_path,
else { else {
// Check for hierarchical pin latency thru edge. // Check for hierarchical pin latency thru edge.
sdc_->clockLatency(edge, clk_tr, min_max, sdc_->clockLatency(edge, clk_tr, min_max,
latency, exists); latency, exists);
if (exists) { if (exists) {
to_latency = latency; to_latency = latency;
to_clk_prop = false; to_clk_prop = false;
@ -2618,8 +2629,7 @@ Search::mutateTag(Tag *from_tag,
} }
} }
// Get the set of -thru exceptions starting at to_pin/edge. // Get the set of -thru exceptions starting at to_pin/edge.
sdc_->exceptionThruStates(from_pin, to_pin, to_tr, min_max, sdc_->exceptionThruStates(from_pin, to_pin, to_tr, min_max, new_states);
new_states);
if (new_states || state_change) { if (new_states || state_change) {
// Second pass to apply state changes and add updated existing // Second pass to apply state changes and add updated existing
// states to new states. // states to new states.
@ -2659,8 +2669,7 @@ Search::mutateTag(Tag *from_tag,
} }
else else
// Get the set of -thru exceptions starting at to_pin/edge. // Get the set of -thru exceptions starting at to_pin/edge.
sdc_->exceptionThruStates(from_pin, to_pin, to_tr, min_max, sdc_->exceptionThruStates(from_pin, to_pin, to_tr, min_max, new_states);
new_states);
if (new_states) if (new_states)
return findTag(to_tr, path_ap, to_clk_info, to_is_clk, 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(); const Pin *pin = from_vertex->pin();
if (role->isWire()) { if (role->isWire()) {
const TransRiseFall *tr = arc->toTrans()->asRiseFall(); const TransRiseFall *tr = arc->toTrans()->asRiseFall();
return sdc_->timingDerateNet(pin, derate_clk_data, return sdc_->timingDerateNet(pin, derate_clk_data, tr,
tr, path_ap->pathMinMax()); path_ap->pathMinMax());
} }
else { else {
TimingDerateType derate_type; TimingDerateType derate_type;
@ -3072,9 +3081,8 @@ Search::timingDerate(Vertex *from_vertex,
derate_type = timing_derate_cell_delay; derate_type = timing_derate_cell_delay;
tr = arc->fromTrans()->asRiseFall(); tr = arc->fromTrans()->asRiseFall();
} }
return sdc_->timingDerateInstance(pin, derate_type, return sdc_->timingDerateInstance(pin, derate_type, derate_clk_data, tr,
derate_clk_data, tr, path_ap->pathMinMax());
path_ap->pathMinMax());
} }
} }
@ -3536,12 +3544,13 @@ RequiredVisitor::visitFromToPath(const Pin *,
VertexPathIterator to_iter(to_vertex, to_tr, path_ap, sta_); VertexPathIterator to_iter(to_vertex, to_tr, path_ap, sta_);
while (to_iter.hasNext()) { while (to_iter.hasNext()) {
PathVertex *to_path = to_iter.next(); 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 to_required = to_path->required(sta_);
Required from_required = to_required - arc_delay; Required from_required = to_required - arc_delay;
debugPrint2(debug, "search", 3, " to tag %2u: %s\n", debugPrint2(debug, "search", 3, " to tag %2u: %s\n",
to_tag->index(), to_path_tag->index(),
to_tag->asString(sta_)); to_path_tag->asString(sta_));
debugPrint5(debug, "search", 3, " %s - %s = %s %s %s\n", debugPrint5(debug, "search", 3, " %s - %s = %s %s %s\n",
delayAsString(to_required, sta_), delayAsString(to_required, sta_),
delayAsString(arc_delay, sta_), delayAsString(arc_delay, sta_),
@ -3676,7 +3685,7 @@ Search::exceptionTo(ExceptionPathType type,
if ((type == exception_type_any if ((type == exception_type_any
|| exception->type() == type) || exception->type() == type)
&& sdc_->isCompleteTo(state, pin, tr, clk_edge, min_max, && 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 && (hi_priority_exception == NULL
|| priority > hi_priority || priority > hi_priority
|| (priority == hi_priority || (priority == hi_priority

View File

@ -68,6 +68,11 @@ public:
virtual void copyState(const StaState *sta); virtual void copyState(const StaState *sta);
// Reset to virgin state. // Reset to virgin state.
void clear(); 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. // Report unconstrained paths.
bool reportUnconstrainedPaths() const { return report_unconstrained_paths_; } bool reportUnconstrainedPaths() const { return report_unconstrained_paths_; }
void setReportUnconstrainedPaths(bool report); void setReportUnconstrainedPaths(bool report);
@ -132,7 +137,7 @@ public:
const MinMax *min_max, const MinMax *min_max,
const PathAnalysisPt *path_ap) const; const PathAnalysisPt *path_ap) const;
// Clock arrival at the path source/launch point. // 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; PathGroup *pathGroup(const PathEnd *path_end) const;
void deletePathGroups(); void deletePathGroups();
@ -571,6 +576,7 @@ protected:
VisitPathEnds *visit_path_ends_; VisitPathEnds *visit_path_ends_;
GatedClk *gated_clk_; GatedClk *gated_clk_;
Crpr *crpr_; Crpr *crpr_;
bool crpr_path_pruning_enabled_;
Genclks *genclks_; Genclks *genclks_;
}; };

View File

@ -67,6 +67,7 @@
#include "VisitPathGroupVertices.hh" #include "VisitPathGroupVertices.hh"
#include "SdfWriter.hh" #include "SdfWriter.hh"
#include "Genclks.hh" #include "Genclks.hh"
#include "Power.hh"
#include "Sta.hh" #include "Sta.hh"
namespace sta { namespace sta {
@ -272,6 +273,7 @@ Sta::Sta() :
check_max_skews_(NULL), check_max_skews_(NULL),
clk_skews_(NULL), clk_skews_(NULL),
report_path_(NULL), report_path_(NULL),
power_(NULL),
link_make_black_boxes_(true), link_make_black_boxes_(true),
update_genclks_(false) update_genclks_(false)
{ {
@ -348,6 +350,8 @@ Sta::updateComponentsState()
report_path_->copyState(this); report_path_->copyState(this);
if (check_timing_) if (check_timing_)
check_timing_->copyState(this); check_timing_->copyState(this);
if (power_)
power_->copyState(this);
} }
void void
@ -466,6 +470,12 @@ Sta::makeReportPath()
report_path_ = new ReportPath(this); report_path_ = new ReportPath(this);
} }
void
Sta::makePower()
{
power_ = new Power(this);
}
void void
Sta::setSta(Sta *sta) Sta::setSta(Sta *sta)
{ {
@ -3185,9 +3195,9 @@ Sta::portExtPinCap(Port *port,
int fanout; int fanout;
bool pin_exists, wire_exists, fanout_exists; bool pin_exists, wire_exists, fanout_exists;
sdc_->portExtCap(port, tr, min_max, sdc_->portExtCap(port, tr, min_max,
pin_cap, pin_exists, pin_cap, pin_exists,
wire_cap, wire_exists, wire_cap, wire_exists,
fanout, fanout_exists); fanout, fanout_exists);
if (pin_exists) if (pin_exists)
return pin_cap; return pin_cap;
else else
@ -3221,9 +3231,9 @@ Sta::portExtWireCap(Port *port,
int fanout; int fanout;
bool pin_exists, wire_exists, fanout_exists; bool pin_exists, wire_exists, fanout_exists;
sdc_->portExtCap(port, tr, min_max, sdc_->portExtCap(port, tr, min_max,
pin_cap, pin_exists, pin_cap, pin_exists,
wire_cap, wire_exists, wire_cap, wire_exists,
fanout, fanout_exists); fanout, fanout_exists);
if (wire_exists) if (wire_exists)
return wire_cap; return wire_cap;
else else
@ -3244,8 +3254,7 @@ Sta::setPortExtWireCap(Port *port,
MinMaxIterator mm_iter(min_max); MinMaxIterator mm_iter(min_max);
while (mm_iter.hasNext()) { while (mm_iter.hasNext()) {
MinMax *mm = mm_iter.next(); MinMax *mm = mm_iter.next();
sdc_->setPortExtWireCap(port, subtract_pin_cap, tr1, sdc_->setPortExtWireCap(port, subtract_pin_cap, tr1, corner, mm, cap);
corner, mm, cap);
} }
} }
delaysInvalidFromFanin(port); delaysInvalidFromFanin(port);
@ -3375,6 +3384,7 @@ Sta::readParasitics(const char *filename,
Instance *instance, Instance *instance,
const MinMaxAll *min_max, const MinMaxAll *min_max,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,
@ -3398,6 +3408,7 @@ Sta::readParasitics(const char *filename,
const OperatingConditions *op_cond = const OperatingConditions *op_cond =
sdc_->operatingConditions(cnst_min_max); sdc_->operatingConditions(cnst_min_max);
bool success = readParasiticsFile(filename, instance, ap, increment, bool success = readParasiticsFile(filename, instance, ap, increment,
pin_cap_included,
keep_coupling_caps, coupling_cap_factor, keep_coupling_caps, coupling_cap_factor,
reduce_to, delete_after_reduce, reduce_to, delete_after_reduce,
op_cond, corner, cnst_min_max, save, quiet, op_cond, corner, cnst_min_max, save, quiet,
@ -4860,4 +4871,39 @@ Sta::reportCheck(MaxSkewCheck *check,
report_path_->reportCheck(check, verbose); 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 &macro,
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 } // namespace

View File

@ -55,6 +55,8 @@ class SearchPred;
class Corner; class Corner;
class ClkSkews; class ClkSkews;
class ReportField; class ReportField;
class Power;
class PowerResult;
typedef InstanceSeq::Iterator SlowDrvrIterator; typedef InstanceSeq::Iterator SlowDrvrIterator;
typedef Vector<const char*> CheckError; typedef Vector<const char*> CheckError;
@ -669,6 +671,7 @@ public:
void reportCheck(MaxSkewCheck *check, void reportCheck(MaxSkewCheck *check,
bool verbose); bool verbose);
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// User visible but non SDC commands. // User visible but non SDC commands.
@ -974,9 +977,11 @@ public:
Slack vertexSlack(Vertex *vertex, Slack vertexSlack(Vertex *vertex,
const TransRiseFall *tr, const TransRiseFall *tr,
const PathAnalysisPt *path_ap); const PathAnalysisPt *path_ap);
// Slew for one delay calc analysis pt(corner).
Slew vertexSlew(Vertex *vertex, Slew vertexSlew(Vertex *vertex,
const TransRiseFall *tr, const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap); const DcalcAnalysisPt *dcalc_ap);
// Slew across all corners.
Slew vertexSlew(Vertex *vertex, Slew vertexSlew(Vertex *vertex,
const TransRiseFall *tr, const TransRiseFall *tr,
const MinMax *min_max); const MinMax *min_max);
@ -1021,6 +1026,7 @@ public:
Instance *instance, Instance *instance,
const MinMaxAll *min_max, const MinMaxAll *min_max,
bool increment, bool increment,
bool pin_cap_included,
bool keep_coupling_caps, bool keep_coupling_caps,
float coupling_cap_factor, float coupling_cap_factor,
ReduceParasiticsTo reduce_to, ReduceParasiticsTo reduce_to,
@ -1143,6 +1149,21 @@ public:
Vertex *vertex, Vertex *vertex,
LibertyCell *to_cell); 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 &macro,
PowerResult &pad);
void power(const Instance *inst,
const Corner *corner,
// Return values.
PowerResult &result);
protected: protected:
// Default constructors that are called by makeComponents in the Sta // Default constructors that are called by makeComponents in the Sta
// constructor. These can be redefined by a derived class to // constructor. These can be redefined by a derived class to
@ -1168,6 +1189,7 @@ protected:
virtual void makeCheckMinPeriods(); virtual void makeCheckMinPeriods();
virtual void makeCheckMaxSkews(); virtual void makeCheckMaxSkews();
virtual void makeReportPath(); virtual void makeReportPath();
virtual void makePower();
virtual void makeObservers(); virtual void makeObservers();
NetworkEdit *networkCmdEdit(); NetworkEdit *networkCmdEdit();
@ -1254,6 +1276,7 @@ protected:
Corner *corner, Corner *corner,
const MinMax *min_max); const MinMax *min_max);
void parasiticsChangedAfter(); void parasiticsChangedAfter();
void powerPreamble();
CmdNamespace cmd_namespace_; CmdNamespace cmd_namespace_;
Instance *current_instance_; Instance *current_instance_;
@ -1264,6 +1287,7 @@ protected:
CheckMaxSkews *check_max_skews_; CheckMaxSkews *check_max_skews_;
ClkSkews *clk_skews_; ClkSkews *clk_skews_;
ReportPath *report_path_; ReportPath *report_path_;
Power *power_;
Tcl_Interp *tcl_interp_; Tcl_Interp *tcl_interp_;
bool link_make_black_boxes_; bool link_make_black_boxes_;
bool update_genclks_; bool update_genclks_;

View File

@ -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 } { proc parse_corner_or_all { keys_var } {
upvar 1 $keys_var keys upvar 1 $keys_var keys

View File

@ -121,8 +121,8 @@ proc report_edge_ { edge vertex_from_name_proc vertex_to_name_proc } {
set iter [$edge timing_arc_iterator] set iter [$edge timing_arc_iterator]
while {[$iter has_next]} { while {[$iter has_next]} {
set arc [$iter next] set arc [$iter next]
set delays [$edge arc_delays $arc] set delays [$edge arc_delay_strings $arc $sta_report_default_digits]
set delays_fmt [format_times $delays $sta_report_default_digits] set delays_fmt [format_delays $delays]
set disable_reason "" set disable_reason ""
if { [timing_arc_disabled $edge $arc] } { if { [timing_arc_disabled $edge $arc] } {
set disable_reason " disabled" set disable_reason " disabled"
@ -144,6 +144,18 @@ proc format_times { values digits } {
return $result 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 } { proc edge_disable_reason { edge } {
set disables "" set disables ""
if [$edge is_disabled_constraint] { if [$edge is_disabled_constraint] {

View File

@ -33,46 +33,5 @@ proc read_liberty { args } {
read_liberty_cmd $filename $corner $min_max $infer_latches 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 # sta namespace end
} }

View File

@ -251,10 +251,11 @@ define_cmd_args "report_net" \
proc_redirect report_net { proc_redirect report_net {
global sta_report_default_digits 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} flags {-connections -verbose -hier_pins}
check_argc_eq1 "report_net" $args check_argc_eq1 "report_net" $args
set corner [parse_corner keys]
set digits $sta_report_default_digits set digits $sta_report_default_digits
if { [info exists keys(-digits)] } { if { [info exists keys(-digits)] } {
set digits $keys(-digits) set digits $keys(-digits)
@ -269,13 +270,13 @@ proc_redirect report_net {
set net_path [lindex $args 0] set net_path [lindex $args 0]
set net [find_net $net_path] set net [find_net $net_path]
if { $net != "NULL" } { if { $net != "NULL" } {
report_net1 $net $connections $verbose $hier_pins $digits report_net1 $net $connections $verbose $hier_pins $corner $digits
} else { } else {
set pin [find_pin $net_path] set pin [find_pin $net_path]
if { $pin != "NULL" } { if { $pin != "NULL" } {
set net [$pin net] set net [$pin net]
if { $net != "NULL" } { if { $net != "NULL" } {
report_net1 $net $connections $verbose $hier_pins $digits report_net1 $net $connections $verbose $hier_pins $corner $digits
} else { } else {
sta_error "net $net_path not found." sta_error "net $net_path not found."
} }
@ -287,27 +288,27 @@ proc_redirect report_net {
proc report_net_ { net } { proc report_net_ { net } {
global sta_report_default_digits 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]" puts "Net [$net path_name]"
if {$connections} { if {$connections} {
set pins [net_connected_pins_sorted $net] set pins [net_connected_pins_sorted $net]
if {$verbose} { if {$verbose} {
report_net_caps $net $pins $digits report_net_caps $net $pins $corner $digits
} }
puts "Driver pins" puts "Driver pins"
report_net_pins $pins "is_driver" $verbose $digits report_net_pins $pins "is_driver" $verbose $corner $digits
puts "" puts ""
puts "Load pins" puts "Load pins"
report_net_pins $pins "is_load" $verbose $digits report_net_pins $pins "is_load" $verbose $corner $digits
if {$hier_pins} { if {$hier_pins} {
puts "" puts ""
puts "Hierarchical pins" 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 return $pins
} }
proc report_net_caps { net pins digits } { proc report_net_caps { net pins corner digits } {
set corner [default_corner]
report_net_cap $net "Pin" "pin_capacitance" $corner $digits report_net_cap $net "Pin" "pin_capacitance" $corner $digits
report_net_cap $net "Wire" "wire_capacitance" $corner $digits report_net_cap $net "Wire" "wire_capacitance" $corner $digits
report_net_cap $net "Total" "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]" 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 { foreach pin $pins {
if {[$pin $pin_pred]} { 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 set header 0
foreach pin $pins { foreach pin $pins {
if { !([$pin is_driver] || [$pin is_load] || [$pin is_hierarchical]) } { 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" puts "Other pins"
set header 1 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] { if [$pin is_leaf] {
set cell_name [[[$pin instance] cell] name] set cell_name [[[$pin instance] cell] name]
puts -nonewline " [$pin path_name] [$pin direction] ($cell_name)" puts -nonewline " [$pin path_name] [$pin direction] ($cell_name)"

138
tcl/Power.tcl Normal file
View File

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

View File

@ -2356,20 +2356,19 @@ proc set_input_transition { args } {
################################################################ ################################################################
define_cmd_args "set_load" \ 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} [-pin_load] [-wire_load] capacitance objects}
proc set_load { args } { proc set_load { args } {
parse_key_args "set_load" args keys {} \ parse_key_args "set_load" args keys {-corner} \
flags {-rise -fall -min -max -corner -subtract_pin_load \ flags {-rise -fall -min -max -subtract_pin_load -pin_load -wire_load}\
-pin_load -wire_load}
check_argc_eq2 "set_load" $args check_argc_eq2 "set_load" $args
set pin_load [info exists flags(-pin_load)] set pin_load [info exists flags(-pin_load)]
set wire_load [info exists flags(-wire_load)] set wire_load [info exists flags(-wire_load)]
set subtract_pin_load [info exists flags(-subtract_pin_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 min_max [parse_min_max_all_check_flags flags]
set tr [parse_rise_fall_flags flags] set tr [parse_rise_fall_flags flags]

View File

@ -25,7 +25,42 @@ namespace eval sta {
define_cmd_args "report_arrival" {pin} define_cmd_args "report_arrival" {pin}
proc 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 } { proc report_wrt_clks { pin_arg what } {
@ -82,6 +117,16 @@ proc times_are_inf { times } {
return 1 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". # 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} define_cmd_args "report_required" {pin}
proc 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} define_cmd_args "report_slack" {pin}
proc report_slack { pin } { proc report_slack { pin } {
report_wrt_clks $pin "slacks_clk" report_delays_wrt_clks $pin "slacks_clk_delays"
} }
################################################################ ################################################################

View File

@ -49,8 +49,6 @@
#include "Transition.hh" #include "Transition.hh"
#include "TimingRole.hh" #include "TimingRole.hh"
#include "TimingArc.hh" #include "TimingArc.hh"
#include "InternalPower.hh"
#include "LeakagePower.hh"
#include "EquivCells.hh" #include "EquivCells.hh"
#include "Liberty.hh" #include "Liberty.hh"
#include "Network.hh" #include "Network.hh"
@ -77,6 +75,7 @@
#include "SearchPred.hh" #include "SearchPred.hh"
#include "PathAnalysisPt.hh" #include "PathAnalysisPt.hh"
#include "ReportPath.hh" #include "ReportPath.hh"
#include "Power.hh"
#include "Sta.hh" #include "Sta.hh"
namespace sta { namespace sta {
@ -693,7 +692,10 @@ edgeDelayProperty(Edge *edge,
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
ArcDelay arc_delay = sta->arcDelay(edge, arc, dcalc_ap); ArcDelay arc_delay = sta->arcDelay(edge, arc, dcalc_ap);
if (!delay_exists 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; delay = arc_delay;
} }
} }
@ -822,6 +824,16 @@ findEndpoints()
return pins; 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 void
@ -1510,11 +1522,11 @@ using namespace sta;
%typemap(in) EarlyLate* { %typemap(in) EarlyLate* {
int length; int length;
char *arg = Tcl_GetStringFromObj($input, &length); char *arg = Tcl_GetStringFromObj($input, &length);
MinMax *min_max = MinMax::find(arg); EarlyLate *early_late = EarlyLate::find(arg);
if (min_max) if (early_late)
$1 = min_max; $1 = early_late;
else { else {
tclError(interp, "Error: %s not min or max.", arg); tclError(interp, "Error: %s not early/min or late/max.", arg);
return TCL_ERROR; return TCL_ERROR;
} }
} }
@ -1523,11 +1535,11 @@ using namespace sta;
%typemap(in) EarlyLateAll* { %typemap(in) EarlyLateAll* {
int length; int length;
char *arg = Tcl_GetStringFromObj($input, &length); char *arg = Tcl_GetStringFromObj($input, &length);
MinMaxAll *min_max = MinMaxAll::find(arg); EarlyLateAll *early_late = EarlyLateAll::find(arg);
if (min_max) if (early_late)
$1 = min_max; $1 = early_late;
else { 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; return TCL_ERROR;
} }
} }
@ -1735,26 +1747,6 @@ using namespace sta;
Tcl_SetObjResult(interp, obj); 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* { %typemap(out) CellTimingArcSetIterator* {
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
Tcl_SetObjResult(interp, obj); Tcl_SetObjResult(interp, obj);
@ -2009,34 +2001,6 @@ private:
~CellTimingArcSetIterator(); ~CellTimingArcSetIterator();
}; };
class InternalPower
{
private:
InternalPower();
~InternalPower();
};
class LibertyCellInternalPowerIterator
{
private:
LibertyCellInternalPowerIterator();
~LibertyCellInternalPowerIterator();
};
class LeakagePower
{
private:
LeakagePower();
~LeakagePower();
};
class LibertyCellLeakagePowerIterator
{
private:
LibertyCellLeakagePowerIterator();
~LibertyCellLeakagePowerIterator();
};
class TimingArcSetArcIterator class TimingArcSetArcIterator
{ {
private: private:
@ -4814,6 +4778,50 @@ report_slew_limit_verbose(Pin *pin,
Sta::sta()->reportSlewLimitVerbose(pin, corner, min_max); 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 * EdgeSeq *
disabled_edges_sorted() disabled_edges_sorted()
{ {
@ -5339,6 +5347,7 @@ find_cells_matching(const char *pattern,
%extend LibertyLibrary { %extend LibertyLibrary {
const char *name() { return self->name(); } const char *name() { return self->name(); }
const char *filename() { return self->filename(); }
const char *object_name() { return self->name(); } const char *object_name() { return self->name(); }
LibertyCell * LibertyCell *
@ -5456,12 +5465,6 @@ liberty_port_iterator() { return self->libertyPortIterator(); }
CellTimingArcSetIterator * CellTimingArcSetIterator *
timing_arc_set_iterator() { return self->timingArcSetIterator(); } timing_arc_set_iterator() { return self->timingArcSetIterator(); }
LibertyCellInternalPowerIterator *
internal_power_iterator() { return self->internalPowerIterator(); }
LibertyCellLeakagePowerIterator *
leakage_power_iterator() { return self->leakagePowerIterator(); }
} // LibertyCell methods } // LibertyCell methods
%extend CellPortIterator { %extend CellPortIterator {
@ -5594,61 +5597,6 @@ TimingArc *next() { return self->next(); }
void finish() { delete self; } 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 { %extend Instance {
const char *name() { return cmdLinkedNetwork()->name(self); } const char *name() { return cmdLinkedNetwork()->name(self); }
const char *object_name() { return cmdLinkedNetwork()->pathName(self); } const char *object_name() { return cmdLinkedNetwork()->pathName(self); }
@ -5954,11 +5902,33 @@ arrivals_clk(const TransRiseFall *tr,
PathAnalysisPtIterator ap_iter(sta); PathAnalysisPtIterator ap_iter(sta);
while (ap_iter.hasNext()) { while (ap_iter.hasNext()) {
PathAnalysisPt *path_ap = ap_iter.next(); 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; 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 * TmpFloatSeq *
requireds_clk(const TransRiseFall *tr, requireds_clk(const TransRiseFall *tr,
Clock *clk, Clock *clk,
@ -5972,11 +5942,33 @@ requireds_clk(const TransRiseFall *tr,
PathAnalysisPtIterator ap_iter(sta); PathAnalysisPtIterator ap_iter(sta);
while (ap_iter.hasNext()) { while (ap_iter.hasNext()) {
PathAnalysisPt *path_ap = ap_iter.next(); 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; 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 * TmpFloatSeq *
slacks(TransRiseFall *tr) slacks(TransRiseFall *tr)
{ {
@ -6004,11 +5996,33 @@ slacks_clk(const TransRiseFall *tr,
PathAnalysisPtIterator ap_iter(sta); PathAnalysisPtIterator ap_iter(sta);
while (ap_iter.hasNext()) { while (ap_iter.hasNext()) {
PathAnalysisPt *path_ap = ap_iter.next(); 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; 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 * VertexPathIterator *
path_iterator(const TransRiseFall *tr, path_iterator(const TransRiseFall *tr,
const MinMax *min_max) const MinMax *min_max)
@ -6070,6 +6084,21 @@ arc_delays(TimingArc *arc)
return floats; 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 bool
delay_annotated(TimingArc *arc, delay_annotated(TimingArc *arc,
const Corner *corner, const Corner *corner,
@ -6085,7 +6114,7 @@ arc_delay(TimingArc *arc,
const MinMax *min_max) const MinMax *min_max)
{ {
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(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 * const char *

View File

@ -90,9 +90,11 @@ MinMax::opposite() const
MinMax * MinMax *
MinMax::find(const char *min_max) MinMax::find(const char *min_max)
{ {
if (stringEq(min_max, "min")) if (stringEq(min_max, "min")
|| stringEq(min_max, "early"))
return min(); return min();
else if (stringEq(min_max, "max")) else if (stringEq(min_max, "max")
|| stringEq(min_max, "late"))
return max(); return max();
else else
return NULL; return NULL;
@ -172,9 +174,11 @@ MinMaxAll::matches(const MinMaxAll *min_max) const
MinMaxAll * MinMaxAll *
MinMaxAll::find(const char *min_max) MinMaxAll::find(const char *min_max)
{ {
if (stringEq(min_max, "min")) if (stringEq(min_max, "min")
|| stringEq(min_max, "early"))
return min(); return min();
else if (stringEq(min_max, "max")) else if (stringEq(min_max, "max")
|| stringEq(min_max, "late"))
return max(); return max();
else if (stringEq(min_max, "all") else if (stringEq(min_max, "all")
|| stringEq(min_max, "min_max") || stringEq(min_max, "min_max")

View File

@ -24,9 +24,12 @@ namespace sta {
class MinMax; class MinMax;
class MinMaxAll; class MinMaxAll;
class MinMaxIterator;
// Use typedefs to make early/late functional equivalents to min/max.
typedef MinMax EarlyLate; typedef MinMax EarlyLate;
typedef MinMaxAll EarlyLateAll; typedef MinMaxAll EarlyLateAll;
typedef MinMaxIterator EarlyLateIterator;
// Large value used for min/max initial values. // Large value used for min/max initial values.
extern const float INF; extern const float INF;
@ -39,8 +42,12 @@ public:
// Singleton accessors. // Singleton accessors.
static MinMax *min() { return min_; } static MinMax *min() { return min_; }
static MinMax *max() { return max_; } static MinMax *max() { return max_; }
static EarlyLate *early() { return min_; }
static EarlyLate *late() { return max_; }
static int minIndex() { return min_->index_; } static int minIndex() { return min_->index_; }
static int earlyIndex() { return min_->index_; }
static int maxIndex() { return max_->index_; } static int maxIndex() { return max_->index_; }
static int lateIndex() { return min_->index_; }
const char *asString() const { return name_; } const char *asString() const { return name_; }
int index() const { return index_; } int index() const { return index_; }
float initValue() const { return init_value_; } float initValue() const { return init_value_; }
@ -98,7 +105,9 @@ public:
static void destroy(); static void destroy();
// Singleton accessors. // Singleton accessors.
static MinMaxAll *min() { return min_; } static MinMaxAll *min() { return min_; }
static MinMaxAll *early() { return min_; }
static MinMaxAll *max() { return max_; } static MinMaxAll *max() { return max_; }
static MinMaxAll *late() { return max_; }
static MinMaxAll *all() { return all_; } static MinMaxAll *all() { return all_; }
const char *asString() const { return name_; } const char *asString() const { return name_; }
int index() const { return index_; } int index() const { return index_; }