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"
TCL_INIT_FILES="../tcl/Util.tcl ../dcalc/DelayCalc.tcl ../tcl/Graph.tcl ../tcl/Liberty.tcl ../tcl/Link.tcl ../tcl/Network.tcl ../tcl/NetworkEdit.tcl ../parasitics/Parasitics.tcl ../tcl/Sdc.tcl ../sdf/Sdf.tcl ../tcl/Search.tcl ../tcl/Cmds.tcl ../tcl/Variables.tcl ../tcl/Sta.tcl ../tcl/Splash.tcl"
TCL_INIT_FILES="../tcl/Util.tcl ../dcalc/DelayCalc.tcl ../tcl/Graph.tcl ../tcl/Liberty.tcl ../tcl/Link.tcl ../tcl/Network.tcl ../tcl/NetworkEdit.tcl ../parasitics/Parasitics.tcl ../tcl/Sdc.tcl ../sdf/Sdf.tcl ../tcl/Search.tcl ../tcl/Cmds.tcl ../tcl/Variables.tcl ../tcl/Sta.tcl ../tcl/Power.tcl ../tcl/Splash.tcl"
if test "$TCL_INCLUDE"; then
STA_INCLUDE="$STA_INCLUDE -I$TCL_INCLUDE"

View File

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

View File

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

View File

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

View File

@ -50,6 +50,14 @@ public:
// return values
ArcDelay &gate_delay,
Slew &drvr_slew);
virtual float ceff(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap);
virtual void reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,

View File

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

View File

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

View File

@ -394,7 +394,7 @@ FindVertexDelays::copy()
{
// Copy StaState::arc_delay_calc_ because it needs separate state
// for each thread.
return new FindVertexDelays(graph_delay_calc1_, arc_delay_calc_->copy(), true);
return new FindVertexDelays(graph_delay_calc1_,arc_delay_calc_->copy(),true);
}
void
@ -1023,8 +1023,7 @@ GraphDelayCalc1::findDriverEdgeDelays(LibertyCell *drvr_cell,
DcalcAnalysisPtIterator ap_iter(this);
while (ap_iter.hasNext()) {
DcalcAnalysisPt *dcalc_ap = ap_iter.next();
const Pvt *pvt = sdc_->pvt(drvr_inst,
dcalc_ap->constraintMinMax());
const Pvt *pvt = sdc_->pvt(drvr_inst, dcalc_ap->constraintMinMax());
if (pvt == NULL)
pvt = dcalc_ap->operatingConditions();
TimingArcSetArcIterator *arc_iter = arc_set->timingArcIterator();
@ -1065,13 +1064,28 @@ GraphDelayCalc1::findDriverEdgeDelays(LibertyCell *drvr_cell,
return delay_changed;
}
float
GraphDelayCalc1::loadCap(const Pin *drvr_pin,
const TransRiseFall *drvr_tr,
const DcalcAnalysisPt *dcalc_ap) const
{
Parasitic *drvr_parasitic;
bool delete_parasitic;
arc_delay_calc_->findParasitic(drvr_pin, drvr_tr, dcalc_ap,
drvr_parasitic, delete_parasitic);
float load_cap = loadCap(drvr_pin, NULL, drvr_parasitic, drvr_tr, dcalc_ap);
arc_delay_calc_->finish(drvr_pin, drvr_tr, dcalc_ap,
drvr_parasitic, delete_parasitic);
return load_cap;
}
float
GraphDelayCalc1::loadCap(const Pin *drvr_pin,
Parasitic *drvr_parasitic,
const TransRiseFall *tr,
const DcalcAnalysisPt *dcalc_ap) const
{
return loadCap(drvr_pin, 0, drvr_parasitic, tr, dcalc_ap);
return loadCap(drvr_pin, NULL, drvr_parasitic, tr, dcalc_ap);
}
float
@ -1160,7 +1174,7 @@ GraphDelayCalc1::netCaps(const Pin *drvr_pin,
const MinMax *min_max = dcalc_ap->constraintMinMax();
// Find pin and external pin/wire capacitance.
sdc_->connectedCap(drvr_pin, tr, op_cond, corner, min_max,
pin_cap, wire_cap, fanout, has_set_load);
pin_cap, wire_cap, fanout, has_set_load);
}
}
@ -1602,10 +1616,12 @@ GraphDelayCalc1::findCheckEdgeDelays(Edge *edge,
arc_delay_calc->finish(related_out_pin, to_tr, dcalc_ap,
related_out_parasitic, delete_related);
}
ArcDelay check_delay = arc_delay_calc->checkDelay(cell, arc,
from_slew, to_slew,
related_out_cap,
pvt, dcalc_ap);
ArcDelay check_delay;
arc_delay_calc->checkDelay(cell, arc,
from_slew, to_slew,
related_out_cap,
pvt, dcalc_ap,
check_delay);
debugPrint1(debug_, "delay_calc", 3,
" check_delay = %s\n",
delayAsString(check_delay, units_));
@ -1727,6 +1743,54 @@ GraphDelayCalc1::isIdealClk(const Vertex *vertex) const
&& clks->size() > 0;
}
float
GraphDelayCalc1::ceff(Edge *edge,
TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap)
{
Vertex *from_vertex = edge->from(graph_);
Vertex *to_vertex = edge->to(graph_);
Pin *to_pin = to_vertex->pin();
Instance *inst = network_->instance(to_pin);
LibertyCell *cell = network_->libertyCell(inst);
TimingArcSet *arc_set = edge->timingArcSet();
float ceff = 0.0;
const Pvt *pvt = sdc_->pvt(inst, dcalc_ap->constraintMinMax());
if (pvt == NULL)
pvt = dcalc_ap->operatingConditions();
TransRiseFall *from_tr = arc->fromTrans()->asRiseFall();
TransRiseFall *to_tr = arc->toTrans()->asRiseFall();
if (from_tr && to_tr) {
const LibertyPort *related_out_port = arc_set->relatedOut();
const Pin *related_out_pin = 0;
if (related_out_port)
related_out_pin = network_->findPin(inst, related_out_port);
float related_out_cap = 0.0;
if (related_out_pin) {
Parasitic *related_out_parasitic;
bool delete_related;
arc_delay_calc_->findParasitic(related_out_pin, to_tr, dcalc_ap,
related_out_parasitic, delete_related);
related_out_cap = loadCap(related_out_pin, related_out_parasitic,
to_tr, dcalc_ap);
arc_delay_calc_->finish(related_out_pin, to_tr, dcalc_ap,
related_out_parasitic, delete_related);
}
Parasitic *to_parasitic;
bool delete_to_parasitic;
arc_delay_calc_->findParasitic(to_pin, to_tr, dcalc_ap,
to_parasitic, delete_to_parasitic);
const Slew &from_slew = edgeFromSlew(from_vertex, from_tr, edge, dcalc_ap);
float load_cap = loadCap(to_pin, to_parasitic, to_tr, dcalc_ap);
ceff = arc_delay_calc_->ceff(cell, arc,
from_slew, load_cap, to_parasitic,
related_out_cap, pvt, dcalc_ap);
arc_delay_calc_->finish(to_pin, to_tr, dcalc_ap,
to_parasitic, delete_to_parasitic);
}
return ceff;
}
////////////////////////////////////////////////////////////////
string *

