diff --git a/CMakeLists.txt b/CMakeLists.txt index 2955d985..07ccac05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,8 @@ set(STA_SOURCE search/CheckMaxSkews.cc search/CheckMinPeriods.cc search/CheckMinPulseWidths.cc + search/CheckCapacitanceLimits.cc + search/CheckFanoutLimits.cc search/CheckSlewLimits.cc search/CheckTiming.cc search/ClkInfo.cc @@ -511,6 +513,9 @@ install(DIRECTORY include/sta DESTINATION include) ################################################################ -add_custom_target(tags etags -o TAGS ${STA_SOURCE} */*.hh include/sta/*.hh ${SWIG_TCL_FILES} +add_custom_target(tags etags -o TAGS + ${STA_SOURCE} + */*.hh include/sta/*.hh + ${STA_TCL_FILES} ${SWIG_TCL_FILES} WORKING_DIRECTORY ${STA_HOME} ) diff --git a/dcalc/DmpDelayCalc.cc b/dcalc/DmpDelayCalc.cc index acaa5880..44823aa7 100644 --- a/dcalc/DmpDelayCalc.cc +++ b/dcalc/DmpDelayCalc.cc @@ -244,7 +244,8 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin, parasitic_ap); // Estimated parasitics are not recorded in the "database", so // it for deletion after the drvr pin delay calc is finished. - unsaved_parasitics_.push_back(parasitic); + if (parasitic) + unsaved_parasitics_.push_back(parasitic); return parasitic; } } @@ -346,7 +347,7 @@ DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue, { ComplexFloat pole2, residue2; parasitics_->poleResidue(pole_residue, 1, pole2, residue2); - if (!fuzzyZero(drvr_slew_) + if (!delayZero(drvr_slew_) && pole2.imag() == 0.0 && residue2.imag() == 0.0) { double p2 = pole2.real(); diff --git a/dcalc/GraphDelayCalc1.cc b/dcalc/GraphDelayCalc1.cc index 33f4bdbd..99d97673 100644 --- a/dcalc/GraphDelayCalc1.cc +++ b/dcalc/GraphDelayCalc1.cc @@ -1246,7 +1246,7 @@ GraphDelayCalc1::findArcDelay(LibertyCell *drvr_cell, // Merge slews. const Slew &drvr_slew = graph_->slew(drvr_vertex, drvr_rf, ap_index); const MinMax *slew_min_max = dcalc_ap->slewMinMax(); - if (fuzzyGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax()) + if (delayGreater(gate_slew, drvr_slew, dcalc_ap->slewMinMax(), this) && !drvr_vertex->slewAnnotated(drvr_rf, slew_min_max)) graph_->setSlew(drvr_vertex, drvr_rf, ap_index, gate_slew); if (!graph_->arcDelayAnnotated(edge, arc, ap_index)) { @@ -1446,7 +1446,7 @@ GraphDelayCalc1::annotateLoadDelays(Vertex *drvr_vertex, else { const Slew &slew = graph_->slew(load_vertex, drvr_rf, ap_index); if (!merge - || fuzzyGreater(load_slew, slew, slew_min_max)) + || delayGreater(load_slew, slew, slew_min_max, this)) graph_->setSlew(load_vertex, drvr_rf, ap_index, load_slew); } } @@ -1459,7 +1459,7 @@ GraphDelayCalc1::annotateLoadDelays(Vertex *drvr_vertex, Delay wire_delay_extra = extra_delay + wire_delay; const MinMax *delay_min_max = dcalc_ap->delayMinMax(); if (!merge - || fuzzyGreater(wire_delay_extra, delay, delay_min_max)) { + || delayGreater(wire_delay_extra, delay, delay_min_max, this)) { graph_->setWireArcDelay(wire_edge, drvr_rf, ap_index, wire_delay_extra); if (observer_) diff --git a/dcalc/LumpedCapDelayCalc.cc b/dcalc/LumpedCapDelayCalc.cc index 79b8710c..f4292a1a 100644 --- a/dcalc/LumpedCapDelayCalc.cc +++ b/dcalc/LumpedCapDelayCalc.cc @@ -90,7 +90,8 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin, parasitic_ap); // Estimated parasitics are not recorded in the "database", so // it for deletion after the drvr pin delay calc is finished. - unsaved_parasitics_.push_back(parasitic); + if (parasitic) + unsaved_parasitics_.push_back(parasitic); return parasitic; } } diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt index 92407f08..a6045afa 100644 Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ diff --git a/graph/DelayFloat.cc b/graph/DelayFloat.cc index 9046da8c..9fda2611 100644 --- a/graph/DelayFloat.cc +++ b/graph/DelayFloat.cc @@ -35,70 +35,6 @@ initDelayConstants() delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue(); } -const Delay & -delayInitValue(const MinMax *min_max) -{ - return delay_init_values[min_max->index()]; -} - -bool -delayIsInitValue(const Delay &delay, - const MinMax *min_max) -{ - return fuzzyEqual(delay, min_max->initValue()); -} - -bool -fuzzyGreater(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max) -{ - if (min_max == MinMax::max()) - return fuzzyGreater(delay1, delay2); - else - return fuzzyLess(delay1, delay2); -} - -bool -fuzzyGreaterEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max) -{ - if (min_max == MinMax::max()) - return fuzzyGreaterEqual(delay1, delay2); - else - return fuzzyLessEqual(delay1, delay2); -} - -bool -fuzzyLess(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max) -{ - if (min_max == MinMax::max()) - return fuzzyLess(delay1, delay2); - else - return fuzzyGreater(delay1, delay2); -} - -bool -fuzzyLessEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max) -{ - if (min_max == MinMax::max()) - return fuzzyLessEqual(delay1, delay2); - else - return fuzzyGreaterEqual(delay1, delay2); -} - -float -delayRatio(const Delay &delay1, - const Delay &delay2) -{ - return delay1 / delay2; -} - const char * delayAsString(const Delay &delay, const StaState *sta) @@ -124,19 +60,130 @@ delayAsString(const Delay &delay, return unit->asString(delay, digits); } -float -delayAsFloat(const Delay &delay, - const EarlyLate *, +const Delay & +delayInitValue(const MinMax *min_max) +{ + return delay_init_values[min_max->index()]; +} + +bool +delayIsInitValue(const Delay &delay, + const MinMax *min_max) +{ + return fuzzyEqual(delay, min_max->initValue()); +} + +bool +delayZero(const Delay &delay) +{ + return fuzzyZero(delay); +} + +bool +delayInf(const Delay &delay) +{ + return fuzzyInf(delay); +} + +bool +delayEqual(const Delay &delay1, + const Delay &delay2) +{ + return fuzzyEqual(delay1, delay2); +} + +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const StaState *) +{ + return fuzzyLess(delay1, delay2); +} + +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *) +{ + if (min_max == MinMax::max()) + return fuzzyLess(delay1, delay2); + else + return fuzzyGreater(delay1, delay2); +} + +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *) +{ + return fuzzyLessEqual(delay1, delay2); +} + +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *) +{ + if (min_max == MinMax::max()) + return fuzzyLessEqual(delay1, delay2); + else + return fuzzyGreaterEqual(delay1, delay2); +} + +bool +delayGreater(const Delay &delay1, + const Delay &delay2, const StaState *) { - return delay; + return fuzzyGreater(delay1, delay2); +} + +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *) +{ + if (min_max == MinMax::max()) + return fuzzyGreater(delay1, delay2); + else + return fuzzyLess(delay1, delay2); +} + +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *) +{ + return fuzzyGreaterEqual(delay1, delay2); +} + +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *) +{ + if (min_max == MinMax::max()) + return fuzzyGreaterEqual(delay1, delay2); + else + return fuzzyLessEqual(delay1, delay2); +} + +Delay +delayRemove(const Delay &delay1, + const Delay &delay2) +{ + return delay1 - delay2; } float -delaySigma2(const Delay &, - const EarlyLate *) +delayRatio(const Delay &delay1, + const Delay &delay2) { - return 0.0; + return delay1 / delay2; } } // namespace diff --git a/graph/DelayNormal1.cc b/graph/DelayNormal1.cc index 4afad127..3b2f5edb 100644 --- a/graph/DelayNormal1.cc +++ b/graph/DelayNormal1.cc @@ -162,32 +162,7 @@ Delay::operator-=(const Delay &delay) bool Delay::operator==(const Delay &delay) const { - return mean_ == delay.mean_ - && sigma2_ == delay.sigma2_; -} - -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_; + return delayEqual(*this, delay); } //////////////////////////////////////////////////////////////// @@ -208,166 +183,6 @@ makeDelay2(float delay, return Delay(delay, sigma2); } -bool -delayIsInitValue(const Delay &delay, - const MinMax *min_max) -{ - return fuzzyEqual(delay.mean(), min_max->initValue()) - && delay.sigma2() == 0.0; -} - -bool -fuzzyZero(const Delay &delay) -{ - return fuzzyZero(delay.mean()) - && fuzzyZero(delay.sigma2()); -} - -bool -fuzzyInf(const Delay &delay) -{ - return fuzzyInf(delay.mean()); -} - -bool -fuzzyEqual(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyEqual(delay1.mean(), delay2.mean()) - && fuzzyEqual(delay1.sigma2(), delay2.sigma2()); -} - -bool -fuzzyLess(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyLess(delay1.mean(), delay2.mean()); -} - -bool -fuzzyLess(const Delay &delay1, - float delay2) -{ - return fuzzyLess(delay1.mean(), delay2); -} - -bool -fuzzyLessEqual(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyLessEqual(delay1.mean(), delay2.mean()); -} - -bool -fuzzyLessEqual(const Delay &delay1, - float delay2) -{ - return fuzzyLessEqual(delay1.mean(), delay2); -} - -bool -fuzzyLessEqual(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 -fuzzyGreater(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyGreater(delay1.mean(), delay2.mean()); -} - -bool -fuzzyGreater(const Delay &delay1, - float delay2) -{ - return fuzzyGreater(delay1.mean(), delay2); -} - -bool -fuzzyGreaterEqual(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyGreaterEqual(delay1.mean(), delay2.mean()); -} - -bool -fuzzyGreaterEqual(const Delay &delay1, - float delay2) -{ - return fuzzyGreaterEqual(delay1.mean(), delay2); -} - -bool -fuzzyGreater(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 -fuzzyGreaterEqual(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 -fuzzyLess(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.sigma2()); -} - -Delay -operator/(float delay1, - const Delay &delay2) -{ - return Delay(delay1 / delay2.mean(), - delay2.sigma2()); -} - -Delay -operator*(const Delay &delay1, - float delay2) -{ - return Delay(delay1.mean() * delay2, - delay1.sigma2() * delay2 * delay2); -} - -float -delayRatio(const Delay &delay1, - const Delay &delay2) -{ - return delay1.mean() / delay2.mean(); -} - float delayAsFloat(const Delay &delay, const EarlyLate *early_late, @@ -425,6 +240,195 @@ delayAsString(const Delay &delay, return sta->units()->timeUnit()->asString(mean_sigma, digits); } +bool +delayIsInitValue(const Delay &delay, + const MinMax *min_max) +{ + return fuzzyEqual(delay.mean(), min_max->initValue()) + && delay.sigma2() == 0.0; +} + +bool +delayZero(const Delay &delay) +{ + return fuzzyZero(delay.mean()) + && fuzzyZero(delay.sigma2()); +} + +bool +delayInf(const Delay &delay) +{ + return fuzzyInf(delay.mean()); +} + +bool +delayEqual(const Delay &delay1, + const Delay &delay2) +{ + return fuzzyEqual(delay1.mean(), delay2.mean()) + && fuzzyEqual(delay1.sigma2(), delay2.sigma2()); +} + +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), + delayAsFloat(delay2, EarlyLate::early(), sta)); +} + +bool +delayLess(const Delay &delay1, + float delay2, + const StaState *sta) +{ + return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), + delay2); +} + +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) +{ + if (min_max == MinMax::max()) + return delayLess(delay1, delay2, sta); + else + return delayGreater(delay1, delay2, sta); +} + +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta), + delayAsFloat(delay2, EarlyLate::early(), sta)); +} + +bool +delayLessEqual(const Delay &delay1, + float delay2, + const StaState *sta) +{ + return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta), + delay2); +} + +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) +{ + if (min_max == MinMax::max()) + return delayLessEqual(delay1, delay2, sta); + else + return delayGreaterEqual(delay1, delay2, sta); +} + +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const StaState *sta) + +{ + return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta), + delayAsFloat(delay2, EarlyLate::late(), sta)); +} + +bool +delayGreater(const Delay &delay1, + float delay2, + const StaState *sta) +{ + return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta), + delay2); +} + +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), + delayAsFloat(delay2, EarlyLate::late(), sta)); +} + +bool +delayGreaterEqual(const Delay &delay1, + float delay2, + const StaState *sta) +{ + return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), + delay2); +} + +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) +{ + if (min_max == MinMax::max()) + return delayGreater(delay1, delay2, sta); + else + return delayLess(delay1, delay2, sta); +} + +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) +{ + if (min_max == MinMax::max()) + return delayGreaterEqual(delay1, delay2, sta); + else + return delayLessEqual(delay1, delay2, sta); +} + +Delay +delayRemove(const Delay &delay1, + const Delay &delay2) +{ + return Delay(delay1.mean() - delay2.mean(), + delay1.sigma2() - delay2.sigma2()); +} + +float +delayRatio(const Delay &delay1, + const Delay &delay2) +{ + return delay1.mean() / delay2.mean(); +} + +Delay +operator+(float delay1, + const Delay &delay2) +{ + return Delay(delay1 + delay2.mean(), + delay2.sigma2()); +} + +Delay +operator/(float delay1, + const Delay &delay2) +{ + return Delay(delay1 / delay2.mean(), + delay2.sigma2()); +} + +Delay +operator*(const Delay &delay1, + float delay2) +{ + return Delay(delay1.mean() * delay2, + delay1.sigma2() * delay2 * delay2); +} + } // namespace #endif // (SSTA == 1) diff --git a/graph/DelayNormal2.cc b/graph/DelayNormal2.cc index 1edeafd4..883aa306 100644 --- a/graph/DelayNormal2.cc +++ b/graph/DelayNormal2.cc @@ -187,30 +187,6 @@ Delay::operator==(const Delay &delay) const && sigma2_[late_index] == delay.sigma2_[early_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_; -} - //////////////////////////////////////////////////////////////// Delay @@ -234,12 +210,12 @@ delayIsInitValue(const Delay &delay, const MinMax *min_max) { return fuzzyEqual(delay.mean(), min_max->initValue()) - && delay.sigma2Early() == 0.0 - && delay.sigma2Late() == 0.0; + && fuzzyZero(delay.sigma2Early()) + && fuzzyZero(delay.sigma2Late()); } bool -fuzzyZero(const Delay &delay) +delayZero(const Delay &delay) { return fuzzyZero(delay.mean()) && fuzzyZero(delay.sigma2Early()) @@ -247,13 +223,13 @@ fuzzyZero(const Delay &delay) } bool -fuzzyInf(const Delay &delay) +delayInf(const Delay &delay) { return fuzzyInf(delay.mean()); } bool -fuzzyEqual(const Delay &delay1, +delayEqual(const Delay &delay1, const Delay &delay2) { return fuzzyEqual(delay1.mean(), delay2.mean()) @@ -262,137 +238,123 @@ fuzzyEqual(const Delay &delay1, } bool -fuzzyLess(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyLess(delay1.mean(), delay2.mean()); -} - -bool -fuzzyLess(const Delay &delay1, - float delay2) -{ - return fuzzyLess(delay1.mean(), delay2); -} - -bool -fuzzyLessEqual(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyLessEqual(delay1.mean(), delay2.mean()); -} - -bool -fuzzyLessEqual(const Delay &delay1, - float delay2) -{ - return fuzzyLessEqual(delay1.mean(), delay2); -} - -bool -fuzzyLessEqual(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 -fuzzyGreater(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyGreater(delay1.mean(), delay2.mean()); -} - -bool -fuzzyGreater(const Delay &delay1, - float delay2) -{ - return fuzzyGreater(delay1.mean(), delay2); -} - -bool -fuzzyGreaterEqual(const Delay &delay1, - const Delay &delay2) -{ - return fuzzyGreaterEqual(delay1.mean(), delay2.mean()); -} - -bool -fuzzyGreaterEqual(const Delay &delay1, - float delay2) -{ - return fuzzyGreaterEqual(delay1.mean(), delay2); -} - -bool -fuzzyGreater(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 -fuzzyGreaterEqual(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 -fuzzyLess(const Delay &delay1, +delayLess(const Delay &delay1, const Delay &delay2, - const MinMax *min_max) + const StaState *sta) +{ + return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), + delayAsFloat(delay2, EarlyLate::early(), sta)); +} + +bool +delayLess(const Delay &delay1, + float delay2, + const StaState *sta) +{ + return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta), + delay2); +} + +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) { if (min_max == MinMax::max()) - return fuzzyLess(delay1.mean(), delay2.mean()); + return delayLess(delay1, delay2, sta); else - return fuzzyGreater(delay1.mean(), delay2.mean()); + return delayGreater(delay1, delay2, sta); } -Delay -operator+(float delay1, - const Delay &delay2) +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) { - return Delay(delay1 + delay2.mean(), - delay2.sigma2Early(), - delay2.sigma2Late()); + return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta), + delayAsFloat(delay2, EarlyLate::early(), sta)); } -Delay -operator/(float delay1, - const Delay &delay2) +bool +delayLessEqual(const Delay &delay1, + float delay2, + const StaState *sta) { - return Delay(delay1 / delay2.mean(), - delay2.sigma2Early(), - delay2.sigma2Late()); + return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta), + delay2); } -Delay -operator*(const Delay &delay1, - float delay2) +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) { - return Delay(delay1.mean() * delay2, - delay1.sigma2Early() * delay2 * delay2, - delay1.sigma2Late() * delay2 * delay2); + if (min_max == MinMax::max()) + return delayLessEqual(delay1, delay2, sta); + else + return delayGreaterEqual(delay1, delay2, sta); } -float -delayRatio(const Delay &delay1, - const Delay &delay2) +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const StaState *sta) { - return delay1.mean() / delay2.mean(); + return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta), + delayAsFloat(delay2, EarlyLate::late(), sta)); +} + +bool +delayGreater(const Delay &delay1, + float delay2, + const StaState *sta) +{ + return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), + delayAsFloat(delay2, EarlyLate::late(), sta)); +} + +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta) +{ + return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), + delayAsFloat(delay2, EarlyLate::late(), sta)); +} + +bool +delayGreaterEqual(const Delay &delay1, + float delay2, + const StaState *sta) +{ + return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta), + delay2); +} + +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) +{ + if (min_max == MinMax::max()) + return delayGreater(delay1, delay2, sta); + else + return delayLess(delay1, delay2, sta); +} + +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta) +{ + if (min_max == MinMax::max()) + return delayGreaterEqual(delay1, delay2, sta); + else + return delayLessEqual(delay1, delay2, sta); } float @@ -454,6 +416,49 @@ delayAsString(const Delay &delay, return sta->units()->timeUnit()->asString(mean_sigma, digits); } +Delay +delayRemove(const Delay &delay1, + const Delay &delay2) +{ + return Delay(delay1.mean() - delay2.mean(), + delay1.sigma2Early() - delay2.sigma2Early(), + delay1.sigma2Late() - delay2.sigma2Late()); +} + +float +delayRatio(const Delay &delay1, + const Delay &delay2) +{ + return delay1.mean() / delay2.mean(); +} + +Delay +operator+(float delay1, + const Delay &delay2) +{ + return Delay(delay1 + delay2.mean(), + delay2.sigma2Early(), + delay2.sigma2Late()); +} + +Delay +operator/(float delay1, + const Delay &delay2) +{ + return Delay(delay1 / delay2.mean(), + delay2.sigma2Early(), + delay2.sigma2Late()); +} + +Delay +operator*(const Delay &delay1, + float delay2) +{ + return Delay(delay1.mean() * delay2, + delay1.sigma2Early() * delay2 * delay2, + delay1.sigma2Late() * delay2 * delay2); +} + } // namespace #endif // (SSTA == 2) diff --git a/include/sta/Delay.hh b/include/sta/Delay.hh index 06ca2929..5b68ae8c 100644 --- a/include/sta/Delay.hh +++ b/include/sta/Delay.hh @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "StaConfig.hh" - #pragma once +#include "StaConfig.hh" + #if (SSTA == 1) // Delays are Normal PDFs. #include "DelayNormal1.hh" diff --git a/include/sta/DelayFloat.hh b/include/sta/DelayFloat.hh index 896145d3..58987103 100644 --- a/include/sta/DelayFloat.hh +++ b/include/sta/DelayFloat.hh @@ -17,7 +17,6 @@ #pragma once #include "MinMax.hh" -#include "Fuzzy.hh" // Delay values defined as floats. @@ -32,6 +31,19 @@ const Delay delay_zero = 0.0; void initDelayConstants(); +const char * +delayAsString(const Delay &delay, + const StaState *sta); +const char * +delayAsString(const Delay &delay, + const StaState *sta, + int digits); +const char * +delayAsString(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta, + int digits); + inline Delay makeDelay(float delay, float, @@ -55,46 +67,74 @@ delayAsFloat(const Delay &delay) } // mean late+/early- sigma -float +inline float delayAsFloat(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta); -float -delaySigma2(const Delay &delay, - const EarlyLate *early_late); -const char * -delayAsString(const Delay &delay, - const StaState *sta); -const char * -delayAsString(const Delay &delay, - const StaState *sta, - int digits); -const char * -delayAsString(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta, - int digits); + const EarlyLate *, + const StaState *) +{ + return delay; +} + +inline float +delaySigma2(const Delay &, + const EarlyLate *) +{ + return 0.0; +} + const Delay & delayInitValue(const MinMax *min_max); bool delayIsInitValue(const Delay &delay, const MinMax *min_max); bool -fuzzyGreater(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max); +delayZero(const Delay &delay); bool -fuzzyGreaterEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max); +delayInf(const Delay &delay); bool -fuzzyLess(const Delay &delay1, +delayEqual(const Delay &delay1, + const Delay &delay2); +bool +delayLess(const Delay &delay1, const Delay &delay2, - const MinMax *min_max); + const StaState *sta); bool -fuzzyLessEqual(const Delay &delay1, +delayLess(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayLessEqual(const Delay &delay1, const Delay &delay2, - const MinMax *min_max); + const StaState *sta); +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); + +// delay1-delay2 subtracting sigma instead of addiing. +Delay +delayRemove(const Delay &delay1, + const Delay &delay2); float delayRatio(const Delay &delay1, const Delay &delay2); diff --git a/include/sta/DelayNormal1.hh b/include/sta/DelayNormal1.hh index 19f20810..b25529c7 100644 --- a/include/sta/DelayNormal1.hh +++ b/include/sta/DelayNormal1.hh @@ -47,10 +47,6 @@ public: 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; - bool operator<(const Delay &delay) const; - bool operator<=(const Delay &delay) const; private: float mean_; @@ -63,6 +59,19 @@ const Delay delay_zero(0.0); void initDelayConstants(); +const char * +delayAsString(const Delay &delay, + const StaState *sta); +const char * +delayAsString(const Delay &delay, + const StaState *sta, + int digits); +const char * +delayAsString(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta, + int digits); + Delay makeDelay(float delay, float sigma_early, @@ -75,7 +84,74 @@ makeDelay2(float delay, float sigma_late); inline float -delayAsFloat(const Delay &delay) { return delay.mean(); } +delayAsFloat(const Delay &delay) +{ + return delay.mean(); +} + +// mean late+/early- sigma +float +delayAsFloat(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta); +float +delaySigma2(const Delay &delay, + const EarlyLate *early_late); +const Delay & +delayInitValue(const MinMax *min_max); +bool +delayIsInitValue(const Delay &delay, + const MinMax *min_max); +bool +delayZero(const Delay &delay); +bool +delayInf(const Delay &delay); +bool +delayEqual(const Delay &delay1, + const Delay &delay2); +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); + +// delay1-delay2 subtracting sigma instead of addiing. +Delay delayRemove(const Delay &delay1, + const Delay &delay2); +float +delayRatio(const Delay &delay1, + const Delay &delay2); // Most non-operator functions on Delay are not defined as member // functions so they can be defined on floats, where there is no class @@ -90,68 +166,4 @@ Delay operator/(float delay1, Delay operator*(const Delay &delay1, float delay2); -// mean late+/early- sigma -float -delayAsFloat(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta); -float -delaySigma2(const Delay &delay, - const EarlyLate *early_late); -const char * -delayAsString(const Delay &delay, - const StaState *sta); -const char * -delayAsString(const Delay &delay, - const StaState *sta, - int digits); -const char * -delayAsString(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta, - int digits); -const Delay & -delayInitValue(const MinMax *min_max); -bool -delayIsInitValue(const Delay &delay, - const MinMax *min_max); -bool -fuzzyZero(const Delay &delay); -bool -fuzzyInf(const Delay &delay); -bool -fuzzyEqual(const Delay &delay1, - const Delay &delay2); -bool -fuzzyLess(const Delay &delay1, - const Delay &delay2); -bool -fuzzyLess(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max); -bool -fuzzyLessEqual(const Delay &delay1, - const Delay &delay2); -bool -fuzzyLessEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max); -bool -fuzzyGreater(const Delay &delay1, - const Delay &delay2); -bool -fuzzyGreaterEqual(const Delay &delay1, - const Delay &delay2); -bool -fuzzyGreaterEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max); -bool -fuzzyGreater(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max); -float -delayRatio(const Delay &delay1, - const Delay &delay2); - } // namespace diff --git a/include/sta/DelayNormal2.hh b/include/sta/DelayNormal2.hh index 73b07419..44f3d278 100644 --- a/include/sta/DelayNormal2.hh +++ b/include/sta/DelayNormal2.hh @@ -50,10 +50,6 @@ public: 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; - bool operator<(const Delay &delay) const; - bool operator<=(const Delay &delay) const; protected: static const int early_index = 0; @@ -70,6 +66,19 @@ const Delay delay_zero(0.0); void initDelayConstants(); +const char * +delayAsString(const Delay &delay, + const StaState *sta); +const char * +delayAsString(const Delay &delay, + const StaState *sta, + int digits); +const char * +delayAsString(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta, + int digits); + Delay makeDelay(float delay, float sigma_early, @@ -82,7 +91,74 @@ makeDelay2(float delay, float sigma_late); inline float -delayAsFloat(const Delay &delay) { return delay.mean(); } +delayAsFloat(const Delay &delay) +{ + return delay.mean(); +} + +// mean late+/early- sigma +float +delayAsFloat(const Delay &delay, + const EarlyLate *early_late, + const StaState *sta); +float +delaySigma2(const Delay &delay, + const EarlyLate *early_late); +const Delay & +delayInitValue(const MinMax *min_max); +bool +delayIsInitValue(const Delay &delay, + const MinMax *min_max); +bool +delayZero(const Delay &delay); +bool +delayInf(const Delay &delay); +bool +delayEqual(const Delay &delay1, + const Delay &delay2); +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayLess(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const StaState *sta); +bool +delayGreaterEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); + +// delay1-delay2 subtracting sigma instead of addiing. +Delay delayRemove(const Delay &delay1, + const Delay &delay2); +float +delayRatio(const Delay &delay1, + const Delay &delay2); // Most non-operator functions on Delay are not defined as member // functions so they can be defined on floats, where there is no class @@ -97,68 +173,4 @@ Delay operator/(float delay1, Delay operator*(const Delay &delay1, float delay2); -// mean late+/early- sigma -float -delayAsFloat(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta); -float -delaySigma2(const Delay &delay, - const EarlyLate *early_late); -const char * -delayAsString(const Delay &delay, - const StaState *sta); -const char * -delayAsString(const Delay &delay, - const StaState *sta, - int digits); -const char * -delayAsString(const Delay &delay, - const EarlyLate *early_late, - const StaState *sta, - int digits); -const Delay & -delayInitValue(const MinMax *min_max); -bool -delayIsInitValue(const Delay &delay, - const MinMax *min_max); -bool -fuzzyZero(const Delay &delay); -bool -fuzzyInf(const Delay &delay); -bool -fuzzyEqual(const Delay &delay1, - const Delay &delay2); -bool -fuzzyLess(const Delay &delay1, - const Delay &delay2); -bool -fuzzyLess(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max); -bool -fuzzyLessEqual(const Delay &delay1, - const Delay &delay2); -bool -fuzzyLessEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max); -bool -fuzzyGreater(const Delay &delay1, - const Delay &delay2); -bool -fuzzyGreaterEqual(const Delay &delay1, - const Delay &delay2); -bool -fuzzyGreaterEqual(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max); -bool -fuzzyGreater(const Delay &delay1, - const Delay &delay2, - const MinMax *min_max); -float -delayRatio(const Delay &delay1, - const Delay &delay2); - } // namespace diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index 205cb4ec..ec898916 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -202,7 +202,9 @@ public: void defaultMaxFanout(float &fanout, bool &exists) const; void setDefaultMaxFanout(float fanout); - float defaultFanoutLoad() const { return default_fanout_load_; } + void defaultFanoutLoad(// Return values. + float &fanout, + bool &exists) const; void setDefaultFanoutLoad(float load); // Logic thresholds. @@ -307,6 +309,7 @@ protected: RiseFallValues default_inout_pin_res_; RiseFallValues default_output_pin_res_; float default_fanout_load_; + bool default_fanout_load_exists_; float default_max_cap_; bool default_max_cap_exists_; float default_max_fanout_; @@ -402,6 +405,8 @@ public: void setDontUse(bool dont_use); bool isMacro() const { return is_macro_; } void setIsMacro(bool is_macro); + bool isMemory() const { return is_memory_; } + void setIsMemory(bool is_memory); bool isPad() const { return is_pad_; } void setIsPad(bool is_pad); bool interfaceTiming() const { return interface_timing_; } @@ -488,6 +493,7 @@ public: Report *report, Debug *debug); bool isBuffer() const; + bool isInverter() const; // Only valid when isBuffer() returns true. void bufferPorts(// Return values. LibertyPort *&input, @@ -517,11 +523,14 @@ protected: void makeTimingArcPortMaps(); bool hasBufferFunc(const LibertyPort *input, const LibertyPort *output) const; + bool hasInverterFunc(const LibertyPort *input, + const LibertyPort *output) const; LibertyLibrary *liberty_library_; float area_; bool dont_use_; bool is_macro_; + bool is_memory_; bool is_pad_; bool has_internal_ports_; bool interface_timing_; @@ -623,6 +632,11 @@ public: LibertyLibrary *libertyLibrary() const { return liberty_cell_->libertyLibrary(); } LibertyPort *findLibertyMember(int index) const; LibertyPort *findLibertyBusBit(int index) const; + void fanoutLoad(// Return values. + float &fanout_load, + bool &exists) const; + void setFanoutLoad(float fanout_load); + float capacitance() const; float capacitance(const RiseFall *rf, const MinMax *min_max) const; void capacitance(const RiseFall *rf, @@ -748,6 +762,8 @@ protected: RiseFallMinMax capacitance_; MinMaxFloatValues slew_limit_; // inputs and outputs MinMaxFloatValues cap_limit_; // outputs + float fanout_load_; // inputs + bool fanout_load_exists_; MinMaxFloatValues fanout_limit_; // outputs float min_period_; float min_pulse_width_[RiseFall::index_count]; diff --git a/include/sta/Network.hh b/include/sta/Network.hh index 4a6e092e..eab973ad 100644 --- a/include/sta/Network.hh +++ b/include/sta/Network.hh @@ -323,6 +323,13 @@ public: virtual VertexId vertexId(const Pin *pin) const = 0; virtual void setVertexId(Pin *pin, VertexId id) = 0; + // Return the physical X/Y coordinates of the pin. + virtual void location(const Pin *pin, + // Return values. + double &x, + double &y, + bool &exists) const; + int pinCount(); int pinCount(Instance *inst); int leafPinCount(); diff --git a/include/sta/PathEnd.hh b/include/sta/PathEnd.hh index c60d8fdc..e5f983d4 100644 --- a/include/sta/PathEnd.hh +++ b/include/sta/PathEnd.hh @@ -425,6 +425,7 @@ private: // Path constrained by an output delay. // If there is a reference pin, clk_path_ is the reference pin clock. +// If there is a path delay PathEndPathDelay is used instead of this. class PathEndOutputDelay : public PathEndClkConstrainedMcp { public: @@ -555,6 +556,7 @@ private: // Path constrained by set_min/max_delay. // "Clocked" when path delay ends at timing check pin. +// May end at output with set_output_delay. class PathEndPathDelay : public PathEndClkConstrained { public: @@ -587,6 +589,7 @@ public: virtual PathDelay *pathDelay() const { return path_delay_; } virtual ArcDelay margin(const StaState *sta) const; virtual float sourceClkOffset(const StaState *sta) const; + virtual ClockEdge *targetClkEdge(const StaState *sta) const; virtual float targetClkTime(const StaState *sta) const; virtual Arrival targetClkArrivalNoCrpr(const StaState *sta) const; virtual float targetClkOffset(const StaState *sta) const; @@ -594,6 +597,7 @@ public: virtual Required requiredTime(const StaState *sta) const; virtual int exceptPathCmp(const PathEnd *path_end, const StaState *sta) const; + bool hasOutputDelay() const { return output_delay_ != nullptr; } protected: PathEndPathDelay(PathDelay *path_delay, @@ -610,8 +614,7 @@ protected: PathDelay *path_delay_; TimingArc *check_arc_; Edge *check_edge_; - // Output delay is nullptr when there is no timing check or output - // delay at the endpoint. + // Output delay is nullptr when there is no output delay at the endpoint. OutputDelay *output_delay_; // Source clk arrival for set_min/max_delay -ignore_clk_latency. Arrival src_clk_arrival_; diff --git a/include/sta/RiseFallMinMax.hh b/include/sta/RiseFallMinMax.hh index 57f2900d..69711fe4 100644 --- a/include/sta/RiseFallMinMax.hh +++ b/include/sta/RiseFallMinMax.hh @@ -36,6 +36,9 @@ public: float &value, bool &exists) const; bool hasValue() const; + void maxValue(// Return values + float &max_value, + bool &exists) const; bool empty() const; bool hasValue(const RiseFall *rf, const MinMax *min_max) const; diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index 4643c5f5..560fddbe 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -295,15 +295,6 @@ public: void setSlewLimit(Port *port, const MinMax *min_max, float slew); - void slewLimit(const Pin *pin, - const MinMax *min_max, - // Return values. - float &slew, - bool &exists); - void setSlewLimit(const Pin *pin, - const MinMax *min_max, - float slew); - void slewLimitPins(ConstPinSeq &pins); void slewLimit(Cell *cell, const MinMax *min_max, float &slew, @@ -1329,7 +1320,6 @@ protected: OutputDelaysPinMap output_delay_leaf_pin_map_; PortSlewLimitMap port_slew_limit_map_; - PinSlewLimitMap pin_slew_limit_map_; CellSlewLimitMap cell_slew_limit_map_; bool have_clk_slew_limits_; CellCapLimitMap cell_cap_limit_map_; diff --git a/include/sta/SdcNetwork.hh b/include/sta/SdcNetwork.hh index 6172a17d..d5aece26 100644 --- a/include/sta/SdcNetwork.hh +++ b/include/sta/SdcNetwork.hh @@ -103,6 +103,11 @@ public: virtual VertexId vertexId(const Pin *pin) const; virtual void setVertexId(Pin *pin, VertexId id); + virtual void location(const Pin *pin, + // Return values. + double &x, + double &y, + bool &exists) const; virtual Net *net(const Term *term) const; virtual Pin *pin(const Term *term) const; @@ -120,7 +125,6 @@ public: virtual char pathEscape() const; virtual void setPathEscape(char escape); - virtual bool isEditable() const; virtual LibertyLibrary *makeLibertyLibrary(const char *name, const char *filename); diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 09929e3c..18efcf20 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -752,7 +752,8 @@ public: const StaState *sta); void requiredSet(int arrival_index, Required required, - const MinMax *min_max); + const MinMax *min_max, + const StaState *sta); // Return true if the requireds changed. bool requiredsSave(Vertex *vertex, const StaState *sta); diff --git a/include/sta/SearchClass.hh b/include/sta/SearchClass.hh index 2eaae23c..c6f49dd3 100644 --- a/include/sta/SearchClass.hh +++ b/include/sta/SearchClass.hh @@ -119,7 +119,8 @@ enum class ReportPathFormat { full, shorter, endpoint, summary, - slack_only + slack_only, + json }; static const int tag_index_bits = 24; diff --git a/include/sta/Sta.hh b/include/sta/Sta.hh index 4f7d4e18..e4e911a1 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -45,6 +45,8 @@ class ReportPath; class CheckTiming; class DcalcAnalysisPt; class CheckSlewLimits; +class CheckFanoutLimits; +class CheckCapacitanceLimits; class CheckMinPulseWidths; class CheckMinPeriods; class CheckMaxSkews; @@ -245,9 +247,6 @@ public: void setSlewLimit(Port *port, const MinMax *min_max, float slew); - void setSlewLimit(Pin *pin, - const MinMax *min_max, - float slew); void setSlewLimit(Cell *cell, const MinMax *min_max, float slew); @@ -612,6 +611,7 @@ public: // Return value. ClockSet &clks); + void checkSlewLimitPreamble(); // Return the pin with the min/max slew limit slack. // corner=nullptr checks all corners. Pin *pinMinSlewLimitSlack(const Corner *corner, @@ -627,15 +627,63 @@ public: void reportSlewLimitVerbose(Pin *pin, const Corner *corner, const MinMax *min_max); - void checkSlews(const Pin *pin, - const Corner *corner, - const MinMax *min_max, - // Return values. - const Corner *&corner1, - const RiseFall *&tr, - Slew &slew, - float &limit, - float &slack); + // requires checkSlewLimitPreamble() + void checkSlew(const Pin *pin, + const Corner *corner, + const MinMax *min_max, + bool check_clks, + // Return values. + const Corner *&corner1, + const RiseFall *&tr, + Slew &slew, + float &limit, + float &slack); + + void checkFanoutLimitPreamble(); + // Return the pin with the min/max fanout limit slack. + Pin *pinMinFanoutLimitSlack(const MinMax *min_max); + // Return all pins with min/max fanout violations. + PinSeq *pinFanoutLimitViolations(const MinMax *min_max); + void reportFanoutLimitShortHeader(); + void reportFanoutLimitShort(Pin *pin, + const MinMax *min_max); + void reportFanoutLimitVerbose(Pin *pin, + const MinMax *min_max); + // requires checkFanoutLimitPreamble() + void checkFanout(const Pin *pin, + const MinMax *min_max, + // Return values. + float &fanout, + float &limit, + float &slack); + + void checkCapacitanceLimitPreamble(); + // Return the pin with the min/max capacitance limit slack. + // corner=nullptr checks all corners. + Pin *pinMinCapacitanceLimitSlack(const Corner *corner, + const MinMax *min_max); + // Return all pins with min/max capacitance violations. + // corner=nullptr checks all corners. + PinSeq *pinCapacitanceLimitViolations(const Corner *corner, + const MinMax *min_max); + void reportCapacitanceLimitShortHeader(); + void reportCapacitanceLimitShort(Pin *pin, + const Corner *corner, + const MinMax *min_max); + void reportCapacitanceLimitVerbose(Pin *pin, + const Corner *corner, + const MinMax *min_max); + // requires checkCapacitanceLimitPreamble() + void checkCapacitance(const Pin *pin, + const Corner *corner, + const MinMax *min_max, + // Return values. + const Corner *&corner1, + const RiseFall *&tr, + float &capacitance, + float &limit, + float &slack); + // Min pulse width check with the least slack. // corner=nullptr checks all corners. MinPulseWidthCheck *minPulseWidthSlack(const Corner *corner); @@ -1227,6 +1275,8 @@ protected: virtual void makeLatches(); virtual void makeCheckTiming(); virtual void makeCheckSlewLimits(); + virtual void makeCheckFanoutLimits(); + virtual void makeCheckCapacitanceLimits(); virtual void makeCheckMinPulseWidths(); virtual void makeCheckMinPeriods(); virtual void makeCheckMaxSkews(); @@ -1268,7 +1318,6 @@ protected: Edge *d_q_edge, const ClockEdge *en_clk_edge); void clockSlewChanged(Clock *clk); - void checkSlewLimitPreamble(); void minPulseWidthPreamble(); void minPeriodPreamble(); void maxSkewPreamble(); @@ -1324,6 +1373,8 @@ protected: Corner *cmd_corner_; CheckTiming *check_timing_; CheckSlewLimits *check_slew_limits_; + CheckFanoutLimits *check_fanout_limits_; + CheckCapacitanceLimits *check_capacitance_limits_; CheckMinPulseWidths *check_min_pulse_widths_; CheckMinPeriods *check_min_periods_; CheckMaxSkews *check_max_skews_; diff --git a/include/sta/Units.hh b/include/sta/Units.hh index 7dea78cb..59402ab1 100644 --- a/include/sta/Units.hh +++ b/include/sta/Units.hh @@ -21,7 +21,7 @@ namespace sta { class Unit { public: - Unit(); + Unit(const char *suffix); ~Unit(); Unit(float scale, const char *suffix, @@ -29,10 +29,12 @@ public: void operator=(const Unit &unit); float scale() const { return scale_; } void setScale(float scale); + const char *scaleAbreviation(); const char *suffix() const { return suffix_; } void setSuffix(const char *suffix); int digits() const { return digits_; } void setDigits(int digits); + // Does not include suffix. int width() const; const char *asString(float value) const; const char *asString(double value) const; @@ -50,7 +52,7 @@ private: class Units { public: - Units() {} + Units(); Unit *find(const char *unit_name); void operator=(const Units &units); Unit *timeUnit() { return &time_unit_; } diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 99958888..11c9c317 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -71,6 +71,7 @@ LibertyLibrary::LibertyLibrary(const char *name, default_output_pin_cap_(0.0), default_bidirect_pin_cap_(0.0), default_fanout_load_(0.0), + default_fanout_load_exists_(false), default_max_cap_(0.0), default_max_cap_exists_(false), default_max_fanout_(0.0), @@ -425,10 +426,20 @@ LibertyLibrary::setDefaultMaxCapacitance(float cap) default_max_cap_exists_ = true; } +void +LibertyLibrary::defaultFanoutLoad(// Return values. + float &fanout, + bool &exists) const +{ + fanout = default_fanout_load_; + exists = default_fanout_load_exists_; +} + void LibertyLibrary::setDefaultFanoutLoad(float load) { default_fanout_load_ = load; + default_fanout_load_exists_ = true; } void @@ -839,6 +850,7 @@ LibertyCell::LibertyCell(LibertyLibrary *library, area_(0.0), dont_use_(false), is_macro_(false), + is_memory_(false), is_pad_(false), has_internal_ports_(false), interface_timing_(false), @@ -984,6 +996,12 @@ LibertyCell::setIsMacro(bool is_macro) is_macro_ = is_macro; } +void +LibertyCell::setIsMemory(bool is_memory) +{ + is_memory_ = is_memory; +} + void LibertyCell::LibertyCell::setIsPad(bool is_pad) { @@ -1046,6 +1064,27 @@ LibertyCell::hasBufferFunc(const LibertyPort *input, && func->port() == input; } +bool +LibertyCell::isInverter() const +{ + LibertyPort *input; + LibertyPort *output; + bufferPorts(input, output); + return input && output + && hasInverterFunc(input, output); +} + +bool +LibertyCell::hasInverterFunc(const LibertyPort *input, + const LibertyPort *output) const +{ + FuncExpr *func = output->function(); + return func + && func->op() == FuncExpr::op_not + && func->left()->op() == FuncExpr::op_port + && func->left()->port() == input; +} + void LibertyCell::bufferPorts(// Return values. LibertyPort *&input, @@ -1811,8 +1850,8 @@ LibertyPort::LibertyPort(LibertyCell *cell, function_(nullptr), tristate_enable_(nullptr), scaled_ports_(nullptr), - // capacitance_ intentionally not initialized so - // liberty reader can apply default capacitance. + fanout_load_(0.0), + fanout_load_exists_(false), min_period_(0.0), pulse_clk_trigger_(nullptr), pulse_clk_sense_(nullptr), @@ -1889,6 +1928,18 @@ LibertyPort::setCapacitance(const RiseFall *rf, } } +float +LibertyPort::capacitance() const +{ + float cap; + bool exists; + capacitance_.maxValue(cap, exists); + if (exists) + return cap; + else + return 0.0; +} + float LibertyPort::capacitance(const RiseFall *rf, const MinMax *min_max) const @@ -2040,6 +2091,22 @@ LibertyPort::setCapacitanceLimit(float cap, cap_limit_.setValue(min_max, cap); } +void +LibertyPort::fanoutLoad(// Return values. + float &fanout_load, + bool &exists) const +{ + fanout_load = fanout_load_; + exists = fanout_load_exists_; +} + +void +LibertyPort::setFanoutLoad(float fanout_load) +{ + fanout_load_ = fanout_load; + fanout_load_exists_ = true; +} + void LibertyPort::fanoutLimit(const MinMax *min_max, // Return values. diff --git a/liberty/LibertyExpr.cc b/liberty/LibertyExpr.cc index 60ce4f55..4933cad9 100644 --- a/liberty/LibertyExpr.cc +++ b/liberty/LibertyExpr.cc @@ -16,6 +16,7 @@ #include "FuncExpr.hh" +#include // min #include "Report.hh" #include "StringUtil.hh" #include "Liberty.hh" @@ -129,14 +130,9 @@ LibExprParser::copyInput(char *buf, { size_t length = strlen(func_); if (length == 0) - return 0; + return 0; else { - size_t count; - - if (length < max_size) - count = length; - else - count = max_size; + size_t count = std::min(length, max_size); strncpy(buf, func_, count); func_ += count; return count; diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index f64950c7..71804fe5 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -286,6 +286,7 @@ LibertyReader::defineVisitors() defineAttrVisitor("area", &LibertyReader::visitArea); defineAttrVisitor("dont_use", &LibertyReader::visitDontUse); defineAttrVisitor("is_macro", &LibertyReader::visitIsMacro); + defineAttrVisitor("is_memory", &LibertyReader::visitIsMemory); defineAttrVisitor("is_pad", &LibertyReader::visitIsPad); defineAttrVisitor("interface_timing", &LibertyReader::visitInterfaceTiming); defineAttrVisitor("scaling_factors", &LibertyReader::visitScalingFactors); @@ -307,6 +308,7 @@ LibertyReader::defineVisitors() &LibertyReader::visitRiseCapRange); defineAttrVisitor("fall_capacitance_range", &LibertyReader::visitFallCapRange); + defineAttrVisitor("fanout_load", &LibertyReader::visitFanoutLoad); defineAttrVisitor("max_fanout", &LibertyReader::visitMaxFanout); defineAttrVisitor("min_fanout", &LibertyReader::visitMinFanout); defineAttrVisitor("max_transition", &LibertyReader::visitMaxTransition); @@ -2026,7 +2028,7 @@ LibertyReader::parseCellFuncs() while (func_iter.hasNext()) { LibertyFunc *func = func_iter.next(); FuncExpr *expr = parseFunc(func->expr(), func->attrName(), func->line()); - if (func->invert()) { + if (func->invert() && expr) { if (expr->op() == FuncExpr::op_not) { FuncExpr *inv = expr; expr = expr->left(); @@ -2425,6 +2427,17 @@ LibertyReader::visitIsMacro(LibertyAttr *attr) } } +void +LibertyReader::visitIsMemory(LibertyAttr *attr) +{ + if (cell_) { + bool is_memory, exists; + getAttrBool(attr, is_memory, exists); + if (exists) + cell_->setIsMemory(is_memory); + } +} + void LibertyReader::visitIsPad(LibertyAttr *attr) { @@ -2967,6 +2980,21 @@ LibertyReader::defaultCap(LibertyPort *port) return cap; } +void +LibertyReader::visitFanoutLoad(LibertyAttr *attr) +{ + if (ports_) { + float fanout; + bool exists; + getAttrFloat(attr, fanout, exists); + if (exists) { + visitPorts([&] (LibertyPort *port) { + port->setFanoutLoad(fanout); + }); + } + } +} + void LibertyReader::visitMaxFanout(LibertyAttr *attr) { @@ -3906,7 +3934,7 @@ LibertyReader::makeFloatTable(LibertyAttr *attr, } else if (value->isFloat()) // Scalar value. - row->push_back(value->floatValue()); + row->push_back(value->floatValue() * scale); else libWarn(attr, "%s is not a list of floats.\n", attr->name()); if (row->size() != cols) { diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index a29862d4..2a356a61 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -181,6 +181,7 @@ public: virtual void visitArea(LibertyAttr *attr); virtual void visitDontUse(LibertyAttr *attr); virtual void visitIsMacro(LibertyAttr *attr); + virtual void visitIsMemory(LibertyAttr *attr); virtual void visitIsPad(LibertyAttr *attr); virtual void visitInterfaceTiming(LibertyAttr *attr); virtual void visitScalingFactors(LibertyAttr *attr); @@ -206,6 +207,7 @@ public: virtual void visitFallCap(LibertyAttr *attr); virtual void visitRiseCapRange(LibertyAttr *attr); virtual void visitFallCapRange(LibertyAttr *attr); + virtual void visitFanoutLoad(LibertyAttr *attr); virtual void visitMaxFanout(LibertyAttr *attr); virtual void visitMinFanout(LibertyAttr *attr); virtual void visitFanout(LibertyAttr *attr, diff --git a/liberty/Units.cc b/liberty/Units.cc index 9d3a4dcd..e0017439 100644 --- a/liberty/Units.cc +++ b/liberty/Units.cc @@ -21,15 +21,17 @@ #include "StringUtil.hh" #include "MinMax.hh" // INF +#include "Fuzzy.hh" namespace sta { using std::abs; -Unit::Unit() : + +Unit::Unit(const char *suffix) : scale_(1.0), - suffix_(stringCopy("")), - digits_(4) + suffix_(stringCopy(suffix)), + digits_(3) { } @@ -62,6 +64,29 @@ Unit::setScale(float scale) scale_ = scale; } +const char * +Unit::scaleAbreviation() +{ + if (fuzzyEqual(scale_, 1E+6)) + return "M"; + else if (fuzzyEqual(scale_, 1E+3)) + return "k"; + if (fuzzyEqual(scale_, 1.0)) + return ""; + else if (fuzzyEqual(scale_, 1E-3)) + return "m"; + else if (fuzzyEqual(scale_, 1E-6)) + return "u"; + else if (fuzzyEqual(scale_, 1E-9)) + return "n"; + else if (fuzzyEqual(scale_, 1E-12)) + return "p"; + else if (fuzzyEqual(scale_, 1E-15)) + return "f"; + else + return "?"; +} + void Unit::setSuffix(const char *suffix) { @@ -78,7 +103,7 @@ Unit::setDigits(int digits) int Unit::width() const { - return digits_ + (suffix_ ? strlen(suffix_) : 0) + 2; + return digits_ + 2; } const char * @@ -105,12 +130,25 @@ Unit::asString(float value, // prevent "-0.00" on slowaris if (abs(scaled_value) < 1E-6) scaled_value = 0.0; - return stringPrintTmp("%.*f%s", digits, scaled_value, suffix_); + return stringPrintTmp("%.*f", digits, scaled_value); } } //////////////////////////////////////////////////////////////// +Units::Units() : + time_unit_("s"), + capacitance_unit_("F"), + voltage_unit_("v"), + resistance_unit_("ohm"), + pulling_resistance_unit_("ohm"), + current_unit_("A"), + power_unit_("W"), + distance_unit_("m"), + scalar_unit_("") +{ +} + Unit * Units::find(const char *unit_name) { diff --git a/network/Network.cc b/network/Network.cc index 8ac29711..412afcfb 100644 --- a/network/Network.cc +++ b/network/Network.cc @@ -935,6 +935,17 @@ Network::findInstPinsMatching(const Instance *instance, } } +void +Network::location(const Pin *pin, + // Return values. + double &x, + double &y, + bool &exists) const +{ + x = y = 0.0; + exists = false; +} + int Network::instanceCount(Instance *inst) { diff --git a/network/SdcNetwork.cc b/network/SdcNetwork.cc index f8b4de73..707687f3 100644 --- a/network/SdcNetwork.cc +++ b/network/SdcNetwork.cc @@ -223,6 +223,16 @@ NetworkNameAdapter::setVertexId(Pin *pin, network_->setVertexId(pin, id); } +void +NetworkNameAdapter::location(const Pin *pin, + // Return values. + double &x, + double &y, + bool &exists) const +{ + network_->location(pin, x, y, exists); +} + bool NetworkNameAdapter::isBundle(const Port *port) const { diff --git a/parasitics/ConcreteParasitics.cc b/parasitics/ConcreteParasitics.cc index f09f76d3..abc8baaa 100644 --- a/parasitics/ConcreteParasitics.cc +++ b/parasitics/ConcreteParasitics.cc @@ -1670,10 +1670,13 @@ ConcreteParasitics::estimatePiElmore(const Pin *drvr_pin, c2, rpi, c1, elmore_res, elmore_cap, elmore_use_load_cap); - return new ConcretePiElmoreEstimated(c2, rpi, c1, elmore_res, elmore_cap, - elmore_use_load_cap, - rf, op_cond, corner, min_max, - sdc_); + if (c1 > 0.0 || c2 > 0.0) + return new ConcretePiElmoreEstimated(c2, rpi, c1, elmore_res, elmore_cap, + elmore_use_load_cap, + rf, op_cond, corner, min_max, + sdc_); + else + return nullptr; } //////////////////////////////////////////////////////////////// diff --git a/parasitics/EstimateParasitics.cc b/parasitics/EstimateParasitics.cc index a9afef0a..3539811a 100644 --- a/parasitics/EstimateParasitics.cc +++ b/parasitics/EstimateParasitics.cc @@ -150,7 +150,8 @@ EstimateParasitics::estimatePiElmoreBalanced(const Pin *drvr_pin, float &elmore_cap, bool &elmore_use_load_cap) { - if (wireload_res == 0.0) { + if (wireload_res == 0.0 + || fanout == 0) { // No resistance, so load is capacitance only. c2 = wireload_cap + net_pin_cap; rpi = 0.0; diff --git a/sdc/ExceptionPath.cc b/sdc/ExceptionPath.cc index 086d7e15..c65c7248 100644 --- a/sdc/ExceptionPath.cc +++ b/sdc/ExceptionPath.cc @@ -1931,8 +1931,8 @@ ExceptionThru::matches(const Pin *from_pin, EdgePins edge_pins(const_cast(from_pin), const_cast(to_pin)); return ((pins_ && pins_->hasKey(const_cast(to_pin))) || (edges_ && edges_->hasKey(&edge_pins)) - || (nets_ && nets_->hasKey(network->net(to_pin))) - || (insts_ && insts_->hasKey(network->instance(to_pin)))) + || (nets_ && to_pin && nets_->hasKey(network->net(to_pin))) + || (insts_ && to_pin && insts_->hasKey(network->instance(to_pin)))) && rf_->matches(to_rf); } diff --git a/sdc/RiseFallMinMax.cc b/sdc/RiseFallMinMax.cc index 47e66a28..35c95b23 100644 --- a/sdc/RiseFallMinMax.cc +++ b/sdc/RiseFallMinMax.cc @@ -163,6 +163,23 @@ RiseFallMinMax::hasValue() const return !empty(); } +void +RiseFallMinMax::maxValue(// Return values + float &max_value, + bool &exists) const +{ + max_value = MinMax::max()->initValue(); + exists = false; + for (int rf_index=0;rf_indexnet_wire_cap_map_) { + for (auto net_cap : *sdc_->net_wire_cap_map_) { + Net *net = net_cap.first; + MinMaxFloatValues &caps = net_cap.second; + float min_cap, max_cap; + bool min_exists, max_exists; + caps.value(MinMax::min(), min_cap, min_exists); + caps.value(MinMax::max(), max_cap, max_exists); + if (min_exists && max_exists + && min_cap == max_cap) + writeNetLoad(net, MinMaxAll::all(), min_cap); + else { + if (min_exists) + writeNetLoad(net, MinMaxAll::min(), min_cap); + if (max_exists) + writeNetLoad(net, MinMaxAll::max(), max_cap); + } + } + } +} + +void +WriteSdc::writeNetLoad(Net *net, + const MinMaxAll *min_max, + float cap) const +{ + fprintf(stream_, "set_load "); + fprintf(stream_, "%s ", minMaxFlag(min_max)); + writeCapacitance(cap); + fprintf(stream_, " "); + writeGetNet(net); + fprintf(stream_, "\n"); +} + +void +WriteSdc::writePortLoads() const { CellPortBitIterator *port_iter = sdc_network_->portBitIterator(cell_); while (port_iter->hasNext()) { @@ -2239,24 +2277,6 @@ WriteSdc::writeSlewLimits() const } delete port_iter; - ConstPinSeq pins; - sdc_->slewLimitPins(pins); - sort(pins, PinPathNameLess(network_)); - ConstPinSeq::Iterator pin_iter(pins); - while (pin_iter.hasNext()) { - const Pin *pin = pin_iter.next(); - float slew; - bool exists; - sdc_->slewLimit(pin, min_max, slew, exists); - if (exists) { - fprintf(stream_, "set_max_transition "); - writeTime(slew); - fprintf(stream_, " "); - writeGetPin(pin, false); - fprintf(stream_, "\n"); - } - } - writeClkSlewLimits(); } diff --git a/sdc/WriteSdcPvt.hh b/sdc/WriteSdcPvt.hh index 83ee4d2e..4cc69ddd 100644 --- a/sdc/WriteSdcPvt.hh +++ b/sdc/WriteSdcPvt.hh @@ -117,7 +117,11 @@ public: void writeEnvironment() const; void writeOperatingConditions() const; void writeWireload() const; - void writePinLoads() const; + void writeNetLoads() const; + void writeNetLoad(Net *net, + const MinMaxAll *min_max, + float cap) const; + void writePortLoads() const; void writePortLoads(Port *port) const; void writePortFanout(Port *port) const; void writeDriveResistances() const; diff --git a/sdf/SdfReader.cc b/sdf/SdfReader.cc index 98f7dff6..e0f91d77 100644 --- a/sdf/SdfReader.cc +++ b/sdf/SdfReader.cc @@ -809,7 +809,7 @@ SdfReader::setEdgeArcDelaysCondUse(Edge *edge, delay = graph_->arcDelay(edge, arc, arc_delay_index) + *value; else if (graph_->arcDelayAnnotated(edge, arc, arc_delay_index)) { ArcDelay prev_value = graph_->arcDelay(edge, arc, arc_delay_index); - if (fuzzyGreater(prev_value, delay, min_max)) + if (delayGreater(prev_value, delay, min_max, this)) delay = prev_value; } graph_->setArcDelay(edge, arc, arc_delay_index, delay); diff --git a/sdf/SdfWriter.cc b/sdf/SdfWriter.cc index 4287776c..09b408ad 100644 --- a/sdf/SdfWriter.cc +++ b/sdf/SdfWriter.cc @@ -605,18 +605,18 @@ SdfWriter::writeEdgeCheck(Edge *edge, && arcs[clk_rf_index][RiseFall::fallIndex()] && arcs[clk_rf_index][RiseFall::riseIndex()] && arcs[clk_rf_index][RiseFall::fallIndex()] - && fuzzyEqual(graph_->arcDelay(edge, - arcs[clk_rf_index][RiseFall::riseIndex()], - arc_delay_min_index_), - graph_->arcDelay(edge, - arcs[clk_rf_index][RiseFall::fallIndex()], - arc_delay_min_index_)) - && fuzzyEqual(graph_->arcDelay(edge, - arcs[clk_rf_index][RiseFall::riseIndex()], - arc_delay_max_index_), - graph_->arcDelay(edge, - arcs[clk_rf_index][RiseFall::fallIndex()], - arc_delay_max_index_))) + && delayEqual(graph_->arcDelay(edge, + arcs[clk_rf_index][RiseFall::riseIndex()], + arc_delay_min_index_), + graph_->arcDelay(edge, + arcs[clk_rf_index][RiseFall::fallIndex()], + arc_delay_min_index_)) + && delayEqual(graph_->arcDelay(edge, + arcs[clk_rf_index][RiseFall::riseIndex()], + arc_delay_max_index_), + graph_->arcDelay(edge, + arcs[clk_rf_index][RiseFall::fallIndex()], + arc_delay_max_index_))) // Rise/fall margins are the same, so no data edge specifier is required. writeCheck(edge, arcs[clk_rf_index][RiseFall::riseIndex()], sdf_check, false, true); diff --git a/search/CheckCapacitanceLimits.cc b/search/CheckCapacitanceLimits.cc new file mode 100644 index 00000000..ced71a7d --- /dev/null +++ b/search/CheckCapacitanceLimits.cc @@ -0,0 +1,330 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2020, 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 "CheckCapacitanceLimits.hh" + +#include "Fuzzy.hh" +#include "Liberty.hh" +#include "Network.hh" +#include "Sdc.hh" +#include "DcalcAnalysisPt.hh" +#include "GraphDelayCalc.hh" +#include "StaState.hh" +#include "Corner.hh" +#include "PortDirection.hh" +#include "Sim.hh" +#include "Graph.hh" +#include "GraphDelayCalc.hh" + +namespace sta { + +class PinCapacitanceLimitSlackLess +{ +public: + PinCapacitanceLimitSlackLess(const Corner *corner, + const MinMax *min_max, + CheckCapacitanceLimits *check_capacitance_limit, + const StaState *sta); + bool operator()(Pin *pin1, + Pin *pin2) const; + +private: + const Corner *corner_; + const MinMax *min_max_; + CheckCapacitanceLimits *check_capacitance_limit_; + const StaState *sta_; + +}; + +PinCapacitanceLimitSlackLess::PinCapacitanceLimitSlackLess(const Corner *corner, + const MinMax *min_max, + CheckCapacitanceLimits *check_capacitance_limit, + const StaState *sta) : + corner_(corner), + min_max_(min_max), + check_capacitance_limit_(check_capacitance_limit), + sta_(sta) +{ +} + +bool +PinCapacitanceLimitSlackLess::operator()(Pin *pin1, + Pin *pin2) const +{ + const Corner *corner1, *corner2; + const RiseFall *rf1, *rf2; + float capacitance1, capacitance2; + float limit1, limit2, slack1, slack2; + check_capacitance_limit_->checkCapacitance(pin1, corner_, min_max_, + corner1, rf1, capacitance1, + limit1, slack1); + check_capacitance_limit_->checkCapacitance(pin2, corner_, min_max_, + corner2, rf2, capacitance2, + limit2, slack2); + return fuzzyLess(slack1, slack2) + || (fuzzyEqual(slack1, slack2) + // Break ties for the sake of regression stability. + && sta_->network()->pinLess(pin1, pin2)); +} + +//////////////////////////////////////////////////////////////// + +CheckCapacitanceLimits::CheckCapacitanceLimits(const StaState *sta) : + sta_(sta) +{ +} + +void +CheckCapacitanceLimits::checkCapacitance(const Pin *pin, + const Corner *corner1, + const MinMax *min_max, + // Return values. + const Corner *&corner, + const RiseFall *&rf, + float &capacitance, + float &limit, + float &slack) const +{ + corner = nullptr; + rf = nullptr; + capacitance = 0.0; + limit = 0.0; + slack = MinMax::min()->initValue(); + if (corner1) + checkCapacitance1(pin, corner1, min_max, + corner, rf, capacitance, limit, slack); + else { + for (auto corner1 : *sta_->corners()) { + checkCapacitance1(pin, corner1, min_max, + corner, rf, capacitance, limit, slack); + } + } +} + +void +CheckCapacitanceLimits::checkCapacitance1(const Pin *pin, + const Corner *corner1, + const MinMax *min_max, + // Return values. + const Corner *&corner, + const RiseFall *&rf, + float &capacitance, + float &limit, + float &slack) const +{ + float limit1; + bool limit1_exists; + findLimit(pin, min_max, limit1, limit1_exists); + if (limit1_exists) { + for (auto rf1 : RiseFall::range()) { + checkCapacitance(pin, corner1, min_max, rf1, limit1, + corner, rf, capacitance, slack, limit); + } + } +} + +// return the tightest limit. +void +CheckCapacitanceLimits::findLimit(const Pin *pin, + const MinMax *min_max, + // Return values. + float &limit, + bool &exists) const +{ + const Network *network = sta_->network(); + Sdc *sdc = sta_->sdc(); + + // Default to top ("design") limit. + Cell *top_cell = network->cell(network->topInstance()); + sdc->capacitanceLimit(top_cell, min_max, + limit, exists); + + float limit1; + bool exists1; + if (network->isTopLevelPort(pin)) { + Port *port = network->port(pin); + sdc->capacitanceLimit(port, min_max, limit1, exists1); + if (exists1 + && (!exists + || min_max->compare(limit, limit1))) { + limit = limit1; + exists = true; + } + } + else { + Cell *cell = network->cell(network->instance(pin)); + sdc->capacitanceLimit(cell, min_max, + limit1, exists1); + if (exists1 + && (!exists + || min_max->compare(limit, limit1))) { + limit = limit1; + exists = true; + } + LibertyPort *port = network->libertyPort(pin); + if (port) { + port->capacitanceLimit(min_max, limit1, exists1); + if (!exists1 + && port->direction()->isAnyOutput()) + port->libertyLibrary()->defaultMaxCapacitance(limit1, exists1); + if (exists1 + && (!exists + || min_max->compare(limit, limit1))) { + limit = limit1; + exists = true; + } + } + } +} + +void +CheckCapacitanceLimits::checkCapacitance(const Pin *pin, + const Corner *corner, + const MinMax *min_max, + const RiseFall *rf1, + float limit1, + // Return values. + const Corner *&corner1, + const RiseFall *&rf, + float &capacitance, + float &slack, + float &limit) const +{ + const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max); + const OperatingConditions *op_cond = dcalc_ap->operatingConditions(); + float cap = sta_->graphDelayCalc()->loadCap(pin, dcalc_ap); + + float slack1 = (min_max == MinMax::max()) + ? limit1 - cap : cap - limit1; + if (corner == nullptr + || (slack1 < slack + // Break ties for the sake of regression stability. + || (fuzzyEqual(slack1, slack) + && rf1->index() < rf->index()))) { + corner1 = corner; + rf = rf1; + capacitance = cap; + slack = slack1; + limit = limit1; + } +} + +PinSeq * +CheckCapacitanceLimits::pinCapacitanceLimitViolations(const Corner *corner, + const MinMax *min_max) +{ + const Network *network = sta_->network(); + PinSeq *violators = new PinSeq; + LeafInstanceIterator *inst_iter = network->leafInstanceIterator(); + while (inst_iter->hasNext()) { + Instance *inst = inst_iter->next(); + pinCapacitanceLimitViolations(inst, corner, min_max, violators); + } + delete inst_iter; + // Check top level ports. + pinCapacitanceLimitViolations(network->topInstance(), corner, min_max, violators); + sort(violators, PinCapacitanceLimitSlackLess(corner, min_max, this, sta_)); + return violators; +} + +void +CheckCapacitanceLimits::pinCapacitanceLimitViolations(Instance *inst, + const Corner *corner, + const MinMax *min_max, + PinSeq *violators) +{ + const Network *network = sta_->network(); + const Sim *sim = sta_->sim(); + InstancePinIterator *pin_iter = network->pinIterator(inst); + while (pin_iter->hasNext()) { + Pin *pin = pin_iter->next(); + if (checkPin(pin)) { + const Corner *corner1; + const RiseFall *rf; + float capacitance, limit, slack; + checkCapacitance(pin, corner, min_max, corner1, rf, capacitance, limit, slack ); + if (rf && slack < 0.0 && !fuzzyInf(slack)) + violators->push_back(pin); + } + } + delete pin_iter; +} + +Pin * +CheckCapacitanceLimits::pinMinCapacitanceLimitSlack(const Corner *corner, + const MinMax *min_max) +{ + const Network *network = sta_->network(); + Pin *min_slack_pin = nullptr; + float min_slack = MinMax::min()->initValue(); + LeafInstanceIterator *inst_iter = network->leafInstanceIterator(); + while (inst_iter->hasNext()) { + Instance *inst = inst_iter->next(); + pinMinCapacitanceLimitSlack(inst, corner, min_max, min_slack_pin, min_slack); + } + delete inst_iter; + // Check top level ports. + pinMinCapacitanceLimitSlack(network->topInstance(), corner, min_max, + min_slack_pin, min_slack); + return min_slack_pin; +} + +void +CheckCapacitanceLimits::pinMinCapacitanceLimitSlack(Instance *inst, + const Corner *corner, + const MinMax *min_max, + // Return values. + Pin *&min_slack_pin, + float &min_slack) +{ + const Network *network = sta_->network(); + const Sim *sim = sta_->sim(); + InstancePinIterator *pin_iter = network->pinIterator(inst); + while (pin_iter->hasNext()) { + Pin *pin = pin_iter->next(); + if (checkPin(pin)) { + const Corner *corner1; + const RiseFall *rf; + float capacitance, limit, slack; + checkCapacitance(pin, corner, min_max, corner1, rf, capacitance, limit, slack); + if (rf + && !fuzzyInf(slack) + && (min_slack_pin == nullptr + || slack < min_slack)) { + min_slack_pin = pin; + min_slack = slack; + } + } + } + delete pin_iter; +} + +bool +CheckCapacitanceLimits::checkPin(const Pin *pin) +{ + const Network *network = sta_->network(); + const Sim *sim = sta_->sim(); + const Sdc *sdc = sta_->sdc(); + const Graph *graph = sta_->graph(); + GraphDelayCalc *dcalc = sta_->graphDelayCalc(); + Vertex *vertex = graph->pinLoadVertex(pin); + return network->direction(pin)->isAnyOutput() + && !sim->logicZeroOne(pin) + && !sdc->isDisabled(pin) + && !(vertex && sta_->graphDelayCalc()->isIdealClk(vertex)); +} + +} // namespace diff --git a/search/CheckCapacitanceLimits.hh b/search/CheckCapacitanceLimits.hh new file mode 100644 index 00000000..39e03789 --- /dev/null +++ b/search/CheckCapacitanceLimits.hh @@ -0,0 +1,92 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2020, 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 . + +#pragma once + +#include "MinMax.hh" +#include "Transition.hh" +#include "NetworkClass.hh" +#include "SdcClass.hh" + +namespace sta { + +class StaState; +class Corner; + +class CheckCapacitanceLimits +{ +public: + CheckCapacitanceLimits(const StaState *sta); + // corner=nullptr checks all corners. + void checkCapacitance(const Pin *pin, + const Corner *corner1, + const MinMax *min_max, + // Return values. + // Corner is nullptr for no capacitance limit. + const Corner *&corner, + const RiseFall *&rf, + float &capacitance, + float &limit, + float &slack) const; + // corner=nullptr checks all corners. + PinSeq *pinCapacitanceLimitViolations(const Corner *corner, + const MinMax *min_max); + // corner=nullptr checks all corners. + Pin *pinMinCapacitanceLimitSlack(const Corner *corner, + const MinMax *min_max); + +protected: + void checkCapacitance(const Pin *pin, + const Corner *corner, + const MinMax *min_max, + const RiseFall *rf1, + float limit1, + // Return values. + const Corner *&corner1, + const RiseFall *&rf, + float &capacitance, + float &slack, + float &limit) const; + void checkCapacitance1(const Pin *pin, + const Corner *corner1, + const MinMax *min_max, + // Return values. + const Corner *&corner, + const RiseFall *&rf, + float &capacitance, + float &limit, + float &slack) const; + void findLimit(const Pin *pin, + const MinMax *min_max, + // Return values. + float &limit, + bool &limit_exists) const; + void pinCapacitanceLimitViolations(Instance *inst, + const Corner *corner, + const MinMax *min_max, + PinSeq *violators); + void pinMinCapacitanceLimitSlack(Instance *inst, + const Corner *corner, + const MinMax *min_max, + // Return values. + Pin *&min_slack_pin, + float &min_slack); + bool checkPin(const Pin *pin); + + const StaState *sta_; +}; + +} // namespace diff --git a/search/CheckFanoutLimits.cc b/search/CheckFanoutLimits.cc new file mode 100644 index 00000000..fcb7ea3e --- /dev/null +++ b/search/CheckFanoutLimits.cc @@ -0,0 +1,303 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2020, 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 "CheckFanoutLimits.hh" + +#include "Fuzzy.hh" +#include "Liberty.hh" +#include "Network.hh" +#include "Sdc.hh" +#include "Sim.hh" +#include "PortDirection.hh" +#include "Graph.hh" +#include "GraphDelayCalc.hh" + +namespace sta { + +class PinFanoutLimitSlackLess +{ +public: + PinFanoutLimitSlackLess(const MinMax *min_max, + CheckFanoutLimits *check_fanout_limit, + const StaState *sta); + bool operator()(Pin *pin1, + Pin *pin2) const; + +private: + const MinMax *min_max_; + CheckFanoutLimits *check_fanout_limit_; + const StaState *sta_; + +}; + +PinFanoutLimitSlackLess::PinFanoutLimitSlackLess(const MinMax *min_max, + CheckFanoutLimits *check_fanout_limit, + const StaState *sta) : + min_max_(min_max), + check_fanout_limit_(check_fanout_limit), + sta_(sta) +{ +} + +bool +PinFanoutLimitSlackLess::operator()(Pin *pin1, + Pin *pin2) const +{ + float fanout1, fanout2; + float limit1, limit2, slack1, slack2; + check_fanout_limit_->checkFanout(pin1, min_max_, + fanout1, limit1, slack1); + check_fanout_limit_->checkFanout(pin2, min_max_, + fanout2, limit2, slack2); + return fuzzyLess(slack1, slack2) + || (fuzzyEqual(slack1, slack2) + // Break ties for the sake of regression stability. + && sta_->network()->pinLess(pin1, pin2)); +} + +//////////////////////////////////////////////////////////////// + +CheckFanoutLimits::CheckFanoutLimits(const StaState *sta) : + sta_(sta) +{ +} + +void +CheckFanoutLimits::checkFanout(const Pin *pin, + const MinMax *min_max, + // Return values. + float &fanout, + float &limit, + float &slack) const +{ + fanout = 0.0; + limit = 0.0; + slack = MinMax::min()->initValue(); + + float limit1; + bool limit1_exists; + findLimit(pin, min_max, limit1, limit1_exists); + if (limit1_exists) + checkFanout(pin, min_max, limit1, + fanout, slack, limit); +} + +// return the tightest limit. +void +CheckFanoutLimits::findLimit(const Pin *pin, + const MinMax *min_max, + // Return values. + float &limit, + bool &exists) const +{ + const Network *network = sta_->network(); + Sdc *sdc = sta_->sdc(); + + // Default to top ("design") limit. + Cell *top_cell = network->cell(network->topInstance()); + sdc->fanoutLimit(top_cell, min_max, + limit, exists); + + float limit1; + bool exists1; + if (network->isTopLevelPort(pin)) { + Port *port = network->port(pin); + sdc->fanoutLimit(port, min_max, limit1, exists1); + if (exists1 + && (!exists + || min_max->compare(limit, limit1))) { + limit = limit1; + exists = true; + } + } + else { + Cell *cell = network->cell(network->instance(pin)); + sdc->fanoutLimit(cell, min_max, + limit1, exists1); + if (exists1 + && (!exists + || min_max->compare(limit, limit1))) { + limit = limit1; + exists = true; + } + LibertyPort *port = network->libertyPort(pin); + if (port) { + port->fanoutLimit(min_max, limit1, exists1); + if (!exists1 + && min_max == MinMax::max() + && port->direction()->isAnyOutput()) + port->libertyLibrary()->defaultMaxFanout(limit1, exists1); + if (exists1 + && (!exists + || min_max->compare(limit, limit1))) { + limit = limit1; + exists = true; + } + } + } +} + +void +CheckFanoutLimits::checkFanout(const Pin *pin, + const MinMax *min_max, + float limit1, + // Return values. + float &fanout, + float &slack, + float &limit) const +{ + float fanout1 = fanoutLoad(pin); + float slack1 = (min_max == MinMax::max()) + ? limit1 - fanout1 + : fanout1 - limit1; + if (fuzzyLessEqual(slack1, slack)) { + fanout = fanout1; + slack = slack1; + limit = limit1; + } +} + +float +CheckFanoutLimits::fanoutLoad(const Pin *pin) const +{ + float fanout = 0; + const Network *network = sta_->network(); + Net *net = network->net(pin); + if (net) { + NetPinIterator *pin_iter = network->pinIterator(net); + while (pin_iter->hasNext()) { + Pin *pin = pin_iter->next(); + if (network->isLoad(pin)) { + LibertyPort *port = network->libertyPort(pin); + if (port) { + float fanout_load; + bool exists; + port->fanoutLoad(fanout_load, exists); + if (!exists) { + LibertyLibrary *lib = port->libertyLibrary(); + lib->defaultFanoutLoad(fanout_load, exists); + } + if (exists) + fanout += fanout_load; + } + else + fanout += 1; + } + } + delete pin_iter; + } + return fanout; +} + +PinSeq * +CheckFanoutLimits::pinFanoutLimitViolations(const MinMax *min_max) +{ + const Network *network = sta_->network(); + PinSeq *violators = new PinSeq; + LeafInstanceIterator *inst_iter = network->leafInstanceIterator(); + while (inst_iter->hasNext()) { + Instance *inst = inst_iter->next(); + pinFanoutLimitViolations(inst, min_max, violators); + } + delete inst_iter; + + // Check top level ports. + pinFanoutLimitViolations(network->topInstance(), min_max, violators); + sort(violators, PinFanoutLimitSlackLess(min_max, this, sta_)); + return violators; +} + +void +CheckFanoutLimits::pinFanoutLimitViolations(Instance *inst, + const MinMax *min_max, + PinSeq *violators) +{ + const Network *network = sta_->network(); + const Sim *sim = sta_->sim(); + InstancePinIterator *pin_iter = network->pinIterator(inst); + while (pin_iter->hasNext()) { + Pin *pin = pin_iter->next(); + if (checkPin(pin)) { + float fanout; + float limit, slack; + checkFanout(pin, min_max, fanout, limit, slack ); + if (slack < 0.0 && !fuzzyInf(slack)) + violators->push_back(pin); + } + } + delete pin_iter; +} + +Pin * +CheckFanoutLimits::pinMinFanoutLimitSlack(const MinMax *min_max) +{ + const Network *network = sta_->network(); + Pin *min_slack_pin = nullptr; + float min_slack = MinMax::min()->initValue(); + LeafInstanceIterator *inst_iter = network->leafInstanceIterator(); + while (inst_iter->hasNext()) { + Instance *inst = inst_iter->next(); + pinMinFanoutLimitSlack(inst, min_max, min_slack_pin, min_slack); + } + delete inst_iter; + // Check top level ports. + pinMinFanoutLimitSlack(network->topInstance(), min_max, + min_slack_pin, min_slack); + return min_slack_pin; +} + +void +CheckFanoutLimits::pinMinFanoutLimitSlack(Instance *inst, + const MinMax *min_max, + // Return values. + Pin *&min_slack_pin, + float &min_slack) +{ + const Network *network = sta_->network(); + InstancePinIterator *pin_iter = network->pinIterator(inst); + while (pin_iter->hasNext()) { + Pin *pin = pin_iter->next(); + if (checkPin(pin)) { + float fanout; + float limit, slack; + checkFanout(pin, min_max, fanout, limit, slack); + if (!fuzzyInf(slack) + && (min_slack_pin == nullptr + || slack < min_slack)) { + min_slack_pin = pin; + min_slack = slack; + } + } + } + delete pin_iter; +} + +bool +CheckFanoutLimits::checkPin(const Pin *pin) +{ + const Network *network = sta_->network(); + const Sim *sim = sta_->sim(); + const Sdc *sdc = sta_->sdc(); + const Graph *graph = sta_->graph(); + GraphDelayCalc *dcalc = sta_->graphDelayCalc(); + Vertex *vertex = graph->pinLoadVertex(pin); + return network->direction(pin)->isAnyOutput() + && !sim->logicZeroOne(pin) + && !sdc->isDisabled(pin) + && !(vertex && dcalc->isIdealClk(vertex)); +} + +} // namespace diff --git a/search/CheckFanoutLimits.hh b/search/CheckFanoutLimits.hh new file mode 100644 index 00000000..280cb9b8 --- /dev/null +++ b/search/CheckFanoutLimits.hh @@ -0,0 +1,67 @@ +// OpenSTA, Static Timing Analyzer +// Copyright (c) 2020, 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 . + +#pragma once + +#include "MinMax.hh" +#include "NetworkClass.hh" +#include "SdcClass.hh" + +namespace sta { + +class StaState; + +class CheckFanoutLimits +{ +public: + CheckFanoutLimits(const StaState *sta); + void checkFanout(const Pin *pin, + const MinMax *min_max, + // Return values. + float &fanout, + float &limit, + float &slack) const; + PinSeq *pinFanoutLimitViolations(const MinMax *min_max); + Pin *pinMinFanoutLimitSlack(const MinMax *min_max); + +protected: + void checkFanout(const Pin *pin, + const MinMax *min_max, + float limit1, + // Return values. + float &fanout, + float &slack, + float &limit) const; + void findLimit(const Pin *pin, + const MinMax *min_max, + // Return values. + float &limit, + bool &limit_exists) const; + void pinFanoutLimitViolations(Instance *inst, + const MinMax *min_max, + PinSeq *violators); + void pinMinFanoutLimitSlack(Instance *inst, + const MinMax *min_max, + // Return values. + Pin *&min_slack_pin, + float &min_slack); + float fanoutLoad(const Pin *pin) const; + bool checkPin(const Pin *pin); + + const StaState *sta_; +}; + +} // namespace diff --git a/search/CheckMaxSkews.cc b/search/CheckMaxSkews.cc index d7020cc5..19583141 100644 --- a/search/CheckMaxSkews.cc +++ b/search/CheckMaxSkews.cc @@ -107,7 +107,7 @@ void MaxSkewViolatorsVisititor::visit(MaxSkewCheck &check, const StaState *sta) { - if (fuzzyLess(check.slack(sta), 0.0)) + if (delayLess(check.slack(sta), 0.0, sta)) checks_.push_back(new MaxSkewCheck(check)); } @@ -280,8 +280,8 @@ MaxSkewSlackLess::operator()(const MaxSkewCheck *check1, { Slack slack1 = check1->slack(sta_); Slack slack2 = check2->slack(sta_); - return slack1 < slack2 - || (fuzzyEqual(slack1, slack2) + return delayLess(slack1, slack2, sta_) + || (delayEqual(slack1, slack2) // Break ties based on constrained pin names. && sta_->network()->pinLess(check1->clkPin(sta_),check2->clkPin(sta_))); } diff --git a/search/CheckMinPeriods.cc b/search/CheckMinPeriods.cc index dd21636d..e4a47c70 100644 --- a/search/CheckMinPeriods.cc +++ b/search/CheckMinPeriods.cc @@ -79,7 +79,7 @@ void MinPeriodViolatorsVisitor::visit(MinPeriodCheck &check, StaState *sta) { - if (fuzzyLess(check.slack(sta), 0.0)) + if (delayLess(check.slack(sta), 0.0, sta)) checks_.push_back(check.copy()); } @@ -231,9 +231,9 @@ MinPeriodSlackLess::operator()(const MinPeriodCheck *check1, Slack slack2 = check2->slack(sta_); const Pin *pin1 = check1->pin(); const Pin *pin2 = check2->pin(); - return fuzzyLess(slack1, slack2) + return delayLess(slack1, slack2, sta_) // Break ties based on pin and clock names. - || (fuzzyEqual(slack1, slack2) + || (delayEqual(slack1, slack2) && (sta_->network()->pinLess(pin1, pin2) || (pin1 == pin2 && ClockNameLess()(check1->clk(), diff --git a/search/CheckMinPulseWidths.cc b/search/CheckMinPulseWidths.cc index 385662c0..28fe6dec 100644 --- a/search/CheckMinPulseWidths.cc +++ b/search/CheckMinPulseWidths.cc @@ -167,7 +167,7 @@ void MinPulseWidthViolatorsVisitor::visit(MinPulseWidthCheck &check, const StaState *sta) { - if (fuzzyLess(check.slack(sta), 0.0) + if (delayLess(check.slack(sta), 0.0, sta) && (corner_ == nullptr || check.corner(sta) == corner_)) { MinPulseWidthCheck *copy = new MinPulseWidthCheck(check.openPath()); @@ -499,8 +499,8 @@ MinPulseWidthSlackLess::operator()(const MinPulseWidthCheck *check1, Slack slack2 = check2->slack(sta_); const Pin *pin1 = check1->pin(sta_); const Pin *pin2 = check2->pin(sta_); - return slack1 < slack2 - || (fuzzyEqual(slack1, slack2) + return delayLess(slack1, slack2, sta_) + || (delayEqual(slack1, slack2) // Break ties for the sake of regression stability. && (sta_->network()->pinLess(pin1, pin2) || (pin1 == pin2 diff --git a/search/CheckSlewLimits.cc b/search/CheckSlewLimits.cc index 2aa2253f..da181844 100644 --- a/search/CheckSlewLimits.cc +++ b/search/CheckSlewLimits.cc @@ -68,10 +68,10 @@ PinSlewLimitSlackLess::operator()(Pin *pin1, const RiseFall *rf1, *rf2; Slew slew1, slew2; float limit1, limit2, slack1, slack2; - check_slew_limit_->checkSlews(pin1, corner_, min_max_, - corner1, rf1, slew1, limit1, slack1); - check_slew_limit_->checkSlews(pin2, corner_, min_max_, - corner2, rf2, slew2, limit2, slack2); + check_slew_limit_->checkSlew(pin1, corner_, min_max_, true, + corner1, rf1, slew1, limit1, slack1); + check_slew_limit_->checkSlew(pin2, corner_, min_max_, true, + corner2, rf2, slew2, limit2, slack2); return fuzzyLess(slack1, slack2) || (fuzzyEqual(slack1, slack2) // Break ties for the sake of regression stability. @@ -86,28 +86,16 @@ CheckSlewLimits::CheckSlewLimits(const StaState *sta) : } void -CheckSlewLimits::init(const MinMax *min_max) -{ - const Network *network = sta_->network(); - Cell *top_cell = network->cell(network->topInstance()); - float top_limit; - bool top_limit_exists; - sta_->sdc()->slewLimit(top_cell, min_max, - top_limit, top_limit_exists); - top_limit_= top_limit; - top_limit_exists_ = top_limit_exists; -} - -void -CheckSlewLimits::checkSlews(const Pin *pin, - const Corner *corner, - const MinMax *min_max, - // Return values. - const Corner *&corner1, - const RiseFall *&rf, - Slew &slew, - float &limit, - float &slack) const +CheckSlewLimits::checkSlew(const Pin *pin, + const Corner *corner, + const MinMax *min_max, + bool check_clks, + // Return values. + const Corner *&corner1, + const RiseFall *&rf, + Slew &slew, + float &limit, + float &slack) const { corner1 = nullptr; rf = nullptr; @@ -115,11 +103,11 @@ CheckSlewLimits::checkSlews(const Pin *pin, limit = 0.0; slack = MinMax::min()->initValue(); if (corner) - checkSlews1(pin, corner, min_max, + checkSlews1(pin, corner, min_max, check_clks, corner1, rf, slew, limit, slack); else { for (auto corner : *sta_->corners()) { - checkSlews1(pin, corner, min_max, + checkSlews1(pin, corner, min_max, check_clks, corner1, rf, slew, limit, slack); } } @@ -129,6 +117,7 @@ void CheckSlewLimits::checkSlews1(const Pin *pin, const Corner *corner, const MinMax *min_max, + bool check_clks, // Return values. const Corner *&corner1, const RiseFall *&rf, @@ -138,13 +127,11 @@ CheckSlewLimits::checkSlews1(const Pin *pin, { Vertex *vertex, *bidirect_drvr_vertex; sta_->graph()->pinVertices(pin, vertex, bidirect_drvr_vertex); - if (vertex - && !vertex->isDisabledConstraint()) - checkSlews1(vertex, corner, min_max, + if (vertex) + checkSlews1(vertex, corner, min_max, check_clks, corner1, rf, slew, limit, slack); - if (bidirect_drvr_vertex - && !vertex->isDisabledConstraint()) - checkSlews1(bidirect_drvr_vertex, corner, min_max, + if (bidirect_drvr_vertex) + checkSlews1(bidirect_drvr_vertex, corner, min_max, check_clks, corner1, rf, slew, limit, slack); } @@ -152,6 +139,7 @@ void CheckSlewLimits::checkSlews1(Vertex *vertex, const Corner *corner1, const MinMax *min_max, + bool check_clks, // Return values. const Corner *&corner, const RiseFall *&rf, @@ -159,34 +147,46 @@ CheckSlewLimits::checkSlews1(Vertex *vertex, float &limit, float &slack) const { - for (auto rf1 : RiseFall::range()) { - float limit1; - bool limit1_exists; - findLimit(vertex->pin(), vertex, rf1, min_max, limit1, limit1_exists); - if (limit1_exists) { - checkSlew(vertex, corner1, min_max, rf1, limit1, - corner, rf, slew, slack, limit); + if (!vertex->isDisabledConstraint() + && !vertex->isConstant() + && !sta_->graphDelayCalc()->isIdealClk(vertex)) { + for (auto rf1 : RiseFall::range()) { + float limit1; + bool limit1_exists; + findLimit(vertex->pin(), vertex, rf1, min_max, check_clks, + limit1, limit1_exists); + if (limit1_exists) { + checkSlew(vertex, corner1, rf1, min_max, limit1, + corner, rf, slew, slack, limit); + } } } } +// return the tightest limit. void CheckSlewLimits::findLimit(const Pin *pin, const Vertex *vertex, const RiseFall *rf, const MinMax *min_max, + bool check_clks, // Return values. float &limit, bool &exists) const { exists = false; - if (!sta_->graphDelayCalc()->isIdealClk(vertex)) { - const Network *network = sta_->network(); - Sdc *sdc = sta_->sdc(); - bool is_clk = sta_->search()->isClock(vertex); - float limit1; - bool exists1; + const Network *network = sta_->network(); + Sdc *sdc = sta_->sdc(); + + // Default to top ("design") limit. + Cell *top_cell = network->cell(network->topInstance()); + sdc->slewLimit(top_cell, min_max, + limit, exists); + float limit1; + bool exists1; + if (check_clks) { // Look for clock slew limits. + bool is_clk = sta_->search()->isClock(vertex); ClockSet clks; clockDomains(vertex, clks); ClockSet::Iterator clk_iter(clks); @@ -198,58 +198,34 @@ CheckSlewLimits::findLimit(const Pin *pin, if (exists1 && (!exists || min_max->compare(limit, limit1))) { - // Use the tightest clock limit. limit = limit1; exists = true; } } - if (!exists) { - // Default to top ("design") limit. - exists = top_limit_exists_; - limit = top_limit_; - if (network->isTopLevelPort(pin)) { - Port *port = network->port(pin); - sdc->slewLimit(port, min_max, limit1, exists1); - // Use the tightest limit. - if (exists1 - && (!exists - || min_max->compare(limit, limit1))) { - limit = limit1; - exists = true; - } - } - else { - sdc->slewLimit(pin, min_max, - limit1, exists1); - // Use the tightest limit. - if (exists1 - && (!exists - || min_max->compare(limit, limit1))) { - limit = limit1; - exists = true; - } - LibertyPort *port = network->libertyPort(pin); - if (port) { - port->slewLimit(min_max, limit1, exists1); - // Use the tightest limit. - if (exists1) { - if (!exists - || min_max->compare(limit, limit1)) { - limit = limit1; - exists = true; - } - } - else if (port->direction()->isAnyOutput() - && min_max == MinMax::max()) { - port->libertyLibrary()->defaultMaxSlew(limit1, exists1); - if (exists1 - && (!exists - || min_max->compare(limit, limit1))) { - limit = limit1; - exists = true; - } - } - } + } + if (network->isTopLevelPort(pin)) { + Port *port = network->port(pin); + sdc->slewLimit(port, min_max, limit1, exists1); + if (exists1 + && (!exists + || min_max->compare(limit, limit1))) { + limit = limit1; + exists = true; + } + } + else { + LibertyPort *port = network->libertyPort(pin); + if (port) { + port->slewLimit(min_max, limit1, exists1); + if (!exists1 + && port->direction()->isAnyOutput() + && min_max == MinMax::max()) + port->libertyLibrary()->defaultMaxSlew(limit1, exists1); + if (exists1 + && (!exists + || min_max->compare(limit, limit1))) { + limit = limit1; + exists = true; } } } @@ -272,8 +248,8 @@ CheckSlewLimits::clockDomains(const Vertex *vertex, void CheckSlewLimits::checkSlew(Vertex *vertex, const Corner *corner1, - const MinMax *min_max, const RiseFall *rf1, + const MinMax *min_max, float limit1, // Return values. const Corner *&corner, @@ -304,7 +280,6 @@ PinSeq * CheckSlewLimits::pinSlewLimitViolations(const Corner *corner, const MinMax *min_max) { - init(min_max); const Network *network = sta_->network(); PinSeq *violators = new PinSeq; LeafInstanceIterator *inst_iter = network->leafInstanceIterator(); @@ -333,8 +308,8 @@ CheckSlewLimits::pinSlewLimitViolations(Instance *inst, const RiseFall *rf; Slew slew; float limit, slack; - checkSlews(pin, corner, min_max, corner1, rf, slew, limit, slack ); - if (rf && slack < 0.0) + checkSlew(pin, corner, min_max, true, corner1, rf, slew, limit, slack); + if (rf && slack < 0.0 && !fuzzyInf(slack)) violators->push_back(pin); } delete pin_iter; @@ -344,9 +319,8 @@ Pin * CheckSlewLimits::pinMinSlewLimitSlack(const Corner *corner, const MinMax *min_max) { - init(min_max); const Network *network = sta_->network(); - Pin *min_slack_pin = 0; + Pin *min_slack_pin = nullptr; float min_slack = MinMax::min()->initValue(); LeafInstanceIterator *inst_iter = network->leafInstanceIterator(); while (inst_iter->hasNext()) { @@ -376,9 +350,9 @@ CheckSlewLimits::pinMinSlewLimitSlack(Instance *inst, const RiseFall *rf; Slew slew; float limit, slack; - checkSlews(pin, corner, min_max, corner1, rf, slew, limit, slack); + checkSlew(pin, corner, min_max, true, corner1, rf, slew, limit, slack); if (rf - && (min_slack_pin == 0 + && (min_slack_pin == nullptr || slack < min_slack)) { min_slack_pin = pin; min_slack = slack; diff --git a/search/CheckSlewLimits.hh b/search/CheckSlewLimits.hh index 0fa728df..8c65a049 100644 --- a/search/CheckSlewLimits.hh +++ b/search/CheckSlewLimits.hh @@ -33,19 +33,18 @@ class CheckSlewLimits { public: CheckSlewLimits(const StaState *sta); - void init(const MinMax *min_max); - // Requires init(). // corner=nullptr checks all corners. - void checkSlews(const Pin *pin, - const Corner *corner, - const MinMax *min_max, - // Return values. - // Corner is nullptr for no slew limit. - const Corner *&corner1, - const RiseFall *&rf, - Slew &slew, - float &limit, - float &slack) const; + void checkSlew(const Pin *pin, + const Corner *corner, + const MinMax *min_max, + bool check_clks, + // Return values. + // Corner is nullptr for no slew limit. + const Corner *&corner1, + const RiseFall *&rf, + Slew &slew, + float &limit, + float &slack) const; // corner=nullptr checks all corners. PinSeq *pinSlewLimitViolations(const Corner *corner, const MinMax *min_max); @@ -57,6 +56,7 @@ protected: void checkSlews1(const Pin *pin, const Corner *corner, const MinMax *min_max, + bool check_clks, // Return values. const Corner *&corner1, const RiseFall *&rf, @@ -66,6 +66,7 @@ protected: void checkSlews1(Vertex *vertex, const Corner *corner1, const MinMax *min_max, + bool check_clks, // Return values. const Corner *&corner, const RiseFall *&rf, @@ -74,8 +75,8 @@ protected: float &slack) const; void checkSlew(Vertex *vertex, const Corner *corner1, - const MinMax *min_max, const RiseFall *rf1, + const MinMax *min_max, float limit1, // Return values. const Corner *&corner, @@ -87,6 +88,7 @@ protected: const Vertex *vertex, const RiseFall *rf, const MinMax *min_max, + bool check_clks, // Return values. float &limit1, bool &limit1_exists) const; @@ -104,8 +106,6 @@ protected: // Return value. ClockSet &clks) const; - float top_limit_; - bool top_limit_exists_; const StaState *sta_; }; diff --git a/search/ClkInfo.cc b/search/ClkInfo.cc index 8638eda3..f8b0c5e0 100644 --- a/search/ClkInfo.cc +++ b/search/ClkInfo.cc @@ -294,9 +294,9 @@ clkInfoCmp(const ClkInfo *clk_info1, const Arrival &insert1 = clk_info1->insertion(); const Arrival &insert2 = clk_info2->insertion(); - if (insert1 < insert2) + if (delayLess(insert1, insert2, sta)) return -1; - if (insert1 > insert2) + if (delayGreater(insert1, insert2, sta)) return 1; float latency1 = clk_info1->latency(); diff --git a/search/Crpr.cc b/search/Crpr.cc index 3d9fc1ee..64496ffb 100644 --- a/search/Crpr.cc +++ b/search/Crpr.cc @@ -165,6 +165,8 @@ CheckCrpr::checkCrpr1(const Path *src_path, const MinMax *src_clk_min_max = src_clk_path ? src_clk_path->minMax(this) : src_path->minMax(this); if (crprPossible(src_clk, tgt_clk) + && src_clk_info->isPropagated() + && tgt_clk_info->isPropagated() // Note that crpr clk min/max is NOT the same as the path min max. // For path from latches that are borrowing the enable path // is from the opposite min/max of the data. @@ -302,6 +304,7 @@ CheckCrpr::findCrpr1(const PathVertex *src_clk_path, float tgt_clk_time = tgt_clk_path->clkEdge(this)->time(); float crpr_mean = abs(delayAsFloat(src_arrival) - src_clk_time - (delayAsFloat(tgt_arrival) - tgt_clk_time)); + // Remove the sigma from both source and target path arrivals. float crpr_sigma2 = delaySigma2(src_arrival, src_el) + delaySigma2(tgt_arrival, tgt_el); return makeDelay2(crpr_mean, -crpr_sigma2, -crpr_sigma2); @@ -371,9 +374,12 @@ CheckCrpr::outputDelayCrpr1(const Path *src_path, { crpr = 0.0; crpr_pin = nullptr; + ClkInfo *src_clk_info = src_path->tag(this)->clkInfo(); Clock *tgt_clk = tgt_clk_edge->clock(); Clock *src_clk = src_path->clock(this); - if (tgt_clk->isGenerated() + if (src_clk_info->isPropagated() + && tgt_clk->isGenerated() + && tgt_clk->isPropagated() && crprPossible(src_clk, tgt_clk)) { PathVertex tgt_genclk_path; portClkPath(tgt_clk_edge, tgt_clk_edge->clock()->defaultPin(), tgt_path_ap, @@ -392,7 +398,7 @@ CheckCrpr::crprPossible(Clock *clk1, return clk1 && clk2 && !clk1->isVirtual() && !clk2->isVirtual() - // Generated clock can have crpr in the source path. + // Generated clocks can have crpr in the source path. && (clk1 == clk2 || clk1->isGenerated() || clk2->isGenerated() diff --git a/search/Genclks.cc b/search/Genclks.cc index 78da5608..9e89fd98 100644 --- a/search/Genclks.cc +++ b/search/Genclks.cc @@ -968,9 +968,10 @@ Genclks::recordSrcPaths(Clock *gclk) && (!has_edges || src_clk_rf == gclk->masterClkEdgeTr(rf)) && (src_path.isNull() - || fuzzyGreater(path->arrival(this), - src_path.arrival(this), - early_late))) { + || delayGreater(path->arrival(this), + src_path.arrival(this), + early_late, + this))) { debugPrint4(debug_, "genclk", 2, " %s insertion %s %s %s\n", network_->pathName(gclk_pin), early_late->asString(), diff --git a/search/Latches.cc b/search/Latches.cc index d47b16a1..687ecfec 100644 --- a/search/Latches.cc +++ b/search/Latches.cc @@ -98,7 +98,7 @@ Latches::latchRequired(const Path *data_path, network_->pathName(data_path->pin(this)), delayAsString(data_arrival, this), delayAsString(enable_arrival, this)); - if (data_arrival <= enable_arrival) { + if (delayLessEqual(data_arrival, enable_arrival, this)) { // Data arrives before latch opens. required = enable_arrival; borrow = 0.0; @@ -108,7 +108,7 @@ Latches::latchRequired(const Path *data_path, else { // Data arrives while latch is transparent. borrow = data_arrival - enable_arrival; - if (borrow <= max_borrow) + if (delayLessEqual(borrow, max_borrow, this)) required = data_arrival; else { borrow = max_borrow; @@ -332,7 +332,7 @@ Latches::latchOutArrival(Path *data_path, latchRequired(data_path, enable_path, &disable_path, path_ap, required, borrow, adjusted_data_arrival, time_given_to_startpoint); - if (borrow > 0.0) { + if (delayGreater(borrow, 0.0, this)) { // Latch is transparent when data arrives. arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge, false, path_ap); diff --git a/search/PathEnd.cc b/search/PathEnd.cc index aecfa1de..ff7a9b32 100644 --- a/search/PathEnd.cc +++ b/search/PathEnd.cc @@ -361,10 +361,11 @@ PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path, if (clk_info->isPropagated()) { // Propagated clock. Propagated arrival is seeded with // early_late==path_min_max insertion delay. + Arrival clk_arrival = tgt_clk_path->arrival(sta); Arrival path_insertion = search->clockInsertion(tgt_clk, tgt_src_pin, tgt_clk_rf, min_max, min_max, tgt_path_ap); - latency=tgt_clk_path->arrival(sta)-tgt_clk_edge->time()-path_insertion; + latency = delayRemove(clk_arrival - tgt_clk_edge->time(), path_insertion); } else // Ideal clock. @@ -1243,7 +1244,7 @@ PathEndLatchCheck::targetClkWidth(const StaState *sta) const if (enable_clk_info->isPulseClk()) return disable_arrival - enable_arrival; else { - if (enable_arrival > disable_arrival) { + if (delayGreater(enable_arrival, disable_arrival, sta)) { float period = enable_clk_info->clock()->period(); disable_arrival += period; } @@ -1844,6 +1845,17 @@ PathEnd::pathDelaySrcClkOffset(const PathRef &path, return offset; } +ClockEdge * +PathEndPathDelay::targetClkEdge(const StaState *sta) const +{ + if (!clk_path_.isNull()) + return clk_path_.clkEdge(sta); + else if (output_delay_) + return output_delay_->clkEdge(); + else + return nullptr; +} + float PathEndPathDelay::targetClkTime(const StaState *sta) const { @@ -1857,14 +1869,12 @@ PathEndPathDelay::targetClkTime(const StaState *sta) const Arrival PathEndPathDelay::targetClkArrivalNoCrpr(const StaState *sta) const { - if (!clk_path_.isNull()) { - ClockEdge *tgt_clk_edge = targetClkEdge(sta); - if (tgt_clk_edge) - return targetClkDelay(sta) - + targetClkUncertainty(sta); - else - return clk_path_.arrival(sta); - } + ClockEdge *tgt_clk_edge = targetClkEdge(sta); + if (tgt_clk_edge) + return targetClkDelay(sta) + + targetClkUncertainty(sta); + else if (!clk_path_.isNull()) + return clk_path_.arrival(sta); else return 0.0; } @@ -1886,9 +1896,7 @@ PathEndPathDelay::requiredTime(const StaState *sta) const return src_clk_arrival_ + delay + margin(sta); } else { - Arrival tgt_clk_arrival = 0.0; - if (!clk_path_.isNull()) - tgt_clk_arrival = targetClkArrival(sta); + Arrival tgt_clk_arrival = targetClkArrival(sta); float src_clk_offset = sourceClkOffset(sta); // Path delay includes target clk latency and timing check setup/hold // margin or external departure at target. @@ -1981,24 +1989,24 @@ PathEnd::cmpSlack(const PathEnd *path_end1, { Slack slack1 = path_end1->slack(sta); Slack slack2 = path_end2->slack(sta); - if (fuzzyZero(slack1) - && fuzzyZero(slack2) + if (delayZero(slack1) + && delayZero(slack2) && path_end1->isLatchCheck() && path_end2->isLatchCheck()) { Arrival borrow1 = path_end1->borrow(sta); Arrival borrow2 = path_end2->borrow(sta); // Latch slack is zero if there is borrowing so break ties // based on borrow time. - if (fuzzyEqual(borrow1, borrow2)) + if (delayEqual(borrow1, borrow2)) return 0; - else if (borrow1 > borrow2) + else if (delayGreater(borrow1, borrow2, sta)) return -1; else return 1; } - else if (fuzzyEqual(slack1, slack2)) + else if (delayEqual(slack1, slack2)) return 0; - else if (slack1 < slack2) + else if (delayLess(slack1, slack2, sta)) return -1; else return 1; @@ -2012,9 +2020,9 @@ PathEnd::cmpArrival(const PathEnd *path_end1, Arrival arrival1 = path_end1->dataArrivalTime(sta); Arrival arrival2 = path_end2->dataArrivalTime(sta); const MinMax *min_max = path_end1->minMax(sta); - if (fuzzyEqual(arrival1, arrival2)) + if (delayEqual(arrival1, arrival2)) return 0; - else if (fuzzyLess(arrival1, arrival2, min_max)) + else if (delayLess(arrival1, arrival2, min_max, sta)) return -1; else return 1; diff --git a/search/PathEnum.cc b/search/PathEnum.cc index 0d650fa1..7ff1f781 100644 --- a/search/PathEnum.cc +++ b/search/PathEnum.cc @@ -348,7 +348,7 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *, // Make the diverted path end to check slack with from_path crpr. makeDivertedPathEnd(from_path, arc, div_end, after_div_copy); // Only enumerate paths with greater slack. - if (fuzzyGreaterEqual(div_end->slack(sta_), path_end_slack_)) { + if (delayGreaterEqual(div_end->slack(sta_), path_end_slack_, sta_)) { reportDiversion(arc, from_path); path_enum_->makeDiversion(div_end, after_div_copy); } @@ -356,7 +356,7 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *, delete div_end; } // Only enumerate slower/faster paths. - else if (fuzzyLessEqual(to_arrival, before_div_arrival_, min_max)) { + else if (delayLessEqual(to_arrival, before_div_arrival_, min_max, sta_)) { PathEnd *div_end; PathEnumed *after_div_copy; makeDivertedPathEnd(from_path, arc, div_end, after_div_copy); diff --git a/search/PathGroup.cc b/search/PathGroup.cc index 20422f8d..0afe3ab2 100644 --- a/search/PathGroup.cc +++ b/search/PathGroup.cc @@ -101,19 +101,19 @@ PathGroup::savable(PathEnd *path_end) // without crpr first because it is expensive to find. Slack slack = path_end->slackNoCrpr(sta_); if (!delayIsInitValue(slack, min_max_) - && fuzzyLessEqual(slack, threshold_) - && fuzzyLessEqual(slack, slack_max_)) { + && delayLessEqual(slack, threshold_, sta_) + && delayLessEqual(slack, slack_max_, sta_)) { // Now check with crpr. slack = path_end->slack(sta_); - savable = fuzzyLessEqual(slack, threshold_) - && fuzzyLessEqual(slack, slack_max_) - && fuzzyGreaterEqual(slack, slack_min_); + savable = delayLessEqual(slack, threshold_, sta_) + && delayLessEqual(slack, slack_max_, sta_) + && delayGreaterEqual(slack, slack_min_, sta_); } } else { const Arrival &arrival = path_end->dataArrivalTime(sta_); savable = !delayIsInitValue(arrival, min_max_) - && fuzzyGreaterEqual(arrival, threshold_, min_max_); + && delayGreaterEqual(arrival, threshold_, min_max_, sta_); } return savable; } diff --git a/search/PathVertex.cc b/search/PathVertex.cc index e870f659..d26b32ab 100644 --- a/search/PathVertex.cc +++ b/search/PathVertex.cc @@ -403,7 +403,7 @@ PrevPathVisitor::visitFromToPath(const Pin *, && path_ap_index == path_ap_index_ && (dcalc_tol_ > 0.0 ? std::abs(delayAsFloat(to_arrival - path_arrival_)) < dcalc_tol_ - : fuzzyEqual(to_arrival, path_arrival_)) + : delayEqual(to_arrival, path_arrival_)) && (tagMatch(to_tag, path_tag_, sta_) // If the filter exception became active searching from // from_path to to_path the tag includes the filter, but diff --git a/search/Power.cc b/search/Power.cc index 95eee7d1..525aecde 100644 --- a/search/Power.cc +++ b/search/Power.cc @@ -154,7 +154,8 @@ Power::power(const Corner *corner, if (cell) { PowerResult inst_power; power(inst, corner, inst_power); - if (cell->isMacro()) + if (cell->isMacro() + || cell->isMemory()) macro.incr(inst_power); else if (cell->isPad()) pad.incr(inst_power); @@ -596,7 +597,7 @@ Power::findInputInternalPower(const Pin *pin, for (auto rf : RiseFall::range()) { float slew = delayAsFloat(graph_->slew(vertex, rf, dcalc_ap->index())); - if (!fuzzyInf(slew)) { + if (!delayInf(slew)) { float table_energy = pwr->power(rf, pvt, slew, load_cap); energy += table_energy; tr_count++; @@ -621,7 +622,7 @@ Power::findInputInternalPower(const Pin *pin, float port_internal = energy * duty * activity.activity(); debugPrint7(debug_, "power", 2, " %3s %6s %.2f %.2f %9.2e %9.2e %s\n", port->name(), - when->asString(), + when ? when->asString() : "", activity.activity() * 1e-9, duty, energy, @@ -734,7 +735,7 @@ Power::findOutputInternalPower(const Pin *to_pin, ? delayAsFloat(graph_->slew(from_vertex, from_rf, dcalc_ap->index())) : 0.0; - if (!fuzzyInf(slew)) { + if (!delayInf(slew)) { float table_energy = pwr->power(to_rf, pvt, slew, load_cap); energy += table_energy; tr_count++; @@ -774,25 +775,26 @@ Power::findInputDuty(const Pin *to_pin, const LibertyPort *from_port = pwr->relatedPort(); if (from_port) { const Pin *from_pin = network_->findPin(inst, from_port); - FuncExpr *when = pwr->when(); - Vertex *from_vertex = graph_->pinLoadVertex(from_pin); - if (func && func->hasPort(from_port)) { - PwrActivity from_activity = findActivity(from_pin); - PwrActivity to_activity = findActivity(to_pin); - float duty1 = evalActivityDifference(func, inst, from_port).duty(); - if (to_activity.activity() == 0.0) - return 0.0; - else - return from_activity.activity() / to_activity.activity() * duty1; + if (from_pin) { + FuncExpr *when = pwr->when(); + Vertex *from_vertex = graph_->pinLoadVertex(from_pin); + if (func && func->hasPort(from_port)) { + PwrActivity from_activity = findActivity(from_pin); + PwrActivity to_activity = findActivity(to_pin); + float duty1 = evalActivityDifference(func, inst, from_port).duty(); + if (to_activity.activity() == 0.0) + return 0.0; + else + return from_activity.activity() / to_activity.activity() * duty1; + } + else if (when) + return evalActivity(when, inst).duty(); + else if (search_->isClock(from_vertex)) + return 1.0; + return 0.5; } - else if (when) - return evalActivity(when, inst).duty(); - else if (search_->isClock(from_vertex)) - return 1.0; - return 0.5; } - else - return 0.0; + return 0.0; } static bool diff --git a/search/Property.cc b/search/Property.cc index 2877fc86..f77e0889 100644 --- a/search/Property.cc +++ b/search/Property.cc @@ -566,6 +566,8 @@ getProperty(const LibertyCell *cell, return PropertyValue(cell->libertyLibrary()); else if (stringEqual(property, "is_buffer")) return PropertyValue(cell->isBuffer()); + else if (stringEqual(property, "is_inverter")) + return PropertyValue(cell->isInverter()); else if (stringEqual(property, "dont_use")) return PropertyValue(cell->dontUse()); else @@ -686,6 +688,8 @@ getProperty(const LibertyPort *port, float cap = port->capacitance(RiseFall::rise(), MinMax::max()); return PropertyValue(sta->units()->capacitanceUnit()->asString(cap, 6)); } + else if (stringEqual(property, "is_register_clock")) + return PropertyValue(port->isRegClk()); else if (stringEqual(property, "drive_resistance_rise_min")) return PropertyValue(port->driveResistance(RiseFall::rise(), MinMax::min())); @@ -732,13 +736,17 @@ getProperty(const Pin *pin, Sta *sta) { auto network = sta->cmdNetwork(); - if (stringEqual(property, "direction")) - return PropertyValue(network->direction(pin)->name()); - else if (stringEqual(property, "name") - || stringEqual(property, "full_name")) - return PropertyValue(network->pathName(pin)); - else if (stringEqual(property, "lib_pin_name")) + if (stringEqual(property, "name") + || stringEqual(property, "lib_pin_name")) return PropertyValue(network->portName(pin)); + else if (stringEqual(property, "full_name")) + return PropertyValue(network->pathName(pin)); + else if (stringEqual(property, "direction")) + return PropertyValue(network->direction(pin)->name()); + else if (stringEqual(property, "is_register_clock")) { + const LibertyPort *port = network->libertyPort(pin); + return PropertyValue(port && port->isRegClk()); + } else if (stringEqual(property, "clocks")) { ClockSet clks; sta->clocks(pin, clks); @@ -793,12 +801,12 @@ pinSlewProperty(const Pin *pin, Slew slew = min_max->initValue(); if (vertex) { Slew vertex_slew = sta->vertexSlew(vertex, rf, min_max); - if (fuzzyGreater(vertex_slew, slew, min_max)) + if (delayGreater(vertex_slew, slew, min_max, sta)) slew = vertex_slew; } if (bidirect_drvr_vertex) { Slew vertex_slew = sta->vertexSlew(bidirect_drvr_vertex, rf, min_max); - if (fuzzyGreater(vertex_slew, slew, min_max)) + if (delayGreater(vertex_slew, slew, min_max, sta)) slew = vertex_slew; } return PropertyValue(delayPropertyValue(slew, sta)); @@ -871,9 +879,9 @@ edgeDelayProperty(Edge *edge, ArcDelay arc_delay = sta->arcDelay(edge, arc, dcalc_ap); if (!delay_exists || ((min_max == MinMax::max() - && arc_delay > delay) + && delayGreater(arc_delay, delay, sta)) || (min_max == MinMax::min() - && arc_delay < delay))) + && delayLess(arc_delay, delay, sta)))) delay = arc_delay; } } @@ -916,7 +924,9 @@ getProperty(Clock *clk, else if (stringEqual(property, "sources")) return PropertyValue(&clk->pins()); else if (stringEqual(property, "propagated")) - return PropertyValue(clk->isPropagated() ? "1" : "0"); + return PropertyValue(clk->isPropagated()); + else if (stringEqual(property, "is_generated")) + return PropertyValue(clk->isGenerated()); else throw PropertyUnknown("clock", property); } diff --git a/search/ReportPath.cc b/search/ReportPath.cc index e0eb8811..2a9187d9 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -143,7 +143,7 @@ ReportPath::~ReportPath() void ReportPath::makeFields() { - field_fanout_ = makeField("fanout", "Fanout", 5, false, nullptr, true); + field_fanout_ = makeField("fanout", "Fanout", 6, false, nullptr, true); field_capacitance_ = makeField("capacitance", "Cap", 6, false, units_->capacitanceUnit(), true); field_slew_ = makeField("slew", "Slew", 6, false, units_->timeUnit(), @@ -578,7 +578,7 @@ ReportPath::reportFull(const PathEndLatchCheck *end, else reportTgtClk(end, result); - if (borrow >= 0.0) + if (delayGreaterEqual(borrow, 0.0, this)) reportLine("time borrowed from endpoint", borrow, req_time, early_late, result); else @@ -644,7 +644,7 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end, if (tgt_clk_path->clkInfo(search_)->isPropagated()) { auto width_msg = stdstrPrint("%s nominal pulse width", tgt_clk_name.c_str()); reportLineTotal(width_msg.c_str(), nom_pulse_width, early_late, result); - if (!fuzzyZero(latency_diff)) + if (!delayZero(latency_diff)) reportLineTotalMinus("clock latency difference", latency_diff, early_late, result); } @@ -655,19 +655,19 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end, ArcDelay margin = end->margin(this); reportLineTotalMinus("library setup time", margin, early_late, result); reportDashLineTotal(result); - if (!fuzzyZero(crpr_diff)) + if (!delayZero(crpr_diff)) reportLineTotalMinus("CRPR difference", crpr_diff, early_late, result); reportLineTotal("max time borrow", max_borrow, early_late, result); } - if (fuzzyGreater(borrow, delay_zero) + if (delayGreater(borrow, delay_zero, this) && (!fuzzyZero(open_uncertainty) - || !fuzzyZero(open_crpr))) { + || !delayZero(open_crpr))) { reportDashLineTotal(result); reportLineTotal("actual time borrow", borrow, early_late, result); if (!fuzzyZero(open_uncertainty)) reportLineTotal("open edge uncertainty", open_uncertainty, early_late, result); - if (!fuzzyZero(open_crpr)) + if (!delayZero(open_crpr)) reportLineTotal("open edge CRPR", open_crpr, early_late, result); reportDashLineTotal(result); reportLineTotal("time given to startpoint", time_given_to_startpoint, @@ -705,12 +705,16 @@ void ReportPath::reportEndpoint(const PathEndPathDelay *end, string &result) { - Instance *inst = network_->instance(end->vertex(this)->pin()); - const char *inst_name = cmd_network_->pathName(inst); - string clk_name = tgtClkName(end); - const char *reg_desc = clkRegLatchDesc(end); - auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str()); - reportEndpoint(inst_name, reason, result); + if (end->hasOutputDelay()) + reportEndpointOutputDelay(end, result); + else { + Instance *inst = network_->instance(end->vertex(this)->pin()); + const char *inst_name = cmd_network_->pathName(inst); + string clk_name = tgtClkName(end); + const char *reg_desc = clkRegLatchDesc(end); + auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str()); + reportEndpoint(inst_name, reason, result); + } } void @@ -746,18 +750,16 @@ ReportPath::reportFull(const PathEndPathDelay *end, float delay = path_delay->delay(); reportLine(delay_msg.c_str(), delay, delay, early_late, result); if (!path_delay->ignoreClkLatency()) { - const Path *tgt_clk_path = end->targetClkPath(); - if (tgt_clk_path) { - float delay = 0.0; - if (path_delay) - delay = path_delay->delay(); + Clock *tgt_clk = end->targetClk(this); + if (tgt_clk) { + const Path *tgt_clk_path = end->targetClkPath(); if (reportClkPath() - && isPropagated(tgt_clk_path)) + && isPropagated(tgt_clk_path, tgt_clk)) reportTgtClk(end, delay, result); else { Arrival tgt_clk_delay = end->targetClkDelay(this); Arrival tgt_clk_arrival = delay + tgt_clk_delay; - if (!fuzzyZero(tgt_clk_delay)) + if (!delayZero(tgt_clk_delay)) reportLine(clkNetworkDelayIdealProp(isPropagated(tgt_clk_path)), tgt_clk_delay, tgt_clk_arrival, early_late, result); reportClkUncertainty(end, tgt_clk_arrival, result); @@ -832,6 +834,13 @@ ReportPath::reportFull(const PathEndOutputDelay *end, void ReportPath::reportEndpoint(const PathEndOutputDelay *end, string &result) +{ + reportEndpointOutputDelay(end, result); +} + +void +ReportPath::reportEndpointOutputDelay(const PathEndClkConstrained *end, + string &result) { Vertex *vertex = end->vertex(this); Pin *pin = vertex->pin(); @@ -851,6 +860,7 @@ ReportPath::reportEndpoint(const PathEndOutputDelay *end, if (tgt_clk) { string clk_name = tgtClkName(end); auto reason = stdstrPrint("internal path endpoint clocked by %s", clk_name.c_str()); + reportEndpoint(pin_name, reason, result); } else @@ -1367,8 +1377,8 @@ ReportPath::reportVerbose(MinPeriodCheck *check, string &result) result += pin_name; reportEndOfLine(result); - reportLine("Period", check->period(), EarlyLate::early(), result); - reportLine("min_period", -check->minPeriod(this), + reportLine("period", check->period(), EarlyLate::early(), result); + reportLine("min period", -check->minPeriod(this), EarlyLate::early(), result); reportDashLine(result); reportSlack(check->slack(this), result); @@ -1549,99 +1559,118 @@ ReportPath::reportSkewClkPath(const char *arrival_msg, //////////////////////////////////////////////////////////////// void -ReportPath::reportSlewLimitShortHeader() +ReportPath::reportLimitShortHeader(const ReportField *field) { string result; - reportSlewLimitShortHeader(result); + reportLimitShortHeader(field, result); report_->print(result); } void -ReportPath::reportSlewLimitShortHeader(string &result) +ReportPath::reportLimitShortHeader(const ReportField *field, + string &result) { reportDescription("Pin", result); result += ' '; - reportField("Limit", field_slew_, result); + reportField("Limit", field, result); result += ' '; - reportField("Trans", field_slew_, result); + reportField(field->title(), field, result); result += ' '; - reportField("Slack", field_slew_, result); + reportField("Slack", field, result); reportEndOfLine(result); - reportDashLine(field_description_->width() + field_slew_->width() * 3 + 3, + reportDashLine(field_description_->width() + field->width() * 3 + 3, result); } void -ReportPath::reportSlewLimitShort(Pin *pin, - const RiseFall *rf, - Slew slew, - float limit, - float slack) +ReportPath::reportLimitShort(const ReportField *field, + Pin *pin, + float value, + float limit, + float slack) { string result; - reportSlewLimitShort(pin, rf, slew, limit, slack, result); + reportLimitShort(field, pin, value, limit, slack, result); report_->print(result); } void -ReportPath::reportSlewLimitShort(Pin *pin, - const RiseFall *, - Slew slew, - float limit, - float slack, - string &result) +ReportPath::reportLimitShort(const ReportField *field, + Pin *pin, + float value, + float limit, + float slack, + string &result) { const char *pin_name = cmd_network_->pathName(pin); reportDescription(pin_name, result); - reportSpaceFieldTime(limit, result); - reportSpaceFieldDelay(slew, EarlyLate::late(), result); - reportSpaceSlack(slack, result); + result += ' '; + reportField(limit, field, result); + result += ' '; + reportField(value, field, result); + result += ' '; + reportField(slack, field, result); + result += (slack >= 0.0) + ? " (MET)" + : " (VIOLATED)"; + reportEndOfLine(result); } void -ReportPath::reportSlewLimitVerbose(Pin *pin, - const Corner *corner, - const RiseFall *rf, - Slew slew, - float limit, - float slack, - const MinMax *min_max) +ReportPath::reportLimitVerbose(const ReportField *field, + Pin *pin, + const RiseFall *rf, + float value, + float limit, + float slack, + const MinMax *min_max) { string result; - reportSlewLimitVerbose(pin, corner, rf, slew, limit, slack, min_max, result); + reportLimitVerbose(field, pin, rf, value, limit, slack, min_max, result); report_->print(result); } void -ReportPath::reportSlewLimitVerbose(Pin *pin, - const Corner *, - const RiseFall *rf, - Slew slew, - float limit, - float slack, - const MinMax *min_max, - string &result) +ReportPath::reportLimitVerbose(const ReportField *field, + Pin *pin, + const RiseFall *rf, + float value, + float limit, + float slack, + const MinMax *min_max, + string &result) { result += "Pin "; result += cmd_network_->pathName(pin); result += ' '; - result += rf->shortName(); + if (rf) + result += rf->shortName(); + else + result += ' '; reportEndOfLine(result); result += min_max->asString(); - result += "_transition "; - reportSpaceFieldTime(limit, result); + result += ' '; + result += field->name(); + result += ' '; + reportField(limit, field, result); reportEndOfLine(result); - result += "transition_time "; - reportField(delayAsFloat(slew), field_slew_, result); + result += field->name(); + result += " "; + reportField(value, field, result); reportEndOfLine(result); + int name_width = strlen(field->name()) + 5; + reportDashLine(name_width + field->width(), result); - reportDashLine(strlen("transition_time") + field_slew_->width() + 1, - result); - - result += "Slack "; - reportSpaceSlack(slack, result); + result += "Slack"; + for (int i = strlen("Slack"); i < name_width; i++) + result += ' '; + reportField(slack, field, result); + result += (slack >= 0.0) + ? " (MET)" + : " (VIOLATED)"; + reportEndOfLine(result); } //////////////////////////////////////////////////////////////// @@ -2021,13 +2050,24 @@ ReportPath::reportSrcClkAndPath(const Path *path, else if (clk_used_as_data) { reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time, early_late, result); - if (clk_insertion > 0.0) + if (delayGreater(clk_insertion, 0.0, this)) reportClkSrcLatency(clk_insertion, clk_time, early_late, result); - reportPath1(path, expanded, true, time_offset, result); + if (reportClkPath()) + reportPath1(path, expanded, true, time_offset, result); + else { + Arrival clk_arrival = clk_end_time; + Arrival end_arrival = path->arrival(this) + time_offset; + Delay clk_delay = end_arrival - clk_arrival; + reportLine("clock network delay", clk_delay, + end_arrival, early_late, result); + Vertex *end_vertex = path->vertex(this); + reportLine(descriptionField(end_vertex).c_str(), + end_arrival, early_late, clk_end_rf, result); + } } else { if (is_path_delay) { - if (clk_delay > 0.0) + if (delayGreater(clk_delay, 0.0, this)) reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay, clk_end_time, early_late, result); } @@ -2167,10 +2207,10 @@ ReportPath::pathFromGenPropClk(const Path *clk_path, float insertion; bool exists; sdc_->clockInsertion(clk, clk_info->clkSrc(), - clk_edge->transition(), - clk_path->minMax(this), - early_late, - insertion, exists); + clk_edge->transition(), + clk_path->minMax(this), + early_late, + insertion, exists); return !exists && clk->isGeneratedWithPropagatedMaster(); } @@ -2187,8 +2227,8 @@ ReportPath::isGenPropClk(const Clock *clk, float insertion; bool exists; sdc_->clockInsertion(clk, clk->srcPin(), clk_rf, - min_max, early_late, - insertion, exists); + min_max, early_late, + insertion, exists); return !exists && clk->isGeneratedWithPropagatedMaster(); } @@ -2474,6 +2514,27 @@ ReportPath::reportPath(const PathEnd *end, void ReportPath::reportPath(const Path *path, string &result) +{ + switch (format_) { + case ReportPathFormat::full: + case ReportPathFormat::full_clock: + case ReportPathFormat::full_clock_expanded: + reportPathFull(path, result); + break; + case ReportPathFormat::json: + reportPathJson(path, result); + break; + case ReportPathFormat::summary: + case ReportPathFormat::slack_only: + default: + internalError("unsupported path type"); + break; + } +} + +void +ReportPath::reportPathFull(const Path *path, + string &result) { reportPathHeader(result); PathExpanded expanded(path, this); @@ -2481,6 +2542,50 @@ ReportPath::reportPath(const Path *path, false, result); } +void +ReportPath::reportPathJson(const Path *path, + string &result) +{ + result += "{ \"path\": [\n"; + PathExpanded expanded(path, this); + for (auto i = expanded.startIndex(); i < expanded.size(); i++) { + PathRef *path = expanded.path(i); + const Pin *pin = path->vertex(this)->pin(); + result += " {\n"; + result += " \"pin\": \""; + result += network_->pathName(pin); + result += "\",\n"; + + double x, y; + bool exists; + string tmp; + network_->location(pin, x, y, exists); + if (exists) { + result += " \"x\": "; + stringPrint(tmp, "%.9f", x); + result += tmp + ",\n"; + result += " \"y\": "; + stringPrint(tmp, "%.9f", y); + result += tmp + ",\n"; + } + + result += " \"arrival\": "; + stringPrint(tmp, "%.3e", delayAsFloat(path->arrival(this))); + result += tmp + ",\n"; + + result += " \"slew\": "; + stringPrint(tmp, "%.3e", delayAsFloat(path->slew(this))); + result += tmp + "\n"; + + result += " }"; + if (i < expanded.size() - 1) + result += ","; + result += "\n"; + } + result += " ]\n"; + result += "}\n"; +} + void ReportPath::reportPath1(const Path *path, PathExpanded &expanded, @@ -2508,7 +2613,7 @@ ReportPath::reportPath1(const Path *path, } Arrival time = latch_enable_time + latch_time_given; Arrival incr = latch_time_given; - if (incr >= 0.0) + if (delayGreaterEqual(incr, 0.0, this)) reportLine("time given to startpoint", incr, time, early_late, result); else reportLine("time borrowed from startpoint", incr, time, @@ -2608,7 +2713,7 @@ ReportPath::reportPath5(const Path *path, Vertex *vertex = path1->vertex(this); Pin *pin = vertex->pin(); Arrival time = path1->arrival(this) + time_offset; - float incr = 0.0; + Delay incr = 0.0; const char *line_case = nullptr; bool is_clk_start = network_->isRegClkPin(pin); bool is_clk = path1->isClock(search_); @@ -2633,8 +2738,7 @@ 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 = delayAsFloat(next_time, min_max, this) - - delayAsFloat(time, min_max, this); + incr = delayIncr(next_time, time, min_max); time = next_time; line_case = "input_drive"; } @@ -2681,13 +2785,11 @@ ReportPath::reportPath5(const Path *path, line_case = "clk_ideal"; } else if (is_clk && !is_clk_start) { - incr = delayAsFloat(time, min_max, this) - - delayAsFloat(prev_time, min_max, this); + incr = delayIncr(time, prev_time, min_max); line_case = "clk_prop"; } else { - incr = delayAsFloat(time, min_max, this) - - delayAsFloat(prev_time, min_max, this); + incr = delayIncr(time, prev_time, min_max); line_case = "normal"; } if (report_input_pin_ @@ -2739,6 +2841,17 @@ ReportPath::reportPath5(const Path *path, } } +Delay +ReportPath::delayIncr(Delay time, + Delay prev, + const MinMax *min_max) +{ + if (report_sigmas_) + return delayRemove(time, prev); + else + return delayAsFloat(time, min_max, this) - delayAsFloat(prev, min_max, this); +} + bool ReportPath::nextArcAnnotated(const PathRef *next_path, size_t next_index, @@ -2884,7 +2997,9 @@ ReportPath::loadCap(Pin *drvr_pin, Parasitic *parasitic = nullptr; if (arc_delay_calc_) parasitic = arc_delay_calc_->findParasitic(drvr_pin, rf, dcalc_ap); - return graph_delay_calc_->loadCap(drvr_pin, parasitic, rf, dcalc_ap); + float load_cap = graph_delay_calc_->loadCap(drvr_pin, parasitic, rf, dcalc_ap); + arc_delay_calc_->finishDrvrPin(); + return load_cap; } //////////////////////////////////////////////////////////////// @@ -3177,8 +3292,8 @@ ReportPath::reportFieldDelayMinus(Delay value, else { const char *str = report_sigmas_ ? delayAsString(-value, this, digits_) - // : delayAsString(-value, early_late, this, digits_); - : units_->timeUnit()->asString(-delayAsFloat(value, early_late, this), digits_); + // Opposite min/max for negative value. + : delayAsString(-value, early_late->opposite(), this, digits_); if (stringEq(str, plus_zero_)) // Force leading minus sign. str = minus_zero_; @@ -3207,20 +3322,24 @@ ReportPath::reportFieldDelay(Delay value, void ReportPath::reportField(float value, - ReportField *field, + const ReportField *field, string &result) { if (value == field_blank_) reportFieldBlank(field, result); else { - const char *value_str = field->unit()->asString(value, digits_); + Unit *unit = field->unit(); + const char *value_str = (unit) + ? unit->asString(value, digits_) + // fanout + : stringPrintTmp("%.0f", value); reportField(value_str, field, result); } } void ReportPath::reportField(const char *value, - ReportField *field, + const ReportField *field, string &result) { if (field->leftJustify()) @@ -3232,7 +3351,7 @@ ReportPath::reportField(const char *value, } void -ReportPath::reportFieldBlank(ReportField *field, +ReportPath::reportFieldBlank(const ReportField *field, string &result) { result += field->blank(); diff --git a/search/ReportPath.hh b/search/ReportPath.hh index 3166fa22..3fda967c 100644 --- a/search/ReportPath.hh +++ b/search/ReportPath.hh @@ -63,6 +63,7 @@ public: void reportPathEnd(PathEnd *end, PathEnd *prev_end); void reportPathEnds(PathEndSeq *ends); + // for debugging void reportPath(const Path *path); void reportShort(const PathEndUnconstrained *end, @@ -137,34 +138,38 @@ public: void reportVerbose(MaxSkewCheck *check, string &result); - void reportSlewLimitShortHeader(); - void reportSlewLimitShortHeader(string &result); - void reportSlewLimitShort(Pin *pin, - const RiseFall *rf, - Slew slew, - float limit, - float slack); - void reportSlewLimitShort(Pin *pin, const - RiseFall *rf, - Slew slew, - float limit, - float slack, - string &result); - void reportSlewLimitVerbose(Pin *pin, - const Corner *corner, - const RiseFall *rf, - Slew slew, - float limit, - float slack, - const MinMax *min_max); - void reportSlewLimitVerbose(Pin *pin, - const Corner *corner, - const RiseFall *rf, - Slew slew, - float limit, - float slack, - const MinMax *min_max, + void reportLimitShortHeader(const ReportField *field); + void reportLimitShortHeader(const ReportField *field, string &result); + void reportLimitShort(const ReportField *field, + Pin *pin, + float value, + float limit, + float slack); + void reportLimitShort(const ReportField *field, + Pin *pin, + float value, + float limit, + float slack, + string &result); + void reportLimitVerbose(const ReportField *field, + Pin *pin, + const RiseFall *rf, + float value, + float limit, + float slack, + const MinMax *min_max); + void reportLimitVerbose(const ReportField *field, + Pin *pin, + const RiseFall *rf, + float value, + float limit, + float slack, + const MinMax *min_max, + string &result); + ReportField *fieldSlew() const { return field_slew_; } + ReportField *fieldFanout() const { return field_fanout_; } + ReportField *fieldCapacitance() const { return field_capacitance_; } protected: void makeFields(); @@ -199,6 +204,8 @@ protected: string &result); void reportEndpoint(const PathEndOutputDelay *end, string &result); + void reportEndpointOutputDelay(const PathEndClkConstrained *end, + string &result); void reportEndpoint(const PathEndPathDelay *end, string &result); void reportEndpoint(const PathEndGatedClock *end, @@ -335,6 +342,10 @@ protected: string &result); void reportPath(const Path *path, string &result); + void reportPathFull(const Path *path, + string &result); + void reportPathJson(const Path *path, + string &result); void reportPathHeader(string &result); void reportPath1(const Path *path, PathExpanded &expanded, @@ -453,12 +464,12 @@ protected: ReportField *field, string &result); void reportField(float value, - ReportField *field, + const ReportField *field, string &result); void reportField(const char *value, - ReportField *field, + const ReportField *field, string &result); - void reportFieldBlank(ReportField *field, + void reportFieldBlank(const ReportField *field, string &result); void reportDashLine(string &result); void reportDashLine(int line_width, @@ -514,6 +525,9 @@ protected: PathRef &ref_path); const char *asRisingFalling(const RiseFall *rf); const char *asRiseFall(const RiseFall *rf); + Delay delayIncr(Delay time, + Delay prev, + const MinMax *min_max); // Path options. ReportPathFormat format_; @@ -564,7 +578,7 @@ public: void setWidth(int width); bool leftJustify() const { return left_justify_; } Unit *unit() const { return unit_; } - const char *blank() { return blank_; } + const char *blank() const { return blank_; } void setEnabled(bool enabled); bool enabled() const { return enabled_; } diff --git a/search/Search.cc b/search/Search.cc index 9c468452..48c7afe1 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -1194,7 +1194,7 @@ Search::arrivalsChanged(Vertex *vertex, bool arrival_exists2; tag_bldr->tagArrival(tag1, arrival2, arrival_exists2); if (!arrival_exists2 - || !fuzzyEqual(arrival1, arrival2)) + || !delayEqual(arrival1, arrival2)) return true; } return false; @@ -1238,7 +1238,7 @@ ArrivalVisitor::visitFromToPath(const Pin *, Tag *tag_match; tag_bldr_->tagMatchArrival(to_tag, tag_match, arrival, arrival_index); if (tag_match == nullptr - || fuzzyGreater(to_arrival, arrival, min_max)) { + || delayGreater(to_arrival, arrival, min_max, sta_)) { debugPrint5(debug, "search", 3, " %s + %s = %s %s %s\n", delayAsString(from_path->arrival(sta_), sta_), delayAsString(arc_delay, sta_), @@ -1258,7 +1258,7 @@ ArrivalVisitor::visitFromToPath(const Pin *, tag_bldr_no_crpr_->tagMatchArrival(to_tag, tag_match, arrival, arrival_index); if (tag_match == nullptr - || fuzzyGreater(to_arrival, arrival, min_max)) { + || delayGreater(to_arrival, arrival, min_max, sta_)) { tag_bldr_no_crpr_->setMatchArrival(to_tag, tag_match, to_arrival, arrival_index, &prev_path); @@ -1300,7 +1300,7 @@ ArrivalVisitor::pruneCrprArrivals() delayAsString(max_crpr, sta_), delayAsString(max_arrival_max_crpr, sta_)); Arrival arrival = tag_bldr_->arrival(arrival_index); - if (fuzzyGreater(max_arrival_max_crpr, arrival, min_max)) { + if (delayGreater(max_arrival_max_crpr, arrival, min_max, sta_)) { debugPrint1(debug, "search", 3, " pruned %s\n", tag->asString(sta_)); tag_bldr_->deleteArrival(tag); @@ -2207,7 +2207,7 @@ PathVisitor::visitFromPath(const Pin *from_pin, } else { arc_delay = search->deratedDelay(from_vertex, arc, edge, false, path_ap); - if (!fuzzyEqual(arc_delay, min_max->initValue())) { + if (!delayEqual(arc_delay, min_max->initValue())) { to_arrival = from_arrival + arc_delay; to_tag = search->thruTag(from_tag, edge, to_rf, min_max, path_ap); } @@ -2262,8 +2262,13 @@ Search::pathClkPathArrival(const Path *path) const pathClkPathArrival1(path, src_clk_path); if (!src_clk_path.isNull()) return clkPathArrival(&src_clk_path); - else - return 0.0; + else { + // Check for input arrival clock. + ClockEdge *clk_edge = path->clkEdge(this); + if (clk_edge) + return clk_edge->time(); + } + return 0.0; } // PathExpanded::expand() and PathExpanded::clkPath(). @@ -3249,7 +3254,7 @@ FindEndRequiredVisitor::visit(PathEnd *path_end) bool arrival_exists; path.arrivalIndex(arrival_index, arrival_exists); Required required = path_end->requiredTime(sta_); - required_cmp_->requiredSet(arrival_index, required, req_min); + required_cmp_->requiredSet(arrival_index, required, req_min, sta_); } } @@ -3314,9 +3319,10 @@ RequiredCmp::requiredsInit(Vertex *vertex, void RequiredCmp::requiredSet(int arrival_index, Required required, - const MinMax *min_max) + const MinMax *min_max, + const StaState *sta) { - if (fuzzyGreater(required, requireds_[arrival_index], min_max)) { + if (delayGreater(required, requireds_[arrival_index], min_max, sta)) { requireds_[arrival_index] = required; have_requireds_ = true; } @@ -3341,7 +3347,7 @@ RequiredCmp::requiredsSave(Vertex *vertex, Required req = requireds_[arrival_index]; if (prev_reqs) { Required prev_req = path->required(sta); - if (!fuzzyEqual(prev_req, req)) { + if (!delayEqual(prev_req, req)) { debugPrint2(debug, "search", 3, "required save %s -> %s\n", delayAsString(prev_req, sta), delayAsString(req, sta)); @@ -3445,7 +3451,7 @@ RequiredVisitor::visitFromToPath(const Pin *, const MinMax *req_min = min_max->opposite(); TagGroup *to_tag_group = sta_->search()->tagGroup(to_vertex); // Check to see if to_tag was pruned. - if (to_tag_group->hasTag(to_tag)) { + if (to_tag_group && to_tag_group->hasTag(to_tag)) { PathVertex to_path(to_vertex, to_tag, sta_); Required to_required = to_path.required(sta_); Required from_required = to_required - arc_delay; @@ -3458,7 +3464,7 @@ RequiredVisitor::visitFromToPath(const Pin *, delayAsString(from_required, sta_), min_max == MinMax::max() ? "<" : ">", delayAsString(required_cmp_->required(arrival_index), sta_)); - required_cmp_->requiredSet(arrival_index, from_required, req_min); + required_cmp_->requiredSet(arrival_index, from_required, req_min, sta_); } else { if (sta_->search()->crprApproxMissingRequireds()) { @@ -3482,7 +3488,7 @@ RequiredVisitor::visitFromToPath(const Pin *, min_max == MinMax::max() ? "<" : ">", delayAsString(required_cmp_->required(arrival_index), sta_)); - required_cmp_->requiredSet(arrival_index, from_required, req_min); + required_cmp_->requiredSet(arrival_index, from_required, req_min, sta_); break; } } @@ -3635,7 +3641,7 @@ Search::totalNegativeSlack(const MinMax *min_max) for (Corner *corner : *corners_) { PathAPIndex path_ap_index = corner->findPathAnalysisPt(min_max)->index(); Slack tns1 = tns_[path_ap_index]; - if (tns1 < tns) + if (delayLess(tns1, tns, this)) tns = tns1; } return tns; @@ -3730,7 +3736,7 @@ Search::tnsIncr(Vertex *vertex, Slack slack, PathAPIndex path_ap_index) { - if (fuzzyLess(slack, 0.0)) { + if (delayLess(slack, 0.0, this)) { debugPrint2(debug_, "tns", 3, "tns+ %s %s\n", delayAsString(slack, this), vertex->name(sdc_network_)); @@ -3749,7 +3755,7 @@ Search::tnsDecr(Vertex *vertex, bool found; tns_slacks_[path_ap_index].findKey(vertex, slack, found); if (found - && fuzzyLess(slack, 0.0)) { + && delayLess(slack, 0.0, this)) { debugPrint2(debug_, "tns", 3, "tns- %s %s\n", delayAsString(slack, this), vertex->name(sdc_network_)); @@ -3875,7 +3881,7 @@ FindEndSlackVisitor::visit(PathEnd *path_end) PathRef &path = path_end->pathRef(); PathAPIndex path_ap_index = path.pathAnalysisPtIndex(sta_); Slack slack = path_end->slack(sta_); - if (fuzzyLess(slack, slacks_[path_ap_index])) + if (delayLess(slack, slacks_[path_ap_index], sta_)) slacks_[path_ap_index] = slack; } } @@ -3902,7 +3908,7 @@ Search::wnsSlacks(Vertex *vertex, PathAPIndex path_ap_index = path->pathAnalysisPtIndex(this); const Slack path_slack = path->slack(this); if (!path->tag(this)->isFilter() - && fuzzyLess(path_slack, slacks[path_ap_index])) + && delayLess(path_slack, slacks[path_ap_index], this)) slacks[path_ap_index] = path_slack; } } diff --git a/search/Sim.cc b/search/Sim.cc index 3ee5d57d..3a1d6fa8 100644 --- a/search/Sim.cc +++ b/search/Sim.cc @@ -837,8 +837,12 @@ Sim::removePropagatedValue(const Pin *pin) if (!exists) { debugPrint1(debug_, "sim", 2, "pin %s remove prop constant\n", network_->pathName(pin)); - Vertex *vertex = graph_->pinLoadVertex(pin); - setSimValue(vertex, LogicValue::unknown); + Vertex *vertex, *bidirect_drvr_vertex; + graph_->pinVertices(pin, vertex, bidirect_drvr_vertex); + if (vertex) + setSimValue(vertex, LogicValue::unknown); + if (bidirect_drvr_vertex) + setSimValue(bidirect_drvr_vertex, LogicValue::unknown); } } } diff --git a/search/Sta.cc b/search/Sta.cc index 109e9efd..f5984228 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -55,6 +55,8 @@ #include "PathGroup.hh" #include "CheckTiming.hh" #include "CheckSlewLimits.hh" +#include "CheckFanoutLimits.hh" +#include "CheckCapacitanceLimits.hh" #include "CheckMinPulseWidths.hh" #include "CheckMinPeriods.hh" #include "CheckMaxSkews.hh" @@ -256,6 +258,8 @@ Sta::Sta() : current_instance_(nullptr), check_timing_(nullptr), check_slew_limits_(nullptr), + check_fanout_limits_(nullptr), + check_capacitance_limits_(nullptr), check_min_pulse_widths_(nullptr), check_min_periods_(nullptr), check_max_skews_(nullptr), @@ -437,6 +441,18 @@ Sta::makeCheckSlewLimits() check_slew_limits_ = new CheckSlewLimits(this); } +void +Sta::makeCheckFanoutLimits() +{ + check_fanout_limits_ = new CheckFanoutLimits(this); +} + +void +Sta::makeCheckCapacitanceLimits() +{ + check_capacitance_limits_ = new CheckCapacitanceLimits(this); +} + void Sta::makeCheckMinPulseWidths() { @@ -483,6 +499,8 @@ Sta::~Sta() { // Delete "top down" to minimize chance of referencing deleted memory. delete check_slew_limits_; + delete check_fanout_limits_; + delete check_capacitance_limits_; delete check_min_pulse_widths_; delete check_min_periods_; delete check_max_skews_; @@ -537,8 +555,6 @@ Sta::clear() void Sta::networkChanged() { - // Remove sdc graph annotations. - sdc_->annotateGraph(false); // Everything else from clear(). search_->clear(); levelize_->clear(); @@ -982,14 +998,6 @@ Sta::setSlewLimit(Port *port, sdc_->setSlewLimit(port, min_max, slew); } -void -Sta::setSlewLimit(Pin *pin, - const MinMax *min_max, - float slew) -{ - sdc_->setSlewLimit(pin, min_max, slew); -} - void Sta::setSlewLimit(Cell *cell, const MinMax *min_max, @@ -2675,7 +2683,7 @@ Sta::vertexWorstArrivalPath(Vertex *vertex, PathVertex *path = path_iter.next(); Arrival arrival = path->arrival(this); if (!path->tag(this)->isGenClkSrcPath() - && fuzzyGreater(arrival, worst_arrival, min_max)) { + && delayGreater(arrival, worst_arrival, min_max, this)) { worst_arrival = arrival; worst_path.init(path); } @@ -2695,7 +2703,7 @@ Sta::vertexWorstArrivalPath(Vertex *vertex, Arrival arrival = path->arrival(this); if (path->minMax(this) == min_max && !path->tag(this)->isGenClkSrcPath() - && fuzzyGreater(arrival, worst_arrival, min_max)) { + && delayGreater(arrival, worst_arrival, min_max, this)) { worst_arrival = arrival; worst_path.init(path); } @@ -2715,7 +2723,7 @@ Sta::vertexWorstSlackPath(Vertex *vertex, PathVertex *path = path_iter.next(); Slack slack = path->slack(this); if (!path->tag(this)->isGenClkSrcPath() - && slack < min_slack) { + && delayLess(slack, min_slack, this)) { min_slack = slack; worst_path.init(path); } @@ -2736,7 +2744,7 @@ Sta::vertexWorstSlackPath(Vertex *vertex, if (path->minMax(this) == min_max && !path->tag(this)->isGenClkSrcPath()) { Slack slack = path->slack(this); - if (fuzzyLess(slack, min_slack)) { + if (delayLess(slack, min_slack, this)) { min_slack = slack; worst_path.init(path); } @@ -2770,7 +2778,7 @@ Sta::vertexArrival(Vertex *vertex, if ((clk_edge == clk_edge_wildcard || clk_info->clkEdge() == clk_edge) && !clk_info->isGenClkSrcPath() - && fuzzyGreater(path->arrival(this), arrival, min_max)) + && delayGreater(path->arrival(this), arrival, min_max, this)) arrival = path_arrival; } return arrival; @@ -2788,7 +2796,7 @@ Sta::vertexRequired(Vertex *vertex, const Path *path = path_iter.next(); if (path->minMax(this) == min_max) { const Required path_required = path->required(this); - if (fuzzyGreater(path_required, required, req_min_max)) + if (delayGreater(path_required, required, req_min_max, this)) required = path_required; } } @@ -2818,7 +2826,7 @@ Sta::vertexRequired(Vertex *vertex, const Required path_required = path->required(this); if ((clk_edge == clk_edge_wildcard || path->clkEdge(search_) == clk_edge) - && fuzzyGreater(path_required, required, min_max)) + && delayGreater(path_required, required, min_max, this)) required = path_required; } return required; @@ -2836,7 +2844,8 @@ Sta::netSlack(const Net *net, if (network_->isLoad(pin)) { Vertex *vertex = graph_->pinLoadVertex(pin); Slack pin_slack = vertexSlack(vertex, min_max); - slack = min(slack, pin_slack); + if (delayLess(pin_slack, slack, this)) + slack = pin_slack; } } return slack; @@ -2852,8 +2861,11 @@ Sta::pinSlack(const Pin *pin, Slack slack = MinMax::min()->initValue(); if (vertex) slack = vertexSlack(vertex, min_max); - if (bidirect_drvr_vertex) - slack = min(slack, vertexSlack(bidirect_drvr_vertex, min_max)); + if (bidirect_drvr_vertex) { + Slack slack1 = vertexSlack(bidirect_drvr_vertex, min_max); + if (delayLess(slack1, slack, this)) + slack = slack1; + } return slack; } @@ -2868,8 +2880,11 @@ Sta::pinSlack(const Pin *pin, Slack slack = MinMax::min()->initValue(); if (vertex) slack = vertexSlack(vertex, rf, min_max); - if (bidirect_drvr_vertex) - slack = min(slack, vertexSlack(bidirect_drvr_vertex, rf, min_max)); + if (bidirect_drvr_vertex) { + Slack slack1 = vertexSlack(bidirect_drvr_vertex, rf, min_max); + if (delayLess(slack1, slack, this)) + slack = slack1; + } return slack; } @@ -2885,7 +2900,7 @@ Sta::vertexSlack(Vertex *vertex, Path *path = path_iter.next(); if (path->minMax(this) == min_max) { Slack path_slack = path->slack(this); - if (path_slack < slack) + if (delayLess(path_slack, slack, this)) slack = path_slack; } } @@ -2903,7 +2918,7 @@ Sta::vertexSlack(Vertex *vertex, while (path_iter.hasNext()) { Path *path = path_iter.next(); Slack path_slack = path->slack(this); - if (path_slack < slack) + if (delayLess(path_slack, slack, this)) slack = path_slack; } return slack; @@ -2942,7 +2957,7 @@ Sta::vertexSlack1(Vertex *vertex, Slack path_slack = path->slack(this); if ((clk_edge == clk_edge_wildcard || path->clkEdge(search_) == clk_edge) - && path_slack < slack) + && delayLess(path_slack, slack, this)) slack = path_slack; } return slack; @@ -2964,7 +2979,7 @@ Sta::vertexSlacks(Vertex *vertex, Slack path_slack = path->slack(this); int rf_index = path->rfIndex(this); int mm_index = path->minMax(this)->index(); - if (path_slack < slacks[rf_index][mm_index]) + if (delayLess(path_slack, slacks[rf_index][mm_index], this)) slacks[rf_index][mm_index] = path_slack; } } @@ -3159,7 +3174,7 @@ Sta::vertexSlew(Vertex *vertex, Slew mm_slew = min_max->initValue(); for (DcalcAnalysisPt *dcalc_ap : corners_->dcalcAnalysisPts()) { Slew slew = graph_->slew(vertex, rf, dcalc_ap->index()); - if (fuzzyGreater(slew, mm_slew, min_max)) + if (delayGreater(slew, mm_slew, min_max, this)) mm_slew = slew; } return mm_slew; @@ -4781,7 +4796,7 @@ bool InstanceMaxSlewGreater::operator()(const Instance *inst1, const Instance *inst2) const { - return instMaxSlew(inst1) > instMaxSlew(inst2); + return delayGreater(instMaxSlew(inst1), instMaxSlew(inst2), sta_); } Slew @@ -4798,7 +4813,7 @@ InstanceMaxSlewGreater::instMaxSlew(const Instance *inst) const for (RiseFall *rf : RiseFall::range()) { for (DcalcAnalysisPt *dcalc_ap : sta_->corners()->dcalcAnalysisPts()) { Slew slew = graph->slew(vertex, rf, dcalc_ap->index()); - if (slew > max_slew) + if (delayGreater(slew, max_slew, sta_)) max_slew = slew; } } @@ -4823,13 +4838,13 @@ Sta::slowDrvrIterator() return new SlowDrvrIterator(insts); } -////////////////////////////////////////////////////////////////' +//////////////////////////////////////////////////////////////// void Sta::checkSlewLimitPreamble() { if (sdc_->haveClkSlewLimits()) - // Arrivals are needed to know what pin clock domains. + // Arrivals are needed to know pin clock domains. updateTiming(false); else findDelays(); @@ -4856,7 +4871,7 @@ Sta::pinSlewLimitViolations(const Corner *corner, void Sta::reportSlewLimitShortHeader() { - report_path_->reportSlewLimitShortHeader(); + report_path_->reportLimitShortHeader(report_path_->fieldSlew()); } void @@ -4868,9 +4883,10 @@ Sta::reportSlewLimitShort(Pin *pin, const RiseFall *rf; Slew slew; float limit, slack; - check_slew_limits_->checkSlews(pin, corner, min_max, - corner1, rf, slew, limit, slack); - report_path_->reportSlewLimitShort(pin, rf, slew, limit, slack); + check_slew_limits_->checkSlew(pin, corner, min_max, true, + corner1, rf, slew, limit, slack); + report_path_->reportLimitShort(report_path_->fieldSlew(), pin, + delayAsFloat(slew), limit, slack); } void @@ -4882,31 +4898,177 @@ Sta::reportSlewLimitVerbose(Pin *pin, const RiseFall *rf; Slew slew; float limit, slack; - check_slew_limits_->checkSlews(pin, corner, min_max, - corner1, rf, slew, limit, slack); - report_path_->reportSlewLimitVerbose(pin, corner1, rf, slew, - limit, slack, min_max); + check_slew_limits_->checkSlew(pin, corner, min_max, true, + corner1, rf, slew, limit, slack); + report_path_->reportLimitVerbose(report_path_->fieldSlew(), pin, rf, + delayAsFloat(slew), + limit, slack, min_max); } void -Sta::checkSlews(const Pin *pin, - const Corner *corner, - const MinMax *min_max, - // Return values. - const Corner *&corner1, - const RiseFall *&rf, - Slew &slew, - float &limit, - float &slack) +Sta::checkSlew(const Pin *pin, + const Corner *corner, + const MinMax *min_max, + bool check_clks, + // Return values. + const Corner *&corner1, + const RiseFall *&rf, + Slew &slew, + float &limit, + float &slack) { - checkSlewLimitPreamble(); - check_slew_limits_->init(min_max); - check_slew_limits_->checkSlews(pin, corner, min_max, - corner1, rf, slew, limit, slack); + check_slew_limits_->checkSlew(pin, corner, min_max, check_clks, + corner1, rf, slew, limit, slack); } ////////////////////////////////////////////////////////////////' +void +Sta::checkFanoutLimitPreamble() +{ + if (check_fanout_limits_ == nullptr) + makeCheckFanoutLimits(); + // For sim values and ideal clocks. + findDelays(); +} + +Pin * +Sta::pinMinFanoutLimitSlack(const MinMax *min_max) +{ + checkFanoutLimitPreamble(); + return check_fanout_limits_->pinMinFanoutLimitSlack(min_max); +} + +PinSeq * +Sta::pinFanoutLimitViolations(const MinMax *min_max) +{ + checkFanoutLimitPreamble(); + return check_fanout_limits_->pinFanoutLimitViolations(min_max); +} + +void +Sta::reportFanoutLimitShortHeader() +{ + report_path_->reportLimitShortHeader(report_path_->fieldFanout()); +} + +void +Sta::reportFanoutLimitShort(Pin *pin, + const MinMax *min_max) +{ + float fanout, limit, slack; + check_fanout_limits_->checkFanout(pin, min_max, + fanout, limit, slack); + report_path_->reportLimitShort(report_path_->fieldFanout(), + pin, fanout, limit, slack); +} + +void +Sta::reportFanoutLimitVerbose(Pin *pin, + const MinMax *min_max) +{ + float fanout, limit, slack; + check_fanout_limits_->checkFanout(pin, min_max, + fanout, limit, slack); + report_path_->reportLimitVerbose(report_path_->fieldFanout(), + pin, nullptr, fanout, + limit, slack, min_max); +} + +void +Sta::checkFanout(const Pin *pin, + const MinMax *min_max, + // Return values. + float &fanout, + float &limit, + float &slack) +{ + check_fanout_limits_->checkFanout(pin, min_max, + fanout, limit, slack); +} + +////////////////////////////////////////////////////////////////' + +void +Sta::checkCapacitanceLimitPreamble() +{ + if (check_capacitance_limits_ == nullptr) + makeCheckCapacitanceLimits(); + // For sim values and ideal clocks. + findDelays(); +} + +Pin * +Sta::pinMinCapacitanceLimitSlack(const Corner *corner, + const MinMax *min_max) +{ + checkCapacitanceLimitPreamble(); + return check_capacitance_limits_->pinMinCapacitanceLimitSlack(corner, min_max); +} + +PinSeq * +Sta::pinCapacitanceLimitViolations(const Corner *corner, + const MinMax *min_max) +{ + checkCapacitanceLimitPreamble(); + return check_capacitance_limits_->pinCapacitanceLimitViolations(corner, min_max); +} + +void +Sta::reportCapacitanceLimitShortHeader() +{ + report_path_->reportLimitShortHeader(report_path_->fieldCapacitance()); +} + +void +Sta::reportCapacitanceLimitShort(Pin *pin, + const Corner *corner, + const MinMax *min_max) +{ + const Corner *corner1; + const RiseFall *rf; + float capacitance, limit, slack; + check_capacitance_limits_->checkCapacitance(pin, corner, min_max, + corner1, rf, capacitance, + limit, slack); + report_path_->reportLimitShort(report_path_->fieldCapacitance(), + pin, capacitance, limit, slack); +} + +void +Sta::reportCapacitanceLimitVerbose(Pin *pin, + const Corner *corner, + const MinMax *min_max) +{ + const Corner *corner1; + const RiseFall *rf; + float capacitance, limit, slack; + check_capacitance_limits_->checkCapacitance(pin, corner, min_max, + corner1, rf, capacitance, + limit, slack); + report_path_->reportLimitVerbose(report_path_->fieldCapacitance(), + pin, rf, capacitance, + limit, slack, min_max); +} + +void +Sta::checkCapacitance(const Pin *pin, + const Corner *corner, + const MinMax *min_max, + // Return values. + const Corner *&corner1, + const RiseFall *&rf, + float &capacitance, + float &limit, + float &slack) +{ + check_capacitance_limits_->checkCapacitance(pin, corner, min_max, + corner1, rf, capacitance, + limit, slack); +} + +//////////////////////////////////////////////////////////////// + void Sta::minPulseWidthPreamble() { diff --git a/search/WorstSlack.cc b/search/WorstSlack.cc index bce83e93..f9c0893a 100644 --- a/search/WorstSlack.cc +++ b/search/WorstSlack.cc @@ -48,7 +48,7 @@ WorstSlacks::worstSlack(const MinMax *min_max, Vertex *worst_vertex1; worst_slacks_[path_ap_index].worstSlack(path_ap_index, sta_, worst_slack1, worst_vertex1); - if (fuzzyLess(worst_slack1, worst_slack)) { + if (delayLess(worst_slack1, worst_slack, sta_)) { worst_slack = worst_slack1; worst_vertex = worst_vertex1; } @@ -159,10 +159,10 @@ WorstSlack::initQueue(PathAPIndex path_ap_index, while (end_iter.hasNext()) { Vertex *vertex = end_iter.next(); Slack slack = search->wnsSlack(vertex, path_ap_index); - if (!fuzzyEqual(slack, slack_init_)) { - if (fuzzyLess(slack, worst_slack_)) + if (!delayEqual(slack, slack_init_)) { + if (delayLess(slack, worst_slack_, sta)) setWorstSlack(vertex, slack, sta); - if (fuzzyLessEqual(slack, slack_threshold_)) + if (delayLessEqual(slack, slack_threshold_, sta)) queue_.insert(vertex); int queue_size = queue_.size(); if (queue_size >= max_queue_size_) @@ -178,41 +178,43 @@ void WorstSlack::sortQueue(PathAPIndex path_ap_index, const StaState *sta) { - Search *search = sta->search(); - const Debug *debug = sta->debug(); - debugPrint0(debug, "wns", 3, "sort queue\n"); + if (queue_.size() > 0) { + Search *search = sta->search(); + const Debug *debug = sta->debug(); + debugPrint0(debug, "wns", 3, "sort queue\n"); - VertexSeq vertices; - vertices.reserve(queue_.size()); - VertexSet::Iterator queue_iter(queue_); - while (queue_iter.hasNext()) { - Vertex *vertex = queue_iter.next(); - vertices.push_back(vertex); + VertexSeq vertices; + vertices.reserve(queue_.size()); + VertexSet::Iterator queue_iter(queue_); + while (queue_iter.hasNext()) { + Vertex *vertex = queue_iter.next(); + vertices.push_back(vertex); + } + WnsSlackLess slack_less(path_ap_index, sta); + sort(vertices, slack_less); + + int vertex_count = vertices.size(); + int threshold_index = min(min_queue_size_, vertex_count - 1); + 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)); + + // Reinsert vertices with slack < threshold. + queue_.clear(); + VertexSeq::Iterator queue_iter2(vertices); + while (queue_iter2.hasNext()) { + Vertex *vertex = queue_iter2.next(); + Slack slack = search->wnsSlack(vertex, path_ap_index); + if (delayGreater(slack, slack_threshold_, sta)) + break; + queue_.insert(vertex); + } + max_queue_size_ = queue_.size() * 2; + Vertex *worst_slack_vertex = vertices[0]; + Slack worst_slack_slack = search->wnsSlack(worst_slack_vertex, path_ap_index); + setWorstSlack(worst_slack_vertex, worst_slack_slack, sta); } - WnsSlackLess slack_less(path_ap_index, sta); - sort(vertices, slack_less); - - int vertex_count = vertices.size(); - int threshold_index = min(min_queue_size_, vertex_count - 1); - 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)); - - // Reinsert vertices with slack < threshold. - queue_.clear(); - VertexSeq::Iterator queue_iter2(vertices); - while (queue_iter2.hasNext()) { - Vertex *vertex = queue_iter2.next(); - Slack slack = search->wnsSlack(vertex, path_ap_index); - if (fuzzyGreater(slack, slack_threshold_)) - break; - queue_.insert(vertex); - } - max_queue_size_ = queue_.size() * 2; - Vertex *worst_slack_vertex = vertices[0]; - Slack worst_slack_slack = search->wnsSlack(worst_slack_vertex, path_ap_index); - setWorstSlack(worst_slack_vertex, worst_slack_slack, sta); } void @@ -229,7 +231,7 @@ WorstSlack::findWorstInQueue(PathAPIndex path_ap_index, while (queue_iter.hasNext()) { Vertex *vertex = queue_iter.next(); Slack slack = search->wnsSlack(vertex, path_ap_index); - if (slack < worst_slack_) + if (delayLess(slack, worst_slack_, sta)) setWorstSlack(vertex, slack, sta); } } @@ -246,8 +248,8 @@ WorstSlack::checkQueue(PathAPIndex path_ap_index, VertexSet::Iterator end_iter(search->endpoints()); while (end_iter.hasNext()) { Vertex *end = end_iter.next(); - if (fuzzyLessEqual(search->wnsSlack(end, path_ap_index), - slack_threshold_)) + if (delayLessEqual(search->wnsSlack(end, path_ap_index), + slack_threshold_, sta)) ends.push_back(end); } WnsSlackLess slack_less(path_ap_index, sta); @@ -259,8 +261,8 @@ WorstSlack::checkQueue(PathAPIndex path_ap_index, Vertex *end = end_iter2.next(); end_set.insert(end); if (!queue_.hasKey(end) - && fuzzyLessEqual(search->wnsSlack(end, path_ap_index), - slack_threshold_)) + && delayLessEqual(search->wnsSlack(end, path_ap_index), + slack_threshold_, sta)) report->print("WorstSlack queue missing %s %s < %s\n", end->name(network), delayAsString(search->wnsSlack(end, path_ap_index), sta), @@ -292,14 +294,14 @@ WorstSlack::updateWorstSlack(Vertex *vertex, // threads. UniqueLock lock(lock_); if (worst_vertex_ - && fuzzyLess(slack, worst_slack_)) + && delayLess(slack, worst_slack_, sta)) setWorstSlack(vertex, slack, sta); else if (vertex == worst_vertex_) // Mark worst slack as unknown (updated by findWorstSlack(). worst_vertex_ = nullptr; - if (!fuzzyEqual(slack, slack_init_) - && fuzzyLessEqual(slack, slack_threshold_)) { + if (!delayEqual(slack, slack_init_) + && delayLessEqual(slack, slack_threshold_, sta)) { debugPrint2(debug, "wns", 3, "insert %s %s\n", vertex->name(network), delayAsString(slack, sta)); @@ -339,8 +341,9 @@ bool WnsSlackLess::operator()(Vertex *vertex1, Vertex *vertex2) { - return fuzzyLess(search_->wnsSlack(vertex1, path_ap_index_), - search_->wnsSlack(vertex2, path_ap_index_)); + return delayLess(search_->wnsSlack(vertex1, path_ap_index_), + search_->wnsSlack(vertex2, path_ap_index_), + search_); } } // namespace diff --git a/tcl/Network.tcl b/tcl/Network.tcl index 901bcf7f..4dbcb7da 100644 --- a/tcl/Network.tcl +++ b/tcl/Network.tcl @@ -331,7 +331,8 @@ proc report_net_caps { net pins corner digits } { } if [$pin is_driver] { incr driver_count - } elseif [$pin is_load] { + } + if [$pin is_load] { incr load_count } } @@ -381,7 +382,7 @@ proc report_net_pin { pin verbose corner digits } { puts -nonewline [port_capacitance_str $liberty_port $digits] } } - puts "" + puts "[pin_location_str $pin]" } elseif [$pin is_top_level_port] { puts -nonewline " [get_full_name $pin] [pin_direction $pin] port" if { $verbose } { @@ -403,12 +404,23 @@ proc report_net_pin { pin verbose corner digits } { puts -nonewline " pin [capacitances_str $cap_r_min $cap_r_max $cap_f_min $cap_f_max $digits]" } } - puts "" + puts "[pin_location_str $pin]" } elseif [$pin is_hierarchical] { puts " [get_full_name $pin] [pin_direction $pin]" } } +# Used by report_net +proc pin_location_str { pin } { + set loc [pin_location $pin] + if { $loc != "" } { + lassign $loc x y + return " ([format_distance $x 0], [format_distance $y 0])" + } else { + return "" + } +} + ################################################################ proc report_pin_ { pin } { diff --git a/tcl/Sdc.tcl b/tcl/Sdc.tcl index 8ead4e8c..8f2e42c0 100644 --- a/tcl/Sdc.tcl +++ b/tcl/Sdc.tcl @@ -297,6 +297,11 @@ proc set_unit_values { unit key unit_name key_var } { } else { set prefix [string index $value 0] set suffix [string range $value 1 end] + # unit includes "1" prefix + if { [string is digit $prefix] } { + set prefix [string index $value 1] + set suffix [string range $value 2 end] + } if { [string equal -nocase $suffix $unit_name] } { set scale [unit_prefix_scale $unit $prefix] set_cmd_unit_scale $unit $scale @@ -497,9 +502,16 @@ proc get_cells { args } { if { $args != {} } { sta_warn "patterns argument not supported with -of_objects." } - parse_pin_net_args $keys(-of_objects) pins nets + parse_port_pin_net_arg $keys(-of_objects) pins nets foreach pin $pins { - lappend insts [$pin instance] + if { [$pin is_top_level_port] } { + set net [get_nets [get_name $pin]] + if { $net != "NULL" } { + lappend nets $net + } + } else { + lappend insts [$pin instance] + } } foreach net $nets { set pin_iter [$net pin_iterator] @@ -992,7 +1004,7 @@ proc get_ports { args } { return $ports } -variable filter_regexp1 {@?([a-zA-Z_]+) +(==|=~) +([0-9a-zA-Z_\*]+)} +variable filter_regexp1 {@?([a-zA-Z_]+) *(==|=~) *([0-9a-zA-Z_\*]+)} variable filter_or_regexp "($filter_regexp1) +\\|\\| +($filter_regexp1)" variable filter_and_regexp "($filter_regexp1) +&& +($filter_regexp1)" @@ -2600,7 +2612,7 @@ proc set_max_transition { args } { set slew [time_ui_sta $slew] set objects [lindex $args 1] - parse_clk_cell_port_pin_args $objects clks cells ports pins + parse_clk_cell_port_args $objects clks cells ports set tr [parse_rise_fall_flags flags] @@ -2617,12 +2629,12 @@ proc set_max_transition { args } { lappend path_types "data" } - if { ($ports != {} || $pins != {} || $cells != {}) \ + if { ($ports != {} || $cells != {}) \ && ([info exists flags(-clock_path)] \ || [info exists flags(-data_path)] || [info exists flags(-rise)] || [info exists flags(-fall)]) } { - sta_warn "-data_path, -clock_path, -rise, -fall ignored for ports, pins and designs." + sta_warn "-data_path, -clock_path, -rise, -fall ignored for ports and designs." } # -clock_path/-data_path and transition only apply to clock objects. @@ -2637,9 +2649,6 @@ proc set_max_transition { args } { foreach port $ports { set_slew_limit_port $port "max" $slew } - foreach pin $pins { - set_slew_limit_pin $pin "max" $slew - } } ################################################################ diff --git a/tcl/Search.tcl b/tcl/Search.tcl index e108e7df..41491223 100644 --- a/tcl/Search.tcl +++ b/tcl/Search.tcl @@ -227,7 +227,7 @@ proc parse_report_path_options { cmd args_var default_format if [info exists path_options(-format)] { set format $path_options(-format) set formats {full full_clock full_clock_expanded short \ - end slack_only summary} + end slack_only summary json} if { [lsearch $formats $format] == -1 } { sta_error "-format $format not recognized." } @@ -247,7 +247,7 @@ proc parse_report_path_options { cmd args_var default_format set path_options(num_fmt) "%.${digits}f" set_report_path_digits $digits - # Numberic field width expands with digits. + # Numeric field width expands with digits. set field_width [expr $digits + $report_path_field_width_extra] if { $report_sigmas } { set delay_field_width [expr $field_width * 3 + $report_path_field_width_extra] @@ -386,7 +386,7 @@ proc report_slew_limits { corner min_max all_violators verbose nosplit } { if { $all_violators } { set violators [pin_slew_limit_violations $corner $min_max] if { $violators != {} } { - puts "${min_max}_transition" + puts "${min_max} slew" puts "" if { $verbose } { foreach pin $violators { @@ -404,7 +404,7 @@ proc report_slew_limits { corner min_max all_violators verbose nosplit } { } else { set pin [pin_min_slew_limit_slack $corner $min_max] if { $pin != "NULL" } { - puts "${min_max}_transition" + puts "${min_max} slew" puts "" if { $verbose } { report_slew_limit_verbose $pin $corner $min_max @@ -418,6 +418,80 @@ proc report_slew_limits { corner min_max all_violators verbose nosplit } { } } +proc report_fanout_limits { min_max all_violators verbose nosplit } { + if { $all_violators } { + set violators [pin_fanout_limit_violations $min_max] + if { $violators != {} } { + puts "${min_max} fanout" + puts "" + if { $verbose } { + foreach pin $violators { + report_fanout_limit_verbose $pin $min_max + puts "" + } + } else { + report_fanout_limit_short_header + foreach pin $violators { + report_fanout_limit_short $pin $min_max + } + puts "" + } + } + } else { + set pin [pin_min_fanout_limit_slack $min_max] + if { $pin != "NULL" } { + puts "${min_max} fanout" + puts "" + if { $verbose } { + report_fanout_limit_verbose $pin $min_max + puts "" + } else { + report_fanout_limit_short_header + report_fanout_limit_short $pin $min_max + puts "" + } + } + } +} + +proc report_capacitance_limits { corner min_max all_violators verbose nosplit } { + if { $all_violators } { + set violators [pin_capacitance_limit_violations $corner $min_max] + if { $violators != {} } { + puts "${min_max} capacitance" + puts "" + if { $verbose } { + foreach pin $violators { + report_capacitance_limit_verbose $pin $corner $min_max + puts "" + } + } else { + report_capacitance_limit_short_header + foreach pin $violators { + report_capacitance_limit_short $pin $corner $min_max + } + puts "" + } + } + } else { + set pin [pin_min_capacitance_limit_slack $corner $min_max] + if { $pin != "NULL" } { + puts "${min_max} capacitance" + puts "" + if { $verbose } { + report_capacitance_limit_verbose $pin $corner $min_max + puts "" + } else { + report_capacitance_limit_short_header + report_capacitance_limit_short $pin $corner $min_max + puts "" + } + } + } +} + +################################################################ + proc report_path_ends { path_ends } { report_path_end_header set prev_end "NULL" diff --git a/tcl/Sta.tcl b/tcl/Sta.tcl index a24f7ee2..598ab846 100644 --- a/tcl/Sta.tcl +++ b/tcl/Sta.tcl @@ -46,7 +46,7 @@ proc define_report_path_fields {} { set_report_path_field_properties "incr" "Delay" $width 0 set_report_path_field_properties "capacitance" "Cap" $width 0 set_report_path_field_properties "slew" "Slew" $width 0 - set_report_path_field_properties "fanout" "Fanout" 5 0 + set_report_path_field_properties "fanout" "Fanout" 6 0 set_report_path_field_properties "edge" " " 1 0 set_report_path_field_properties "case" " " 11 0 } @@ -319,6 +319,8 @@ define_sta_cmd_args "report_check_types" \ [-recovery] [-removal]\ [-clock_gating_setup] [-clock_gating_hold]\ [-max_slew] [-min_slew]\ + [-max_fanout] [-min_fanout]\ + [-max_capacitance] [-min_capacitance]\ [-min_pulse_width] [-min_period] [-max_skew]\ [-digits digits] [-no_line_splits]\ [> filename] [>> filename]} @@ -358,23 +360,31 @@ proc_redirect report_check_types { set recovery 1 set clk_gating_setup 1 set max_slew 1 + set max_fanout 1 + set max_capacitance 1 } else { set setup 0 set recovery 0 set clk_gating_setup 0 set max_slew 0 + set max_fanout 0 + set max_capacitance 0 } if { $min_max == "min" || $min_max == "min_max" } { set hold 1 set removal 1 set clk_gating_hold 1 set min_slew 1 + set min_fanout 1 + set min_capacitance 1 } else { set hold 0 set min_delay 0 set removal 0 set clk_gating_hold 0 set min_slew 0 + set min_fanout 0 + set min_capacitance 0 } set min_pulse_width 1 set min_period 1 @@ -384,9 +394,11 @@ proc_redirect report_check_types { flags {-max_delay -min_delay -recovery -removal \ -clock_gating_setup -clock_gating_hold \ -max_slew -min_slew \ - -max_transition -min_transition \ + -max_fanout -min_fanout \ + -max_capacitance -min_capacitance \ -min_pulse_width \ - -min_period -max_skew} 1 + -min_period -max_skew \ + -max_transition -min_transition } 1 set setup [info exists flags(-max_delay)] set hold [info exists flags(-min_delay)] @@ -404,6 +416,10 @@ proc_redirect report_check_types { sta_warn "-min_transition deprecated. Use -min_slew." set min_slew 1 } + set max_fanout [info exists flags(-max_fanout)] + set min_fanout [info exists flags(-min_fanout)] + set max_capacitance [info exists flags(-max_capacitance)] + set min_capacitance [info exists flags(-min_capacitance)] set min_pulse_width [info exists flags(-min_pulse_width)] set min_period [info exists flags(-min_period)] set max_skew [info exists flags(-max_skew)] @@ -457,6 +473,18 @@ proc_redirect report_check_types { if { $min_slew } { report_slew_limits $corner "min" $violators $verbose $nosplit } + if { $max_fanout } { + report_fanout_limits "max" $violators $verbose $nosplit + } + if { $min_fanout } { + report_fanout_limits "min" $violators $verbose $nosplit + } + if { $max_capacitance } { + report_capacitance_limits $corner "max" $violators $verbose $nosplit + } + if { $min_capacitance } { + report_capacitance_limits $corner "min" $violators $verbose $nosplit + } if { $min_pulse_width } { if { $violators } { set checks [min_pulse_width_violations $corner] @@ -1076,6 +1104,17 @@ proc report_object_names { args } { ################################################################ +define_sta_cmd_args "report_units" {} + +proc report_units { args } { + check_argc_eq0 "report_units" $args + foreach unit {"time" "capacitance" "resistance" "voltage" "current" "power" "distance"} { + puts " $unit 1[unit_scale_abreviation $unit][unit_suffix $unit]" + } +} + +################################################################ + define_sta_cmd_args "with_output_to_variable" { var { cmds }} # with_output_to_variable variable { command args... } diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 6162de85..1a8bb558 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -1065,6 +1065,8 @@ using namespace sta; $1 = ReportPathFormat::summary; else if (stringEq(arg, "slack_only")) $1 = ReportPathFormat::slack_only; + else if (stringEq(arg, "json")) + $1 = ReportPathFormat::json; else { tclError(interp, "Error: unknown path type %s.", arg); return TCL_ERROR; @@ -3516,15 +3518,6 @@ set_slew_limit_port(Port *port, Sta::sta()->setSlewLimit(port, min_max, slew); } -void -set_slew_limit_pin(Pin *pin, - const MinMax *min_max, - float slew) -{ - cmdLinkedNetwork(); - Sta::sta()->setSlewLimit(pin, min_max, slew); -} - void set_slew_limit_cell(Cell *cell, const MinMax *min_max, @@ -3958,6 +3951,26 @@ set_cmd_unit_suffix(const char *unit_name, } } +const char * +unit_scale_abreviation(const char *unit_name) +{ + Unit *unit = Sta::sta()->units()->find(unit_name); + if (unit) + return unit->scaleAbreviation(); + else + return ""; +} + +const char * +unit_suffix(const char *unit_name) +{ + Unit *unit = Sta::sta()->units()->find(unit_name); + if (unit) + return unit->suffix(); + else + return ""; +} + //////////////////////////////////////////////////////////////// VertexIterator * @@ -4613,6 +4626,8 @@ report_delay_calc_cmd(Edge *edge, return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits); } +//////////////////////////////////////////////////////////////// + Pin * pin_min_slew_limit_slack(const Corner *corner, const MinMax *min_max) @@ -4653,6 +4668,82 @@ report_slew_limit_verbose(Pin *pin, //////////////////////////////////////////////////////////////// +Pin * +pin_min_fanout_limit_slack(const MinMax *min_max) +{ + cmdLinkedNetwork(); + return Sta::sta()->pinMinFanoutLimitSlack(min_max); +} + +PinSeq * +pin_fanout_limit_violations(const MinMax *min_max) +{ + cmdLinkedNetwork(); + return Sta::sta()->pinFanoutLimitViolations(min_max); +} + +void +report_fanout_limit_short_header() +{ + Sta::sta()->reportFanoutLimitShortHeader(); +} + +void +report_fanout_limit_short(Pin *pin, + const MinMax *min_max) +{ + Sta::sta()->reportFanoutLimitShort(pin, min_max); +} + +void +report_fanout_limit_verbose(Pin *pin, + const MinMax *min_max) +{ + Sta::sta()->reportFanoutLimitVerbose(pin, min_max); +} + +//////////////////////////////////////////////////////////////// + +Pin * +pin_min_capacitance_limit_slack(const Corner *corner, + const MinMax *min_max) +{ + cmdLinkedNetwork(); + return Sta::sta()->pinMinCapacitanceLimitSlack(corner, min_max); +} + +PinSeq * +pin_capacitance_limit_violations(const Corner *corner, + const MinMax *min_max) +{ + cmdLinkedNetwork(); + return Sta::sta()->pinCapacitanceLimitViolations(corner, min_max); +} + +void +report_capacitance_limit_short_header() +{ + Sta::sta()->reportCapacitanceLimitShortHeader(); +} + +void +report_capacitance_limit_short(Pin *pin, + const Corner *corner, + const MinMax *min_max) +{ + Sta::sta()->reportCapacitanceLimitShort(pin, corner, min_max); +} + +void +report_capacitance_limit_verbose(Pin *pin, + const Corner *corner, + const MinMax *min_max) +{ + Sta::sta()->reportCapacitanceLimitVerbose(pin, corner, min_max); +} + +//////////////////////////////////////////////////////////////// + TmpFloatSeq * design_power(const Corner *corner) { @@ -5213,6 +5304,27 @@ arrivals_invalid() sta->arrivalsInvalid(); } +void +delays_invalid() +{ + Sta *sta = Sta::sta(); + sta->delaysInvalid(); +} + +const char * +pin_location(Pin *pin) +{ + Network *network = cmdNetwork(); + double x, y; + bool exists; + network->location(pin, x, y, exists); + // return x/y as tcl list + if (exists) + return sta::stringPrintTmp("%f %f", x, y); + else + return ""; +} + %} // inline //////////////////////////////////////////////////////////////// diff --git a/verilog/VerilogWriter.cc b/verilog/VerilogWriter.cc index 52ffc0f4..ed475971 100644 --- a/verilog/VerilogWriter.cc +++ b/verilog/VerilogWriter.cc @@ -165,12 +165,20 @@ VerilogWriter::verilogPortDir(PortDirection *dir) return "input"; else if (dir == PortDirection::output()) return "output"; - else if (dir == PortDirection::bidirect()) - return "inout"; else if (dir == PortDirection::tristate()) return "output"; - else + else if (dir == PortDirection::bidirect()) + return "inout"; + else if (dir == PortDirection::power()) + return "input"; + else if (dir == PortDirection::ground()) + return "input"; + else if (dir == PortDirection::internal()) return nullptr; + else { + internalError("unknown port direction"); + return nullptr; + } } void