diff --git a/CMakeLists.txt b/CMakeLists.txt index 518b5447..eb0a520d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ cmake_minimum_required (VERSION 3.9) -project(STA VERSION 2.0.5) +project(STA VERSION 2.0.6) set(CMAKE_VERBOSE_MAKEFILE ON) set(CMAKE_CXX_STANDARD 11) diff --git a/configure.ac b/configure.ac index c68f8ba4..c6eafc85 100644 --- a/configure.ac +++ b/configure.ac @@ -16,7 +16,7 @@ # Process this file with autoconf to produce a configure script. -AC_INIT(sta, 2.0.5) +AC_INIT(sta, 2.0.6) AM_INIT_AUTOMAKE AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS(config.h) diff --git a/dcalc/ArcDelayCalc.hh b/dcalc/ArcDelayCalc.hh index 70f64895..30730f0a 100644 --- a/dcalc/ArcDelayCalc.hh +++ b/dcalc/ArcDelayCalc.hh @@ -84,7 +84,8 @@ public: float load_cap, Parasitic *drvr_parasitic, float related_out_cap, - const Pvt *pvt, const DcalcAnalysisPt *dcalc_ap, + const Pvt *pvt, + const DcalcAnalysisPt *dcalc_ap, // Return values. ArcDelay &gate_delay, Slew &drvr_slew) = 0; diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc index 3d7e482b..c9b90a31 100644 --- a/dcalc/ArnoldiDelayCalc.cc +++ b/dcalc/ArnoldiDelayCalc.cc @@ -1309,7 +1309,8 @@ ArnoldiDelayCalc::ra_get_r(delay_work *D, ArcDelay d1; Slew s1; tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, - c1, tab->relcap, d1, s1); + c1, tab->relcap, pocv_enabled_, + d1, s1); tlohi = slew_derate*delayAsFloat(s1); r = tlohi/(c_log*c1); if (rdelay>0.0 && r > rdelay) @@ -1332,7 +1333,7 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D, ArcDelay d1; Slew s1; tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, - c, tab->relcap, d1, s1); + c, tab->relcap, pocv_enabled_, d1, 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) { @@ -1366,9 +1367,9 @@ ArnoldiDelayCalc::ra_rdelay_1(timing_table *tab, ArcDelay d1, d2; Slew s1, s2; tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, - c1, tab->relcap, d1, s1); + c1, tab->relcap, pocv_enabled_, d1, s1); tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, - c2, tab->relcap, d2, s2); + c2, tab->relcap, pocv_enabled_, d2, s2); double dt50 = delayAsFloat(d1)-delayAsFloat(d2); if (dt50 <= 0.0) return 0.0; @@ -1421,12 +1422,12 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, thix = ra_solve_for_t(p,s,vhi); tlox = ra_solve_for_t(p,s,vlo); tab->table->gateDelay(tab->cell, tab->pvt,tab->in_slew, - ctot, tab->relcap, df, sf); + ctot, tab->relcap, pocv_enabled_, df, sf); debugPrint3(debug_, "arnoldi", 1, "table slew (in_slew %s ctot %s) = %s\n", units_->timeUnit()->asString(tab->in_slew), units_->capacitanceUnit()->asString(ctot), - delayAsString(sf, units_)); + delayAsString(sf, this)); tlohi = slew_derate*delayAsFloat(sf); debugPrint2(debug_, "arnoldi", 1, "tlohi %s %s\n", units_->timeUnit()->asString(tlohi), @@ -1434,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); + ceff, tab->relcap, pocv_enabled_, df, sf); t50_sy = delayAsFloat(df); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); @@ -1476,7 +1477,7 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, units_->capacitanceUnit()->asString(ceff)); tab->table->gateDelay(tab->cell, tab->pvt, tab->in_slew, ceff, - tab->relcap, df, sf); + tab->relcap, pocv_enabled_, df, sf); t50_sy = delayAsFloat(df); t50_sr = ra_solve_for_t(1.0/(r*ceff),s,0.5); for (j=0;jn;j++) { diff --git a/dcalc/DmpCeff.cc b/dcalc/DmpCeff.cc index afe8df33..1e08662b 100644 --- a/dcalc/DmpCeff.cc +++ b/dcalc/DmpCeff.cc @@ -77,7 +77,8 @@ gateModelRd(const LibertyCell *cell, double c2, double c1, float related_out_cap, - const Pvt *pvt); + const Pvt *pvt, + bool pocv_enabled); static bool evalDmpEqnsState(void *state); static void @@ -378,6 +379,7 @@ DmpAlg::gateCapDelaySlew(double ceff, static_cast(in_slew_), static_cast(ceff), related_out_cap_, + pocv_enabled_, model_delay, model_slew); delay = delayAsFloat(model_delay); slew = delayAsFloat(model_slew); @@ -1640,7 +1642,7 @@ DmpCeffDelayCalc::setCeffAlgorithm(const LibertyLibrary *drvr_library, { double rd = gate_model ? gateModelRd(drvr_cell, gate_model, in_slew, c2, c1, - related_out_cap, pvt) + related_out_cap, pvt, pocv_enabled_) : 0.0; // Zero Rd means the table is constant and thus independent of load cap. if (rd < 1e-2 @@ -1726,7 +1728,8 @@ DmpCeffDelayCalc::reportGateDelay(const LibertyCell *drvr_cell, if (model) { float in_slew1 = delayAsFloat(in_slew); model->reportGateDelay(drvr_cell, pvt, in_slew1, c_eff, - related_out_cap, digits, result); + related_out_cap, pocv_enabled_, + digits, result); } } @@ -1737,15 +1740,18 @@ gateModelRd(const LibertyCell *cell, double c2, double c1, float related_out_cap, - const Pvt *pvt) + const Pvt *pvt, + bool pocv_enabled) { float cap1 = static_cast((c1 + c2) * .75); float cap2 = cap1 * 1.1F; float in_slew1 = static_cast(in_slew); 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); + gate_model->gateDelay(cell, pvt, in_slew1, cap1, related_out_cap, pocv_enabled, + d1, s1); + gate_model->gateDelay(cell, pvt, in_slew1, cap2, related_out_cap, pocv_enabled, + d2, s2); return abs(delayAsFloat(d1) - delayAsFloat(d2)) / (cap2 - cap1); } diff --git a/dcalc/GraphDelayCalc1.cc b/dcalc/GraphDelayCalc1.cc index 699e84b4..bf2b9ddd 100644 --- a/dcalc/GraphDelayCalc1.cc +++ b/dcalc/GraphDelayCalc1.cc @@ -846,9 +846,9 @@ GraphDelayCalc1::findInputArcDelay(LibertyCell *drvr_cell, ArcDelay load_delay = gate_delay - intrinsic_delay; debugPrint3(debug_, "delay_calc", 3, " gate delay = %s intrinsic = %s slew = %s\n", - delayAsString(gate_delay, units_), - delayAsString(intrinsic_delay, units_), - delayAsString(gate_slew, units_)); + delayAsString(gate_delay, this), + delayAsString(intrinsic_delay, this), + delayAsString(gate_slew, this)); graph_->setSlew(drvr_vertex, drvr_tr, ap_index, gate_slew); annotateLoadDelays(drvr_vertex, drvr_tr, load_delay, false, dcalc_ap, arc_delay_calc_); @@ -1274,8 +1274,8 @@ GraphDelayCalc1::findArcDelay(LibertyCell *drvr_cell, } debugPrint2(debug_, "delay_calc", 3, " gate delay = %s slew = %s\n", - delayAsString(gate_delay, units_), - delayAsString(gate_slew, units_)); + delayAsString(gate_delay, this), + delayAsString(gate_slew, this)); // Merge slews. const Slew &drvr_slew = graph_->slew(drvr_vertex, drvr_tr, ap_index); if (delayFuzzyGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax()) @@ -1477,8 +1477,8 @@ GraphDelayCalc1::annotateLoadDelays(Vertex *drvr_vertex, debugPrint3(debug_, "delay_calc", 3, " %s load delay = %s slew = %s\n", load_vertex->name(sdc_network_), - delayAsString(wire_delay, units_), - delayAsString(load_slew, units_)); + delayAsString(wire_delay, this), + delayAsString(load_slew, this)); if (!load_vertex->slewAnnotated(drvr_tr, ap_index)) { if (drvr_vertex->slewAnnotated(drvr_tr, ap_index)) { // Copy the driver slew to the load if it is annotated. @@ -1593,8 +1593,8 @@ GraphDelayCalc1::findCheckEdgeDelays(Edge *edge, arc_set->role()->asString()); debugPrint2(debug_, "delay_calc", 3, " from_slew = %s to_slew = %s\n", - delayAsString(from_slew, units_), - delayAsString(to_slew, units_)); + delayAsString(from_slew, this), + delayAsString(to_slew, this)); float related_out_cap = 0.0; if (related_out_pin) { Parasitic *related_out_parasitic; @@ -1616,7 +1616,7 @@ GraphDelayCalc1::findCheckEdgeDelays(Edge *edge, check_delay); debugPrint1(debug_, "delay_calc", 3, " check_delay = %s\n", - delayAsString(check_delay, units_)); + delayAsString(check_delay, this)); graph_->setArcDelay(edge, arc, ap_index, check_delay); delay_changed = true; } diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc index e6782c7e..2a63d394 100644 --- a/dcalc/LumpedCapDelayCalc.cc +++ b/dcalc/LumpedCapDelayCalc.cc @@ -151,7 +151,7 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell, GateTimingModel *model = gateModel(arc, dcalc_ap); debugPrint3(debug_, "delay_calc", 3, " in_slew = %s load_cap = %s related_load_cap = %s lumped\n", - delayAsString(in_slew, units()), + delayAsString(in_slew, this), units()->capacitanceUnit()->asString(load_cap), units()->capacitanceUnit()->asString(related_out_cap)); if (model) { @@ -159,7 +159,7 @@ LumpedCapDelayCalc::gateDelay(const LibertyCell *drvr_cell, 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); + pocv_enabled_, gate_delay1, drvr_slew1); gate_delay = gate_delay1; drvr_slew = drvr_slew1; drvr_slew_ = drvr_slew1; @@ -245,7 +245,7 @@ LumpedCapDelayCalc::reportGateDelay(const LibertyCell *drvr_cell, if (model) { float in_slew1 = delayAsFloat(in_slew); model->reportGateDelay(drvr_cell, pvt, in_slew1, load_cap, - related_out_cap, digits, result); + related_out_cap, false, digits, result); } } @@ -264,7 +264,8 @@ LumpedCapDelayCalc::checkDelay(const LibertyCell *cell, if (model) { float from_slew1 = delayAsFloat(from_slew); float to_slew1 = delayAsFloat(to_slew); - model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap, margin); + model->checkDelay(cell, pvt, from_slew1, to_slew1, related_out_cap, + false, margin); } else margin = delay_zero; @@ -287,7 +288,7 @@ LumpedCapDelayCalc::reportCheckDelay(const LibertyCell *cell, float from_slew1 = delayAsFloat(from_slew); float to_slew1 = delayAsFloat(to_slew); model->reportCheckDelay(cell, pvt, from_slew1, from_slew_annotation, to_slew1, - related_out_cap, digits, result); + related_out_cap, false, digits, result); } } diff --git a/graph/Delay.cc b/graph/Delay.cc index d6053bf3..52172f63 100644 --- a/graph/Delay.cc +++ b/graph/Delay.cc @@ -22,18 +22,11 @@ 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()); + return delayAsString(delay, sta, sta->units()->timeUnit()->digits()); } } // namespace diff --git a/graph/Delay.hh b/graph/Delay.hh index f769409f..a9ca5d32 100644 --- a/graph/Delay.hh +++ b/graph/Delay.hh @@ -63,19 +63,16 @@ float delaySigma2(const Delay &delay, const EarlyLate *early_late); 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, + const StaState *sta, int digits); const char * delayAsString(const Delay &delay, const EarlyLate *early_late, - const Units *units, + const StaState *sta, int digits); const Delay & delayInitValue(const MinMax *min_max); diff --git a/graph/DelayFloat.cc b/graph/DelayFloat.cc index fba90b06..4a376d2d 100644 --- a/graph/DelayFloat.cc +++ b/graph/DelayFloat.cc @@ -148,10 +148,20 @@ delayRatio(const Delay &delay1, const char * delayAsString(const Delay &delay, - const Units *units, + const StaState *sta, int digits) { - return units->timeUnit()->asString(delay, digits); + return sta->units()->timeUnit()->asString(delay, digits); +} + +const char * +delayAsString(const Delay &delay, + const EarlyLate *, + const StaState *sta, + int digits) +{ + const Unit *unit = sta->units()->timeUnit(); + return unit->asString(delay, digits); } float @@ -161,16 +171,6 @@ delayAsFloat(const Delay &delay, return delay; } -const char * -delayAsString(const Delay &delay, - const EarlyLate *, - const Units *units, - int digits) -{ - const Unit *unit = units->timeUnit(); - return unit->asString(delay, digits); -} - float delaySigma(const Delay &, const EarlyLate *) diff --git a/graph/DelayNormal2.cc b/graph/DelayNormal2.cc index 4b2755c6..5ae66814 100644 --- a/graph/DelayNormal2.cc +++ b/graph/DelayNormal2.cc @@ -167,7 +167,15 @@ Delay::operator-() const void Delay::operator-=(float delay) { - mean_ -= - delay; + mean_ -= delay; +} + +void +Delay::operator-=(const Delay &delay) +{ + mean_ -= delay.mean_; + sigma2_[early_index] -= delay.sigma2_[early_index]; + sigma2_[late_index] -= delay.sigma2_[late_index]; } bool @@ -409,31 +417,35 @@ delaySigma2(const Delay &delay, const char * delayAsString(const Delay &delay, - const Units *units, + const StaState *sta, int digits) { - const Unit *unit = units->timeUnit(); - float sigma_early = delay.sigma(EarlyLate::early()); - float sigma_late = delay.sigma(EarlyLate::late()); - if (fuzzyEqual(sigma_early, sigma_late)) - return stringPrintTmp("%s|%s", - unit->asString(delay.mean(), digits), - unit->asString(sigma_early, digits)); + const Unit *unit = sta->units()->timeUnit(); + if (sta->pocvEnabled()) { + float sigma_early = delay.sigma(EarlyLate::early()); + float sigma_late = delay.sigma(EarlyLate::late()); + if (fuzzyEqual(sigma_early, sigma_late)) + return stringPrintTmp("%s|%s", + unit->asString(delay.mean(), digits), + unit->asString(sigma_early, digits)); + else + return stringPrintTmp("%s|%s:%s", + unit->asString(delay.mean(), digits), + unit->asString(sigma_early, digits), + unit->asString(sigma_late, digits)); + } else - return stringPrintTmp("%s|%s:%s", - unit->asString(delay.mean(), digits), - unit->asString(sigma_early, digits), - unit->asString(sigma_late, digits)); + return unit->asString(delay.mean(), digits); } const char * delayAsString(const Delay &delay, const EarlyLate *early_late, - const Units *units, + const StaState *sta, int digits) { float mean_sigma = delayAsFloat(delay, early_late); - return units->timeUnit()->asString(mean_sigma, digits); + return sta->units()->timeUnit()->asString(mean_sigma, digits); } } // namespace diff --git a/graph/DelayNormal2.hh b/graph/DelayNormal2.hh index 84a3ed21..d967706a 100644 --- a/graph/DelayNormal2.hh +++ b/graph/DelayNormal2.hh @@ -50,6 +50,7 @@ public: Delay operator-(float delay) const; Delay operator-() const; void operator-=(float delay); + void operator-=(const Delay &delay); bool operator==(const Delay &delay) const; bool operator>(const Delay &delay) const; bool operator>=(const Delay &delay) const; diff --git a/liberty/LinearModel.cc b/liberty/LinearModel.cc index ff5e5483..a6afb5fb 100644 --- a/liberty/LinearModel.cc +++ b/liberty/LinearModel.cc @@ -34,6 +34,7 @@ GateLinearModel::gateDelay(const LibertyCell *, float, float load_cap, float, + bool, // return values ArcDelay &gate_delay, Slew &drvr_slew) const @@ -48,6 +49,7 @@ GateLinearModel::reportGateDelay(const LibertyCell *cell, float, float load_cap, float, + bool, int digits, string *result) const { @@ -90,6 +92,7 @@ CheckLinearModel::checkDelay(const LibertyCell *, float, float, float, + bool, ArcDelay &margin) const { margin = intrinsic_; @@ -102,6 +105,7 @@ CheckLinearModel::reportCheckDelay(const LibertyCell *cell, const char *, float, float, + bool, int digits, string *result) const { diff --git a/liberty/LinearModel.hh b/liberty/LinearModel.hh index 5ef5a022..4baef95d 100644 --- a/liberty/LinearModel.hh +++ b/liberty/LinearModel.hh @@ -31,14 +31,18 @@ public: const Pvt *pvt, float load_cap, float in_slew, float related_out_cap, + bool pocv_enabled, // return values ArcDelay &gate_delay, Slew &drvr_slew) const; virtual void reportGateDelay(const LibertyCell *cell, const Pvt *pvt, - float load_cap, float in_slew, + float load_cap, + float in_slew, float related_out_cap, - int digits, string *result) const; + bool pocv_enabled, + int digits, + string *result) const; virtual float driveResistance(const LibertyCell *cell, const Pvt *pvt) const; @@ -59,8 +63,10 @@ public: // Timing check margin delay calculation. virtual void checkDelay(const LibertyCell *cell, const Pvt *pvt, - float from_slew, float to_slew, + float from_slew, + float to_slew, float related_out_cap, + bool pocv_enabled, ArcDelay &margin) const; virtual void reportCheckDelay(const LibertyCell *cell, const Pvt *pvt, @@ -68,7 +74,9 @@ public: const char *from_slew_annotation, float to_slew, float related_out_cap, - int digits, string *result) const; + bool pocv_enabled, + int digits, + string *result) const; protected: virtual void setIsScaled(bool is_scaled); diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 64a8e572..ac89fe41 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -76,6 +76,7 @@ GateTableModel::gateDelay(const LibertyCell *cell, float in_slew, float load_cap, float related_out_cap, + bool pocv_enabled, // return values ArcDelay &gate_delay, Slew &drvr_slew) const @@ -85,11 +86,11 @@ GateTableModel::gateDelay(const LibertyCell *cell, load_cap, related_out_cap); float sigma_early = 0.0; float sigma_late = 0.0; - if (delay_sigma_models_[EarlyLate::earlyIndex()]) + if (pocv_enabled && 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()]) + if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()]) sigma_late = findValue(library, cell, pvt, delay_sigma_models_[EarlyLate::earlyIndex()], in_slew, load_cap, related_out_cap); @@ -97,16 +98,14 @@ GateTableModel::gateDelay(const LibertyCell *cell, float slew = findValue(library, cell, pvt, slew_model_, in_slew, load_cap, related_out_cap); - if (slew_sigma_models_[EarlyLate::earlyIndex()]) + if (pocv_enabled && 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()]) + if (pocv_enabled && 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; @@ -119,6 +118,7 @@ GateTableModel::reportGateDelay(const LibertyCell *cell, float in_slew, float load_cap, float related_out_cap, + bool pocv_enabled, int digits, string *result) const { @@ -126,22 +126,22 @@ GateTableModel::reportGateDelay(const LibertyCell *cell, reportPvt(library, 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()]) + if (pocv_enabled && 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()]) + if (pocv_enabled && 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()]) + if (pocv_enabled && 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()]) + if (pocv_enabled && 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); @@ -355,21 +355,50 @@ CheckTableModel::checkDelay(const LibertyCell *cell, float from_slew, float to_slew, float related_out_cap, + bool pocv_enabled, // 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(); - margin = model_->findValue(library, cell, pvt, - axis_value1, axis_value2, axis_value3); + float mean = findValue(library, cell, pvt, model_, + from_slew, to_slew, related_out_cap); + float sigma_early = 0.0; + float sigma_late = 0.0; + if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()]) + sigma_early = findValue(library, cell, pvt, + sigma_models_[EarlyLate::earlyIndex()], + from_slew, to_slew, related_out_cap); + if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()]) + sigma_late = findValue(library, cell, pvt, + sigma_models_[EarlyLate::earlyIndex()], + from_slew, to_slew, related_out_cap); + margin = makeDelay(mean, sigma_early, sigma_late); } else margin = 0.0; } +float +CheckTableModel::findValue(const LibertyLibrary *library, + const LibertyCell *cell, + const Pvt *pvt, + const TableModel *model, + float from_slew, + float to_slew, + float related_out_cap) const +{ + if (model) { + float axis_value1, axis_value2, axis_value3; + findAxisValues(from_slew, to_slew, related_out_cap, + axis_value1, axis_value2, axis_value3); + return model->findValue(library, cell, pvt, + axis_value1, axis_value2, axis_value3); + } + else + return 0.0; +} + void CheckTableModel::reportCheckDelay(const LibertyCell *cell, const Pvt *pvt, @@ -377,16 +406,45 @@ CheckTableModel::reportCheckDelay(const LibertyCell *cell, const char *from_slew_annotation, float to_slew, float related_out_cap, + bool pocv_enabled, int digits, string *result) const { - if (model_) { + const LibertyLibrary *library = cell->libertyLibrary(); + reportTableDelay("Check", library, cell, pvt, model_, + from_slew, from_slew_annotation, to_slew, + related_out_cap, digits, result); + if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()]) + reportTableDelay("Check sigma early", library, cell, pvt, + sigma_models_[EarlyLate::earlyIndex()], + from_slew, from_slew_annotation, to_slew, + related_out_cap, digits, result); + if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()]) + reportTableDelay("Check sigma late", library, cell, pvt, + sigma_models_[EarlyLate::lateIndex()], + from_slew, from_slew_annotation, to_slew, + related_out_cap, digits, result); +} + +void +CheckTableModel::reportTableDelay(const char *result_name, + const LibertyLibrary *library, + const LibertyCell *cell, + const Pvt *pvt, + const TableModel *model, + float from_slew, + const char *from_slew_annotation, + float to_slew, + float related_out_cap, + int digits, + string *result) 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(); reportPvt(library, pvt, digits, result); - model_->reportValue("Check", library, cell, pvt, + model_->reportValue(result_name, library, cell, pvt, axis_value1, from_slew_annotation, axis_value2, axis_value3, digits, result); } diff --git a/liberty/TableModel.hh b/liberty/TableModel.hh index 2f285d5b..d96b4354 100644 --- a/liberty/TableModel.hh +++ b/liberty/TableModel.hh @@ -55,6 +55,7 @@ public: float in_slew, float load_cap, float related_out_cap, + bool pocv_enabled, // Return values. ArcDelay &gate_delay, Slew &drvr_slew) const; @@ -63,6 +64,7 @@ public: float in_slew, float load_cap, float related_out_cap, + bool pocv_enabled, int digits, string *result) const; virtual float driveResistance(const LibertyCell *cell, @@ -131,6 +133,7 @@ public: float from_slew, float to_slew, float related_out_cap, + bool pocv_enabled, // Return values. ArcDelay &margin) const; virtual void reportCheckDelay(const LibertyCell *cell, @@ -139,6 +142,7 @@ public: const char *from_slew_annotation, float to_slew, float related_out_cap, + bool pocv_enabled, int digits, string *result) const; @@ -148,6 +152,13 @@ public: protected: virtual void setIsScaled(bool is_scaled); + float findValue(const LibertyLibrary *library, + const LibertyCell *cell, + const Pvt *pvt, + const TableModel *model, + float from_slew, + float to_slew, + float related_out_cap) const; void findAxisValues(float from_slew, float to_slew, float related_out_cap, @@ -159,9 +170,21 @@ protected: float load_cap, float in_slew, float related_out_cap) const; + void reportTableDelay(const char *result_name, + const LibertyLibrary *library, + const LibertyCell *cell, + const Pvt *pvt, + const TableModel *model, + float from_slew, + const char *from_slew_annotation, + float to_slew, + float related_out_cap, + int digits, + string *result) const; static bool checkAxis(TableAxis *axis); TableModel *model_; + TableModel *sigma_models_[EarlyLate::index_count]; private: DISALLOW_COPY_AND_ASSIGN(CheckTableModel); diff --git a/liberty/TimingModel.hh b/liberty/TimingModel.hh index d8da4b0d..2ec345c8 100644 --- a/liberty/TimingModel.hh +++ b/liberty/TimingModel.hh @@ -47,6 +47,7 @@ public: float in_slew, float load_cap, float related_out_cap, + bool pocv_enabled, // Return values. ArcDelay &gate_delay, Slew &drvr_slew) const = 0; @@ -55,6 +56,7 @@ public: float in_slew, float load_cap, float related_out_cap, + bool pocv_enabled, int digits, string *result) const = 0; virtual float driveResistance(const LibertyCell *cell, @@ -71,6 +73,7 @@ public: float from_slew, float to_slew, float related_out_cap, + bool pocv_enabled, // Return values. ArcDelay &margin) const = 0; virtual void reportCheckDelay(const LibertyCell *cell, @@ -79,6 +82,7 @@ public: const char *from_slew_annotation, float to_slew, float related_out_cap, + bool pocv_enabled, int digits, string *result) const = 0; }; diff --git a/sdc/Sdc.hh b/sdc/Sdc.hh index 830912fe..334b4eaf 100644 --- a/sdc/Sdc.hh +++ b/sdc/Sdc.hh @@ -1400,6 +1400,7 @@ protected: WireloadSelection *wireload_selection_[MinMax::index_count]; bool crpr_enabled_; CrprMode crpr_mode_; + bool pocv_enabled_; bool propagate_gated_clock_enable_; bool preset_clr_arcs_enabled_; bool cond_default_arcs_enabled_; diff --git a/search/ClkSkew.cc b/search/ClkSkew.cc index 95d05df0..50c56359 100644 --- a/search/ClkSkew.cc +++ b/search/ClkSkew.cc @@ -155,7 +155,7 @@ ClkSkews::reportClkSkew(ClockSet *clks, tgt_path->transition(this)->asString()); report_->print("%7s %7s %7s\n", time_unit->asString(clk_skew->tgtLatency(this), digits), - delayAsString(-clk_skew->crpr(this), units_, digits), + time_unit->asString(delayAsFloat(-clk_skew->crpr(this)), digits), time_unit->asString(clk_skew->skew(), digits)); } else diff --git a/search/Crpr.cc b/search/Crpr.cc index 9e694879..6e869be5 100644 --- a/search/Crpr.cc +++ b/search/Crpr.cc @@ -283,40 +283,36 @@ CheckCrpr::genClkSrcPaths(const PathVertex *path, } } -#if SSTA Crpr CheckCrpr::findCrpr1(const PathVertex *src_clk_path, const PathVertex *tgt_clk_path) { - // Remove variation on the common path. - // Note that the crpr sigma is negative to offset the - // sigma of the common clock path. - const EarlyLate *src_el = src_clk_path->minMax(this); - const EarlyLate *tgt_el = tgt_clk_path->minMax(this); - float crpr_sigma2 = delaySigma2(src_clk_path->arrival(this), src_el) - + delaySigma2(src_clk_path->arrival(this), tgt_el); - return makeDelay2(0.0, -crpr_sigma2, -crpr_sigma2); + if (pocv_enabled_) { + // Remove variation on the common path. + // Note that the crpr sigma is negative to offset the + // sigma of the common clock path. + const EarlyLate *src_el = src_clk_path->minMax(this); + const EarlyLate *tgt_el = tgt_clk_path->minMax(this); + float crpr_sigma2 = delaySigma2(src_clk_path->arrival(this), src_el) + + delaySigma2(src_clk_path->arrival(this), tgt_el); + return makeDelay2(0.0, -crpr_sigma2, -crpr_sigma2); + } + else { + // The source and target edges are different so the crpr + // is the min of the source and target max-min delay. + float src_delta = crprArrivalDiff(src_clk_path); + float tgt_delta = crprArrivalDiff(tgt_clk_path); + debugPrint1(debug_, "crpr", 2, " src delta %s\n", + delayAsString(src_delta, this)); + debugPrint1(debug_, "crpr", 2, " tgt delta %s\n", + delayAsString(tgt_delta, this)); + float common_delay = min(src_delta, tgt_delta); + debugPrint2(debug_, "crpr", 2, " %s delta %s\n", + network_->pathName(src_clk_path->pin(this)), + delayAsString(common_delay, this)); + return common_delay; + } } -#else -Crpr -CheckCrpr::findCrpr1(const PathVertex *src_clk_path, - const PathVertex *tgt_clk_path) -{ - // The source and target edges are different so the crpr - // is the min of the source and target max-min delay. - float src_delta = crprArrivalDiff(src_clk_path); - float tgt_delta = crprArrivalDiff(tgt_clk_path); - debugPrint1(debug_, "crpr", 2, " src delta %s\n", - delayAsString(src_delta, units_)); - debugPrint1(debug_, "crpr", 2, " tgt delta %s\n", - delayAsString(tgt_delta, units_)); - float common_delay = min(src_delta, tgt_delta); - debugPrint2(debug_, "crpr", 2, " %s delta %s\n", - network_->pathName(src_clk_path->pin(this)), - delayAsString(common_delay, units_)); - return common_delay; -} -#endif Crpr CheckCrpr::outputDelayCrpr(const Path *src_clk_path, diff --git a/search/Genclks.cc b/search/Genclks.cc index da6a850a..dc08864d 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -990,7 +990,7 @@ Genclks::recordSrcPaths(Clock *gclk) network_->pathName(gclk_pin), early_late->asString(), tr->asString(), - delayAsString(path->arrival(this), units_)); + delayAsString(path->arrival(this), this)); src_path.init(path, this); found_src_paths = true; } diff --git a/search/Latches.cc b/search/Latches.cc index 89677d5e..944e9795 100644 --- a/search/Latches.cc +++ b/search/Latches.cc @@ -96,8 +96,8 @@ Latches::latchRequired(const Path *data_path, + open_crpr; debugPrint3(debug_, "latch", 1, "latch data %s %s enable %s\n", network_->pathName(data_path->pin(this)), - delayAsString(data_arrival, units_), - delayAsString(enable_arrival, units_)); + delayAsString(data_arrival, this), + delayAsString(enable_arrival, this)); if (data_arrival <= enable_arrival) { // Data arrives before latch opens. required = enable_arrival; diff --git a/search/PathEnum.cc b/search/PathEnum.cc index a7d88535..a6df2cc2 100644 --- a/search/PathEnum.cc +++ b/search/PathEnum.cc @@ -125,7 +125,7 @@ PathEnum::insert(PathEnd *path_end) path_end->path()->name(this), cmp_slack_ ? "slack" : "delay", delayAsString(cmp_slack_ ? path_end->slack(this) : - path_end->dataArrivalTime(this), units_)); + path_end->dataArrivalTime(this), this)); Diversion *div = new Diversion(path_end, path_end->path()); div_queue_.push(div); div_count_++; @@ -178,8 +178,8 @@ PathEnum::findNext() Path *path = path_end->path(); debug_->print("path_enum: next path %s delay %s slack %s\n", path->name(this), - delayAsString(path_end->dataArrivalTime(this), units_), - delayAsString(path_end->slack(this), units_)); + delayAsString(path_end->dataArrivalTime(this), this), + delayAsString(path_end->slack(this), this)); reportDiversionPath(div); } @@ -213,7 +213,7 @@ PathEnum::reportDiversionPath(Diversion *div) while (!p.isNull()) { debug_->print("path_enum: %s %s%s\n", p.name(this), - delayAsString(p.arrival(this), units_), + delayAsString(p.arrival(this), this), Path::equal(&p, after_div, this) ? " <-diversion" : ""); if (network_->isLatchData(p.pin(this))) break; @@ -387,7 +387,6 @@ PathEnumFaninVisitor::reportDiversion(TimingArc *div_arc, { Debug *debug = sta_->debug(); if (debug->check("path_enum", 3)) { - Units *units = sta_->units(); Path *path = path_end_->path(); const PathAnalysisPt *path_ap = path->pathAnalysisPt(sta_); Arrival path_delay = path_enum_->cmp_slack_ @@ -401,8 +400,8 @@ PathEnumFaninVisitor::reportDiversion(TimingArc *div_arc, debug->print("path_enum: diversion %s %s %s -> %s\n", path->name(sta_), path_enum_->cmp_slack_ ? "slack" : "delay", - delayAsString(path_delay, units), - delayAsString(div_delay, units)); + delayAsString(path_delay, sta_), + delayAsString(div_delay, sta_)); debug->print("path_enum: from %s -> %s\n", div_prev.name(sta_), before_div_.name(sta_)); @@ -592,8 +591,8 @@ PathEnum::updatePathHeadDelays(PathEnumedSeq &paths, Arrival arrival = prev_arrival + arc_delay; debugPrint3(debug_, "path_enum", 3, "update arrival %s %s -> %s\n", path->name(this), - delayAsString(path->arrival(this), units_), - delayAsString(arrival, units_)); + delayAsString(path->arrival(this), this), + delayAsString(arrival, this)); path->setArrival(arrival, this); prev_arrival = arrival; if (sdc_->crprActive()) { diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 2b4f4c1c..872a94ad 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -1936,6 +1936,7 @@ ReportPath::reportSrcClkAndPath(const Path *path, string &result) { ClockEdge *clk_edge = path->clkEdge(this); + const MinMax *min_max = path->minMax(this); if (clk_edge) { Clock *clk = clk_edge->clock(); TransRiseFall *clk_tr = clk_edge->transition(); @@ -1943,9 +1944,11 @@ ReportPath::reportSrcClkAndPath(const Path *path, if (clk == sdc_->defaultArrivalClock()) { if (!is_path_delay) { float clk_end_time = clk_time + time_offset; + const EarlyLate *early_late = min_max; reportLine("clock (input port clock) (rise edge)", - clk_end_time, clk_end_time, result); - reportLine(clkNetworkDelayIdealProp(false), 0.0, clk_end_time, result); + clk_end_time, clk_end_time, early_late, result); + reportLine(clkNetworkDelayIdealProp(false), 0.0, clk_end_time, + early_late, result); } reportPath1(path, expanded, false, time_offset, result); } @@ -1953,7 +1956,6 @@ ReportPath::reportSrcClkAndPath(const Path *path, bool path_from_input = false; bool input_has_ref_path = false; Arrival clk_delay, clk_end_time; - const MinMax *min_max = path->minMax(this); PathRef clk_path; expanded.clkPath(clk_path); const TransRiseFall *clk_end_tr; @@ -2929,16 +2931,6 @@ ReportPath::reportLine(const char *what, } // Report increment, and total. -void -ReportPath::reportLine(const char *what, - float incr, - float total, - string &result) -{ - reportLine(what, field_blank_, field_blank_, field_blank_, - incr, total, false, NULL, NULL, NULL, result); -} - void ReportPath::reportLine(const char *what, Delay incr, @@ -3143,7 +3135,7 @@ ReportPath::reportTotalDelay(Delay value, const EarlyLate *early_late, string &result) { - const char *str = delayAsString(value, early_late, units_, digits_); + const char *str = delayAsString(value, early_late, this, digits_); if (stringEq(str, minus_zero_)) // Filter "-0.00" fields. str = plus_zero_; @@ -3178,7 +3170,7 @@ ReportPath::reportFieldDelay(Delay value, if (delayAsFloat(value) == field_blank_) reportFieldBlank(field, result); else { - const char *str = delayAsString(value, early_late, units_, digits_); + const char *str = delayAsString(value, early_late, this, digits_); if (stringEq(str, minus_zero_)) // Filter "-0.00" fields. str = plus_zero_; diff --git a/search/ReportPath.hh b/search/ReportPath.hh index e0ea40b5..9b0c7fea 100644 --- a/search/ReportPath.hh +++ b/search/ReportPath.hh @@ -407,10 +407,6 @@ protected: const EarlyLate *early_late, const TransRiseFall *tr, string &result); - void reportLine(const char *what, - float incr, - float total, - string &result); void reportLine(const char *what, Delay incr, Delay total, diff --git a/search/Search.cc b/search/Search.cc index 837e3744..f7e5fc83 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -2797,13 +2797,13 @@ Search::reportArrivals(Vertex *vertex) const arrival_index, tr->asString(), path_ap->pathMinMax()->asString(), - delayAsString(arrivals[arrival_index], units_)); + delayAsString(arrivals[arrival_index], this)); if (vertex->hasRequireds()) { int req_index; bool exists; tag_group->requiredIndex(tag, req_index, exists); if (exists) - report_->print(" / %s", delayAsString(arrivals[req_index], units_)); + report_->print(" / %s", delayAsString(arrivals[req_index], this)); } report_->print(" %s", tag->asString(this)); if (tag_group->hasClkTag()) { @@ -3417,15 +3417,15 @@ RequiredCmp::requiredsSave(Vertex *vertex, Required prev_req = path->required(sta); if (!delayFuzzyEqual(prev_req, req)) { debugPrint2(debug, "search", 3, "required save %s -> %s\n", - delayAsString(prev_req, sta->units()), - delayAsString(req, sta->units())); + delayAsString(prev_req, sta), + delayAsString(req, sta)); path->setRequired(req, sta); requireds_changed = true; } } else { debugPrint1(debug, "search", 3, "required save MIA -> %s\n", - delayAsString(req, sta->units())); + delayAsString(req, sta)); path->setRequired(req, sta); } } @@ -3811,7 +3811,7 @@ Search::tnsIncr(Vertex *vertex, { if (delayFuzzyLess(slack, 0.0)) { debugPrint2(debug_, "tns", 3, "tns+ %s %s\n", - delayAsString(slack, units_), + delayAsString(slack, this), vertex->name(sdc_network_)); tns_[path_ap_index] += slack; if (tns_slacks_[path_ap_index].hasKey(vertex)) @@ -3830,9 +3830,9 @@ Search::tnsDecr(Vertex *vertex, if (found && delayFuzzyLess(slack, 0.0)) { debugPrint2(debug_, "tns", 3, "tns- %s %s\n", - delayAsString(slack, units_), + delayAsString(slack, this), vertex->name(sdc_network_)); - tns_[path_ap_index] -= delayAsFloat(slack); + tns_[path_ap_index] -= slack; tns_slacks_[path_ap_index].eraseKey(vertex); } } diff --git a/search/Sta.cc b/search/Sta.cc index da3c8d2f..b478dd8e 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -2142,6 +2142,23 @@ Sta::setCrprMode(CrprMode mode) sdc_->setCrprMode(mode); } +bool +Sta::pocvEnabled() const +{ + return pocv_enabled_; +} + +void +Sta::setPocvEnabled(bool enabled) +{ + if (enabled != pocv_enabled_) { + graph_delay_calc_->delaysInvalid(); + search_->arrivalsInvalid(); + } + pocv_enabled_ = enabled; + updateComponentsState(); +} + bool Sta::propagateGatedClockEnable() const { diff --git a/search/Sta.hh b/search/Sta.hh index a7f143c2..ae3ec1b1 100644 --- a/search/Sta.hh +++ b/search/Sta.hh @@ -730,6 +730,10 @@ public: // TCL variable sta_crpr_mode. CrprMode crprMode() const; void setCrprMode(CrprMode mode); + // TCL variable sta_pocv_enabled. + // Parametric on chip variation (statisical sta). + bool pocvEnabled() const; + void setPocvEnabled(bool enabled); // TCL variable sta_propagate_gated_clock_enable. // Propagate gated clock enable arrivals. bool propagateGatedClockEnable() const; diff --git a/search/StaState.cc b/search/StaState.cc index 358d6ef9..7e6e4cf0 100644 --- a/search/StaState.cc +++ b/search/StaState.cc @@ -36,7 +36,8 @@ StaState::StaState() : sim_(NULL), search_(NULL), latches_(NULL), - thread_count_(1) + thread_count_(1), + pocv_enabled_(false) { } @@ -57,7 +58,8 @@ StaState::StaState(const StaState *sta) : sim_(sta->sim_), search_(sta->search_), latches_(sta->latches_), - thread_count_(sta->thread_count_) + thread_count_(sta->thread_count_), + pocv_enabled_(sta->pocv_enabled_) { } @@ -81,6 +83,7 @@ StaState::copyState(const StaState *sta) search_ = sta->search_; latches_ = sta->latches_; thread_count_ = sta->thread_count_; + pocv_enabled_ = sta->pocv_enabled_; } NetworkEdit * diff --git a/search/StaState.hh b/search/StaState.hh index 3c2ea142..316e514e 100644 --- a/search/StaState.hh +++ b/search/StaState.hh @@ -90,6 +90,7 @@ public: Latches *latches() { return latches_; } Latches *latches() const { return latches_; } unsigned threadCount() const { return thread_count_; } + bool pocvEnabled() const { return pocv_enabled_; } protected: Report *report_; @@ -110,6 +111,7 @@ protected: Search *search_; Latches *latches_; int thread_count_; + bool pocv_enabled_; private: DISALLOW_COPY_AND_ASSIGN(StaState); diff --git a/search/WorstSlack.cc b/search/WorstSlack.cc index 0624f413..4ab95659 100644 --- a/search/WorstSlack.cc +++ b/search/WorstSlack.cc @@ -173,7 +173,7 @@ WorstSlack::initQueue(PathAPIndex path_ap_index, } } debugPrint1(debug, "wns", 3, "threshold %s\n", - delayAsString(slack_threshold_, sta->units())); + delayAsString(slack_threshold_, sta)); // checkQueue(); } @@ -200,7 +200,7 @@ WorstSlack::sortQueue(PathAPIndex path_ap_index, Vertex *threshold_vertex = vertices[threshold_index]; slack_threshold_ = search->wnsSlack(threshold_vertex, path_ap_index); debugPrint1(debug, "wns", 3, "threshold %s\n", - delayAsString(slack_threshold_, sta->units())); + delayAsString(slack_threshold_, sta)); // Reinsert vertices with slack < threshold. queue_.clear(); @@ -243,7 +243,6 @@ WorstSlack::checkQueue(PathAPIndex path_ap_index, { Search *search = sta->search(); Report *report = sta->report(); - Units *units = sta->units(); const Network *network = sta->network(); VertexSeq ends; @@ -267,8 +266,8 @@ WorstSlack::checkQueue(PathAPIndex path_ap_index, slack_threshold_)) report->print("WorstSlack queue missing %s %s < %s\n", end->name(network), - delayAsString(search->wnsSlack(end, path_ap_index), units), - delayAsString(slack_threshold_, units)); + delayAsString(search->wnsSlack(end, path_ap_index), sta), + delayAsString(slack_threshold_, sta)); } VertexSet::Iterator queue_iter(queue_); @@ -277,9 +276,8 @@ WorstSlack::checkQueue(PathAPIndex path_ap_index, if (!end_set.hasKey(end)) report->print("WorstSlack queue extra %s %s > %s\n", end->name(network), - delayAsString(search->wnsSlack(end, path_ap_index), - units), - delayAsString(slack_threshold_, units)); + delayAsString(search->wnsSlack(end, path_ap_index), sta), + delayAsString(slack_threshold_, sta)); } } @@ -307,13 +305,13 @@ WorstSlack::updateWorstSlack(Vertex *vertex, && delayFuzzyLessEqual(slack, slack_threshold_)) { debugPrint2(debug, "wns", 3, "insert %s %s\n", vertex->name(network), - delayAsString(slack, sta->units())); + delayAsString(slack, sta)); queue_.insert(vertex); } else { debugPrint2(debug, "wns", 3, "delete %s %s\n", vertex->name(network), - delayAsString(slack, sta->units())); + delayAsString(slack, sta)); queue_.eraseKey(vertex); } lock_.unlock(); @@ -327,7 +325,7 @@ WorstSlack::setWorstSlack(Vertex *vertex, { debugPrint2(sta->debug(), "wns", 3, "%s %s\n", vertex->name(sta->network()), - delayAsString(slack, sta->units())); + delayAsString(slack, sta)); worst_vertex_ = vertex; worst_slack_ = slack; } diff --git a/search/WritePathSpice.cc b/search/WritePathSpice.cc index 511f6387..e0de92b8 100644 --- a/search/WritePathSpice.cc +++ b/search/WritePathSpice.cc @@ -26,6 +26,7 @@ #include "FuncExpr.hh" #include "Units.hh" #include "Sequential.hh" +#include "TableModel.hh" #include "Liberty.hh" #include "TimingArc.hh" #include "Network.hh" @@ -136,9 +137,11 @@ private: float clkWaveformTImeOffset(const Clock *clk); float findSlew(Path *path); float findSlew(Path *path, - const TransRiseFall *tr); + const TransRiseFall *tr, + TimingArc *next_arc); float findSlew(Vertex *vertex, const TransRiseFall *tr, + TimingArc *next_arc, DcalcAPIndex dcalc_ap_index); LibertyPort *onePort(FuncExpr *expr); void writeVoltageSource(LibertyCell *cell, @@ -146,6 +149,7 @@ private: const char *subckt_port_name, const char *pg_port_name, int &volt_index); + float slewAxisMinValue(TimingArc *arc); // Stage "accessors". // @@ -324,7 +328,9 @@ WritePathSpice::maxTime() { auto input_stage = stageFirst(); auto input_path = stageDrvrPath(input_stage); - auto input_slew = findSlew(input_path); + auto tr = input_path->transition(this); + auto next_arc = stageGateArc(input_stage + 1); + auto input_slew = findSlew(input_path, tr, next_arc); if (input_path->isClock(this)) { auto clk = input_path->clock(this); auto period = clk->period(); @@ -407,11 +413,13 @@ WritePathSpice::writeInputWaveform() auto input_stage = stageFirst(); auto input_path = stageDrvrPath(input_stage); auto tr = input_path->transition(this); - auto slew0 = findSlew(input_path, tr); + auto next_arc = stageGateArc(input_stage + 1); + auto slew0 = findSlew(input_path, tr, next_arc); // Arbitrary offset. auto time0 = slew0; int volt_index = 1; - writeStepVoltSource(stageDrvrPin(input_stage), tr, slew0, time0, volt_index); + auto drvr_pin = stageDrvrPin(input_stage); + writeStepVoltSource(drvr_pin, tr, slew0, time0, volt_index); } void @@ -445,6 +453,7 @@ WritePathSpice::writeClkWaveform() { auto input_stage = stageFirst(); auto input_path = stageDrvrPath(input_stage); + auto next_arc = stageGateArc(input_stage + 1); auto clk_edge = input_path->clkEdge(this); auto clk = clk_edge->clock(); auto period = clk->period(); @@ -461,8 +470,8 @@ WritePathSpice::writeClkWaveform() tr1 = TransRiseFall::rise(); volt0 = power_voltage_; } - auto slew0 = findSlew(input_path, tr0); - auto slew1 = findSlew(input_path, tr1); + auto slew0 = findSlew(input_path, tr0, next_arc); + auto slew1 = findSlew(input_path, tr1, next_arc); streamPrint(spice_stream_, "v1 %s 0 pwl(\n", stageDrvrPinName(input_stage)); streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0); @@ -488,29 +497,63 @@ WritePathSpice::findSlew(Path *path) auto vertex = path->vertex(this); auto dcalc_ap_index = path->dcalcAnalysisPt(this)->index(); auto tr = path->transition(this); - return findSlew(vertex, tr, dcalc_ap_index); + return findSlew(vertex, tr, NULL, dcalc_ap_index); } float WritePathSpice::findSlew(Path *path, - const TransRiseFall *tr) + const TransRiseFall *tr, + TimingArc *next_arc) { auto vertex = path->vertex(this); auto dcalc_ap_index = path->dcalcAnalysisPt(this)->index(); - return findSlew(vertex, tr, dcalc_ap_index); + return findSlew(vertex, tr, next_arc, dcalc_ap_index); } float WritePathSpice::findSlew(Vertex *vertex, const TransRiseFall *tr, + TimingArc *next_arc, DcalcAPIndex dcalc_ap_index) { auto slew = delayAsFloat(graph_->slew(vertex, tr, dcalc_ap_index)); + if (slew == 0.0 && next_arc) + slew = slewAxisMinValue(next_arc); if (slew == 0.0) slew = units_->timeUnit()->scale(); return slew; } +// Look up the smallest slew axis value in the timing arc delay table. +float +WritePathSpice::slewAxisMinValue(TimingArc *arc) +{ + GateTableModel *gate_model = dynamic_cast(arc->model()); + if (gate_model) { + const TableModel *model = gate_model->delayModel(); + TableAxis *axis; + TableAxisVariable var; + axis = model->axis1(); + var = axis->variable(); + if (var == table_axis_input_transition_time + || var == table_axis_input_net_transition) + return axis->axisValue(0); + + axis = model->axis2(); + var = axis->variable(); + if (var == table_axis_input_transition_time + || var == table_axis_input_net_transition) + return axis->axisValue(0); + + axis = model->axis3(); + var = axis->variable(); + if (var == table_axis_input_transition_time + || var == table_axis_input_net_transition) + return axis->axisValue(0); + } + return 0.0; +} + // Write PWL rise/fall edge that crosses threshold at time. void WritePathSpice::writeWaveformEdge(const TransRiseFall *tr, @@ -807,6 +850,7 @@ WritePathSpice::writeStageVoltageSources(Stage stage, } } +// PWL voltage source that rises half way into the first clock cycle. void WritePathSpice::writeClkedStepSource(const Pin *pin, const TransRiseFall *tr, @@ -815,7 +859,7 @@ WritePathSpice::writeClkedStepSource(const Pin *pin, int &volt_index) { auto vertex = graph_->pinLoadVertex(pin); - auto slew = findSlew(vertex, tr, dcalc_ap_index); + auto slew = findSlew(vertex, tr, NULL, dcalc_ap_index); auto time = clkWaveformTImeOffset(clk) + clk->period() / 2.0; writeStepVoltSource(pin, tr, slew, time, volt_index); } diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index af512d3a..608125b5 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -4011,6 +4011,18 @@ set_crpr_mode(const char *mode) internalError("unknown common clk pessimism mode."); } +bool +pocv_enabled() +{ + return Sta::sta()->pocvEnabled(); +} + +void +set_pocv_enabled(bool enabled) +{ + return Sta::sta()->setPocvEnabled(enabled); +} + bool propagate_gated_clock_enable() { @@ -5699,7 +5711,7 @@ arrivals_clk_delays(const TransRiseFall *tr, PathAnalysisPt *path_ap = ap_iter.next(); arrivals->push_back(delayAsString(sta->vertexArrival(self, tr, clk_edge, path_ap), - sta->units(), digits)); + sta, digits)); } return arrivals; } @@ -5739,7 +5751,7 @@ requireds_clk_delays(const TransRiseFall *tr, PathAnalysisPt *path_ap = ap_iter.next(); requireds->push_back(delayAsString(sta->vertexRequired(self, tr, clk_edge, path_ap), - sta->units(), digits)); + sta, digits)); } return requireds; } @@ -5793,7 +5805,7 @@ slacks_clk_delays(const TransRiseFall *tr, PathAnalysisPt *path_ap = ap_iter.next(); slacks->push_back(delayAsString(sta->vertexSlack(self, tr, clk_edge, path_ap), - sta->units(), digits)); + sta, digits)); } return slacks; } @@ -5869,7 +5881,7 @@ arc_delay_strings(TimingArc *arc, while (ap_iter.hasNext()) { DcalcAnalysisPt *dcalc_ap = ap_iter.next(); delays->push_back(delayAsString(sta->arcDelay(self, arc, dcalc_ap), - sta->units(), digits)); + sta, digits)); } return delays; } diff --git a/tcl/Variables.tcl b/tcl/Variables.tcl index ea07f296..2ae57454 100644 --- a/tcl/Variables.tcl +++ b/tcl/Variables.tcl @@ -160,6 +160,14 @@ proc trace_propagate_gated_clock_enable { name1 name2 op } { propagate_gated_clock_enable set_propagate_gated_clock_enable } +trace variable ::sta_pocv_enabled "rw" \ + sta::trace_pocv_enabled + +proc trace_pocv_enabled { name1 name2 op } { + trace_boolean_var $op ::sta_pocv_enabled \ + pocv_enabled set_pocv_enabled +} + ################################################################ proc trace_boolean_var { op var_name get_proc set_proc } {