View File

@ -51,6 +51,10 @@ public:
virtual float incrementalDelayTolerance();
virtual void setIncrementalDelayTolerance(float tol);
virtual void setObserver(DelayCalcObserver *observer);
// Load pin_cap + wire_cap.
virtual float loadCap(const Pin *drvr_pin,
const TransRiseFall *drvr_tr,
const DcalcAnalysisPt *dcalc_ap) const;
virtual void loadCap(const Pin *drvr_pin,
Parasitic *drvr_parasitic,
const TransRiseFall *tr,
@ -70,6 +74,9 @@ public:
float &wire_cap,
float &fanout,
bool &has_set_load) const;
float ceff(Edge *edge,
TimingArc *arc,
const DcalcAnalysisPt *dcalc_ap);
protected:
void seedInvalidDelays();

View File

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

View File

@ -60,13 +60,23 @@ public:
// Return values.
ArcDelay &wire_delay,
Slew &load_slew);
virtual ArcDelay checkDelay(const LibertyCell *cell,
TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap);
virtual void checkDelay(const LibertyCell *cell,
TimingArc *arc,
const Slew &from_slew,
const Slew &to_slew,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap,
// Return values.
ArcDelay &margin);
virtual float ceff(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,
float load_cap,
Parasitic *drvr_parasitic,
float related_out_cap,
const Pvt *pvt,
const DcalcAnalysisPt *dcalc_ap);
virtual void reportGateDelay(const LibertyCell *drvr_cell,
TimingArc *arc,
const Slew &in_slew,

View File

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

View File

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

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
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef STA_DELAY_H
#define STA_DELAY_H
// Define one of the following:
// Define DELAY_FLOAT to use the float definitions.
#define DELAY_FLOAT
// Define DELAY_FLOAT_CLASS to use the Delay class definitions.
// Define DELAY_FLOAT_CLASS to use the DelayClass definitions.
//#define DELAY_FLOAT_CLASS
// Define DELAY_NORMAL2 to use the DelayNormal2 definitions.
//#define DELAY_NORMAL2
#ifdef DELAY_FLOAT
#include "DelayFloat.hh"
#endif
@ -27,3 +35,91 @@
#ifdef DELAY_FLOAT_CLASS
#include "DelayFloatClass.hh"
#endif
#ifdef DELAY_NORMAL2
#include "DelayNormal2.hh"
#endif
namespace sta {
class Units;
class StaState;
typedef Delay ArcDelay;
typedef Delay Slew;
typedef Delay Arrival;
typedef Delay Required;
typedef Delay Slack;
void
initDelayConstants();
Delay
makeDelay(float delay,
float sigma_early,
float sigma_late);
float
delayAsFloat(const Delay &delay);
const char *
delayAsString(const Delay &delay,
const Units *units);
const char *
delayAsString(const Delay &delay,
const StaState *sta);
const char *
delayAsString(const Delay &delay,
const Units *units,
int digits);
// mean late+/early- sigma
// early_late = NULL returns mean.
float
delayMeanSigma(const Delay &delay,
const EarlyLate *early_late);
const char *
delayMeanSigmaString(const Delay &delay,
const EarlyLate *early_late,
const Units *units,
int digits);
const Delay &
delayInitValue(const MinMax *min_max);
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max);
bool
delayFuzzyZero(const Delay &delay);
bool
delayFuzzyEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLess(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLess(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool
delayFuzzyGreater(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool
delayFuzzyGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
float
delayRatio(const Delay &delay1,
const Delay &delay2);
} // namespace
#endif

View File

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

View File

@ -18,75 +18,22 @@
#define STA_DELAY_FLOAT_H
#include "MinMax.hh"
#include "Pool.hh"
// Delay values defined as floats.
namespace sta {
class Units;
class StaState;
typedef float Delay;
typedef Delay ArcDelay;
typedef Delay Slew;
typedef Delay Arrival;
typedef Delay Required;
typedef Delay Slack;
typedef Pool<float> DelayPool;
const Delay delay_zero = 0.0;
void initDelayConstants();
inline float delayAsFloat(const Delay &delay) { return delay; }
const char *
delayAsString(const Delay &delay,
Units *units);
const char *
delayAsString(const Delay &delay,
const StaState *sta);
const Delay &
delayInitValue(const MinMax *min_max);
bool
delayIsInitValue(const Delay &delay,
const MinMax *min_max);
bool
delayFuzzyZero(const Delay &delay);
bool
delayFuzzyEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLess(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyLessEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool delayFuzzyGreater(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2);
bool
delayFuzzyGreater(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool
delayFuzzyGreaterEqual(const Delay &delay1,
const Delay &delay2,
const MinMax *min_max);
bool
delayFuzzyLess(const Delay &delay1, const
Delay &delay2,
const MinMax *min_max);
float
delayRatio(const Delay &delay1,
const Delay &delay2);
inline Delay
makeDelay(float delay,
float,
float)
{
return delay;
}
} // namespace
#endif

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -287,6 +287,8 @@ LibertyReader::defineVisitors()
&LibertyReader::visitClockGatingIntegratedCell);
defineAttrVisitor("area", &LibertyReader::visitArea);
defineAttrVisitor("dont_use", &LibertyReader::visitDontUse);
defineAttrVisitor("is_macro", &LibertyReader::visitIsMacro);
defineAttrVisitor("is_pad", &LibertyReader::visitIsPad);
defineAttrVisitor("interface_timing", &LibertyReader::visitInterfaceTiming);
defineAttrVisitor("scaling_factors", &LibertyReader::visitScalingFactors);
@ -399,6 +401,8 @@ LibertyReader::defineVisitors()
&LibertyReader::endRiseFallPower);
defineGroupVisitor("rise_power", &LibertyReader::beginRisePower,
&LibertyReader::endRiseFallPower);
defineAttrVisitor("related_power_pin", &LibertyReader::visitRelatedPowerPin);
defineAttrVisitor("related_pg_pin", &LibertyReader::visitRelatedPgPin);
// AOCV attributes.
defineAttrVisitor("ocv_arc_depth", &LibertyReader::visitOcvArcDepth);
@ -417,6 +421,20 @@ LibertyReader::defineVisitors()
defineAttrVisitor("rf_type", &LibertyReader::visitRfType);
defineAttrVisitor("derate_type", &LibertyReader::visitDerateType);
defineAttrVisitor("path_type", &LibertyReader::visitPathType);
// POCV attributes.
defineGroupVisitor("ocv_sigma_cell_rise", &LibertyReader::beginOcvSigmaCellRise,
&LibertyReader::endOcvSigmaCell);
defineGroupVisitor("ocv_sigma_cell_fall", &LibertyReader::beginOcvSigmaCellFall,
&LibertyReader::endOcvSigmaCell);
defineGroupVisitor("ocv_sigma_rise_transition",
&LibertyReader::beginOcvSigmaRiseTransition,
&LibertyReader::endOcvSigmaTransition);
defineGroupVisitor("ocv_sigma_fall_transition",
&LibertyReader::beginOcvSigmaFallTransition,
&LibertyReader::endOcvSigmaTransition);
defineAttrVisitor("sigma_type", &LibertyReader::visitSigmaType);
defineAttrVisitor("cell_leakage_power", &LibertyReader::visitCellLeakagePower);
}
void
@ -535,6 +553,8 @@ LibertyReader::beginLibrary(LibertyGroup *group)
curr_scale_ = 1E-3F;
// Default is 1;
power_scale_ = 1;
// Default is fJ.
energy_scale_ = 1e-15;
library_->units()->timeUnit()->setScale(time_scale_);
library_->units()->capacitanceUnit()->setScale(cap_scale_);
@ -1720,7 +1740,11 @@ void
LibertyReader::endCell(LibertyGroup *group)
{
if (cell_) {
// Sequentials and leakage powers reference expressions outside of port definitions
// so they do not require LibertyFunc's.
makeCellSequentials();
// Parse functions defined inside of port groups that reference other ports
// and replace the references with the parsed expressions.
parseCellFuncs();
makeLeakagePowers();
finishPortGroups();
@ -2128,7 +2152,8 @@ TimingGroup::makeTableModels(LibertyReader *visitor)
TableModel *constraint = constraint_[tr_index];
TableModel *transition = transition_[tr_index];
if (cell || transition) {
models_[tr_index] = new GateTableModel(cell, transition);
models_[tr_index] = new GateTableModel(cell, delay_sigma_[tr_index],
transition, slew_sigma_[tr_index]);
if (timing_type_ == timing_type_clear
|| timing_type_ == timing_type_combinational
|| timing_type_ == timing_type_combinational_fall
@ -2142,11 +2167,10 @@ TimingGroup::makeTableModels(LibertyReader *visitor)
|| timing_type_ == timing_type_three_state_enable
|| timing_type_ == timing_type_three_state_enable_fall
|| timing_type_ == timing_type_three_state_enable_rise) {
const char *tr_name = tr == TransRiseFall::rise() ? "rise" : "fall";
if (transition == NULL)
visitor->libWarn(line_, "missing %s_transition.\n", tr_name);
visitor->libWarn(line_, "missing %s_transition.\n", tr->name());
if (cell == NULL)
visitor->libWarn(line_, "missing cell_%s.\n", tr_name);
visitor->libWarn(line_, "missing cell_%s.\n", tr->name());
}
}
if (constraint)
@ -2354,6 +2378,28 @@ LibertyReader::visitDontUse(LibertyAttr *attr)
}
}
void
LibertyReader::visitIsMacro(LibertyAttr *attr)
{
if (cell_) {
bool is_macro, exists;
getAttrBool(attr, is_macro, exists);
if (exists)
cell_->setIsMacro(is_macro);
}
}
void
LibertyReader::visitIsPad(LibertyAttr *attr)
{
if (cell_) {
bool is_pad, exists;
getAttrBool(attr, is_pad, exists);
if (exists)
cell_->setIsPad(is_pad);
}
}
void
LibertyReader::visitInterfaceTiming(LibertyAttr *attr)
{
@ -3705,6 +3751,7 @@ LibertyReader::beginTableModel(LibertyGroup *group,
beginTable(group, scale);
tr_ = tr;
scale_factor_type_ = scale_factor_type;
sigma_type_ = EarlyLateAll::all();
}
void
@ -4248,6 +4295,20 @@ LibertyReader::parseFunc(const char *func,
return parseFuncExpr(func, cell_, error_msg, report_);
}
EarlyLateAll *
LibertyReader::getAttrEarlyLate(LibertyAttr *attr)
{
const char *value = getAttrString(attr);
if (stringEq(value, "early"))
return EarlyLateAll::min();
else if (stringEq(value, "late"))
return EarlyLateAll::max();
else {
libWarn(attr, "unknown early/late value.\n");
return EarlyLateAll::all();
}
}
////////////////////////////////////////////////////////////////
void
@ -4356,7 +4417,7 @@ void
LibertyReader::beginFallPower(LibertyGroup *group)
{
if (internal_power_)
beginTableModel(group, TransRiseFall::fall(), power_scale_,
beginTableModel(group, TransRiseFall::fall(), energy_scale_,
scale_factor_internal_power);
}
@ -4364,7 +4425,7 @@ void
LibertyReader::beginRisePower(LibertyGroup *group)
{
if (internal_power_)
beginTableModel(group, TransRiseFall::rise(), power_scale_,
beginTableModel(group, TransRiseFall::rise(), energy_scale_,
scale_factor_internal_power);
}
@ -4378,6 +4439,26 @@ LibertyReader::endRiseFallPower(LibertyGroup *)
endTableModel();
}
void
LibertyReader::visitRelatedPowerPin(LibertyAttr *attr)
{
if (ports_) {
const char *related_power_pin = getAttrString(attr);
LibertyPortSeq::Iterator port_iter(ports_);
while (port_iter.hasNext()) {
LibertyPort *port = port_iter.next();
port->setRelatedPowerPin(stringCopy(related_power_pin));
}
}
}
void
LibertyReader::visitRelatedPgPin(LibertyAttr *attr)
{
if (internal_power_)
internal_power_->setRelatedPgPin(getAttrString(attr));
}
////////////////////////////////////////////////////////////////
void
@ -4438,7 +4519,7 @@ LibertyReader::beginOcvDerateFactors(LibertyGroup *group)
{
if (ocv_derate_) {
rf_type_ = TransRiseFallBoth::riseFall();
early_late_ = EarlyLateAll::all();
derate_type_ = EarlyLateAll::all();
path_type_ = path_type_clk_and_data;
beginTable(group, 1.0);
}
@ -4448,7 +4529,7 @@ void
LibertyReader::endOcvDerateFactors(LibertyGroup *)
{
if (ocv_derate_) {
MinMaxIterator el_iter(early_late_);
EarlyLateIterator el_iter(derate_type_);
while (el_iter.hasNext()) {
EarlyLate *early_late = el_iter.next();
TransRiseFallIterator tr_iter(rf_type_);
@ -4483,13 +4564,7 @@ LibertyReader::visitRfType(LibertyAttr *attr)
void
LibertyReader::visitDerateType(LibertyAttr *attr)
{
const char *derate_type = getAttrString(attr);
if (stringEq(derate_type, "early"))
early_late_ = EarlyLateAll::min();
else if (stringEq(derate_type, "late"))
early_late_ = EarlyLateAll::max();
else
libWarn(attr, "unknown derate type.\n");
derate_type_ = getAttrEarlyLate(attr);
}
void
@ -4508,6 +4583,92 @@ LibertyReader::visitPathType(LibertyAttr *attr)
////////////////////////////////////////////////////////////////
void
LibertyReader::beginOcvSigmaCellRise(LibertyGroup *group)
{
beginTimingTableModel(group, TransRiseFall::rise(), scale_factor_unknown);
}
void
LibertyReader::beginOcvSigmaCellFall(LibertyGroup *group)
{
beginTimingTableModel(group, TransRiseFall::fall(), scale_factor_unknown);
}
void
LibertyReader::endOcvSigmaCell(LibertyGroup *group)
{
if (table_) {
if (GateTableModel::checkAxes(table_)) {
TableModel *table_model = new TableModel(table_, scale_factor_type_, tr_);
if (sigma_type_ == EarlyLateAll::all()) {
timing_->setDelaySigma(tr_, EarlyLate::min(), table_model);
timing_->setDelaySigma(tr_, EarlyLate::max(), table_model);
}
else
timing_->setDelaySigma(tr_, sigma_type_->asMinMax(), table_model);
}
else {
libWarn(group, "unsupported model axis.\n");
delete table_;
}
}
endTableModel();
}
void
LibertyReader::beginOcvSigmaRiseTransition(LibertyGroup *group)
{
beginTimingTableModel(group, TransRiseFall::rise(), scale_factor_unknown);
}
void
LibertyReader::beginOcvSigmaFallTransition(LibertyGroup *group)
{
beginTimingTableModel(group, TransRiseFall::fall(), scale_factor_unknown);
}
void
LibertyReader::endOcvSigmaTransition(LibertyGroup *group)
{
if (table_) {
if (GateTableModel::checkAxes(table_)) {
TableModel *table_model = new TableModel(table_, scale_factor_type_, tr_);
if (sigma_type_ == EarlyLateAll::all()) {
timing_->setSlewSigma(tr_, EarlyLate::min(), table_model);
timing_->setSlewSigma(tr_, EarlyLate::max(), table_model);
}
else
timing_->setSlewSigma(tr_, sigma_type_->asMinMax(), table_model);
}
else {
libWarn(group, "unsupported model axis.\n");
delete table_;
}
}
endTableModel();
}
void
LibertyReader::visitSigmaType(LibertyAttr *attr)
{
sigma_type_ = getAttrEarlyLate(attr);
}
void
LibertyReader::visitCellLeakagePower(LibertyAttr *attr)
{
if (cell_) {
float value;
bool exists;
getAttrFloat(attr, value, exists);
if (exists)
cell_->setLeakagePower(value * power_scale_);
}
}
////////////////////////////////////////////////////////////////
LibertyFunc::LibertyFunc(const char *expr,
FuncExpr *&func_ref,
bool invert,
@ -4672,6 +4833,14 @@ TimingGroup::TimingGroup(int line) :
intrinsic_exists_[tr_index] = false;
resistance_[tr_index] = 0.0F;
resistance_exists_[tr_index] = false;
MinMaxIterator el_iter;
while (el_iter.hasNext()) {
EarlyLate *early_late = el_iter.next();
int el_index = early_late->index();
delay_sigma_[tr_index][el_index] = NULL;
slew_sigma_[tr_index][el_index] = NULL;
}
}
}
@ -4766,7 +4935,23 @@ TimingGroup::setTransition(TransRiseFall *tr,
transition_[tr->index()] = model;
}
////////////////////////////////////////////////////////////////
void
TimingGroup::setDelaySigma(TransRiseFall *tr,
EarlyLate *early_late,
TableModel *model)
{
delay_sigma_[tr->index()][early_late->index()] = model;
}
void
TimingGroup::setSlewSigma(TransRiseFall *tr,
EarlyLate *early_late,
TableModel *model)
{
slew_sigma_[tr->index()][early_late->index()] = model;
}
////////////////////////////////////////////////////////////////
InternalPowerGroup::InternalPowerGroup(int line) :
InternalPowerAttrs(),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -40,29 +40,19 @@ TimingArcAttrs::TimingArcAttrs() :
sdf_cond_end_(NULL),
mode_name_(NULL),
mode_value_(NULL),
ocv_arc_depth_(0.0)
ocv_arc_depth_(0.0),
models_{NULL, NULL},
model_refs_{false, false}
{
TransRiseFallIterator tr_iter;
while (tr_iter.hasNext()) {
TransRiseFall *tr = tr_iter.next();
int tr_index = tr->index();
models_[tr_index] = NULL;
model_refs_[tr_index] = false;
}
}
TimingArcAttrs::~TimingArcAttrs()
{
if (sdf_cond_)
stringDelete(sdf_cond_);
if (sdf_cond_start_)
stringDelete(sdf_cond_start_);
if (sdf_cond_end_)
stringDelete(sdf_cond_end_);
if (mode_name_)
stringDelete(mode_name_);
if (mode_value_)
stringDelete(mode_value_);
stringDelete(sdf_cond_);
stringDelete(sdf_cond_start_);
stringDelete(sdf_cond_end_);
stringDelete(mode_name_);
stringDelete(mode_value_);
}
void
@ -162,8 +152,9 @@ TimingArcSet::TimingArcSet(LibertyCell *cell,
is_cond_default_(false),
sdf_cond_start_(NULL),
sdf_cond_end_(NULL),
mode_name_(NULL),
mode_value_(NULL),
mode_name_(stringCopy(attrs->modeName())),
mode_value_(stringCopy(attrs->modeValue())),
ocv_arc_depth_(attrs->ocvArcDepth()),
index_(0),
is_disabled_constraint_(false)
{
@ -177,14 +168,6 @@ TimingArcSet::TimingArcSet(LibertyCell *cell,
if (sdf_cond_end)
sdf_cond_end_ = stringCopy(sdf_cond_end);
const char *mode_name = attrs->modeName();
if (mode_name)
mode_name_ = stringCopy(mode_name);
const char *mode_value = attrs->modeValue();
if (mode_value)
mode_value_ = stringCopy(mode_value);
ocv_arc_depth_ = attrs->ocvArcDepth();
init(cell);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -419,10 +419,10 @@ SdfWriter::writeArcDelays(Edge *edge)
TimingArc *arc = arc_iter->next();
TransRiseFall *tr = arc->toTrans()->asRiseFall();
ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_);
delays.setValue(tr, MinMax::min(), min_delay);
delays.setValue(tr, MinMax::min(), delayAsFloat(min_delay));
ArcDelay max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_);
delays.setValue(tr, MinMax::max(), max_delay);
delays.setValue(tr, MinMax::max(), delayAsFloat(max_delay));
}
delete arc_iter;
@ -682,7 +682,7 @@ SdfWriter::writeCheck(Edge *edge,
ArcDelay min_delay = graph_->arcDelay(edge, arc, arc_delay_min_index_);
ArcDelay max_delay = graph_->arcDelay(edge, arc, arc_delay_max_index_);
writeSdfTuple(min_delay, max_delay);
writeSdfTuple(delayAsFloat(min_delay), delayAsFloat(max_delay));
gzprintf(stream_, ")\n");
}

View File

@ -93,14 +93,14 @@ float
ClkSkew::srcLatency(StaState *sta)
{
Arrival src_arrival = src_path_.arrival(sta);
return src_arrival - src_path_.clkEdge(sta)->time();
return delayAsFloat(src_arrival) - src_path_.clkEdge(sta)->time();
}
float
ClkSkew::tgtLatency(StaState *sta)
{
Arrival tgt_arrival = tgt_path_.arrival(sta);
return tgt_arrival - tgt_path_.clkEdge(sta)->time();
return delayAsFloat(tgt_arrival) - tgt_path_.clkEdge(sta)->time();
}
float

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

@ -68,6 +68,11 @@ public:
virtual void copyState(const StaState *sta);
// Reset to virgin state.
void clear();
// When enabled, non-critical path arrivals are pruned to improve
// run time and reduce memory. The side-effect is that slacks for
// non-critical paths on intermediate pins may be incorrect.
bool crprPathPruningEnabled() const;
void setCrprpathPruningEnabled(bool enabled);
// Report unconstrained paths.
bool reportUnconstrainedPaths() const { return report_unconstrained_paths_; }
void setReportUnconstrainedPaths(bool report);
@ -132,7 +137,7 @@ public:
const MinMax *min_max,
const PathAnalysisPt *path_ap) const;
// Clock arrival at the path source/launch point.
float pathClkPathArrival(const Path *path) const;
Arrival pathClkPathArrival(const Path *path) const;
PathGroup *pathGroup(const PathEnd *path_end) const;
void deletePathGroups();
@ -571,6 +576,7 @@ protected:
VisitPathEnds *visit_path_ends_;
GatedClk *gated_clk_;
Crpr *crpr_;
bool crpr_path_pruning_enabled_;
Genclks *genclks_;
};

View File

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

View File

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

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 } {
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]
while {[$iter has_next]} {
set arc [$iter next]
set delays [$edge arc_delays $arc]
set delays_fmt [format_times $delays $sta_report_default_digits]
set delays [$edge arc_delay_strings $arc $sta_report_default_digits]
set delays_fmt [format_delays $delays]
set disable_reason ""
if { [timing_arc_disabled $edge $arc] } {
set disable_reason " disabled"
@ -144,6 +144,18 @@ proc format_times { values digits } {
return $result
}
# Separate delay list elements with colons.
proc format_delays { values } {
set result ""
foreach value $values {
if { $result != "" } {
append result ":"
}
append result $value
}
return $result
}
proc edge_disable_reason { edge } {
set disables ""
if [$edge is_disabled_constraint] {

View File

@ -33,46 +33,5 @@ proc read_liberty { args } {
read_liberty_cmd $filename $corner $min_max $infer_latches
}
################################################################
define_hidden_cmd_args "report_lib_cell_power" {lib_cell}
proc report_lib_cell_power { args } {
global sta_report_default_digits
check_argc_eq3 "report_internal_power" $args
set cells [get_lib_cells [lindex $args 0]]
set slew [time_ui_sta [lindex $args 1]]
set cap [capacitance_ui_sta [lindex $args 2]]
foreach cell $cells {
puts "[$cell name] Leakage Power"
set leakage_iter [$cell leakage_power_iterator]
while {[$leakage_iter has_next]} {
set leakage [$leakage_iter next]
puts "[format_power [$leakage power] 5] [$leakage when]"
}
$leakage_iter finish
puts "[$cell name] Internal Power"
set internal_iter [$cell internal_power_iterator]
while {[$internal_iter has_next]} {
set internal [$internal_iter next]
set port_name [[$internal port] name]
set related_port [$internal related_port]
if { $related_port != "NULL" } {
set related_port_name [$related_port name]
} else {
set related_port_name ""
}
set digits $sta_report_default_digits
set rise [format_power [$internal power rise $slew $cap] $digits]
set fall [format_power [$internal power fall $slew $cap] $digits]
puts "$port_name $related_port_name [rise_short_name] $rise [fall_short_name] $fall [$internal when]"
}
$internal_iter finish
}
}
# sta namespace end
}

View File

@ -251,10 +251,11 @@ define_cmd_args "report_net" \
proc_redirect report_net {
global sta_report_default_digits
parse_key_args "report_net" args keys {-digits -significant_digits} \
parse_key_args "report_net" args keys {-corner -digits -significant_digits} \
flags {-connections -verbose -hier_pins}
check_argc_eq1 "report_net" $args
set corner [parse_corner keys]
set digits $sta_report_default_digits
if { [info exists keys(-digits)] } {
set digits $keys(-digits)
@ -269,13 +270,13 @@ proc_redirect report_net {
set net_path [lindex $args 0]
set net [find_net $net_path]
if { $net != "NULL" } {
report_net1 $net $connections $verbose $hier_pins $digits
report_net1 $net $connections $verbose $hier_pins $corner $digits
} else {
set pin [find_pin $net_path]
if { $pin != "NULL" } {
set net [$pin net]
if { $net != "NULL" } {
report_net1 $net $connections $verbose $hier_pins $digits
report_net1 $net $connections $verbose $hier_pins $corner $digits
} else {
sta_error "net $net_path not found."
}
@ -287,27 +288,27 @@ proc_redirect report_net {
proc report_net_ { net } {
global sta_report_default_digits
report_net1 $net 1 1 1 $sta_report_default_digits
report_net1 $net 1 1 1 $corner $sta_report_default_digits
}
proc report_net1 { net connections verbose hier_pins digits } {
proc report_net1 { net connections verbose hier_pins corner digits } {
puts "Net [$net path_name]"
if {$connections} {
set pins [net_connected_pins_sorted $net]
if {$verbose} {
report_net_caps $net $pins $digits
report_net_caps $net $pins $corner $digits
}
puts "Driver pins"
report_net_pins $pins "is_driver" $verbose $digits
report_net_pins $pins "is_driver" $verbose $corner $digits
puts ""
puts "Load pins"
report_net_pins $pins "is_load" $verbose $digits
report_net_pins $pins "is_load" $verbose $corner $digits
if {$hier_pins} {
puts ""
puts "Hierarchical pins"
report_net_pins $pins "is_hierarchical" $verbose $digits
report_net_pins $pins "is_hierarchical" $verbose $corner $digits
}
report_net_other_pins $pins $verbose $digits
report_net_other_pins $pins $verbose $corner $digits
}
}
@ -323,8 +324,7 @@ proc net_connected_pins_sorted { net } {
return $pins
}
proc report_net_caps { net pins digits } {
set corner [default_corner]
proc report_net_caps { net pins corner digits } {
report_net_cap $net "Pin" "pin_capacitance" $corner $digits
report_net_cap $net "Wire" "wire_capacitance" $corner $digits
report_net_cap $net "Total" "capacitance" $corner $digits
@ -356,15 +356,15 @@ proc report_net_cap { net caption cap_msg corner digits } {
puts " $caption capacitance: [capacitances_str $cap_r_min $cap_r_max $cap_f_min $cap_f_max $digits]"
}
proc report_net_pins { pins pin_pred verbose digits } {
proc report_net_pins { pins pin_pred verbose corner digits } {
foreach pin $pins {
if {[$pin $pin_pred]} {
report_net_pin $pin $verbose $digits
report_net_pin $pin $verbose $corner $digits
}
}
}
proc report_net_other_pins { pins verbose digits } {
proc report_net_other_pins { pins verbose corner digits } {
set header 0
foreach pin $pins {
if { !([$pin is_driver] || [$pin is_load] || [$pin is_hierarchical]) } {
@ -373,12 +373,12 @@ proc report_net_other_pins { pins verbose digits } {
puts "Other pins"
set header 1
}
report_net_pin $pin $verbose $digits
report_net_pin $pin $verbose $corner $digits
}
}
}
proc report_net_pin { pin verbose digits } {
proc report_net_pin { pin verbose corner digits } {
if [$pin is_leaf] {
set cell_name [[[$pin instance] cell] name]
puts -nonewline " [$pin path_name] [$pin direction] ($cell_name)"

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" \
{[-rise] [-fall] [-max] [-min] [-corner corner] [-subtract_pin_load]\
{[-rise] [-fall] [-max] [-min] [-subtract_pin_load]\
[-pin_load] [-wire_load] capacitance objects}
proc set_load { args } {
parse_key_args "set_load" args keys {} \
flags {-rise -fall -min -max -corner -subtract_pin_load \
-pin_load -wire_load}
parse_key_args "set_load" args keys {-corner} \
flags {-rise -fall -min -max -subtract_pin_load -pin_load -wire_load}\
check_argc_eq2 "set_load" $args
set pin_load [info exists flags(-pin_load)]
set wire_load [info exists flags(-wire_load)]
set subtract_pin_load [info exists flags(-subtract_pin_load)]
set corner [parse_corner keys]
set corner [parse_corner_or_default keys]
set min_max [parse_min_max_all_check_flags flags]
set tr [parse_rise_fall_flags flags]

View File

@ -25,7 +25,42 @@ namespace eval sta {
define_cmd_args "report_arrival" {pin}
proc report_arrival { pin } {
report_wrt_clks $pin "arrivals_clk"
report_delays_wrt_clks $pin "arrivals_clk_delays"
}
proc report_delays_wrt_clks { pin_arg what } {
set pin [get_port_pin_error "pin" $pin_arg]
foreach vertex [$pin vertices] {
if { $vertex != "NULL" } {
report_delays_wrt_clk $vertex $what "NULL" "rise"
report_delays_wrt_clk $vertex $what [default_arrival_clock] "rise"
set clk_iter [clock_iterator]
while {[$clk_iter has_next]} {
set clk [$clk_iter next]
report_delays_wrt_clk $vertex $what $clk "rise"
report_delays_wrt_clk $vertex $what $clk "fall"
}
$clk_iter finish
}
}
}
proc report_delays_wrt_clk { vertex what clk clk_tr } {
global sta_report_default_digits
set rise [$vertex $what rise $clk $clk_tr $sta_report_default_digits]
set fall [$vertex $what fall $clk $clk_tr $sta_report_default_digits]
# Filter INF/-INF arrivals.
if { !([delays_are_inf $rise] && [delays_are_inf $fall]) } {
set rise_fmt [format_delays $rise]
set fall_fmt [format_delays $fall]
if {$clk != "NULL"} {
set clk_str " ([$clk name] [rise_fall_short_name $clk_tr])"
} else {
set clk_str ""
}
puts "$clk_str r $rise_fmt f $fall_fmt"
}
}
proc report_wrt_clks { pin_arg what } {
@ -82,6 +117,16 @@ proc times_are_inf { times } {
return 1
}
proc delays_are_inf { delays } {
foreach delay $delays {
if { !([string match "INF*" $delay] \
|| [string match "-INF*" $delay]) } {
return 0
}
}
return 1
}
################################################################
# Note that -all and -tags are intentionally "hidden".
@ -221,7 +266,7 @@ proc parse_report_path_options { cmd args_var default_format
define_cmd_args "report_required" {pin}
proc report_required { pin } {
report_wrt_clks $pin "requireds_clk"
report_delays_wrt_clks $pin "requireds_clk_delays"
}
################################################################
@ -229,7 +274,7 @@ proc report_required { pin } {
define_cmd_args "report_slack" {pin}
proc report_slack { pin } {
report_wrt_clks $pin "slacks_clk"
report_delays_wrt_clks $pin "slacks_clk_delays"
}
################################################################

View File

@ -49,8 +49,6 @@
#include "Transition.hh"
#include "TimingRole.hh"
#include "TimingArc.hh"
#include "InternalPower.hh"
#include "LeakagePower.hh"
#include "EquivCells.hh"
#include "Liberty.hh"
#include "Network.hh"
@ -77,6 +75,7 @@
#include "SearchPred.hh"
#include "PathAnalysisPt.hh"
#include "ReportPath.hh"
#include "Power.hh"
#include "Sta.hh"
namespace sta {
@ -693,7 +692,10 @@ edgeDelayProperty(Edge *edge,
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
ArcDelay arc_delay = sta->arcDelay(edge, arc, dcalc_ap);
if (!delay_exists
|| min_max->compare(arc_delay, delay))
|| ((min_max == MinMax::max()
&& arc_delay > delay)
|| (min_max == MinMax::min()
&& arc_delay < delay)))
delay = arc_delay;
}
}
@ -822,6 +824,16 @@ findEndpoints()
return pins;
}
void
pushPowerResultFloats(PowerResult &power,
TmpFloatSeq *floats)
{
floats->push_back(power.internal());
floats->push_back(power.switching());
floats->push_back(power.leakage());
floats->push_back(power.total());
}
////////////////////////////////////////////////////////////////
void
@ -1510,11 +1522,11 @@ using namespace sta;
%typemap(in) EarlyLate* {
int length;
char *arg = Tcl_GetStringFromObj($input, &length);
MinMax *min_max = MinMax::find(arg);
if (min_max)
$1 = min_max;
EarlyLate *early_late = EarlyLate::find(arg);
if (early_late)
$1 = early_late;
else {
tclError(interp, "Error: %s not min or max.", arg);
tclError(interp, "Error: %s not early/min or late/max.", arg);
return TCL_ERROR;
}
}
@ -1523,11 +1535,11 @@ using namespace sta;
%typemap(in) EarlyLateAll* {
int length;
char *arg = Tcl_GetStringFromObj($input, &length);
MinMaxAll *min_max = MinMaxAll::find(arg);
if (min_max)
$1 = min_max;
EarlyLateAll *early_late = EarlyLateAll::find(arg);
if (early_late)
$1 = early_late;
else {
tclError(interp, "Error: %s not min, max or min_max.", arg);
tclError(interp, "Error: %s not early/min, late/max or early_late/min_max.", arg);
return TCL_ERROR;
}
}
@ -1735,26 +1747,6 @@ using namespace sta;
Tcl_SetObjResult(interp, obj);
}
%typemap(out) InternalPower* {
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
Tcl_SetObjResult(interp, obj);
}
%typemap(out) LibertyCellInternalPowerIterator* {
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
Tcl_SetObjResult(interp, obj);
}
%typemap(out) LeakagePower* {
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
Tcl_SetObjResult(interp, obj);
}
%typemap(out) LibertyCellLeakagePowerIterator* {
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
Tcl_SetObjResult(interp, obj);
}
%typemap(out) CellTimingArcSetIterator* {
Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false);
Tcl_SetObjResult(interp, obj);
@ -2009,34 +2001,6 @@ private:
~CellTimingArcSetIterator();
};
class InternalPower
{
private:
InternalPower();
~InternalPower();
};
class LibertyCellInternalPowerIterator
{
private:
LibertyCellInternalPowerIterator();
~LibertyCellInternalPowerIterator();
};
class LeakagePower
{
private:
LeakagePower();
~LeakagePower();
};
class LibertyCellLeakagePowerIterator
{
private:
LibertyCellLeakagePowerIterator();
~LibertyCellLeakagePowerIterator();
};
class TimingArcSetArcIterator
{
private:
@ -4814,6 +4778,50 @@ report_slew_limit_verbose(Pin *pin,
Sta::sta()->reportSlewLimitVerbose(pin, corner, min_max);
}
////////////////////////////////////////////////////////////////
TmpFloatSeq *
design_power(const Corner *corner)
{
PowerResult total, sequential, combinational, macro, pad;
Sta::sta()->power(corner, total, sequential, combinational, macro, pad);
FloatSeq *floats = new FloatSeq;
pushPowerResultFloats(total, floats);
pushPowerResultFloats(sequential, floats);
pushPowerResultFloats(combinational, floats);
pushPowerResultFloats(macro, floats);
pushPowerResultFloats(pad, floats);
return floats;
}
TmpFloatSeq *
instance_power(Instance *inst,
const Corner *corner)
{
PowerResult power;
Sta::sta()->power(inst, corner, power);
FloatSeq *floats = new FloatSeq;
floats->push_back(power.switching());
floats->push_back(power.internal());
floats->push_back(power.leakage());
floats->push_back(power.total());
return floats;
}
float
power_default_signal_toggle_rate()
{
return Sta::sta()->power()->defaultSignalToggleRate();
}
void
set_power_default_signal_toggle_rate(float rate)
{
return Sta::sta()->power()->setDefaultSignalToggleRate(rate);
}
////////////////////////////////////////////////////////////////
EdgeSeq *
disabled_edges_sorted()
{
@ -5339,6 +5347,7 @@ find_cells_matching(const char *pattern,
%extend LibertyLibrary {
const char *name() { return self->name(); }
const char *filename() { return self->filename(); }
const char *object_name() { return self->name(); }
LibertyCell *
@ -5456,12 +5465,6 @@ liberty_port_iterator() { return self->libertyPortIterator(); }
CellTimingArcSetIterator *
timing_arc_set_iterator() { return self->timingArcSetIterator(); }
LibertyCellInternalPowerIterator *
internal_power_iterator() { return self->internalPowerIterator(); }
LibertyCellLeakagePowerIterator *
leakage_power_iterator() { return self->leakagePowerIterator(); }
} // LibertyCell methods
%extend CellPortIterator {
@ -5594,61 +5597,6 @@ TimingArc *next() { return self->next(); }
void finish() { delete self; }
}
%extend InternalPower {
LibertyPort *port() { return self->port(); }
LibertyPort *related_port() { return self->relatedPort(); }
const char *
when()
{
FuncExpr *when = self->when();
if (when)
return when->asString();
else
return "";
}
float
power(TransRiseFall *tr,
float in_slew,
float load_cap)
{
Sta *sta = Sta::sta();
Corner *corner = sta->corners()->defaultCorner();
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max());
const Pvt *pvt = dcalc_ap->operatingConditions();
return self->power(tr, pvt, in_slew, load_cap);
}
} // InternalPower methods
%extend LibertyCellInternalPowerIterator {
bool has_next() { return self->hasNext(); }
InternalPower *next() { return self->next(); }
void finish() { delete self; }
}
%extend LeakagePower {
float power() { return self->power(); }
const char *
when()
{
FuncExpr *when = self->when();
if (when)
return when->asString();
else
return "";
}
} // LeakagePower methods
%extend LibertyCellLeakagePowerIterator {
bool has_next() { return self->hasNext(); }
LeakagePower *next() { return self->next(); }
void finish() { delete self; }
}
%extend Instance {
const char *name() { return cmdLinkedNetwork()->name(self); }
const char *object_name() { return cmdLinkedNetwork()->pathName(self); }
@ -5954,11 +5902,33 @@ arrivals_clk(const TransRiseFall *tr,
PathAnalysisPtIterator ap_iter(sta);
while (ap_iter.hasNext()) {
PathAnalysisPt *path_ap = ap_iter.next();
floats->push_back(delayAsFloat(sta->vertexArrival(self, tr, clk_edge, path_ap)));
floats->push_back(delayAsFloat(sta->vertexArrival(self, tr, clk_edge,
path_ap)));
}
return floats;
}
StringSeq *
arrivals_clk_delays(const TransRiseFall *tr,
Clock *clk,
const TransRiseFall *clk_tr,
int digits)
{
Sta *sta = Sta::sta();
StringSeq *arrivals = new StringSeq;
const ClockEdge *clk_edge = NULL;
if (clk)
clk_edge = clk->edge(clk_tr);
PathAnalysisPtIterator ap_iter(sta);
while (ap_iter.hasNext()) {
PathAnalysisPt *path_ap = ap_iter.next();
arrivals->push_back(delayAsString(sta->vertexArrival(self, tr, clk_edge,
path_ap),
sta->units(), digits));
}
return arrivals;
}
TmpFloatSeq *
requireds_clk(const TransRiseFall *tr,
Clock *clk,
@ -5972,11 +5942,33 @@ requireds_clk(const TransRiseFall *tr,
PathAnalysisPtIterator ap_iter(sta);
while (ap_iter.hasNext()) {
PathAnalysisPt *path_ap = ap_iter.next();
floats->push_back(delayAsFloat(sta->vertexRequired(self,tr,clk_edge,path_ap)));
floats->push_back(delayAsFloat(sta->vertexRequired(self, tr, clk_edge,
path_ap)));
}
return floats;
}
StringSeq *
requireds_clk_delays(const TransRiseFall *tr,
Clock *clk,
const TransRiseFall *clk_tr,
int digits)
{
Sta *sta = Sta::sta();
StringSeq *requireds = new StringSeq;
const ClockEdge *clk_edge = NULL;
if (clk)
clk_edge = clk->edge(clk_tr);
PathAnalysisPtIterator ap_iter(sta);
while (ap_iter.hasNext()) {
PathAnalysisPt *path_ap = ap_iter.next();
requireds->push_back(delayAsString(sta->vertexRequired(self, tr, clk_edge,
path_ap),
sta->units(), digits));
}
return requireds;
}
TmpFloatSeq *
slacks(TransRiseFall *tr)
{
@ -6004,11 +5996,33 @@ slacks_clk(const TransRiseFall *tr,
PathAnalysisPtIterator ap_iter(sta);
while (ap_iter.hasNext()) {
PathAnalysisPt *path_ap = ap_iter.next();
floats->push_back(delayAsFloat(sta->vertexSlack(self, tr, clk_edge, path_ap)));
floats->push_back(delayAsFloat(sta->vertexSlack(self, tr, clk_edge,
path_ap)));
}
return floats;
}
StringSeq *
slacks_clk_delays(const TransRiseFall *tr,
Clock *clk,
const TransRiseFall *clk_tr,
int digits)
{
Sta *sta = Sta::sta();
StringSeq *slacks = new StringSeq;
const ClockEdge *clk_edge = NULL;
if (clk)
clk_edge = clk->edge(clk_tr);
PathAnalysisPtIterator ap_iter(sta);
while (ap_iter.hasNext()) {
PathAnalysisPt *path_ap = ap_iter.next();
slacks->push_back(delayAsString(sta->vertexSlack(self, tr, clk_edge,
path_ap),
sta->units(), digits));
}
return slacks;
}
VertexPathIterator *
path_iterator(const TransRiseFall *tr,
const MinMax *min_max)
@ -6070,6 +6084,21 @@ arc_delays(TimingArc *arc)
return floats;
}
StringSeq *
arc_delay_strings(TimingArc *arc,
int digits)
{
Sta *sta = Sta::sta();
StringSeq *delays = new StringSeq;
DcalcAnalysisPtIterator ap_iter(sta);
while (ap_iter.hasNext()) {
DcalcAnalysisPt *dcalc_ap = ap_iter.next();
delays->push_back(delayAsString(sta->arcDelay(self, arc, dcalc_ap),
sta->units(), digits));
}
return delays;
}
bool
delay_annotated(TimingArc *arc,
const Corner *corner,
@ -6085,7 +6114,7 @@ arc_delay(TimingArc *arc,
const MinMax *min_max)
{
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
return Sta::sta()->arcDelay(self, arc, dcalc_ap);
return delayAsFloat(Sta::sta()->arcDelay(self, arc, dcalc_ap));
}
const char *

View File

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

View File

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