diff --git a/configure.ac b/configure.ac index af6a0969..ac18ea6e 100644 --- a/configure.ac +++ b/configure.ac @@ -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" diff --git a/dcalc/ArcDelayCalc.hh b/dcalc/ArcDelayCalc.hh index 15c31429..5ddb9bc4 100644 --- a/dcalc/ArcDelayCalc.hh +++ b/dcalc/ArcDelayCalc.hh @@ -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, diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc index 8c65e2d1..637a8780 100644 --- a/dcalc/ArnoldiDelayCalc.cc +++ b/dcalc/ArnoldiDelayCalc.cc @@ -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;jn;j++) { rr = delay_work_get_residues(D,j); diff --git a/dcalc/DmpCeff.cc b/dcalc/DmpCeff.cc index f7014031..5a8a94dc 100644 --- a/dcalc/DmpCeff.cc +++ b/dcalc/DmpCeff.cc @@ -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(in_slew_), static_cast(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((c1 + c2) * .75); float cap2 = cap1 * 1.1F; float in_slew1 = static_cast(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 diff --git a/dcalc/DmpCeff.hh b/dcalc/DmpCeff.hh index d984805c..0c033519 100644 --- a/dcalc/DmpCeff.hh +++ b/dcalc/DmpCeff.hh @@ -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, diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 232b5912..b07e87db 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -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 *, diff --git a/dcalc/GraphDelayCalc.hh b/dcalc/GraphDelayCalc.hh index 9b1a713d..b1e438f7 100644 --- a/dcalc/GraphDelayCalc.hh +++ b/dcalc/GraphDelayCalc.hh @@ -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 diff --git a/dcalc/GraphDelayCalc1.cc b/dcalc/GraphDelayCalc1.cc index 256ecd38..c8a1ad75 100644 --- a/dcalc/GraphDelayCalc1.cc +++ b/dcalc/GraphDelayCalc1.cc @@ -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 * diff --git a/dcalc/GraphDelayCalc1.hh b/dcalc/GraphDelayCalc1.hh index bbbd91aa..b329abc1 100644 --- a/dcalc/GraphDelayCalc1.hh +++ b/dcalc/GraphDelayCalc1.hh @@ -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(); diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc index caa5cd0f..a6174d63 100644 --- a/dcalc/LumpedCapDelayCalc.cc +++ b/dcalc/LumpedCapDelayCalc.cc @@ -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 diff --git a/dcalc/LumpedCapDelayCalc.hh b/dcalc/LumpedCapDelayCalc.hh index 8f9145c4..abea6e9e 100644 --- a/dcalc/LumpedCapDelayCalc.hh +++ b/dcalc/LumpedCapDelayCalc.hh @@ -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, diff --git a/dcalc/UnitDelayCalc.cc b/dcalc/UnitDelayCalc.cc index 1296da05..31363819 100644 --- a/dcalc/UnitDelayCalc.cc +++ b/dcalc/UnitDelayCalc.cc @@ -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 diff --git a/dcalc/UnitDelayCalc.hh b/dcalc/UnitDelayCalc.hh index 7e006651..3fa1aeb4 100644 --- a/dcalc/UnitDelayCalc.hh +++ b/dcalc/UnitDelayCalc.hh @@ -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, diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt index 89dc8aa0..048d53af 100644 Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ diff --git a/graph/Delay.cc b/graph/Delay.cc new file mode 100644 index 00000000..5f4ca7f9 --- /dev/null +++ b/graph/Delay.cc @@ -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 . + +#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 diff --git a/graph/Delay.hh b/graph/Delay.hh index dfbe1573..159ca218 100644 --- a/graph/Delay.hh +++ b/graph/Delay.hh @@ -14,12 +14,20 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#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 diff --git a/graph/DelayFloat.cc b/graph/DelayFloat.cc index bbc5fcf1..1ab8b4b2 100644 --- a/graph/DelayFloat.cc +++ b/graph/DelayFloat.cc @@ -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 diff --git a/graph/DelayFloat.hh b/graph/DelayFloat.hh index bce126c6..071e8aa3 100644 --- a/graph/DelayFloat.hh +++ b/graph/DelayFloat.hh @@ -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 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 diff --git a/graph/DelayFloatClass.cc b/graph/DelayFloatClass.cc index fa4081b3..d420184e 100644 --- a/graph/DelayFloatClass.cc +++ b/graph/DelayFloatClass.cc @@ -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 diff --git a/graph/DelayFloatClass.hh b/graph/DelayFloatClass.hh index 7ffa8208..028ebd64 100644 --- a/graph/DelayFloatClass.hh +++ b/graph/DelayFloatClass.hh @@ -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 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 diff --git a/graph/DelayNormal2.cc b/graph/DelayNormal2.cc new file mode 100644 index 00000000..7a5218a9 --- /dev/null +++ b/graph/DelayNormal2.cc @@ -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 . + +#include // 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 diff --git a/graph/DelayNormal2.hh b/graph/DelayNormal2.hh new file mode 100644 index 00000000..7f320be0 --- /dev/null +++ b/graph/DelayNormal2.hh @@ -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 . + +#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 diff --git a/graph/Graph.cc b/graph/Graph.cc index df30bf0c..53b91b00 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -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; } diff --git a/graph/Graph.hh b/graph/Graph.hh index e2651f5f..794a5113 100644 --- a/graph/Graph.hh +++ b/graph/Graph.hh @@ -40,6 +40,7 @@ enum VertexColor { vertex_color_black }; +typedef Pool DelayPool; typedef Pool VertexPool; typedef Pool EdgePool; typedef Map PinVertexMap; diff --git a/graph/Makefile.am b/graph/Makefile.am index ebb6cb6f..9825a8fc 100644 --- a/graph/Makefile.am +++ b/graph/Makefile.am @@ -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 diff --git a/liberty/InternalPower.cc b/liberty/InternalPower.cc index 3050fc63..2caadaf7 100644 --- a/liberty/InternalPower.cc +++ b/liberty/InternalPower.cc @@ -23,14 +23,15 @@ namespace sta { InternalPowerAttrs::InternalPowerAttrs() : - when_(NULL) + when_(NULL), + models_{NULL, NULL}, + related_pg_pin_(NULL) { - TransRiseFallIterator tr_iter; - while (tr_iter.hasNext()) { - TransRiseFall *tr = tr_iter.next(); - int tr_index = tr->index(); - models_[tr_index] = NULL; - } +} + +InternalPowerAttrs::~InternalPowerAttrs() +{ + stringDelete(related_pg_pin_); } InternalPowerModel * @@ -46,6 +47,13 @@ InternalPowerAttrs::setModel(TransRiseFall *tr, models_[tr->index()] = model; } +void +InternalPowerAttrs::setRelatedPgPin(const char *related_pg_pin) +{ + stringDelete(related_pg_pin_); + related_pg_pin_ = stringCopy(related_pg_pin); +} + //////////////////////////////////////////////////////////////// InternalPower::InternalPower(LibertyCell *cell, @@ -54,7 +62,8 @@ InternalPower::InternalPower(LibertyCell *cell, InternalPowerAttrs *attrs) : port_(port), related_port_(related_port), - when_(attrs->when()) + when_(attrs->when()), + related_pg_pin_(stringCopy(attrs->relatedPgPin())) { TransRiseFallIterator tr_iter; while (tr_iter.hasNext()) { @@ -77,6 +86,7 @@ InternalPower::~InternalPower() } if (when_) when_->deleteSubexprs(); + stringDelete(related_pg_pin_); } LibertyCell * diff --git a/liberty/InternalPower.hh b/liberty/InternalPower.hh index e132ccaa..9310d52d 100644 --- a/liberty/InternalPower.hh +++ b/liberty/InternalPower.hh @@ -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: diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 059a541c..9a1cb5bf 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -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 models; - MinMaxIterator el_iter; + EarlyLateIterator el_iter; while (el_iter.hasNext()) { EarlyLate *early_late = el_iter.next(); int el_index = early_late->index(); diff --git a/liberty/Liberty.hh b/liberty/Liberty.hh index 2600f639..256b92c6 100644 --- a/liberty/Liberty.hh +++ b/liberty/Liberty.hh @@ -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 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 corner_ports_; unsigned int min_pulse_width_exists_:TransRiseFall::index_count; diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 35a0fbaf..d0ff2762 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -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(), diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index aa5d4393..2a59e29b 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -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); diff --git a/liberty/LinearModel.cc b/liberty/LinearModel.cc index 261c8373..7d90e882 100644 --- a/liberty/LinearModel.cc +++ b/liberty/LinearModel.cc @@ -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 diff --git a/liberty/LinearModel.hh b/liberty/LinearModel.hh index ce9c1ac8..39d326d8 100644 --- a/liberty/LinearModel.hh +++ b/liberty/LinearModel.hh @@ -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, diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 76f3a78c..a16deb7c 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -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); + } } //////////////////////////////////////////////////////////////// diff --git a/liberty/TableModel.hh b/liberty/TableModel.hh index 7019e844..7b981352 100644 --- a/liberty/TableModel.hh +++ b/liberty/TableModel.hh @@ -19,6 +19,7 @@ #include #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, diff --git a/liberty/TimingArc.cc b/liberty/TimingArc.cc index e92c69c7..5a07fa7f 100644 --- a/liberty/TimingArc.cc +++ b/liberty/TimingArc.cc @@ -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); } diff --git a/liberty/TimingArc.hh b/liberty/TimingArc.hh index dbdd84ac..1519495d 100644 --- a/liberty/TimingArc.hh +++ b/liberty/TimingArc.hh @@ -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); diff --git a/liberty/TimingModel.hh b/liberty/TimingModel.hh index c815de83..b60b1547 100644 --- a/liberty/TimingModel.hh +++ b/liberty/TimingModel.hh @@ -18,6 +18,7 @@ #define STA_TIMING_MODEL_H #include +#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, diff --git a/liberty/Units.cc b/liberty/Units.cc index b7b32177..45f102eb 100644 --- a/liberty/Units.cc +++ b/liberty/Units.cc @@ -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 { diff --git a/liberty/Units.hh b/liberty/Units.hh index 735a8489..2d43d60f 100644 --- a/liberty/Units.hh +++ b/liberty/Units.hh @@ -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, diff --git a/parasitics/ConcreteParasitics.cc b/parasitics/ConcreteParasitics.cc index 8963dcc6..b542d43c 100644 --- a/parasitics/ConcreteParasitics.cc +++ b/parasitics/ConcreteParasitics.cc @@ -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(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); } diff --git a/parasitics/ConcreteParasitics.hh b/parasitics/ConcreteParasitics.hh index 8d52deb1..8a1b9949 100644 --- a/parasitics/ConcreteParasitics.hh +++ b/parasitics/ConcreteParasitics.hh @@ -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, diff --git a/parasitics/ConcreteParasiticsPvt.hh b/parasitics/ConcreteParasiticsPvt.hh index 97348229..f92a6c47 100644 --- a/parasitics/ConcreteParasiticsPvt.hh +++ b/parasitics/ConcreteParasiticsPvt.hh @@ -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 diff --git a/parasitics/NullParasitics.cc b/parasitics/NullParasitics.cc index e0ff3746..ef7c56f3 100644 --- a/parasitics/NullParasitics.cc +++ b/parasitics/NullParasitics.cc @@ -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 *) { } diff --git a/parasitics/NullParasitics.hh b/parasitics/NullParasitics.hh index 9827a91f..7b826a1d 100644 --- a/parasitics/NullParasitics.hh +++ b/parasitics/NullParasitics.hh @@ -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, diff --git a/parasitics/Parasitics.cc b/parasitics/Parasitics.cc index 0e7db972..d58b62e3 100644 --- a/parasitics/Parasitics.cc +++ b/parasitics/Parasitics.cc @@ -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); diff --git a/parasitics/Parasitics.hh b/parasitics/Parasitics.hh index acf9ce2d..95561550 100644 --- a/parasitics/Parasitics.hh +++ b/parasitics/Parasitics.hh @@ -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, diff --git a/parasitics/Parasitics.i b/parasitics/Parasitics.i index 12c84603..8e5f6ca0 100644 --- a/parasitics/Parasitics.i +++ b/parasitics/Parasitics.i @@ -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); } diff --git a/parasitics/Parasitics.tcl b/parasitics/Parasitics.tcl index 25efb09d..69e5740e 100644 --- a/parasitics/Parasitics.tcl +++ b/parasitics/Parasitics.tcl @@ -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 diff --git a/parasitics/ReadParasitics.cc b/parasitics/ReadParasitics.cc index 3c9355f7..c3d361af 100644 --- a/parasitics/ReadParasitics.cc +++ b/parasitics/ReadParasitics.cc @@ -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, diff --git a/parasitics/ReadParasitics.hh b/parasitics/ReadParasitics.hh index 399002cc..f562eaa8 100644 --- a/parasitics/ReadParasitics.hh +++ b/parasitics/ReadParasitics.hh @@ -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, diff --git a/parasitics/ReduceParasitics.cc b/parasitics/ReduceParasitics.cc index 0e2a8493..a36fc034 100644 --- a/parasitics/ReduceParasitics.cc +++ b/parasitics/ReduceParasitics.cc @@ -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; } diff --git a/parasitics/ReduceParasitics.hh b/parasitics/ReduceParasitics.hh index 24dddd9f..69ba8f18 100644 --- a/parasitics/ReduceParasitics.hh +++ b/parasitics/ReduceParasitics.hh @@ -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, diff --git a/parasitics/SpefReader.cc b/parasitics/SpefReader.cc index a706d8d2..533a6411 100644 --- a/parasitics/SpefReader.cc +++ b/parasitics/SpefReader.cc @@ -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_); diff --git a/parasitics/SpefReader.hh b/parasitics/SpefReader.hh index 1090beaf..2466d0de 100644 --- a/parasitics/SpefReader.hh +++ b/parasitics/SpefReader.hh @@ -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, diff --git a/parasitics/SpefReaderPvt.hh b/parasitics/SpefReaderPvt.hh index 88102d5f..5956ca3b 100644 --- a/parasitics/SpefReaderPvt.hh +++ b/parasitics/SpefReaderPvt.hh @@ -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, diff --git a/parasitics/SpfReader.cc b/parasitics/SpfReader.cc index 93696cc1..2d63f96e 100644 --- a/parasitics/SpfReader.cc +++ b/parasitics/SpfReader.cc @@ -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 { diff --git a/parasitics/SpfReader.hh b/parasitics/SpfReader.hh index 84ecccf7..426d7f65 100644 --- a/parasitics/SpfReader.hh +++ b/parasitics/SpfReader.hh @@ -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, diff --git a/parasitics/SpfReaderPvt.hh b/parasitics/SpfReaderPvt.hh index 6df8eacb..988ea132 100644 --- a/parasitics/SpfReaderPvt.hh +++ b/parasitics/SpfReaderPvt.hh @@ -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, diff --git a/parasitics/SpfSpefReader.cc b/parasitics/SpfSpefReader.cc index a925d472..3d11255f 100644 --- a/parasitics/SpfSpefReader.cc +++ b/parasitics/SpfSpefReader.cc @@ -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), diff --git a/parasitics/SpfSpefReader.hh b/parasitics/SpfSpefReader.hh index ed45115a..eb92044d 100644 --- a/parasitics/SpfSpefReader.hh +++ b/parasitics/SpfSpefReader.hh @@ -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_; diff --git a/sdc/ClockInsertion.cc b/sdc/ClockInsertion.cc index bcdc7443..8778e969 100644 --- a/sdc/ClockInsertion.cc +++ b/sdc/ClockInsertion.cc @@ -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); diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 8fd70e77..a625febb 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -102,6 +102,7 @@ Sdc::Sdc(StaState *sta) : clk_sense_map_(network_), clk_gating_check_(NULL), input_delay_index_(0), + port_cap_map_(NULL), net_wire_cap_map_(NULL), drvr_pin_wire_cap_map_(NULL), first_from_pin_exceptions_(NULL), @@ -314,12 +315,6 @@ Sdc::deleteConstraints() } } - delete net_wire_cap_map_; - net_wire_cap_map_ = NULL; - - delete drvr_pin_wire_cap_map_; - drvr_pin_wire_cap_map_ = NULL; - clk_hpin_disables_.deleteContentsClear(); clk_hpin_disables_valid_ = false; @@ -355,28 +350,22 @@ Sdc::deleteInstancePvts() void Sdc::removeNetLoadCaps() { - // set_load net - delete net_wire_cap_map_; + delete [] net_wire_cap_map_; net_wire_cap_map_ = NULL; - delete drvr_pin_wire_cap_map_; + delete [] drvr_pin_wire_cap_map_; drvr_pin_wire_cap_map_ = NULL; } void Sdc::removeLoadCaps() { - // set_load port - // set_fanout_load port - port_cap_map_.deleteContents(); - port_cap_map_.clear(); - - // set_load net - delete net_wire_cap_map_; - net_wire_cap_map_ = NULL; - - delete drvr_pin_wire_cap_map_; - drvr_pin_wire_cap_map_ = NULL; + if (port_cap_map_) { + port_cap_map_->deleteContents(); + delete port_cap_map_; + port_cap_map_ = NULL; + } + removeNetLoadCaps(); } void @@ -470,7 +459,7 @@ Sdc::isConstrained(const Pin *pin) const || pin_cap_limit_map_.hasKey(pin1) || port_cap_limit_map_.hasKey(port) || port_fanout_limit_map_.hasKey(port) - || port_cap_map_.hasKey(port) + || hasPortExtCap(port) || disabled_pins_.hasKey(pin1) || disabled_ports_.hasKey(port) || disabled_clk_gating_checks_pin_.hasKey(pin1) @@ -515,8 +504,7 @@ Sdc::isConstrained(const Net *net) const Net *net1 = const_cast(net); 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)); + drvr_pin_wire_cap_map_[corner->index()].findKey(const_cast(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; } diff --git a/sdc/Sdc.hh b/sdc/Sdc.hh index f99b930e..81e84095 100644 --- a/sdc/Sdc.hh +++ b/sdc/Sdc.hh @@ -582,10 +582,12 @@ public: const Corner *corner, const MinMax *min_max, float cap); + bool hasNetWireCap(Net *net) const; // True if driver pin net has wire capacitance. bool drvrPinHasWireCap(const Pin *pin); // Net wire capacitance (set_load -wire net). void drvrPinWireCap(const Pin *drvr_pin, + const Corner *corner, const MinMax *min_max, // Return values. float &cap, @@ -907,6 +909,7 @@ public: PinOutputDelayIterator *outputDelayVertexIterator(const Pin *vertex_pin)const; bool hasOutputDelay(const Pin *vertex_pin) const; PortExtCap *portExtCap(Port *port) const; + bool hasPortExtCap(Port *port) const; void portExtCap(Port *port, const TransRiseFall *tr, const MinMax *min_max, @@ -1333,9 +1336,15 @@ protected: PinCapLimitMap pin_cap_limit_map_; PortFanoutLimitMap port_fanout_limit_map_; CellFanoutLimitMap cell_fanout_limit_map_; - // External parasitics on top level ports (from set_load). - PortExtCapMap port_cap_map_; + // External parasitics on top level ports. + // set_load port + // set_fanout_load port + // Indexed by corner_index. + PortExtCapMap *port_cap_map_; + // set_load net + // Indexed by corner_index. NetWireCapMap *net_wire_cap_map_; + // Indexed by corner_index. PinWireCapMap *drvr_pin_wire_cap_map_; NetResistanceMap net_res_map_; PinSet disabled_pins_; diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index 67b51157..5877bbdc 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -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); diff --git a/sdf/SdfWriter.cc b/sdf/SdfWriter.cc index e43f0b55..f6954fdd 100644 --- a/sdf/SdfWriter.cc +++ b/sdf/SdfWriter.cc @@ -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"); } diff --git a/search/ClkSkew.cc b/search/ClkSkew.cc index 8d6e9321..3426f833 100644 --- a/search/ClkSkew.cc +++ b/search/ClkSkew.cc @@ -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 diff --git a/search/Corner.hh b/search/Corner.hh index 4186b2ce..fa22aa14 100644 --- a/search/Corner.hh +++ b/search/Corner.hh @@ -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; diff --git a/search/Latches.cc b/search/Latches.cc index 145ccd51..532dd89b 100644 --- a/search/Latches.cc +++ b/search/Latches.cc @@ -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(excpt); PathDelay *path_delay = dynamic_cast(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, diff --git a/search/Latches.hh b/search/Latches.hh index f15d4843..ac0730e7 100644 --- a/search/Latches.hh +++ b/search/Latches.hh @@ -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, diff --git a/search/Makefile.am b/search/Makefile.am index cdb2cb9b..3d3c9309 100644 --- a/search/Makefile.am +++ b/search/Makefile.am @@ -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 \ diff --git a/search/PathEnd.cc b/search/PathEnd.cc index f01729e9..c6a5b4d1 100644 --- a/search/PathEnd.cc +++ b/search/PathEnd.cc @@ -68,6 +68,18 @@ PathEnd::minMax(const StaState *sta) const return path_.pathAnalysisPt(sta)->pathMinMax(); } +const EarlyLate * +PathEnd::pathEarlyLate(const StaState *sta) const +{ + return path_.pathAnalysisPt(sta)->pathMinMax(); +} + +const EarlyLate * +PathEnd::clkEarlyLate(const StaState *sta) const +{ + return NULL; +} + const TransRiseFall * PathEnd::transition(const StaState *sta) const { @@ -540,6 +552,15 @@ PathEndClkConstrained::setPath(PathEnumed *path, crpr_valid_ = false; } +const EarlyLate * +PathEndClkConstrained::clkEarlyLate(const StaState *sta) const +{ + if (clk_path_.isNull()) + return NULL; + else + return clk_path_.pathAnalysisPt(sta)->pathMinMax(); +} + float PathEndClkConstrained::sourceClkOffset(const StaState *sta) const { @@ -1565,15 +1586,15 @@ PathEndDataCheck::type() const Arrival PathEndDataCheck::requiredTimeNoCrpr(const StaState *sta) const { - float data_clk_arrival = data_clk_path_.arrival(sta); + Arrival data_clk_arrival = data_clk_path_.arrival(sta); float data_clk_time = data_clk_path_.clkEdge(sta)->time(); - float data_clk_delay = data_clk_arrival - data_clk_time; - float tgt_clk_arrival = targetClkTime(sta) + Arrival data_clk_delay = data_clk_arrival - data_clk_time; + Arrival tgt_clk_arrival = targetClkTime(sta) + data_clk_delay + targetClkUncertainty(sta) + targetClkMcpAdjustment(sta); - float check_margin = margin(sta); + ArcDelay check_margin = margin(sta); if (checkGenericRole(sta) == TimingRole::setup()) return tgt_clk_arrival - check_margin; else @@ -1773,14 +1794,14 @@ PathEndPathDelay::sourceClkOffset(const StaState *sta) const float PathEnd::pathDelaySrcClkOffset(const PathRef &path, PathDelay *path_delay, - float src_clk_arrival, + Arrival src_clk_arrival, const StaState *sta) { float offset = 0.0; ClockEdge *clk_edge = path.clkEdge(sta); if (clk_edge) { if (path_delay->ignoreClkLatency()) - offset = -src_clk_arrival; + offset = -delayAsFloat(src_clk_arrival); else // Arrival includes src clock edge time that is not counted in the // path delay. diff --git a/search/PathEnd.hh b/search/PathEnd.hh index 7d2dfe9d..7e096d5d 100644 --- a/search/PathEnd.hh +++ b/search/PathEnd.hh @@ -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); }; diff --git a/search/PathEnum.cc b/search/PathEnum.cc index 6592a45a..799c4611 100644 --- a/search/PathEnum.cc +++ b/search/PathEnum.cc @@ -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) diff --git a/search/PathEnum.hh b/search/PathEnum.hh index c75e6efd..88dd970c 100644 --- a/search/PathEnum.hh +++ b/search/PathEnum.hh @@ -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_; }; diff --git a/search/Power.cc b/search/Power.cc new file mode 100644 index 00000000..ac37651b --- /dev/null +++ b/search/Power.cc @@ -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 . + +#include // max +#include "Machine.hh" +#include "Debug.hh" +#include "Units.hh" +#include "Transition.hh" +#include "MinMax.hh" +#include "Liberty.hh" +#include "InternalPower.hh" +#include "LeakagePower.hh" +#include "InternalPower.hh" +#include "TimingArc.hh" +#include "FuncExpr.hh" +#include "PortDirection.hh" +#include "Network.hh" +#include "Graph.hh" +#include "Sim.hh" +#include "Corner.hh" +#include "DcalcAnalysisPt.hh" +#include "GraphDelayCalc.hh" +#include "PathVertex.hh" +#include "Clock.hh" +#include "Power.hh" + +// Related liberty not supported: +// library +// default_cell_leakage_power : 0; +// output_voltage (default_VDD_VSS_output) { +// leakage_power +// related_pg_pin : VDD; +// internal_power +// input_voltage : default_VDD_VSS_input; +// pin +// output_voltage : default_VDD_VSS_output; + + +namespace sta { + +Power::Power(Sta *sta) : + StaState(sta), + sta_(sta), + default_signal_toggle_rate_(.1) +{ +} + +float +Power::defaultSignalToggleRate() +{ + return default_signal_toggle_rate_; +} + +void +Power::setDefaultSignalToggleRate(float rate) +{ + default_signal_toggle_rate_ = rate; +} + + +void +Power::power(const Corner *corner, + // Return values. + PowerResult &total, + PowerResult &sequential, + PowerResult &combinational, + PowerResult ¯o, + PowerResult &pad) +{ + total.clear(); + sequential.clear(); + combinational.clear(); + macro.clear(); + pad.clear(); + LeafInstanceIterator *inst_iter = network_->leafInstanceIterator(); + while (inst_iter->hasNext()) { + Instance *inst = inst_iter->next(); + LibertyCell *cell = network_->libertyCell(inst); + if (cell) { + PowerResult inst_power; + power(inst, corner, inst_power); + if (cell->isMacro()) + macro.incr(inst_power); + else if (cell->isPad()) + pad.incr(inst_power); + else if (cell->hasSequentials()) + sequential.incr(inst_power); + else + combinational.incr(inst_power); + total.incr(inst_power); + } + } +} + +//////////////////////////////////////////////////////////////// + +void +Power::power(const Instance *inst, + const Corner *corner, + // Return values. + PowerResult &result) +{ + LibertyCell *cell = network_->libertyCell(inst); + if (cell) + power(inst, cell, corner, result); +} + +void +Power::power(const Instance *inst, + LibertyCell *cell, + const Corner *corner, + // Return values. + PowerResult &result) +{ + MinMax *mm = MinMax::max(); + const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(mm); + InstancePinIterator *pin_iter = network_->pinIterator(inst); + while (pin_iter->hasNext()) { + const Pin *to_pin = pin_iter->next(); + const LibertyPort *to_port = network_->libertyPort(to_pin); + float load_cap = to_port->direction()->isAnyOutput() + ? loadCap(to_pin, dcalc_ap) + : 0.0; + float activity1; + bool is_clk; + activity(to_pin, activity1, is_clk); + if (to_port->direction()->isAnyOutput()) { + findSwitchingPower(inst, cell, to_pin, to_port, activity1, load_cap, + dcalc_ap, result); + } + findInternalPower(inst, cell, to_pin, to_port, activity1, is_clk, + load_cap, dcalc_ap, result); + } + delete pin_iter; + findLeakagePower(inst, cell, result); +} + +void +Power::findInternalPower(const Instance *inst, + LibertyCell *cell, + const Pin *to_pin, + const LibertyPort *to_port, + float activity, + bool is_clk, + float load_cap, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + PowerResult &result) +{ + debugPrint3(debug_, "power", 2, "internal %s/%s %ss\n", + network_->pathName(inst), + to_port->name(), + cell->name()); + float port_internal = 0.0; + const Pvt *pvt = dcalc_ap->operatingConditions(); + float volt = voltage(cell, to_port, dcalc_ap); + const char *pwr_pin = to_port->relatedPowerPin(); + float duty = is_clk ? 1.0 : .5; + debugPrint3(debug_, "power", 2, "cap = %s activity = %.2f/ns duty = %.1f\n", + units_->capacitanceUnit()->asString(load_cap), + activity * 1e-9, + duty); + LibertyCellInternalPowerIterator *pwr_iter = cell->internalPowerIterator(); + while (pwr_iter->hasNext()) { + InternalPower *pwr = pwr_iter->next(); + const char *related_pg_pin = pwr->relatedPgPin(); + if (pwr->port() == to_port + && ((related_pg_pin == NULL || pwr_pin == NULL) + || stringEqual(related_pg_pin, pwr_pin))) { + const LibertyPort *from_port = pwr->relatedPort(); + if (from_port == NULL) + from_port = to_port; + const Pin *from_pin = network_->findPin(inst, from_port); + Vertex *from_vertex = graph_->pinLoadVertex(from_pin); + TransRiseFallIterator tr_iter; + while (tr_iter.hasNext()) { + TransRiseFall *to_tr = tr_iter.next(); + // Need unateness to find from_tr. + float slew = sta_->vertexSlew(from_vertex, to_tr, dcalc_ap); + float energy, tr_internal; + if (from_port) { + float energy1 = pwr->power(to_tr, pvt, slew, load_cap); + // Scale by voltage and rise/fall transition count. + energy = energy1 * volt / 2.0; + } + else { + float energy1 = pwr->power(to_tr, pvt, 0.0, 0.0); + // Scale by voltage and rise/fall transition count. + energy = energy1 * volt / 2.0; + } + tr_internal = energy * activity * duty; + port_internal += tr_internal; + debugPrint5(debug_, "power", 2, " %s -> %s %s %s (%s)\n", + from_port->name(), + to_tr->shortName(), + to_port->name(), + pwr->when() ? pwr->when()->asString() : "", + related_pg_pin ? related_pg_pin : ""); + debugPrint3(debug_, "power", 2, " slew = %s energy = %.5g pwr = %.5g\n", + units_->timeUnit()->asString(slew), + energy, + tr_internal); + } + } + } + delete pwr_iter; + debugPrint1(debug_, "power", 2, " internal = %.5g\n", port_internal); + result.setInternal(result.internal() + port_internal); +} + +float +Power::loadCap(const Pin *to_pin, + const DcalcAnalysisPt *dcalc_ap) +{ + float ceff_sum = 0.0; + int ceff_count = 0; + Vertex *to_vertex = graph_->pinDrvrVertex(to_pin); + VertexInEdgeIterator edge_iter(to_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + TimingArcSet *arc_set = edge->timingArcSet(); + TimingArcSetArcIterator *arc_iter = arc_set->timingArcIterator(); + while (arc_iter->hasNext()) { + TimingArc *arc = arc_iter->next(); + ceff_sum += graph_delay_calc_->ceff(edge, arc, dcalc_ap); + ceff_count++; + } + delete arc_iter; + } + return ceff_sum / ceff_count; +} + +void +Power::findLeakagePower(const Instance *inst, + LibertyCell *cell, + // Return values. + PowerResult &result) +{ + float leakage = cell->leakagePower(); + LibertyCellLeakagePowerIterator *pwr_iter = cell->leakagePowerIterator(); + while (pwr_iter->hasNext()) { + LeakagePower *leak = pwr_iter->next(); + FuncExpr *when = leak->when(); + if (when) { + LogicValue when_value = sim_->evalExpr(when, inst); + switch (when_value) { + case logic_zero: + case logic_one: + leakage = max(leakage, leak->power()); + break; + case logic_unknown: + default: + break; + } + } + } + delete pwr_iter; + result.setLeakage(leakage); +} + +void +Power::findSwitchingPower(const Instance *inst, + LibertyCell *cell, + const Pin *to_pin, + const LibertyPort *to_port, + float activity, + float load_cap, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + PowerResult &result) +{ + float volt = voltage(cell, to_port, dcalc_ap); + float switching = load_cap * volt * volt * activity / 2.0; + result.setSwitching(switching); +} + +void +Power::activity(const Pin *pin, + // Return values. + float &activity, + bool &is_clk) +{ + const Clock *clk; + findClk(pin, clk, is_clk); + if (clk) { + if (is_clk) + activity = 2.0 / clk->period(); + else + activity = default_signal_toggle_rate_ * 2.0 / clk->period(); + } + else + activity = 0.0; +} + +float +Power::voltage(LibertyCell *cell, + const LibertyPort *port, + const DcalcAnalysisPt *dcalc_ap) +{ + // Should use cell pg_pin voltage name to voltage. + const Pvt *pvt = dcalc_ap->operatingConditions(); + if (pvt == NULL) + pvt = cell->libertyLibrary()->defaultOperatingConditions(); + if (pvt) + return pvt->voltage(); + else + return 0.0; +} + +void +Power::findClk(const Pin *to_pin, + // Return values. + const Clock *&clk, + bool &is_clk) +{ + clk = NULL; + is_clk = false; + Vertex *to_vertex = graph_->pinDrvrVertex(to_pin); + VertexPathIterator path_iter(to_vertex, this); + while (path_iter.hasNext()) { + PathVertex *path = path_iter.next(); + const Clock *path_clk = path->clock(this); + if (path_clk + && (clk == NULL + || path_clk->period() < clk->period())) + clk = path_clk; + if (path->isClock(this)) + is_clk = true; + } +} + +//////////////////////////////////////////////////////////////// + +PowerResult::PowerResult() : + internal_(0.0), + switching_(0.0), + leakage_(0.0) +{ +} + +void +PowerResult::clear() +{ + internal_ = 0.0; + switching_ = 0.0; + leakage_ = 0.0; +} + +float +PowerResult::total() const +{ + return internal_ + switching_ + leakage_; +} + +void +PowerResult::setInternal(float internal) +{ + internal_ = internal; +} + +void +PowerResult::setLeakage(float leakage) +{ + leakage_ = leakage; +} + +void +PowerResult::setSwitching(float switching) +{ + switching_ = switching; +} + +void +PowerResult::incr(PowerResult &result) +{ + internal_ += result.internal_; + switching_ += result.switching_; + leakage_ += result.leakage_; +} + +} // namespace diff --git a/search/Power.hh b/search/Power.hh new file mode 100644 index 00000000..9a69b44e --- /dev/null +++ b/search/Power.hh @@ -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 . + +#ifndef STA_POWER_H +#define STA_POWER_H + +#include "Sta.hh" + +namespace sta { + +class PowerResult; + +// The Power class has access to Sta components directly for +// convenience but also requires access to the Sta class member functions. +class Power : public StaState +{ +public: + Power(Sta *sta); + void power(const Corner *corner, + // Return values. + PowerResult &total, + PowerResult &sequential, + PowerResult &combinational, + PowerResult ¯o, + PowerResult &pad); + void power(const Instance *inst, + const Corner *corner, + // Return values. + PowerResult &result); + float defaultSignalToggleRate(); + void setDefaultSignalToggleRate(float rate); + +protected: + void power(const Instance *inst, + LibertyCell *cell, + const Corner *corner, + // Return values. + PowerResult &result); + void findInternalPower(const Instance *inst, + LibertyCell *cell, + const Pin *to_pin, + const LibertyPort *to_port, + float activity, + bool is_clk, + float load_cap, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + PowerResult &result); + void findLeakagePower(const Instance *inst, + LibertyCell *cell, + // Return values. + PowerResult &result); + void findSwitchingPower(const Instance *inst, + LibertyCell *cell, + const Pin *to_pin, + const LibertyPort *to_port, + float activity, + float load_cap, + const DcalcAnalysisPt *dcalc_ap, + // Return values. + PowerResult &result); + void findClk(const Pin *to_pin, + // Return values. + const Clock *&clk, + bool &is_clk); + float loadCap(const Pin *to_pin, + const DcalcAnalysisPt *dcalc_ap);; + void activity(const Pin *pin, + // Return values. + float &activity, + bool &is_clk); + float voltage(LibertyCell *cell, + const LibertyPort *port, + const DcalcAnalysisPt *dcalc_ap); + +private: + Sta *sta_; + float default_signal_toggle_rate_; +}; + +class PowerResult +{ +public: + PowerResult(); + void clear(); + float internal() const { return internal_; } + void setInternal(float internal); + float switching() const { return switching_; } + void setSwitching(float switching); + float leakage() const { return leakage_; } + void setLeakage(float leakage); + float total() const; + void incr(PowerResult &result); + +private: + float internal_; + float switching_; + float leakage_; +}; + +} // namespace +#endif diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 899963c1..19eb30b5 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -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 diff --git a/search/ReportPath.hh b/search/ReportPath.hh index 50765c1b..ac878772 100644 --- a/search/ReportPath.hh +++ b/search/ReportPath.hh @@ -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); diff --git a/search/Search.cc b/search/Search.cc index 600ec940..39a6fae7 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -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 diff --git a/search/Search.hh b/search/Search.hh index 3e58f6eb..7a88ca6a 100644 --- a/search/Search.hh +++ b/search/Search.hh @@ -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_; }; diff --git a/search/Sta.cc b/search/Sta.cc index 72fc3de8..6ef6c813 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -67,6 +67,7 @@ #include "VisitPathGroupVertices.hh" #include "SdfWriter.hh" #include "Genclks.hh" +#include "Power.hh" #include "Sta.hh" namespace sta { @@ -272,6 +273,7 @@ Sta::Sta() : check_max_skews_(NULL), clk_skews_(NULL), report_path_(NULL), + power_(NULL), link_make_black_boxes_(true), update_genclks_(false) { @@ -348,6 +350,8 @@ Sta::updateComponentsState() report_path_->copyState(this); if (check_timing_) check_timing_->copyState(this); + if (power_) + power_->copyState(this); } void @@ -466,6 +470,12 @@ Sta::makeReportPath() report_path_ = new ReportPath(this); } +void +Sta::makePower() +{ + power_ = new Power(this); +} + void Sta::setSta(Sta *sta) { @@ -3185,9 +3195,9 @@ Sta::portExtPinCap(Port *port, int fanout; bool pin_exists, wire_exists, fanout_exists; sdc_->portExtCap(port, tr, min_max, - pin_cap, pin_exists, - wire_cap, wire_exists, - fanout, fanout_exists); + pin_cap, pin_exists, + wire_cap, wire_exists, + fanout, fanout_exists); if (pin_exists) return pin_cap; else @@ -3221,9 +3231,9 @@ Sta::portExtWireCap(Port *port, int fanout; bool pin_exists, wire_exists, fanout_exists; sdc_->portExtCap(port, tr, min_max, - pin_cap, pin_exists, - wire_cap, wire_exists, - fanout, fanout_exists); + pin_cap, pin_exists, + wire_cap, wire_exists, + fanout, fanout_exists); if (wire_exists) return wire_cap; else @@ -3244,8 +3254,7 @@ Sta::setPortExtWireCap(Port *port, MinMaxIterator mm_iter(min_max); while (mm_iter.hasNext()) { MinMax *mm = mm_iter.next(); - sdc_->setPortExtWireCap(port, subtract_pin_cap, tr1, - corner, mm, cap); + sdc_->setPortExtWireCap(port, subtract_pin_cap, tr1, corner, mm, cap); } } delaysInvalidFromFanin(port); @@ -3375,6 +3384,7 @@ Sta::readParasitics(const char *filename, Instance *instance, const MinMaxAll *min_max, bool increment, + bool pin_cap_included, bool keep_coupling_caps, float coupling_cap_factor, ReduceParasiticsTo reduce_to, @@ -3398,6 +3408,7 @@ Sta::readParasitics(const char *filename, const OperatingConditions *op_cond = sdc_->operatingConditions(cnst_min_max); bool success = readParasiticsFile(filename, instance, ap, increment, + pin_cap_included, keep_coupling_caps, coupling_cap_factor, reduce_to, delete_after_reduce, op_cond, corner, cnst_min_max, save, quiet, @@ -4860,4 +4871,39 @@ Sta::reportCheck(MaxSkewCheck *check, report_path_->reportCheck(check, verbose); } +//////////////////////////////////////////////////////////////// + +void +Sta::powerPreamble() +{ + // Use arrivals to find clocking info. + searchPreamble(); + search_->findAllArrivals(); + if (power_ == NULL) + makePower(); +} + +void +Sta::power(const Corner *corner, + // Return values. + PowerResult &total, + PowerResult &sequential, + PowerResult &combinational, + PowerResult ¯o, + PowerResult &pad) +{ + powerPreamble(); + power_->power(corner, total, sequential, combinational, macro, pad); +} + +void +Sta::power(const Instance *inst, + const Corner *corner, + // Return values. + PowerResult &result) +{ + powerPreamble(); + power_->power(inst, corner, result); +} + } // namespace diff --git a/search/Sta.hh b/search/Sta.hh index c8eedaca..17e3cf42 100644 --- a/search/Sta.hh +++ b/search/Sta.hh @@ -55,6 +55,8 @@ class SearchPred; class Corner; class ClkSkews; class ReportField; +class Power; +class PowerResult; typedef InstanceSeq::Iterator SlowDrvrIterator; typedef Vector CheckError; @@ -669,6 +671,7 @@ public: void reportCheck(MaxSkewCheck *check, bool verbose); + //////////////////////////////////////////////////////////////// // User visible but non SDC commands. @@ -974,9 +977,11 @@ public: Slack vertexSlack(Vertex *vertex, const TransRiseFall *tr, const PathAnalysisPt *path_ap); + // Slew for one delay calc analysis pt(corner). Slew vertexSlew(Vertex *vertex, const TransRiseFall *tr, const DcalcAnalysisPt *dcalc_ap); + // Slew across all corners. Slew vertexSlew(Vertex *vertex, const TransRiseFall *tr, const MinMax *min_max); @@ -1021,6 +1026,7 @@ public: Instance *instance, const MinMaxAll *min_max, bool increment, + bool pin_cap_included, bool keep_coupling_caps, float coupling_cap_factor, ReduceParasiticsTo reduce_to, @@ -1143,6 +1149,21 @@ public: Vertex *vertex, LibertyCell *to_cell); + // Power API. + Power *power() { return power_; } + const Power *power() const { return power_; } + void power(const Corner *corner, + // Return values. + PowerResult &total, + PowerResult &sequential, + PowerResult &combinational, + PowerResult ¯o, + PowerResult &pad); + void power(const Instance *inst, + const Corner *corner, + // Return values. + PowerResult &result); + protected: // Default constructors that are called by makeComponents in the Sta // constructor. These can be redefined by a derived class to @@ -1168,6 +1189,7 @@ protected: virtual void makeCheckMinPeriods(); virtual void makeCheckMaxSkews(); virtual void makeReportPath(); + virtual void makePower(); virtual void makeObservers(); NetworkEdit *networkCmdEdit(); @@ -1254,6 +1276,7 @@ protected: Corner *corner, const MinMax *min_max); void parasiticsChangedAfter(); + void powerPreamble(); CmdNamespace cmd_namespace_; Instance *current_instance_; @@ -1264,6 +1287,7 @@ protected: CheckMaxSkews *check_max_skews_; ClkSkews *clk_skews_; ReportPath *report_path_; + Power *power_; Tcl_Interp *tcl_interp_; bool link_make_black_boxes_; bool update_genclks_; diff --git a/tcl/Cmds.tcl b/tcl/Cmds.tcl index dc6d1c6c..8ee51ec6 100644 --- a/tcl/Cmds.tcl +++ b/tcl/Cmds.tcl @@ -1246,6 +1246,22 @@ proc parse_corner { keys_var } { } } +proc parse_corner_or_default { keys_var } { + upvar 1 $keys_var keys + + if { [info exists keys(-corner)] } { + set corner_name $keys(-corner) + set corner [find_corner $corner_name] + if { $corner == "NULL" } { + sta_error "$corner_name is not the name of process corner." + } else { + return $corner + } + } else { + return [default_corner] + } +} + proc parse_corner_or_all { keys_var } { upvar 1 $keys_var keys diff --git a/tcl/Graph.tcl b/tcl/Graph.tcl index 0e2084dc..95d09c0a 100644 --- a/tcl/Graph.tcl +++ b/tcl/Graph.tcl @@ -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] { diff --git a/tcl/Liberty.tcl b/tcl/Liberty.tcl index 7ef19702..1da2995c 100644 --- a/tcl/Liberty.tcl +++ b/tcl/Liberty.tcl @@ -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 } diff --git a/tcl/Network.tcl b/tcl/Network.tcl index 4a4acb33..a317e577 100644 --- a/tcl/Network.tcl +++ b/tcl/Network.tcl @@ -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)" diff --git a/tcl/Power.tcl b/tcl/Power.tcl new file mode 100644 index 00000000..ea2483e7 --- /dev/null +++ b/tcl/Power.tcl @@ -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 . + +################################################################ +# +# 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. +} diff --git a/tcl/Sdc.tcl b/tcl/Sdc.tcl index 60f95e6a..c70e6932 100644 --- a/tcl/Sdc.tcl +++ b/tcl/Sdc.tcl @@ -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] diff --git a/tcl/Search.tcl b/tcl/Search.tcl index 69e9e0e9..d0a55909 100644 --- a/tcl/Search.tcl +++ b/tcl/Search.tcl @@ -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" } ################################################################ diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index e1281337..a1d7ead3 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -49,8 +49,6 @@ #include "Transition.hh" #include "TimingRole.hh" #include "TimingArc.hh" -#include "InternalPower.hh" -#include "LeakagePower.hh" #include "EquivCells.hh" #include "Liberty.hh" #include "Network.hh" @@ -77,6 +75,7 @@ #include "SearchPred.hh" #include "PathAnalysisPt.hh" #include "ReportPath.hh" +#include "Power.hh" #include "Sta.hh" namespace sta { @@ -693,7 +692,10 @@ edgeDelayProperty(Edge *edge, DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); ArcDelay arc_delay = sta->arcDelay(edge, arc, dcalc_ap); if (!delay_exists - || min_max->compare(arc_delay, delay)) + || ((min_max == MinMax::max() + && arc_delay > delay) + || (min_max == MinMax::min() + && arc_delay < delay))) delay = arc_delay; } } @@ -822,6 +824,16 @@ findEndpoints() return pins; } +void +pushPowerResultFloats(PowerResult &power, + TmpFloatSeq *floats) +{ + floats->push_back(power.internal()); + floats->push_back(power.switching()); + floats->push_back(power.leakage()); + floats->push_back(power.total()); +} + //////////////////////////////////////////////////////////////// void @@ -1510,11 +1522,11 @@ using namespace sta; %typemap(in) EarlyLate* { int length; char *arg = Tcl_GetStringFromObj($input, &length); - MinMax *min_max = MinMax::find(arg); - if (min_max) - $1 = min_max; + EarlyLate *early_late = EarlyLate::find(arg); + if (early_late) + $1 = early_late; else { - tclError(interp, "Error: %s not min or max.", arg); + tclError(interp, "Error: %s not early/min or late/max.", arg); return TCL_ERROR; } } @@ -1523,11 +1535,11 @@ using namespace sta; %typemap(in) EarlyLateAll* { int length; char *arg = Tcl_GetStringFromObj($input, &length); - MinMaxAll *min_max = MinMaxAll::find(arg); - if (min_max) - $1 = min_max; + EarlyLateAll *early_late = EarlyLateAll::find(arg); + if (early_late) + $1 = early_late; else { - tclError(interp, "Error: %s not min, max or min_max.", arg); + tclError(interp, "Error: %s not early/min, late/max or early_late/min_max.", arg); return TCL_ERROR; } } @@ -1735,26 +1747,6 @@ using namespace sta; Tcl_SetObjResult(interp, obj); } -%typemap(out) InternalPower* { - Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) LibertyCellInternalPowerIterator* { - Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) LeakagePower* { - Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - -%typemap(out) LibertyCellLeakagePowerIterator* { - Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); - Tcl_SetObjResult(interp, obj); -} - %typemap(out) CellTimingArcSetIterator* { Tcl_Obj *obj=SWIG_NewInstanceObj($1, $1_descriptor, false); Tcl_SetObjResult(interp, obj); @@ -2009,34 +2001,6 @@ private: ~CellTimingArcSetIterator(); }; -class InternalPower -{ -private: - InternalPower(); - ~InternalPower(); -}; - -class LibertyCellInternalPowerIterator -{ -private: - LibertyCellInternalPowerIterator(); - ~LibertyCellInternalPowerIterator(); -}; - -class LeakagePower -{ -private: - LeakagePower(); - ~LeakagePower(); -}; - -class LibertyCellLeakagePowerIterator -{ -private: - LibertyCellLeakagePowerIterator(); - ~LibertyCellLeakagePowerIterator(); -}; - class TimingArcSetArcIterator { private: @@ -4814,6 +4778,50 @@ report_slew_limit_verbose(Pin *pin, Sta::sta()->reportSlewLimitVerbose(pin, corner, min_max); } +//////////////////////////////////////////////////////////////// + +TmpFloatSeq * +design_power(const Corner *corner) +{ + PowerResult total, sequential, combinational, macro, pad; + Sta::sta()->power(corner, total, sequential, combinational, macro, pad); + FloatSeq *floats = new FloatSeq; + pushPowerResultFloats(total, floats); + pushPowerResultFloats(sequential, floats); + pushPowerResultFloats(combinational, floats); + pushPowerResultFloats(macro, floats); + pushPowerResultFloats(pad, floats); + return floats; +} + +TmpFloatSeq * +instance_power(Instance *inst, + const Corner *corner) +{ + PowerResult power; + Sta::sta()->power(inst, corner, power); + FloatSeq *floats = new FloatSeq; + floats->push_back(power.switching()); + floats->push_back(power.internal()); + floats->push_back(power.leakage()); + floats->push_back(power.total()); + return floats; +} + +float +power_default_signal_toggle_rate() +{ + return Sta::sta()->power()->defaultSignalToggleRate(); +} + +void +set_power_default_signal_toggle_rate(float rate) +{ + return Sta::sta()->power()->setDefaultSignalToggleRate(rate); +} + +//////////////////////////////////////////////////////////////// + EdgeSeq * disabled_edges_sorted() { @@ -5339,6 +5347,7 @@ find_cells_matching(const char *pattern, %extend LibertyLibrary { const char *name() { return self->name(); } +const char *filename() { return self->filename(); } const char *object_name() { return self->name(); } LibertyCell * @@ -5456,12 +5465,6 @@ liberty_port_iterator() { return self->libertyPortIterator(); } CellTimingArcSetIterator * timing_arc_set_iterator() { return self->timingArcSetIterator(); } -LibertyCellInternalPowerIterator * -internal_power_iterator() { return self->internalPowerIterator(); } - -LibertyCellLeakagePowerIterator * -leakage_power_iterator() { return self->leakagePowerIterator(); } - } // LibertyCell methods %extend CellPortIterator { @@ -5594,61 +5597,6 @@ TimingArc *next() { return self->next(); } void finish() { delete self; } } -%extend InternalPower { -LibertyPort *port() { return self->port(); } -LibertyPort *related_port() { return self->relatedPort(); } - -const char * -when() -{ - FuncExpr *when = self->when(); - if (when) - return when->asString(); - else - return ""; -} - -float -power(TransRiseFall *tr, - float in_slew, - float load_cap) -{ - Sta *sta = Sta::sta(); - Corner *corner = sta->corners()->defaultCorner(); - DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max()); - const Pvt *pvt = dcalc_ap->operatingConditions(); - return self->power(tr, pvt, in_slew, load_cap); -} - -} // InternalPower methods - -%extend LibertyCellInternalPowerIterator { -bool has_next() { return self->hasNext(); } -InternalPower *next() { return self->next(); } -void finish() { delete self; } -} - -%extend LeakagePower { -float power() { return self->power(); } - -const char * -when() -{ - FuncExpr *when = self->when(); - if (when) - return when->asString(); - else - return ""; -} - -} // LeakagePower methods - -%extend LibertyCellLeakagePowerIterator { -bool has_next() { return self->hasNext(); } -LeakagePower *next() { return self->next(); } -void finish() { delete self; } -} - %extend Instance { const char *name() { return cmdLinkedNetwork()->name(self); } const char *object_name() { return cmdLinkedNetwork()->pathName(self); } @@ -5954,11 +5902,33 @@ arrivals_clk(const TransRiseFall *tr, PathAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { PathAnalysisPt *path_ap = ap_iter.next(); - floats->push_back(delayAsFloat(sta->vertexArrival(self, tr, clk_edge, path_ap))); + floats->push_back(delayAsFloat(sta->vertexArrival(self, tr, clk_edge, + path_ap))); } return floats; } +StringSeq * +arrivals_clk_delays(const TransRiseFall *tr, + Clock *clk, + const TransRiseFall *clk_tr, + int digits) +{ + Sta *sta = Sta::sta(); + StringSeq *arrivals = new StringSeq; + const ClockEdge *clk_edge = NULL; + if (clk) + clk_edge = clk->edge(clk_tr); + PathAnalysisPtIterator ap_iter(sta); + while (ap_iter.hasNext()) { + PathAnalysisPt *path_ap = ap_iter.next(); + arrivals->push_back(delayAsString(sta->vertexArrival(self, tr, clk_edge, + path_ap), + sta->units(), digits)); + } + return arrivals; +} + TmpFloatSeq * requireds_clk(const TransRiseFall *tr, Clock *clk, @@ -5972,11 +5942,33 @@ requireds_clk(const TransRiseFall *tr, PathAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { PathAnalysisPt *path_ap = ap_iter.next(); - floats->push_back(delayAsFloat(sta->vertexRequired(self,tr,clk_edge,path_ap))); + floats->push_back(delayAsFloat(sta->vertexRequired(self, tr, clk_edge, + path_ap))); } return floats; } +StringSeq * +requireds_clk_delays(const TransRiseFall *tr, + Clock *clk, + const TransRiseFall *clk_tr, + int digits) +{ + Sta *sta = Sta::sta(); + StringSeq *requireds = new StringSeq; + const ClockEdge *clk_edge = NULL; + if (clk) + clk_edge = clk->edge(clk_tr); + PathAnalysisPtIterator ap_iter(sta); + while (ap_iter.hasNext()) { + PathAnalysisPt *path_ap = ap_iter.next(); + requireds->push_back(delayAsString(sta->vertexRequired(self, tr, clk_edge, + path_ap), + sta->units(), digits)); + } + return requireds; +} + TmpFloatSeq * slacks(TransRiseFall *tr) { @@ -6004,11 +5996,33 @@ slacks_clk(const TransRiseFall *tr, PathAnalysisPtIterator ap_iter(sta); while (ap_iter.hasNext()) { PathAnalysisPt *path_ap = ap_iter.next(); - floats->push_back(delayAsFloat(sta->vertexSlack(self, tr, clk_edge, path_ap))); + floats->push_back(delayAsFloat(sta->vertexSlack(self, tr, clk_edge, + path_ap))); } return floats; } +StringSeq * +slacks_clk_delays(const TransRiseFall *tr, + Clock *clk, + const TransRiseFall *clk_tr, + int digits) +{ + Sta *sta = Sta::sta(); + StringSeq *slacks = new StringSeq; + const ClockEdge *clk_edge = NULL; + if (clk) + clk_edge = clk->edge(clk_tr); + PathAnalysisPtIterator ap_iter(sta); + while (ap_iter.hasNext()) { + PathAnalysisPt *path_ap = ap_iter.next(); + slacks->push_back(delayAsString(sta->vertexSlack(self, tr, clk_edge, + path_ap), + sta->units(), digits)); + } + return slacks; +} + VertexPathIterator * path_iterator(const TransRiseFall *tr, const MinMax *min_max) @@ -6070,6 +6084,21 @@ arc_delays(TimingArc *arc) return floats; } +StringSeq * +arc_delay_strings(TimingArc *arc, + int digits) +{ + Sta *sta = Sta::sta(); + StringSeq *delays = new StringSeq; + DcalcAnalysisPtIterator ap_iter(sta); + while (ap_iter.hasNext()) { + DcalcAnalysisPt *dcalc_ap = ap_iter.next(); + delays->push_back(delayAsString(sta->arcDelay(self, arc, dcalc_ap), + sta->units(), digits)); + } + return delays; +} + bool delay_annotated(TimingArc *arc, const Corner *corner, @@ -6085,7 +6114,7 @@ arc_delay(TimingArc *arc, const MinMax *min_max) { DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); - return Sta::sta()->arcDelay(self, arc, dcalc_ap); + return delayAsFloat(Sta::sta()->arcDelay(self, arc, dcalc_ap)); } const char * diff --git a/util/MinMax.cc b/util/MinMax.cc index e495d6e0..398ddf29 100644 --- a/util/MinMax.cc +++ b/util/MinMax.cc @@ -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") diff --git a/util/MinMax.hh b/util/MinMax.hh index 289fd1aa..763fe405 100644 --- a/util/MinMax.hh +++ b/util/MinMax.hh @@ -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_; }