diff --git a/CMakeLists.txt b/CMakeLists.txt index fa6dd609..67b8de44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14) cmake_policy(SET CMP0086 NEW) endif() -project(STA VERSION 2.1.0 +project(STA VERSION 2.2.0 LANGUAGES CXX ) @@ -141,6 +141,7 @@ set(STA_SOURCE sdc/RiseFallMinMax.cc sdc/RiseFallValues.cc sdc/Sdc.cc + sdc/SdcGraph.cc sdc/SdcCmdComment.cc sdc/WriteSdc.cc @@ -329,7 +330,7 @@ swig_add_library(sta_swig SOURCES ${STA_SWIG_FILE} ) -swig_link_libraries(sta_swig +target_link_libraries(sta_swig PUBLIC OpenSTA ) @@ -477,8 +478,8 @@ target_compile_options(sta ) target_link_libraries(sta - OpenSTA sta_swig + OpenSTA ${TCL_LIBRARY} ) diff --git a/app/StaMain.cc b/app/StaMain.cc index 88d5821d..aaed624a 100644 --- a/app/StaMain.cc +++ b/app/StaMain.cc @@ -19,7 +19,6 @@ #include #include -#include "util/Machine.hh" #include "StringUtil.hh" #include "Vector.hh" #include "Sta.hh" diff --git a/dcalc/DmpDelayCalc.cc b/dcalc/DmpDelayCalc.cc index 77ea8c11..44823aa7 100644 --- a/dcalc/DmpDelayCalc.cc +++ b/dcalc/DmpDelayCalc.cc @@ -347,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/doc/OpenSTA.odt b/doc/OpenSTA.odt index 1eb3cf7b..6c52b060 100644 Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ diff --git a/graph/DelayFloat.cc b/graph/DelayFloat.cc index 2b06819a..9fda2611 100644 --- a/graph/DelayFloat.cc +++ b/graph/DelayFloat.cc @@ -35,19 +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()); -} - const char * delayAsString(const Delay &delay, const StaState *sta) @@ -73,25 +60,91 @@ 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; -} - -float -delaySigma2(const Delay &, - const EarlyLate *) -{ - return 0.0; + return fuzzyGreater(delay1, delay2); } bool -fuzzyGreater(const Delay &delay1, +delayGreater(const Delay &delay1, const Delay &delay2, - const MinMax *min_max) + const MinMax *min_max, + const StaState *) { if (min_max == MinMax::max()) return fuzzyGreater(delay1, delay2); @@ -100,9 +153,18 @@ fuzzyGreater(const Delay &delay1, } bool -fuzzyGreaterEqual(const Delay &delay1, +delayGreaterEqual(const Delay &delay1, const Delay &delay2, - const MinMax *min_max) + 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); @@ -110,28 +172,6 @@ fuzzyGreaterEqual(const Delay &delay1, 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); -} - Delay delayRemove(const Delay &delay1, const Delay &delay2) diff --git a/graph/DelayNormal1.cc b/graph/DelayNormal1.cc index f0d58659..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,135 +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()); -} - float delayAsFloat(const Delay &delay, const EarlyLate *early_late, @@ -394,6 +240,156 @@ 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) diff --git a/graph/DelayNormal2.cc b/graph/DelayNormal2.cc index db5a7eca..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,146 +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); } -Delay -delayRemove(const Delay &delay1, - const Delay &delay2) +bool +delayGreater(const Delay &delay1, + const Delay &delay2, + const StaState *sta) { - return Delay(delay1.mean() - delay2.mean(), - delay1.sigma2Early() - delay2.sigma2Early(), - delay1.sigma2Late() - delay2.sigma2Late()); + return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta), + delayAsFloat(delay2, EarlyLate::late(), sta)); } -float -delayRatio(const Delay &delay1, - const Delay &delay2) +bool +delayGreater(const Delay &delay1, + float delay2, + const StaState *sta) { - return delay1.mean() / delay2.mean(); + 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 @@ -463,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/Clock.hh b/include/sta/Clock.hh index d38c65ee..33d48898 100644 --- a/include/sta/Clock.hh +++ b/include/sta/Clock.hh @@ -294,12 +294,4 @@ void sortClockSet(ClockSet * set, ClockSeq &clks); -// Clock source pins. -class ClockPinIterator : public PinSet::Iterator -{ -public: - // Use range iterator on Clock::pins(). - ClockPinIterator(Clock *clk) __attribute__ ((deprecated)); -}; - } // namespace diff --git a/include/sta/Debug.hh b/include/sta/Debug.hh index eb70468a..22c57794 100644 --- a/include/sta/Debug.hh +++ b/include/sta/Debug.hh @@ -17,6 +17,7 @@ #pragma once #include +#include "Machine.hh" #include "DisallowCopyAssign.hh" #include "Map.hh" #include "StringUtil.hh" 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 70bd51f1..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,47 +67,71 @@ 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); diff --git a/include/sta/DelayNormal1.hh b/include/sta/DelayNormal1.hh index 1b99f139..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,10 @@ 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 @@ -85,58 +97,55 @@ delayAsFloat(const Delay &delay, 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); +delayZero(const Delay &delay); bool -fuzzyInf(const Delay &delay); +delayInf(const Delay &delay); bool -fuzzyEqual(const Delay &delay1, +delayEqual(const Delay &delay1, const Delay &delay2); bool -fuzzyLess(const Delay &delay1, - const Delay &delay2); -bool -fuzzyLess(const Delay &delay1, +delayLess(const Delay &delay1, const Delay &delay2, - const MinMax *min_max); + const StaState *sta); bool -fuzzyLessEqual(const Delay &delay1, - const Delay &delay2); +delayLess(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); bool -fuzzyLessEqual(const Delay &delay1, +delayLessEqual(const Delay &delay1, const Delay &delay2, - const MinMax *min_max); + const StaState *sta); bool -fuzzyGreater(const Delay &delay1, - const Delay &delay2); +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); 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, +delayGreater(const Delay &delay1, const Delay &delay2, - const MinMax *min_max); + 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); diff --git a/include/sta/DelayNormal2.hh b/include/sta/DelayNormal2.hh index d39a5ec3..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,28 +66,6 @@ const Delay delay_zero(0.0); void initDelayConstants(); -Delay -makeDelay(float delay, - float sigma_early, - float sigma_late); - -Delay -makeDelay2(float delay, - // sigma^2 - float sigma_early, - float sigma_late); - -inline float -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 char * delayAsString(const Delay &delay, const StaState *sta); @@ -104,46 +78,81 @@ delayAsString(const Delay &delay, const EarlyLate *early_late, const StaState *sta, int digits); + +Delay +makeDelay(float delay, + float sigma_early, + float sigma_late); + +Delay +makeDelay2(float delay, + // sigma^2 + float sigma_early, + float sigma_late); + +inline float +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 -fuzzyZero(const Delay &delay); +delayZero(const Delay &delay); bool -fuzzyInf(const Delay &delay); +delayInf(const Delay &delay); bool -fuzzyEqual(const Delay &delay1, +delayEqual(const Delay &delay1, const Delay &delay2); bool -fuzzyLess(const Delay &delay1, - const Delay &delay2); -bool -fuzzyLess(const Delay &delay1, +delayLess(const Delay &delay1, const Delay &delay2, - const MinMax *min_max); + const StaState *sta); bool -fuzzyLessEqual(const Delay &delay1, - const Delay &delay2); +delayLess(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); bool -fuzzyLessEqual(const Delay &delay1, +delayLessEqual(const Delay &delay1, const Delay &delay2, - const MinMax *min_max); + const StaState *sta); bool -fuzzyGreater(const Delay &delay1, - const Delay &delay2); +delayLessEqual(const Delay &delay1, + const Delay &delay2, + const MinMax *min_max, + const StaState *sta); 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, +delayGreater(const Delay &delay1, const Delay &delay2, - const MinMax *min_max); + 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); diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index 5818e4bb..ec898916 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -493,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, @@ -522,6 +523,8 @@ 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_; @@ -633,6 +636,7 @@ public: 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, diff --git a/util/Machine.hh b/include/sta/Machine.hh similarity index 100% rename from util/Machine.hh rename to include/sta/Machine.hh 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..82e16883 100644 --- a/include/sta/PathEnd.hh +++ b/include/sta/PathEnd.hh @@ -142,6 +142,7 @@ public: virtual TimingArc *checkArc() const { return nullptr; } // PathEndDataCheck data clock path. virtual const PathVertex *dataClkPath() const { return nullptr; } + virtual int setupDefaultCycles() const { return 1; } static bool less(const PathEnd *path_end1, const PathEnd *path_end2, @@ -181,6 +182,7 @@ public: static float checkSetupMcpAdjustment(const ClockEdge *src_clk_edge, const ClockEdge *tgt_clk_edge, const MultiCyclePath *mcp, + int default_cycles, Sdc *sdc); protected: @@ -425,6 +427,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: @@ -544,6 +547,8 @@ protected: Crpr crpr, bool crpr_valid); Arrival requiredTimeNoCrpr(const StaState *sta) const; + // setup uses zero cycle default + virtual int setupDefaultCycles() const { return 0; } private: PathVertex data_clk_path_; @@ -555,6 +560,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 +593,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 +601,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 +618,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/PowerClass.hh b/include/sta/PowerClass.hh new file mode 100644 index 00000000..706e1f45 --- /dev/null +++ b/include/sta/PowerClass.hh @@ -0,0 +1,73 @@ +// 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 + +namespace sta { + +enum class PwrActivityOrigin +{ + global, + input, + user, + propagated, + clock, + constant, + defaulted, + unknown +}; + +class PwrActivity +{ +public: + PwrActivity(); + PwrActivity(float activity, + float duty, + PwrActivityOrigin origin); + float activity() const { return activity_; } + float duty() const { return duty_; } + PwrActivityOrigin origin() { return origin_; } + const char *originName() const; + void set(float activity, + float duty, + PwrActivityOrigin origin); + bool isSet() const; + +private: + // In general activity is per clock cycle, NOT per second. + float activity_; + float duty_; + PwrActivityOrigin origin_; +}; + +class PowerResult +{ +public: + PowerResult(); + void clear(); + float &internal() { return internal_; } + float &switching() { return switching_; } + float &leakage() { return leakage_; } + float total() const; + void incr(PowerResult &result); + +private: + float internal_; + float switching_; + float leakage_; +}; + +} // namespace diff --git a/include/sta/Property.hh b/include/sta/Property.hh index c83f1af1..d4b35bee 100644 --- a/include/sta/Property.hh +++ b/include/sta/Property.hh @@ -22,7 +22,7 @@ #include "NetworkClass.hh" #include "SearchClass.hh" #include "SdcClass.hh" -#include "Power.hh" +#include "PowerClass.hh" namespace sta { diff --git a/include/sta/Report.hh b/include/sta/Report.hh index 6dd0ca47..df45765d 100644 --- a/include/sta/Report.hh +++ b/include/sta/Report.hh @@ -20,6 +20,7 @@ #include #include #include +#include "Machine.hh" #include "DisallowCopyAssign.hh" struct Tcl_Interp; 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 560fddbe..03dd6513 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -824,7 +824,6 @@ public: // Find the clocks defined for pin. ClockSet *findClocks(const Pin *pin) const; ClockSet *findLeafPinClocks(const Pin *pin) const; - ClockIterator *clockIterator() __attribute__ ((deprecated)); void sortedClocks(ClockSeq &clks); ClockSeq *clocks() { return &clocks_; } ClockSeq &clks() { return clocks_; } @@ -990,11 +989,8 @@ public: void deleteException(ExceptionPath *exception); void recordException(ExceptionPath *exception); void unrecordException(ExceptionPath *exception); - // Annotate graph from constraints. If the graph exists when the - // constraints are defined it is annotated incrementally. This is - // called after building the graph to annotate any constraints that - // were defined before the graph is built. - void annotateGraph(bool annotate); + void annotateGraph(); + void removeGraphAnnotations(); // Network edit before/after methods. void disconnectPinBefore(Pin *pin); @@ -1180,34 +1176,25 @@ protected: // Liberty library to look for defaults. LibertyLibrary *defaultLibertyLibrary(); void annotateGraphConstrainOutputs(); - void annotateDisables(bool annotate); - void annotateGraphDisabled(const Pin *pin, - bool annotate); - void setEdgeDisabledInstPorts(DisabledInstancePorts *disabled_inst, - bool annotate); + void annotateDisables(); + void annotateGraphDisabled(const Pin *pin); + void setEdgeDisabledInstPorts(DisabledInstancePorts *disabled_inst); void setEdgeDisabledInstFrom(Pin *from_pin, - bool disable_checks, - bool annotate); + bool disable_checks); void setEdgeDisabledInstPorts(DisabledPorts *disabled_port, - Instance *inst, - bool annotate); + Instance *inst); void deleteClockLatenciesReferencing(Clock *clk); void deleteClockLatency(ClockLatency *latency); void deleteDeratingFactors(); - void annotateGraphOutputDelays(bool annotate); - void annotateGraphDataChecks(bool annotate); - void annotateGraphConstrained(const PinSet *pins, - bool annotate); - void annotateGraphConstrained(const InstanceSet *insts, - bool annotate); - void annotateGraphConstrained(const Instance *inst, - bool annotate); - void annotateGraphConstrained(const Pin *pin, - bool annotate); - void annotateHierClkLatency(bool annotate); + void annotateGraphOutputDelays(); + void annotateGraphDataChecks(); + void annotateGraphConstrained(const PinSet *pins); + void annotateGraphConstrained(const InstanceSet *insts); + void annotateGraphConstrained(const Instance *inst); + void annotateGraphConstrained(const Pin *pin); + void annotateHierClkLatency(); void annotateHierClkLatency(const Pin *hpin, ClockLatency *latency); - void deannotateHierClkLatency(const Pin *hpin); void initInstancePvtMaps(); void pinCaps(const Pin *pin, const RiseFall *rf, @@ -1257,9 +1244,6 @@ protected: void disconnectPinBefore(Pin *pin, ExceptionPathSet *exceptions); void clockGroupsDeleteClkRefs(Clock *clk); - void makeVertexClkHpinDisables(Clock *clk, - Vertex *vertex, - FindClkHpinDisables &visitor); void clearGroupPathMap(); AnalysisType analysis_type_; 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 150d9610..af0b67e1 100644 --- a/include/sta/Sta.hh +++ b/include/sta/Sta.hh @@ -18,6 +18,7 @@ #include +#include "Machine.hh" #include "DisallowCopyAssign.hh" #include "StringSeq.hh" #include "LibertyClass.hh" @@ -28,6 +29,7 @@ #include "StaState.hh" #include "VertexVisitor.hh" #include "SearchClass.hh" +#include "PowerClass.hh" struct Tcl_Interp; @@ -292,17 +294,8 @@ public: void removeClock(Clock *clk); // Update period/waveform for generated clocks from source pin clock. void updateGeneratedClks(); - // Use Sdc::findClock - Clock *findClock(const char *name) const __attribute__ ((deprecated)); - // Use findClocksMatching. - void findClocksMatching(PatternMatch *pattern, - ClockSeq *clks) const __attribute__ ((deprecated)); - // Use Sdc::clockIterator. - ClockIterator *clockIterator() const __attribute__ ((deprecated)); // True if pin is defined as a clock source (pin may be hierarchical). bool isClockSrc(const Pin *pin) const; - // Use Sdc::defaultArrivalClock. - Clock *defaultArrivalClock() const __attribute__ ((deprecated)); // Propagated (non-ideal) clocks. void setPropagatedClock(Clock *clk); void removePropagatedClock(Clock *clk); @@ -873,42 +866,6 @@ public: bool removal, bool clk_gating_setup, bool clk_gating_hold); - PathEndSeq *reportTiming(ExceptionFrom *from, - ExceptionThruSeq *thrus, - ExceptionTo *to, - // Use corner nullptr to report timing - // for all corners. - const Corner *corner, - // max for setup checks. - // min for hold checks. - // min_max for setup and hold checks. - const MinMaxAll *min_max, - // Number of path ends to report in - // each group. - int group_count, - // Number of paths to report for - // each endpoint. - int endpoint_count, - // endpoint_count paths report unique pins - // without rise/fall variations. - bool unique_pins, - // Min/max bounds for slack of - // returned path ends. - float slack_min, - float slack_max, - // Sort path ends by slack ignoring path groups. - bool sort_by_slack, - // Path groups to report. - // Null or empty list reports all groups. - PathGroupNameSet *group_names, - // Predicates to filter the type of path - // ends returned. - bool setup, - bool hold, - bool recovery, - bool removal, - bool clk_gating_setup, - bool clk_gating_hold) __attribute__ ((deprecated)); void setReportPathFormat(ReportPathFormat format); void setReportPathFieldOrder(StringSeq *field_names); void setReportPathFields(bool report_input_pin, @@ -947,7 +904,6 @@ public: void delaysInvalid(); // Invalidate all arrival and required times. void arrivalsInvalid(); - void setPathMinMax(const MinMaxAll *min_max) __attribute__ ((deprecated)); void visitStartpoints(VertexVisitor *visitor); void visitEndpoints(VertexVisitor *visitor); // Find the fanin vertices for a group path. @@ -1379,6 +1335,8 @@ protected: void findClkPins(); void findClkPins(bool ideal_only, PinSet &clk_pins); + void sdcChangedGraph(); + void ensureGraphSdcAnnotated(); CmdNamespace cmd_namespace_; Instance *current_instance_; @@ -1397,6 +1355,7 @@ protected: bool link_make_black_boxes_; bool update_genclks_; EquivCells *equiv_cells_; + bool graph_sdc_annotated_; // findClkPins PinSet clk_pins_; PinSet ideal_clk_pins_; diff --git a/include/sta/StringUtil.hh b/include/sta/StringUtil.hh index 5cfc650a..d06eef34 100644 --- a/include/sta/StringUtil.hh +++ b/include/sta/StringUtil.hh @@ -19,6 +19,7 @@ #include #include #include +#include "Machine.hh" #include "Vector.hh" namespace sta { diff --git a/include/sta/TimingArc.hh b/include/sta/TimingArc.hh index ce1a2fc9..00cea66b 100644 --- a/include/sta/TimingArc.hh +++ b/include/sta/TimingArc.hh @@ -16,6 +16,7 @@ #pragma once +#include "Machine.hh" #include "DisallowCopyAssign.hh" #include "Vector.hh" #include "Transition.hh" diff --git a/include/sta/VerilogWriter.hh b/include/sta/VerilogWriter.hh index 0c877195..163e5f38 100644 --- a/include/sta/VerilogWriter.hh +++ b/include/sta/VerilogWriter.hh @@ -16,13 +16,19 @@ #pragma once +#include + namespace sta { +using std::vector; + class Network; +class LibertyCell; void writeVerilog(const char *filename, bool sort, + vector *remove_cells, Network *network); } // namespace diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 38a64706..11c9c317 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -1064,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, @@ -1907,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 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/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index 2a356a61..26dffdcc 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -18,6 +18,7 @@ #include +#include "Machine.hh" #include "DisallowCopyAssign.hh" #include "Vector.hh" #include "Map.hh" 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/SpefReaderPvt.hh b/parasitics/SpefReaderPvt.hh index 3008230a..41a9cfd6 100644 --- a/parasitics/SpefReaderPvt.hh +++ b/parasitics/SpefReaderPvt.hh @@ -16,6 +16,7 @@ #pragma once +#include "Machine.hh" #include "Zlib.hh" #include "Map.hh" #include "StringSeq.hh" diff --git a/sdc/Clock.cc b/sdc/Clock.cc index 51a991a5..04cf3bbb 100644 --- a/sdc/Clock.cc +++ b/sdc/Clock.cc @@ -699,9 +699,4 @@ sortClockSet(ClockSet *set, sort(clks, ClockNameLess()); } -ClockPinIterator::ClockPinIterator(Clock *clk) : - PinSet::Iterator(clk->pins()) -{ -} - } // namespace 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_index PvtSet; static ExceptionThruSeq * clone(ExceptionThruSeq *thrus, Network *network); -static void -annotateGraphDisabledWireEdge(Pin *from_pin, - Pin *to_pin, - bool annotate, - Graph *graph); //////////////////////////////////////////////////////////////// @@ -409,15 +404,6 @@ Sdc::initInstancePvtMaps() //////////////////////////////////////////////////////////////// -void -Sdc::searchPreamble() -{ - ensureClkHpinDisables(); - ensureClkGroupExclusions(); -} - -//////////////////////////////////////////////////////////////// - bool Sdc::isConstrained(const Pin *pin) const { @@ -1254,12 +1240,6 @@ Sdc::findClocksMatching(PatternMatch *pattern, } } -ClockIterator * -Sdc::clockIterator() -{ - return new ClockIterator(clocks_); -} - void Sdc::sortedClocks(ClockSeq &clks) { @@ -1398,18 +1378,6 @@ FindClkHpinDisables::drvrLoadExists(Pin *drvr, return drvr_loads_.hasKey(&probe); } -void -Sdc::makeClkHpinDisable(Clock *clk, - Pin *drvr, - Pin *load) -{ - ClkHpinDisable probe(clk, drvr, load); - if (!clk_hpin_disables_.hasKey(&probe)) { - ClkHpinDisable *disable = new ClkHpinDisable(clk, drvr, load); - clk_hpin_disables_.insert(disable); - } -} - void Sdc::ensureClkHpinDisables() { @@ -1418,16 +1386,20 @@ Sdc::ensureClkHpinDisables() for (auto clk : clocks_) { for (Pin *src : clk->pins()) { if (network_->isHierarchical(src)) { - FindClkHpinDisables visitor(clk, network_, this); - visitHpinDrvrLoads(src, network_, &visitor); + FindClkHpinDisables visitor1(clk, network_, this); + visitHpinDrvrLoads(src, network_, &visitor1); + PinSeq loads, drvrs; + PinSet visited_drvrs; + FindNetDrvrLoads visitor2(nullptr, visited_drvrs, loads, drvrs, network_); + network_->visitConnectedPins(src, visitor2); + // Disable fanouts from the src driver pins that do // not go thru the hierarchical src pin. - for (Pin *lpin : clk->leafPins()) { - Vertex *vertex, *bidirect_drvr_vertex; - graph_->pinVertices(lpin, vertex, bidirect_drvr_vertex); - makeVertexClkHpinDisables(clk, vertex, visitor); - if (bidirect_drvr_vertex) - makeVertexClkHpinDisables(clk, bidirect_drvr_vertex, visitor); + for (Pin *drvr : drvrs) { + for (Pin *load : loads) { + if (!visitor1.drvrLoadExists(drvr, load)) + makeClkHpinDisable(clk, drvr, load); + } } } } @@ -1437,19 +1409,14 @@ Sdc::ensureClkHpinDisables() } void -Sdc::makeVertexClkHpinDisables(Clock *clk, - Vertex *vertex, - FindClkHpinDisables &visitor) +Sdc::makeClkHpinDisable(Clock *clk, + Pin *drvr, + Pin *load) { - VertexOutEdgeIterator edge_iter(vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->isWire()) { - Pin *drvr = edge->from(graph_)->pin(); - Pin *load = edge->to(graph_)->pin(); - if (!visitor.drvrLoadExists(drvr, load)) - makeClkHpinDisable(clk, drvr, load); - } + ClkHpinDisable probe(clk, drvr, load); + if (!clk_hpin_disables_.hasKey(&probe)) { + ClkHpinDisable *disable = new ClkHpinDisable(clk, drvr, load); + clk_hpin_disables_.insert(disable); } } @@ -1539,8 +1506,6 @@ Sdc::setClockLatency(Clock *clk, clk_latencies_.insert(latency); } latency->setDelay(rf, min_max, delay); - if (pin && graph_ && network_->isHierarchical(pin)) - annotateHierClkLatency(pin, latency); // set_clock_latency removes set_propagated_clock on the same object. if (clk && pin == nullptr) @@ -1563,8 +1528,6 @@ void Sdc::deleteClockLatency(ClockLatency *latency) { const Pin *pin = latency->pin(); - if (pin && graph_ && network_->isHierarchical(pin)) - deannotateHierClkLatency(pin); clk_latencies_.erase(latency); delete latency; } @@ -2530,9 +2493,6 @@ Sdc::setDataCheck(Pin *from, data_checks_to_map_[to] = checks; } checks->insert(check); - - if (graph_) - annotateGraphConstrained(to, true); } void @@ -2966,8 +2926,6 @@ Sdc::makeOutputDelay(Pin *pin, output_delay_leaf_pin_map_[lpin] = leaf_outputs; } leaf_outputs->insert(output_delay); - if (graph_) - annotateGraphConstrained(lpin, true); } return output_delay; } @@ -3591,19 +3549,11 @@ void Sdc::disable(Port *port) { disabled_ports_.insert(port); - if (graph_) { - Pin *pin = network_->findPin(network_->topInstance(), port); - annotateGraphDisabled(pin, true); - } } void Sdc::removeDisable(Port *port) { - if (graph_) { - Pin *pin = network_->findPin(network_->topInstance(), port); - annotateGraphDisabled(pin, false); - } disabled_ports_.erase(port); } @@ -3625,9 +3575,6 @@ Sdc::disable(Instance *inst, disabled_inst->setDisabledTo(to); else disabled_inst->setDisabledAll(); - - if (graph_) - setEdgeDisabledInstPorts(disabled_inst, true); } void @@ -3637,8 +3584,6 @@ Sdc::removeDisable(Instance *inst, { DisabledInstancePorts *disabled_inst = disabled_inst_ports_.findKey(inst); if (disabled_inst) { - if (graph_) - setEdgeDisabledInstPorts(disabled_inst, false); if (from && to) disabled_inst->removeDisabledFromTo(from, to); else if (from) @@ -3658,8 +3603,6 @@ Sdc::disable(Pin *from, if (!disabled_wire_edges_.hasKey(&probe)) { PinPair *pair = new PinPair(from, to); disabled_wire_edges_.insert(pair); - if (graph_) - annotateGraphDisabledWireEdge(from, to, true, graph_); } } @@ -3667,7 +3610,6 @@ void Sdc::removeDisable(Pin *from, Pin *to) { - annotateGraphDisabledWireEdge(from, to, false, graph_); PinPair probe(from, to); disabled_wire_edges_.erase(&probe); } @@ -3725,8 +3667,6 @@ DisableEdgesThruHierPin::visit(Pin *drvr, if (!pairs_->hasKey(&probe)) { PinPair *pair = new PinPair(drvr, load); pairs_->insert(pair); - if (graph_) - annotateGraphDisabledWireEdge(drvr, load, true, graph_); } } @@ -3738,17 +3678,15 @@ Sdc::disable(Pin *pin) DisableEdgesThruHierPin visitor(&disabled_wire_edges_, graph_); visitDrvrLoadsThruHierPin(pin, network_, &visitor); } - else { + else disabled_pins_.insert(pin); - if (graph_) - annotateGraphDisabled(pin, true); - } } class RemoveDisableEdgesThruHierPin : public HierPinThruVisitor { public: - RemoveDisableEdgesThruHierPin(PinPairSet *pairs, Graph *graph); + RemoveDisableEdgesThruHierPin(PinPairSet *pairs, + Graph *graph); protected: virtual void visit(Pin *drvr, Pin *load); @@ -3772,8 +3710,6 @@ void RemoveDisableEdgesThruHierPin::visit(Pin *drvr, Pin *load) { - if (graph_) - annotateGraphDisabledWireEdge(drvr, load, false, graph_); PinPair probe(drvr, load); PinPair *pair = pairs_->findKey(&probe); if (pair) { @@ -3790,11 +3726,8 @@ Sdc::removeDisable(Pin *pin) RemoveDisableEdgesThruHierPin visitor(&disabled_wire_edges_, graph_); visitDrvrLoadsThruHierPin(pin, network_, &visitor); } - else { - if (graph_) - annotateGraphDisabled(pin, false); + else disabled_pins_.erase(pin); - } } bool @@ -6056,370 +5989,6 @@ Sdc::clkHpinDisablesChanged(Pin *pin) //////////////////////////////////////////////////////////////// -// Annotate constraints to the timing graph. -void -Sdc::annotateGraph(bool annotate) -{ - Stats stats(debug_); - // All output pins are considered constrained because - // they may be downstream from a set_min/max_delay -from that - // does not have a set_output_delay. - annotateGraphConstrainOutputs(); - annotateDisables(annotate); - annotateGraphOutputDelays(annotate); - annotateGraphDataChecks(annotate); - annotateHierClkLatency(annotate); - stats.report("Annotate constraints to graph"); -} - -void -Sdc::annotateGraphConstrainOutputs() -{ - Instance *top_inst = network_->topInstance(); - InstancePinIterator *pin_iter = network_->pinIterator(top_inst); - while (pin_iter->hasNext()) { - Pin *pin = pin_iter->next(); - if (network_->direction(pin)->isAnyOutput()) - annotateGraphConstrained(pin, true); - } - delete pin_iter; -} - -void -Sdc::annotateDisables(bool annotate) -{ - PinSet::Iterator pin_iter(disabled_pins_); - while (pin_iter.hasNext()) { - Pin *pin = pin_iter.next(); - annotateGraphDisabled(pin, annotate); - } - - if (!disabled_lib_ports_.empty()) { - VertexIterator vertex_iter(graph_); - while (vertex_iter.hasNext()) { - Vertex *vertex = vertex_iter.next(); - Pin *pin = vertex->pin(); - LibertyPort *port = network_->libertyPort(pin); - if (disabled_lib_ports_.hasKey(port)) - annotateGraphDisabled(pin, annotate); - } - } - - Instance *top_inst = network_->topInstance(); - PortSet::Iterator port_iter(disabled_ports_); - while (port_iter.hasNext()) { - Port *port = port_iter.next(); - Pin *pin = network_->findPin(top_inst, port); - annotateGraphDisabled(pin, annotate); - } - - PinPairSet::Iterator pair_iter(disabled_wire_edges_); - while (pair_iter.hasNext()) { - PinPair *pair = pair_iter.next(); - annotateGraphDisabledWireEdge(pair->first, pair->second, annotate, graph_); - } - - EdgeSet::Iterator edge_iter(disabled_edges_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - edge->setIsDisabledConstraint(annotate); - } - - DisabledInstancePortsMap::Iterator disable_inst_iter(disabled_inst_ports_); - while (disable_inst_iter.hasNext()) { - DisabledInstancePorts *disabled_inst = disable_inst_iter.next(); - setEdgeDisabledInstPorts(disabled_inst, annotate); - } -} - -class DisableHpinEdgeVisitor : public HierPinThruVisitor -{ -public: - DisableHpinEdgeVisitor(bool annotate, Graph *graph); - virtual void visit(Pin *from_pin, - Pin *to_pin); - -protected: - bool annotate_; - Graph *graph_; - -private: - DISALLOW_COPY_AND_ASSIGN(DisableHpinEdgeVisitor); -}; - -DisableHpinEdgeVisitor::DisableHpinEdgeVisitor(bool annotate, - Graph *graph) : - HierPinThruVisitor(), - annotate_(annotate), - graph_(graph) -{ -} - -void -DisableHpinEdgeVisitor::visit(Pin *from_pin, - Pin *to_pin) -{ - annotateGraphDisabledWireEdge(from_pin, to_pin, annotate_, graph_); -} - -static void -annotateGraphDisabledWireEdge(Pin *from_pin, - Pin *to_pin, - bool annotate, - Graph *graph) -{ - Vertex *from_vertex = graph->pinDrvrVertex(from_pin); - Vertex *to_vertex = graph->pinLoadVertex(to_pin); - if (from_vertex && to_vertex) { - VertexOutEdgeIterator edge_iter(from_vertex, graph); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->isWire() - && edge->to(graph) == to_vertex) - edge->setIsDisabledConstraint(annotate); - } - } -} - -void -Sdc::annotateGraphDisabled(const Pin *pin, - bool annotate) -{ - Vertex *vertex, *bidirect_drvr_vertex; - graph_->pinVertices(pin, vertex, bidirect_drvr_vertex); - vertex->setIsDisabledConstraint(annotate); - if (bidirect_drvr_vertex) - bidirect_drvr_vertex->setIsDisabledConstraint(annotate); -} - -void -Sdc::setEdgeDisabledInstPorts(DisabledInstancePorts *disabled_inst, - bool annotate) -{ - setEdgeDisabledInstPorts(disabled_inst, disabled_inst->instance(), annotate); -} - -void -Sdc::setEdgeDisabledInstPorts(DisabledPorts *disabled_port, - Instance *inst, - bool annotate) -{ - if (disabled_port->all()) { - InstancePinIterator *pin_iter = network_->pinIterator(inst); - while (pin_iter->hasNext()) { - Pin *pin = pin_iter->next(); - // set_disable_timing instance does not disable timing checks. - setEdgeDisabledInstFrom(pin, false, annotate); - } - delete pin_iter; - } - - // Disable from pins. - LibertyPortSet::Iterator from_iter(disabled_port->from()); - while (from_iter.hasNext()) { - LibertyPort *from_port = from_iter.next(); - Pin *from_pin = network_->findPin(inst, from_port); - if (from_pin) - setEdgeDisabledInstFrom(from_pin, true, annotate); - } - - // Disable to pins. - LibertyPortSet::Iterator to_iter(disabled_port->to()); - while (to_iter.hasNext()) { - LibertyPort *to_port = to_iter.next(); - Pin *to_pin = network_->findPin(inst, to_port); - if (to_pin) { - if (network_->direction(to_pin)->isAnyOutput()) { - Vertex *vertex = graph_->pinDrvrVertex(to_pin); - if (vertex) { - VertexInEdgeIterator edge_iter(vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - edge->setIsDisabledConstraint(annotate); - } - } - } - } - } - - // Disable from/to pins. - LibertyPortPairSet::Iterator from_to_iter(disabled_port->fromTo()); - while (from_to_iter.hasNext()) { - LibertyPortPair *pair = from_to_iter.next(); - const LibertyPort *from_port = pair->first; - const LibertyPort *to_port = pair->second; - Pin *from_pin = network_->findPin(inst, from_port); - Pin *to_pin = network_->findPin(inst, to_port); - if (from_pin && network_->direction(from_pin)->isAnyInput() - && to_pin) { - Vertex *from_vertex = graph_->pinLoadVertex(from_pin); - Vertex *to_vertex = graph_->pinDrvrVertex(to_pin); - if (from_vertex && to_vertex) { - VertexOutEdgeIterator edge_iter(from_vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->to(graph_) == to_vertex) - edge->setIsDisabledConstraint(annotate); - } - } - } - } -} - -void -Sdc::setEdgeDisabledInstFrom(Pin *from_pin, - bool disable_checks, - bool annotate) -{ - if (network_->direction(from_pin)->isAnyInput()) { - Vertex *from_vertex = graph_->pinLoadVertex(from_pin); - if (from_vertex) { - VertexOutEdgeIterator edge_iter(from_vertex, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (disable_checks - || !edge->role()->isTimingCheck()) - edge->setIsDisabledConstraint(annotate); - } - } - } -} - -void -Sdc::annotateGraphOutputDelays(bool annotate) -{ - for (OutputDelay *output_delay : output_delays_) { - for (Pin *lpin : output_delay->leafPins()) - annotateGraphConstrained(lpin, annotate); - } -} - -void -Sdc::annotateGraphDataChecks(bool annotate) -{ - DataChecksMap::Iterator data_checks_iter(data_checks_to_map_); - while (data_checks_iter.hasNext()) { - DataCheckSet *checks = data_checks_iter.next(); - DataCheckSet::Iterator check_iter(checks); - // There may be multiple data checks on a single pin, - // but we only need to mark it as constrained once. - if (check_iter.hasNext()) { - DataCheck *check = check_iter.next(); - annotateGraphConstrained(check->to(), annotate); - } - } -} - -void -Sdc::annotateGraphConstrained(const PinSet *pins, - bool annotate) -{ - PinSet::ConstIterator pin_iter(pins); - while (pin_iter.hasNext()) { - const Pin *pin = pin_iter.next(); - annotateGraphConstrained(pin, annotate); - } -} - -void -Sdc::annotateGraphConstrained(const InstanceSet *insts, - bool annotate) -{ - InstanceSet::ConstIterator inst_iter(insts); - while (inst_iter.hasNext()) { - const Instance *inst = inst_iter.next(); - annotateGraphConstrained(inst, annotate); - } -} - -void -Sdc::annotateGraphConstrained(const Instance *inst, - bool annotate) -{ - InstancePinIterator *pin_iter = network_->pinIterator(inst); - while (pin_iter->hasNext()) { - Pin *pin = pin_iter->next(); - if (network_->direction(pin)->isAnyInput()) - annotateGraphConstrained(pin, annotate); - } - delete pin_iter; -} - -void -Sdc::annotateGraphConstrained(const Pin *pin, - bool annotate) -{ - Vertex *vertex, *bidirect_drvr_vertex; - graph_->pinVertices(pin, vertex, bidirect_drvr_vertex); - // Pin may be hierarchical and have no vertex. - if (vertex) - vertex->setIsConstrained(annotate); - if (bidirect_drvr_vertex) - bidirect_drvr_vertex->setIsConstrained(annotate); -} - -void -Sdc::annotateHierClkLatency(bool annotate) -{ - if (annotate) { - ClockLatencies::Iterator latency_iter(clk_latencies_); - while (latency_iter.hasNext()) { - ClockLatency *latency = latency_iter.next(); - const Pin *pin = latency->pin(); - if (pin && network_->isHierarchical(pin)) - annotateHierClkLatency(pin, latency); - } - } - else - edge_clk_latency_.clear(); -} - -void -Sdc::annotateHierClkLatency(const Pin *hpin, - ClockLatency *latency) -{ - EdgesThruHierPinIterator edge_iter(hpin, network_, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - edge_clk_latency_[edge] = latency; - } -} - -void -Sdc::deannotateHierClkLatency(const Pin *hpin) -{ - EdgesThruHierPinIterator edge_iter(hpin, network_, graph_); - while (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - edge_clk_latency_.erase(edge); - } -} - -ClockLatency * -Sdc::clockLatency(Edge *edge) const -{ - return edge_clk_latency_.findKey(edge); -} - -void -Sdc::clockLatency(Edge *edge, - const RiseFall *rf, - const MinMax *min_max, - // Return values. - float &latency, - bool &exists) const -{ - ClockLatency *latencies = edge_clk_latency_.findKey(edge); - if (latencies) - latencies->delay(rf, min_max, latency, exists); - else { - latency = 0.0; - exists = false; - } -} - -//////////////////////////////////////////////////////////////// - // Find the leaf load pins corresponding to pin. // If the pin is hierarchical, the leaf pins are: // hierarchical input - load pins inside the hierarchical instance diff --git a/sdc/SdcGraph.cc b/sdc/SdcGraph.cc new file mode 100644 index 00000000..5fca8d79 --- /dev/null +++ b/sdc/SdcGraph.cc @@ -0,0 +1,397 @@ +// 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 "Stats.hh" +#include "PortDirection.hh" +#include "Network.hh" +#include "Graph.hh" +#include "DisabledPorts.hh" +#include "PortDelay.hh" +#include "ClockLatency.hh" +#include "Sdc.hh" + +namespace sta { + +static void +annotateGraphDisabledWireEdge(Pin *from_pin, + Pin *to_pin, + Graph *graph); + +// Annotate constraints to the timing graph. +void +Sdc::annotateGraph() +{ + Stats stats(debug_); + // All output pins are considered constrained because + // they may be downstream from a set_min/max_delay -from that + // does not have a set_output_delay. + annotateGraphConstrainOutputs(); + annotateDisables(); + annotateGraphOutputDelays(); + annotateGraphDataChecks(); + annotateHierClkLatency(); + stats.report("Annotate constraints to graph"); +} + +void +Sdc::annotateGraphConstrainOutputs() +{ + Instance *top_inst = network_->topInstance(); + InstancePinIterator *pin_iter = network_->pinIterator(top_inst); + while (pin_iter->hasNext()) { + Pin *pin = pin_iter->next(); + if (network_->direction(pin)->isAnyOutput()) + annotateGraphConstrained(pin); + } + delete pin_iter; +} + +void +Sdc::annotateDisables() +{ + PinSet::Iterator pin_iter(disabled_pins_); + while (pin_iter.hasNext()) { + Pin *pin = pin_iter.next(); + annotateGraphDisabled(pin); + } + + if (!disabled_lib_ports_.empty()) { + VertexIterator vertex_iter(graph_); + while (vertex_iter.hasNext()) { + Vertex *vertex = vertex_iter.next(); + Pin *pin = vertex->pin(); + LibertyPort *port = network_->libertyPort(pin); + if (disabled_lib_ports_.hasKey(port)) + annotateGraphDisabled(pin); + } + } + + Instance *top_inst = network_->topInstance(); + PortSet::Iterator port_iter(disabled_ports_); + while (port_iter.hasNext()) { + Port *port = port_iter.next(); + Pin *pin = network_->findPin(top_inst, port); + annotateGraphDisabled(pin); + } + + PinPairSet::Iterator pair_iter(disabled_wire_edges_); + while (pair_iter.hasNext()) { + PinPair *pair = pair_iter.next(); + annotateGraphDisabledWireEdge(pair->first, pair->second, graph_); + } + + EdgeSet::Iterator edge_iter(disabled_edges_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + edge->setIsDisabledConstraint(true); + } + + DisabledInstancePortsMap::Iterator disable_inst_iter(disabled_inst_ports_); + while (disable_inst_iter.hasNext()) { + DisabledInstancePorts *disabled_inst = disable_inst_iter.next(); + setEdgeDisabledInstPorts(disabled_inst); + } +} + +class DisableHpinEdgeVisitor : public HierPinThruVisitor +{ +public: + DisableHpinEdgeVisitor(Graph *graph); + virtual void visit(Pin *from_pin, + Pin *to_pin); + +protected: + bool annotate_; + Graph *graph_; + +private: + DISALLOW_COPY_AND_ASSIGN(DisableHpinEdgeVisitor); +}; + +DisableHpinEdgeVisitor::DisableHpinEdgeVisitor(Graph *graph) : + HierPinThruVisitor(), + graph_(graph) +{ +} + +void +DisableHpinEdgeVisitor::visit(Pin *from_pin, + Pin *to_pin) +{ + annotateGraphDisabledWireEdge(from_pin, to_pin, graph_); +} + +static void +annotateGraphDisabledWireEdge(Pin *from_pin, + Pin *to_pin, + Graph *graph) +{ + Vertex *from_vertex = graph->pinDrvrVertex(from_pin); + Vertex *to_vertex = graph->pinLoadVertex(to_pin); + if (from_vertex && to_vertex) { + VertexOutEdgeIterator edge_iter(from_vertex, graph); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->isWire() + && edge->to(graph) == to_vertex) + edge->setIsDisabledConstraint(true); + } + } +} + +void +Sdc::annotateGraphDisabled(const Pin *pin) +{ + Vertex *vertex, *bidirect_drvr_vertex; + graph_->pinVertices(pin, vertex, bidirect_drvr_vertex); + vertex->setIsDisabledConstraint(true); + if (bidirect_drvr_vertex) + bidirect_drvr_vertex->setIsDisabledConstraint(true); +} + +void +Sdc::setEdgeDisabledInstPorts(DisabledInstancePorts *disabled_inst) +{ + setEdgeDisabledInstPorts(disabled_inst, disabled_inst->instance()); +} + +void +Sdc::setEdgeDisabledInstPorts(DisabledPorts *disabled_port, + Instance *inst) +{ + if (disabled_port->all()) { + InstancePinIterator *pin_iter = network_->pinIterator(inst); + while (pin_iter->hasNext()) { + Pin *pin = pin_iter->next(); + // set_disable_timing instance does not disable timing checks. + setEdgeDisabledInstFrom(pin, false); + } + delete pin_iter; + } + + // Disable from pins. + LibertyPortSet::Iterator from_iter(disabled_port->from()); + while (from_iter.hasNext()) { + LibertyPort *from_port = from_iter.next(); + Pin *from_pin = network_->findPin(inst, from_port); + if (from_pin) + setEdgeDisabledInstFrom(from_pin, true); + } + + // Disable to pins. + LibertyPortSet::Iterator to_iter(disabled_port->to()); + while (to_iter.hasNext()) { + LibertyPort *to_port = to_iter.next(); + Pin *to_pin = network_->findPin(inst, to_port); + if (to_pin) { + if (network_->direction(to_pin)->isAnyOutput()) { + Vertex *vertex = graph_->pinDrvrVertex(to_pin); + if (vertex) { + VertexInEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + edge->setIsDisabledConstraint(true); + } + } + } + } + } + + // Disable from/to pins. + LibertyPortPairSet::Iterator from_to_iter(disabled_port->fromTo()); + while (from_to_iter.hasNext()) { + LibertyPortPair *pair = from_to_iter.next(); + const LibertyPort *from_port = pair->first; + const LibertyPort *to_port = pair->second; + Pin *from_pin = network_->findPin(inst, from_port); + Pin *to_pin = network_->findPin(inst, to_port); + if (from_pin && network_->direction(from_pin)->isAnyInput() + && to_pin) { + Vertex *from_vertex = graph_->pinLoadVertex(from_pin); + Vertex *to_vertex = graph_->pinDrvrVertex(to_pin); + if (from_vertex && to_vertex) { + VertexOutEdgeIterator edge_iter(from_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->to(graph_) == to_vertex) + edge->setIsDisabledConstraint(true); + } + } + } + } +} + +void +Sdc::setEdgeDisabledInstFrom(Pin *from_pin, + bool disable_checks) +{ + if (network_->direction(from_pin)->isAnyInput()) { + Vertex *from_vertex = graph_->pinLoadVertex(from_pin); + if (from_vertex) { + VertexOutEdgeIterator edge_iter(from_vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (disable_checks + || !edge->role()->isTimingCheck()) + edge->setIsDisabledConstraint(true); + } + } + } +} + +void +Sdc::annotateGraphOutputDelays() +{ + for (OutputDelay *output_delay : output_delays_) { + for (Pin *lpin : output_delay->leafPins()) + annotateGraphConstrained(lpin); + } +} + +void +Sdc::annotateGraphDataChecks() +{ + DataChecksMap::Iterator data_checks_iter(data_checks_to_map_); + while (data_checks_iter.hasNext()) { + DataCheckSet *checks = data_checks_iter.next(); + DataCheckSet::Iterator check_iter(checks); + // There may be multiple data checks on a single pin, + // but we only need to mark it as constrained once. + if (check_iter.hasNext()) { + DataCheck *check = check_iter.next(); + annotateGraphConstrained(check->to()); + } + } +} + +void +Sdc::annotateGraphConstrained(const PinSet *pins) +{ + PinSet::ConstIterator pin_iter(pins); + while (pin_iter.hasNext()) { + const Pin *pin = pin_iter.next(); + annotateGraphConstrained(pin); + } +} + +void +Sdc::annotateGraphConstrained(const InstanceSet *insts) +{ + InstanceSet::ConstIterator inst_iter(insts); + while (inst_iter.hasNext()) { + const Instance *inst = inst_iter.next(); + annotateGraphConstrained(inst); + } +} + +void +Sdc::annotateGraphConstrained(const Instance *inst) +{ + InstancePinIterator *pin_iter = network_->pinIterator(inst); + while (pin_iter->hasNext()) { + Pin *pin = pin_iter->next(); + if (network_->direction(pin)->isAnyInput()) + annotateGraphConstrained(pin); + } + delete pin_iter; +} + +void +Sdc::annotateGraphConstrained(const Pin *pin) +{ + Vertex *vertex, *bidirect_drvr_vertex; + graph_->pinVertices(pin, vertex, bidirect_drvr_vertex); + // Pin may be hierarchical and have no vertex. + if (vertex) + vertex->setIsConstrained(true); + if (bidirect_drvr_vertex) + bidirect_drvr_vertex->setIsConstrained(true); +} + +void +Sdc::annotateHierClkLatency() +{ + ClockLatencies::Iterator latency_iter(clk_latencies_); + while (latency_iter.hasNext()) { + ClockLatency *latency = latency_iter.next(); + const Pin *pin = latency->pin(); + if (pin && network_->isHierarchical(pin)) + annotateHierClkLatency(pin, latency); + } +} + +void +Sdc::annotateHierClkLatency(const Pin *hpin, + ClockLatency *latency) +{ + EdgesThruHierPinIterator edge_iter(hpin, network_, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + edge_clk_latency_[edge] = latency; + } +} + +ClockLatency * +Sdc::clockLatency(Edge *edge) const +{ + return edge_clk_latency_.findKey(edge); +} + +void +Sdc::clockLatency(Edge *edge, + const RiseFall *rf, + const MinMax *min_max, + // Return values. + float &latency, + bool &exists) const +{ + ClockLatency *latencies = edge_clk_latency_.findKey(edge); + if (latencies) + latencies->delay(rf, min_max, latency, exists); + else { + latency = 0.0; + exists = false; + } +} + +//////////////////////////////////////////////////////////////// + +void +Sdc::removeGraphAnnotations() +{ + VertexIterator vertex_iter(graph_); + while (vertex_iter.hasNext()) { + Vertex *vertex = vertex_iter.next(); + vertex->setIsDisabledConstraint(false); + vertex->setIsConstrained(false); + + VertexOutEdgeIterator edge_iter(vertex, graph_); + while (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + edge->setIsDisabledConstraint(false); + } + } + edge_clk_latency_.clear(); +} + +void +Sdc::searchPreamble() +{ + ensureClkHpinDisables(); + ensureClkGroupExclusions(); +} + +} // namespace diff --git a/sdc/WriteSdc.cc b/sdc/WriteSdc.cc index 71515f65..15b27e19 100644 --- a/sdc/WriteSdc.cc +++ b/sdc/WriteSdc.cc @@ -1578,7 +1578,8 @@ WriteSdc::writeEnvironment() const writeCommentSection("Environment"); writeOperatingConditions(); writeWireload(); - writePinLoads(); + writePortLoads(); + writeNetLoads(); writeDriveResistances(); writeDrivingCells(); writeInputTransitions(); @@ -1606,7 +1607,44 @@ WriteSdc::writeWireload() const } void -WriteSdc::writePinLoads() const +WriteSdc::writeNetLoads() const +{ + if (sdc_->net_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()) { 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/CheckFanoutLimits.cc b/search/CheckFanoutLimits.cc index cda77d9c..b5c2ae42 100644 --- a/search/CheckFanoutLimits.cc +++ b/search/CheckFanoutLimits.cc @@ -182,15 +182,19 @@ CheckFanoutLimits::fanoutLoad(const Pin *pin) const Pin *pin = pin_iter->next(); if (network->isLoad(pin)) { LibertyPort *port = network->libertyPort(pin); - float fanout_load; - bool exists; - port->fanoutLoad(fanout_load, exists); - if (!exists) { - LibertyLibrary *lib = port->libertyLibrary(); - lib->defaultFanoutLoad(fanout_load, exists); + 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; } - if (exists) - fanout += fanout_load; + else + fanout += 1; } } delete pin_iter; 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/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 31d032cf..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. @@ -372,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, @@ -393,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..629ce6fe 100644 --- a/search/Latches.cc +++ b/search/Latches.cc @@ -92,13 +92,13 @@ Latches::latchRequired(const Path *data_path, + open_latency + open_uncertainty + PathEnd::checkSetupMcpAdjustment(data_clk_edge, enable_clk_edge, mcp, - sdc_) + 1, sdc_) + open_crpr; debugPrint3(debug_, "latch", 1, "latch data %s %s enable %s\n", 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 57a014c1..8e1ab6be 100644 --- a/search/PathEnd.cc +++ b/search/PathEnd.cc @@ -358,7 +358,9 @@ PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path, const RiseFall *tgt_clk_rf = tgt_clk_edge->transition(); insertion = search->clockInsertion(tgt_clk, tgt_src_pin, tgt_clk_rf, min_max, early_late, tgt_path_ap); - if (clk_info->isPropagated()) { + if (clk_info->isPropagated() + // Data check target clock is always propagated. + || check_role->isDataCheck()) { // Propagated clock. Propagated arrival is seeded with // early_late==path_min_max insertion delay. Arrival clk_arrival = tgt_clk_path->arrival(sta); @@ -824,7 +826,7 @@ PathEndClkConstrainedMcp::checkMcpAdjustment(const Path *path, Sdc *sdc = sta->sdc(); if (min_max == MinMax::max()) return PathEnd::checkSetupMcpAdjustment(src_clk_edge, tgt_clk_edge, - mcp_, sdc); + mcp_, setupDefaultCycles(), sdc); else { // Hold check. // Default arrival clock is a proxy for the target clock. @@ -874,6 +876,7 @@ float PathEnd::checkSetupMcpAdjustment(const ClockEdge *src_clk_edge, const ClockEdge *tgt_clk_edge, const MultiCyclePath *mcp, + int default_cycles, Sdc *sdc) { if (mcp) { @@ -887,7 +890,7 @@ PathEnd::checkSetupMcpAdjustment(const ClockEdge *src_clk_edge, const ClockEdge *clk_edge = mcp->useEndClk() ? tgt_clk_edge : src_clk_edge; float period = clk_edge->clock()->period(); - return (mult - 1) * period; + return (mult - default_cycles) * period; } else return 0.0; @@ -1244,7 +1247,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; } @@ -1845,6 +1848,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 { @@ -1858,14 +1872,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; } @@ -1887,9 +1899,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. @@ -1982,24 +1992,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; @@ -2013,9 +2023,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 ba5ecdd5..3e274280 100644 --- a/search/Power.cc +++ b/search/Power.cc @@ -20,6 +20,7 @@ #include "Debug.hh" #include "EnumNameMap.hh" +#include "Hash.hh" #include "MinMax.hh" #include "Units.hh" #include "Transition.hh" @@ -64,7 +65,7 @@ isPositiveUnate(const LibertyCell *cell, const LibertyPort *from, const LibertyPort *to); -Power::Power(Sta *sta) : +Power::Power(StaState *sta) : StaState(sta), global_activity_{0.0, 0.0, PwrActivityOrigin::unknown}, input_activity_{0.1, 0.5, PwrActivityOrigin::input}, @@ -96,41 +97,93 @@ Power::setInputPortActivity(const Port *input_port, Instance *top_inst = network_->topInstance(); const Pin *pin = network_->findPin(top_inst, input_port); if (pin) { - activity_map_[pin] = {activity, duty, PwrActivityOrigin::user}; + user_activity_map_[pin] = {activity, duty, PwrActivityOrigin::user}; activities_valid_ = false; } } +void +Power::setUserActivity(const Pin *pin, + float activity, + float duty, + PwrActivityOrigin origin) +{ + user_activity_map_[pin] = {activity, duty, origin}; + activities_valid_ = false; +} + PwrActivity & -Power::pinActivity(const Pin *pin) +Power::userActivity(const Pin *pin) +{ + return user_activity_map_[pin]; +} + +bool +Power::hasUserActivity(const Pin *pin) +{ + return user_activity_map_.hasKey(pin); +} + +void +Power::setActivity(const Pin *pin, + PwrActivity &activity) +{ + activity_map_[pin] = activity; +} + +PwrActivity & +Power::activity(const Pin *pin) { return activity_map_[pin]; } bool -Power::hasPinActivity(const Pin *pin) +Power::hasActivity(const Pin *pin) { return activity_map_.hasKey(pin); } +// Sequential internal pins may not be in the netlist so their +// activities are stored by instance/liberty_port pairs. void -Power::setPinActivity(const Pin *pin, +Power::setSeqActivity(const Instance *reg, + LibertyPort *output, PwrActivity &activity) { - activity_map_[pin] = activity; + seq_activity_map_[SeqPin(reg, output)] = activity; activities_valid_ = false; } -void -Power::setPinActivity(const Pin *pin, - float activity, - float duty, - PwrActivityOrigin origin) +bool +Power::hasSeqActivity(const Instance *reg, + LibertyPort *output) { - activity_map_[pin] = {activity, duty, origin}; - activities_valid_ = false; + return seq_activity_map_.hasKey(SeqPin(reg, output)); } +PwrActivity +Power::seqActivity(const Instance *reg, + LibertyPort *output) +{ + return seq_activity_map_[SeqPin(reg, output)]; +} + +size_t +SeqPinHash::operator()(const SeqPin &pin) const +{ + return hashSum(hashPtr(pin.first), hashPtr(pin.second)); +} + +bool +SeqPinEqual::operator()(const SeqPin &pin1, + const SeqPin &pin2) const +{ + return pin1.first == pin2.first + && pin1.second == pin2.second; +} + +//////////////////////////////////////////////////////////////// + void Power::power(const Corner *corner, // Return values. @@ -153,7 +206,7 @@ Power::power(const Corner *corner, LibertyCell *cell = network_->libertyCell(inst); if (cell) { PowerResult inst_power; - power(inst, corner, inst_power); + power(inst, cell, corner, inst_power); if (cell->isMacro() || cell->isMemory()) macro.incr(inst_power); @@ -290,44 +343,48 @@ PropActivityVisitor::visit(Vertex *vertex) auto pin = vertex->pin(); debugPrint1(debug_, "power_activity", 3, "visit %s\n", vertex->name(network_)); - bool input_without_activity = false; - if (network_->isLoad(pin)) { - VertexInEdgeIterator edge_iter(vertex, graph_); - if (edge_iter.hasNext()) { - Edge *edge = edge_iter.next(); - if (edge->isWire()) { - Vertex *from_vertex = edge->from(graph_); - const Pin *from_pin = from_vertex->pin(); - PwrActivity &from_activity = power_->pinActivity(from_pin); - PwrActivity to_activity(from_activity.activity(), - from_activity.duty(), - PwrActivityOrigin::propagated); - if (!power_->hasPinActivity(pin)) - input_without_activity = true; - power_->setPinActivity(pin, to_activity); + if (power_->hasUserActivity(pin)) + power_->setActivity(pin, power_->userActivity(pin)); + else { + bool input_without_activity = false; + if (network_->isLoad(pin)) { + VertexInEdgeIterator edge_iter(vertex, graph_); + if (edge_iter.hasNext()) { + Edge *edge = edge_iter.next(); + if (edge->isWire()) { + Vertex *from_vertex = edge->from(graph_); + const Pin *from_pin = from_vertex->pin(); + PwrActivity &from_activity = power_->activity(from_pin); + PwrActivity to_activity(from_activity.activity(), + from_activity.duty(), + PwrActivityOrigin::propagated); + if (!power_->hasActivity(pin)) + input_without_activity = true; + power_->setActivity(pin, to_activity); + } + } + Instance *inst = network_->instance(pin); + auto cell = network_->libertyCell(inst); + if (cell && cell->hasSequentials()) { + debugPrint1(debug_, "power_activity", 3, "pending reg %s\n", + network_->pathName(inst)); + visited_regs_->insert(inst); + found_reg_without_activity_ = input_without_activity; } } - Instance *inst = network_->instance(pin); - auto cell = network_->libertyCell(inst); - if (cell && cell->hasSequentials()) { - debugPrint1(debug_, "power_activity", 3, "pending reg %s\n", - network_->pathName(inst)); - visited_regs_->insert(inst); - found_reg_without_activity_ = input_without_activity; - } - } - if (network_->isDriver(pin)) { - LibertyPort *port = network_->libertyPort(pin); - if (port) { - FuncExpr *func = port->function(); - if (func) { - Instance *inst = network_->instance(pin); - PwrActivity activity = power_->evalActivity(func, inst); - power_->setPinActivity(pin, activity); - debugPrint3(debug_, "power_activity", 3, "set %s %.2e %.2f\n", - vertex->name(network_), - activity.activity(), - activity.duty()); + if (network_->isDriver(pin)) { + LibertyPort *port = network_->libertyPort(pin); + if (port) { + FuncExpr *func = port->function(); + if (func) { + Instance *inst = network_->instance(pin); + PwrActivity activity = power_->evalActivity(func, inst); + power_->setActivity(pin, activity); + debugPrint3(debug_, "power_activity", 3, "set %s %.2e %.2f\n", + vertex->name(network_), + activity.activity(), + activity.duty()); + } } } } @@ -358,11 +415,14 @@ Power::evalActivity(FuncExpr *expr, else return PwrActivity(0.0, 0.0, PwrActivityOrigin::constant); } - Pin *pin = network_->findPin(inst, port->name()); - if (pin) - return findActivity(pin); - else - return PwrActivity(0.0, 0.0, PwrActivityOrigin::constant); + if (port->direction()->isInternal()) + return findSeqActivity(inst, port); + else { + Pin *pin = network_->findPin(inst, port); + if (pin) + return findActivity(pin); + } + return PwrActivity(0.0, 0.0, PwrActivityOrigin::constant); } case FuncExpr::op_not: { PwrActivity activity1 = evalActivity(expr->left(), inst, @@ -424,14 +484,21 @@ Power::preamble() void Power::ensureActivities() { + // No need to propagate activites if global activity is set. if (!global_activity_.isSet()) { if (!activities_valid_) { + // Clear existing activities. + activity_map_.clear(); + seq_activity_map_.clear(); + ActivitySrchPred activity_srch_pred(this); BfsFwdIterator bfs(BfsIndex::other, &activity_srch_pred, this); seedActivities(bfs); PropActivityVisitor visitor(this, &bfs); visitor.init(); + // Propagate activities through combinational logic. bfs.visit(levelize_->maxLevel(), &visitor); + // Propagate activiities through registers. while (visitor.foundRegWithoutActivity()) { InstanceSet *regs = visitor.stealVisitedRegs(); InstanceSet::Iterator reg_iter(regs); @@ -441,7 +508,10 @@ Power::ensureActivities() seedRegOutputActivities(reg, bfs); } delete regs; + visitor.init(); + // Propagate register output activities through + // combinational logic. bfs.visit(levelize_->maxLevel(), &visitor); } activities_valid_ = true; @@ -456,14 +526,14 @@ Power::seedActivities(BfsFwdIterator &bfs) const Pin *pin = vertex->pin(); // Clock activities are baked in. if (!sdc_->isLeafPinClock(pin) - && network_->direction(pin) != PortDirection::internal()) { + && !network_->direction(pin)->isInternal()) { debugPrint1(debug_, "power_activity", 3, "seed %s\n", vertex->name(network_)); - PwrActivity &activity = pinActivity(pin); - PwrActivityOrigin origin = activity.origin(); - // Default inputs without explicit activities to the input default. - if (origin != PwrActivityOrigin::user) - setPinActivity(pin, input_activity_); + if (hasUserActivity(pin)) + setActivity(pin, userActivity(pin)); + else + // Default inputs without explicit activities to the input default. + setActivity(pin, input_activity_); Vertex *vertex = graph_->pinDrvrVertex(pin); bfs.enqueueAdjacentVertices(vertex); } @@ -484,9 +554,9 @@ Power::seedRegOutputActivities(const Instance *inst, // the sequential internal pins (IQ, IQN). InstancePinIterator *pin_iter = network_->pinIterator(inst); while (pin_iter->hasNext()) { - auto pin = pin_iter->next(); - auto port = network_->libertyPort(pin); - auto func = port->function(); + Pin *pin = pin_iter->next(); + LibertyPort *port = network_->libertyPort(pin); + FuncExpr *func = port->function(); if (func) { Vertex *vertex = graph_->pinDrvrVertex(pin); if (func->port() == seq->output() @@ -507,15 +577,12 @@ Power::seedRegOutputActivities(const Instance *reg, LibertyPort *output, bool invert) { - const Pin *pin = network_->findPin(reg, output); - if (pin) { - PwrActivity activity = evalActivity(seq->data(), reg); - if (invert) - activity.set(activity.activity(), - 1.0 - activity.duty(), - activity.origin()); - setPinActivity(pin, activity); - } + PwrActivity activity = evalActivity(seq->data(), reg); + if (invert) + activity.set(activity.activity(), + 1.0 - activity.duty(), + activity.origin()); + setSeqActivity(reg, output, activity); } //////////////////////////////////////////////////////////////// @@ -597,7 +664,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++; @@ -735,7 +802,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++; @@ -951,12 +1018,24 @@ Power::findActivity(const Pin *pin) return PwrActivity(2.0, 0.5, PwrActivityOrigin::clock); else if (global_activity_.isSet()) return global_activity_; - else { - if (activity_map_.hasKey(pin)) { - PwrActivity &activity = activity_map_[pin]; - if (activity.origin() != PwrActivityOrigin::unknown) - return activity; - } + else if (activity_map_.hasKey(pin)) { + PwrActivity &activity = activity_map_[pin]; + if (activity.origin() != PwrActivityOrigin::unknown) + return activity; + } + return input_activity_; +} + +PwrActivity +Power::findSeqActivity(const Instance *inst, + LibertyPort *port) +{ + if (global_activity_.isSet()) + return global_activity_; + else if (hasSeqActivity(inst, port)) { + PwrActivity activity = seqActivity(inst, port); + if (activity.origin() != PwrActivityOrigin::unknown) + return activity; } return input_activity_; } diff --git a/include/sta/Power.hh b/search/Power.hh similarity index 75% rename from include/sta/Power.hh rename to search/Power.hh index 12625a5e..ec51b5d8 100644 --- a/include/sta/Power.hh +++ b/search/Power.hh @@ -16,58 +16,47 @@ #pragma once -#include "Sta.hh" +#include + +#include "UnorderedMap.hh" +#include "Network.hh" +#include "SdcClass.hh" +#include "PowerClass.hh" +#include "StaState.hh" namespace sta { -class PowerResult; -class PwrActivity; +class Sta; +class Corner; +class DcalcAnalysisPt; class PropActivityVisitor; class BfsFwdIterator; -typedef UnorderedMap PwrActivityMap; +typedef std::pair SeqPin; -enum class PwrActivityOrigin -{ - global, - input, - user, - propagated, - clock, - constant, - defaulted, - unknown -}; - -class PwrActivity +class SeqPinHash { public: - PwrActivity(); - PwrActivity(float activity, - float duty, - PwrActivityOrigin origin); - float activity() const { return activity_; } - float duty() const { return duty_; } - PwrActivityOrigin origin() { return origin_; } - const char *originName() const; - void set(float activity, - float duty, - PwrActivityOrigin origin); - bool isSet() const; - -private: - // In general activity is per clock cycle, NOT per second. - float activity_; - float duty_; - PwrActivityOrigin origin_; + size_t operator()(const SeqPin &pin) const; }; +class SeqPinEqual +{ +public: + bool operator()(const SeqPin &pin1, + const SeqPin &pin2) const; +}; + +typedef UnorderedMap PwrActivityMap; +typedef UnorderedMap PwrSeqActivityMap; + // The Power class has access to Sta components directly for // convenience but also requires access to the Sta class member functions. class Power : public StaState { public: - Power(Sta *sta); + Power(StaState *sta); void power(const Corner *corner, // Return values. PowerResult &total, @@ -86,20 +75,29 @@ public: void setInputPortActivity(const Port *input_port, float activity, float duty); - PwrActivity &pinActivity(const Pin *pin); - bool hasPinActivity(const Pin *pin); - void setPinActivity(const Pin *pin, - PwrActivity &activity); - void setPinActivity(const Pin *pin, - float activity, - float duty, - PwrActivityOrigin origin); + PwrActivity &activity(const Pin *pin); + void setUserActivity(const Pin *pin, + float activity, + float duty, + PwrActivityOrigin origin); // Activity is toggles per second. PwrActivity findClkedActivity(const Pin *pin); protected: void preamble(); void ensureActivities(); + bool hasUserActivity(const Pin *pin); + PwrActivity &userActivity(const Pin *pin); + void setSeqActivity(const Instance *reg, + LibertyPort *output, + PwrActivity &activity); + bool hasSeqActivity(const Instance *reg, + LibertyPort *output); + PwrActivity seqActivity(const Instance *reg, + LibertyPort *output); + bool hasActivity(const Pin *pin); + void setActivity(const Pin *pin, + PwrActivity &activity); void power(const Instance *inst, LibertyCell *cell, @@ -140,6 +138,8 @@ protected: PwrActivity findClkedActivity(const Pin *pin, const Clock *inst_clk); PwrActivity findActivity(const Pin *pin); + PwrActivity findSeqActivity(const Instance *inst, + LibertyPort *port); float portVoltage(LibertyCell *cell, const LibertyPort *port, const DcalcAnalysisPt *dcalc_ap); @@ -169,29 +169,19 @@ protected: const LibertyPort *cofactor_port); private: + // Port/pin activities set by set_pin_activity. + // set_pin_activity -global PwrActivity global_activity_; + // set_pin_activity -input PwrActivity input_activity_; + // set_pin_activity -input_ports -pins + PwrActivityMap user_activity_map_; + // Propagated activities. PwrActivityMap activity_map_; + PwrSeqActivityMap seq_activity_map_; bool activities_valid_; friend class PropActivityVisitor; }; -class PowerResult -{ -public: - PowerResult(); - void clear(); - float &internal() { return internal_; } - float &switching() { return switching_; } - float &leakage() { return leakage_; } - float total() const; - void incr(PowerResult &result); - -private: - float internal_; - float switching_; - float leakage_; -}; - } // namespace diff --git a/search/Property.cc b/search/Property.cc index 2877fc86..d56a1447 100644 --- a/search/Property.cc +++ b/search/Property.cc @@ -36,6 +36,7 @@ namespace sta { using std::string; +using std::max; static PropertyValue pinSlewProperty(const Pin *pin, @@ -566,6 +567,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 +689,13 @@ 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")) { + float drive = max(port->driveResistance(RiseFall::rise(), MinMax::max()), + port->driveResistance(RiseFall::fall(), MinMax::max())); + return PropertyValue(drive); + } else if (stringEqual(property, "drive_resistance_rise_min")) return PropertyValue(port->driveResistance(RiseFall::rise(), MinMax::min())); @@ -732,13 +742,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 +807,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 +885,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 +930,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 07b6e3d8..367d5c27 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -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 @@ -937,8 +947,8 @@ ReportPath::reportFull(const PathEndDataCheck *end, reportShort(end, expanded, result); reportSrcPathArrival(end, expanded, result); - // Capture/target clock path reporting resembles both source (reportSrcPath) - // and target (reportTgtClk) clocks. + // Data check target clock path reporting resembles + // both source (reportSrcPath) and target (reportTgtClk) clocks. // It is like a source because it can be a non-clock path. // It is like a target because crpr and uncertainty are reported. // It is always propagated, even if the clock is ideal. @@ -950,12 +960,14 @@ ReportPath::reportFull(const PathEndDataCheck *end, float src_offset = end->sourceClkOffset(this); Delay clk_delay = end->targetClkDelay(this); Arrival clk_arrival = end->targetClkArrival(this); - float offset = delayAsFloat(clk_arrival - clk_delay + src_offset); + ClockEdge *tgt_clk_edge = end->targetClkEdge(this); + float prev = delayAsFloat(clk_arrival) + src_offset; + float offset = prev - delayAsFloat(clk_delay) - tgt_clk_edge->time(); reportPath5(data_clk_path, clk_expanded, clk_expanded.startIndex(), clk_expanded.size() - 1, data_clk_path->clkInfo(search_)->isPropagated(), false, // Delay to startpoint is already included. - clk_arrival + src_offset, offset, result); + prev, offset, result); } reportRequired(end, checkRoleReason(end), result); reportSlack(end, result); @@ -2040,13 +2052,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); } @@ -2493,6 +2516,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); @@ -2500,6 +2544,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, @@ -2527,7 +2615,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, diff --git a/search/ReportPath.hh b/search/ReportPath.hh index 8f24cc9d..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, @@ -203,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, @@ -339,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, diff --git a/search/Search.cc b/search/Search.cc index e585456b..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); } @@ -3254,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_); } } @@ -3319,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; } @@ -3346,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)); @@ -3463,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()) { @@ -3487,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; } } @@ -3640,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; @@ -3735,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_)); @@ -3754,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_)); @@ -3880,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; } } @@ -3907,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/Sta.cc b/search/Sta.cc index 2d7868cb..8063d27e 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -16,7 +16,6 @@ #include "Sta.hh" -#include "util/Machine.hh" #include "DispatchQueue.hh" #include "ReportTcl.hh" #include "Debug.hh" @@ -269,6 +268,7 @@ Sta::Sta() : link_make_black_boxes_(true), update_genclks_(false), equiv_cells_(nullptr), + graph_sdc_annotated_(false), clk_pins_valid_(false) { } @@ -537,6 +537,7 @@ Sta::clear() // Constraints reference search filter, so clear search first. search_->clear(); sdc_->clear(); + graph_sdc_annotated_ = false; // corners are NOT cleared because they are used to index liberty files. levelize_->clear(); if (parasitics_) @@ -570,6 +571,7 @@ Sta::networkChanged() check_min_periods_->clear(); delete graph_; graph_ = nullptr; + graph_sdc_annotated_ = false; current_instance_ = nullptr; updateComponentsState(); } @@ -1101,37 +1103,12 @@ Sta::removeClock(Clock *clk) search_->arrivalsInvalid(); } -Clock * -Sta::findClock(const char *name) const -{ - return sdc_->findClock(name); -} - -void -Sta::findClocksMatching(PatternMatch *pattern, - ClockSeq *clks) const -{ - sdc_->findClocksMatching(pattern, clks); -} - -ClockIterator * -Sta::clockIterator() const -{ - return new ClockIterator(sdc_); -} - bool Sta::isClockSrc(const Pin *pin) const { return sdc_->isClock(pin); } -Clock * -Sta::defaultArrivalClock() const -{ - return sdc_->defaultArrivalClock(); -} - void Sta::setPropagatedClock(Clock *clk) { @@ -1200,14 +1177,33 @@ Sta::setClockLatency(Clock *clk, const MinMaxAll *min_max, float delay) { + sdcChangedGraph(); sdc_->setClockLatency(clk, pin, rf, min_max, delay); search_->arrivalsInvalid(); } +void +Sta::sdcChangedGraph() +{ + if (graph_sdc_annotated_) + sdc_->removeGraphAnnotations(); + graph_sdc_annotated_ = false; +} + +void +Sta::ensureGraphSdcAnnotated() +{ + if (!graph_sdc_annotated_) { + sdc_->annotateGraph(); + graph_sdc_annotated_ = true; + } +} + void Sta::removeClockLatency(const Clock *clk, const Pin *pin) { + sdcChangedGraph(); sdc_->removeClockLatency(clk, pin); search_->arrivalsInvalid(); } @@ -1398,6 +1394,7 @@ Sta::setDataCheck(Pin *from, const SetupHoldAll *setup_hold, float margin) { + sdcChangedGraph(); sdc_->setDataCheck(from, from_rf, to, to_rf, clk, setup_hold,margin); search_->requiredInvalid(to); } @@ -1419,6 +1416,7 @@ Sta::removeDataCheck(Pin *from, void Sta::disable(Pin *pin) { + sdcChangedGraph(); sdc_->disable(pin); // Levelization respects disabled edges. levelize_->invalid(); @@ -1429,6 +1427,7 @@ Sta::disable(Pin *pin) void Sta::removeDisable(Pin *pin) { + sdcChangedGraph(); sdc_->removeDisable(pin); disableAfter(); // Levelization respects disabled edges. @@ -1442,6 +1441,7 @@ Sta::disable(Instance *inst, LibertyPort *from, LibertyPort *to) { + sdcChangedGraph(); sdc_->disable(inst, from, to); if (from) { @@ -1470,6 +1470,7 @@ Sta::removeDisable(Instance *inst, LibertyPort *from, LibertyPort *to) { + sdcChangedGraph(); sdc_->removeDisable(inst, from, to); if (from) { @@ -1514,6 +1515,7 @@ Sta::removeDisable(LibertyCell *cell, void Sta::disable(LibertyPort *port) { + sdcChangedGraph(); sdc_->disable(port); disableAfter(); } @@ -1521,6 +1523,7 @@ Sta::disable(LibertyPort *port) void Sta::removeDisable(LibertyPort *port) { + sdcChangedGraph(); sdc_->removeDisable(port); disableAfter(); } @@ -1882,6 +1885,7 @@ Sta::setOutputDelay(Pin *pin, sdc_->setOutputDelay(pin, rf, clk, clk_rf, ref_pin, source_latency_included,network_latency_included, min_max, add, delay); + sdcChangedGraph(); search_->requiredInvalid(pin); } @@ -1893,6 +1897,7 @@ Sta::removeOutputDelay(Pin *pin, MinMaxAll *min_max) { sdc_->removeOutputDelay(pin, rf, clk, clk_rf, min_max); + sdcChangedGraph(); search_->arrivalInvalid(pin); } @@ -2083,8 +2088,7 @@ Sta::removeConstraints() search_->clear(); sim_->constantsInvalid(); if (graph_) - // Remove graph constraint annotations. - sdc_->annotateGraph(false); + sdc_->removeGraphAnnotations(); sdc_->clear(); } @@ -2403,11 +2407,6 @@ Sta::setCmdCorner(Corner *corner) cmd_corner_ = corner; } -void -Sta::setPathMinMax(const MinMaxAll *) -{ -} - //////////////////////////////////////////////////////////////// // from/thrus/to are owned and deleted by Search. @@ -2675,7 +2674,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 +2694,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 +2714,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 +2735,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 +2769,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 +2787,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 +2817,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 +2835,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 +2852,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 +2871,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 +2891,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 +2909,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 +2948,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 +2970,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 +3165,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; @@ -3174,7 +3180,6 @@ Sta::ensureGraph() makeGraph(); // Update pointers to graph. updateComponentsState(); - sdc_->annotateGraph(true); } return graph_; } @@ -3190,6 +3195,7 @@ void Sta::ensureLevelized() { ensureGraph(); + ensureGraphSdcAnnotated(); // Need constant propagation before levelization to know edges that // are disabled by constants. sim_->ensureConstantsPropagated(); @@ -3806,7 +3812,9 @@ Sta::makeInstanceAfter(Instance *inst) while (port_iter.hasNext()) { LibertyPort *lib_port = port_iter.next(); Pin *pin = network_->findPin(inst, lib_port); - connectPinAfter(pin); + // Internal pins may not exist. + if (pin) + connectPinAfter(pin); } } } @@ -4392,6 +4400,7 @@ void Sta::findRegisterPreamble() { ensureGraph(); + ensureGraphSdcAnnotated(); sim_->ensureConstantsPropagated(); } @@ -4785,7 +4794,7 @@ bool InstanceMaxSlewGreater::operator()(const Instance *inst1, const Instance *inst2) const { - return instMaxSlew(inst1) > instMaxSlew(inst2); + return delayGreater(instMaxSlew(inst1), instMaxSlew(inst2), sta_); } Slew @@ -4802,7 +4811,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; } } @@ -4971,7 +4980,6 @@ Sta::checkFanout(const Pin *pin, float &limit, float &slack) { - checkFanoutLimitPreamble(); check_fanout_limits_->checkFanout(pin, min_max, fanout, limit, slack); } @@ -5050,7 +5058,6 @@ Sta::checkCapacitance(const Pin *pin, float &limit, float &slack) { - checkCapacitanceLimitPreamble(); check_capacitance_limits_->checkCapacitance(pin, corner, min_max, corner1, rf, capacitance, limit, slack); diff --git a/search/VisitPathEnds.cc b/search/VisitPathEnds.cc index d3bd3da7..99e1152a 100644 --- a/search/VisitPathEnds.cc +++ b/search/VisitPathEnds.cc @@ -556,8 +556,8 @@ VisitPathEnds::visitDataCheckEnd1(DataCheck *check, || exception->isMultiCycle()) && (!filtered || search_->matchesFilter(path, tgt_clk_edge))) { - // No mcp for data checks. - PathEndDataCheck path_end(check, path, tgt_clk_path, nullptr, this); + MultiCyclePath *mcp=dynamic_cast(exception); + PathEndDataCheck path_end(check, path, tgt_clk_path, mcp, this); visitor->visit(&path_end); is_constrained = true; } 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/Cmds.tcl b/tcl/Cmds.tcl index 7a541783..91548b66 100644 --- a/tcl/Cmds.tcl +++ b/tcl/Cmds.tcl @@ -45,15 +45,6 @@ proc report_clock1 { clk } { } } -proc_redirect read_parasitics { - variable native - - if { $native } { - sta_warn "The read_parasitics command is deprecated. Use read_spef." - } - eval [concat read_spef $args] -} - proc check_setup_cmd { cmd cmd_args } { parse_key_args $cmd cmd_args keys {} flags {-verbose} 0 # When nothing is everything. @@ -1145,6 +1136,12 @@ proc parse_libcell_libport_inst_port_pin_edge_timing_arc_set_arg { objects \ edges timing_arc_sets } +proc parse_libcell_arg { objects } { + set libcells {} + get_object_args $objects {} libcells {} {} {} {} {} {} {} {} + return $libcells +} + proc parse_libcell_inst_arg { objects libcells_var insts_var } { upvar 1 $libcells_var libcells upvar 1 $insts_var insts diff --git a/tcl/Network.tcl b/tcl/Network.tcl index 352207a2..4dbcb7da 100644 --- a/tcl/Network.tcl +++ b/tcl/Network.tcl @@ -382,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 } { @@ -404,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/Power.tcl b/tcl/Power.tcl index 840801ba..d8bfaaa3 100644 --- a/tcl/Power.tcl +++ b/tcl/Power.tcl @@ -247,7 +247,7 @@ proc set_power_activity { args } { } } if { [info exists keys(-pins)] } { - set ports [get_pins_error "pins" $keys(-pins)] + set pins [get_pins $keys(-pins)] foreach pin $pins { if { [get_property $pin "direction"] == "input" } { set_power_pin_activity $pin $activity $duty diff --git a/tcl/Sdc.tcl b/tcl/Sdc.tcl index 1839abc3..8f2e42c0 100644 --- a/tcl/Sdc.tcl +++ b/tcl/Sdc.tcl @@ -502,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] @@ -997,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)" diff --git a/tcl/Search.tcl b/tcl/Search.tcl index 23a06b0e..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." } diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 8e6ff2e1..0e4c5f31 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -68,17 +68,16 @@ #include "PathEnd.hh" #include "PathGroup.hh" #include "PathAnalysisPt.hh" -#include "Power.hh" #include "Property.hh" #include "WritePathSpice.hh" #include "Search.hh" #include "Sta.hh" -#include "util/Machine.hh" #include "search/Tag.hh" #include "search/CheckTiming.hh" #include "search/CheckMinPulseWidths.hh" #include "search/Levelize.hh" #include "search/ReportPath.hh" +#include "search/Power.hh" namespace sta { @@ -106,6 +105,8 @@ typedef MinMaxAll MinMaxAllNull; typedef ClockSet TmpClockSet; typedef StringSeq TmpStringSeq; +using std::vector; + class CmdErrorNetworkNotLinked : public Exception { public: @@ -188,6 +189,30 @@ tclListSeq(Tcl_Obj *const source, return nullptr; } +template +vector * +tclListStdSeq(Tcl_Obj *const source, + swig_type_info *swig_type, + Tcl_Interp *interp) +{ + int argc; + Tcl_Obj **argv; + + if (Tcl_ListObjGetElements(interp, source, &argc, &argv) == TCL_OK + && argc > 0) { + vector *seq = new vector; + for (int i = 0; i < argc; i++) { + void *obj; + // Ignore returned TCL_ERROR because can't get swig_type_info. + SWIG_ConvertPtr(argv[i], &obj, swig_type, false); + seq->push_back(reinterpret_cast(obj)); + } + return seq; + } + else + return nullptr; +} + LibertyLibrarySeq * tclListSeqLibertyLibrary(Tcl_Obj *const source, Tcl_Interp *interp) @@ -195,11 +220,11 @@ tclListSeqLibertyLibrary(Tcl_Obj *const source, return tclListSeq(source, SWIGTYPE_p_LibertyLibrary, interp); } -LibertyCellSeq * +vector * tclListSeqLibertyCell(Tcl_Obj *const source, Tcl_Interp *interp) { - return tclListSeq(source, SWIGTYPE_p_LibertyCell, interp); + return tclListStdSeq(source, SWIGTYPE_p_LibertyCell, interp); } template @@ -442,6 +467,10 @@ using namespace sta; delete cells; } +%typemap(in) vector * { + $1 = tclListSeqLibertyCell($input, interp); +} + %typemap(out) LibertyCellSeq* { Tcl_Obj *list = Tcl_NewListObj(0, nullptr); LibertyCellSeq *cells = $1; @@ -1065,6 +1094,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; @@ -4799,8 +4830,8 @@ set_power_pin_activity(const Pin *pin, float activity, float duty) { - return Sta::sta()->power()->setPinActivity(pin, activity, duty, - PwrActivityOrigin::user); + return Sta::sta()->power()->setUserActivity(pin, activity, duty, + PwrActivityOrigin::user); } //////////////////////////////////////////////////////////////// @@ -5309,6 +5340,20 @@ delays_invalid() 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/util/Report.cc b/util/Report.cc index 0d8d07eb..fea3d287 100644 --- a/util/Report.cc +++ b/util/Report.cc @@ -19,7 +19,6 @@ #include // min #include "Error.hh" -#include "Machine.hh" namespace sta { diff --git a/util/Stats.cc b/util/Stats.cc index 5b647f63..d27f89f0 100644 --- a/util/Stats.cc +++ b/util/Stats.cc @@ -16,9 +16,9 @@ #include "Stats.hh" +#include "Machine.hh" #include "StringUtil.hh" #include "Debug.hh" -#include "Machine.hh" namespace sta { diff --git a/util/StringUtil.cc b/util/StringUtil.cc index 151b9a08..95f8d13e 100644 --- a/util/StringUtil.cc +++ b/util/StringUtil.cc @@ -20,8 +20,8 @@ #include #include -#include "Mutex.hh" #include "Machine.hh" +#include "Mutex.hh" namespace sta { diff --git a/verilog/Verilog.i b/verilog/Verilog.i index 34f7609a..2d740479 100644 --- a/verilog/Verilog.i +++ b/verilog/Verilog.i @@ -51,13 +51,14 @@ delete_verilog_reader() void write_verilog_cmd(const char *filename, - bool sort) + bool sort, + vector *remove_cells) { // This does NOT want the SDC (cmd) network because it wants // to see the sta internal names. Sta *sta = Sta::sta(); Network *network = sta->network(); - writeVerilog(filename, sort, network); + writeVerilog(filename, sort, remove_cells, network); } %} // inline diff --git a/verilog/Verilog.tcl b/verilog/Verilog.tcl index 3f46461a..59c5f0a8 100644 --- a/verilog/Verilog.tcl +++ b/verilog/Verilog.tcl @@ -19,15 +19,19 @@ namespace eval sta { # Defined by SWIG interface Verilog.i. define_cmd_args "read_verilog" {filename} -define_cmd_args "write_verilog" {[-sort] filename} +define_cmd_args "write_verilog" {[-sort] [-remove_cells cells] filename} proc write_verilog { args } { - parse_key_args "write_verilog" args keys {} flags {-sort} + parse_key_args "write_verilog" args keys {-remove_cells} flags {-sort} + set remove_cells {} + if { [info exists keys(-remove_cells)] } { + set remove_cells [sta::parse_libcell_arg $keys(-remove_cells)] + } set sort [info exists flags(-sort)] check_argc_eq1 "write_verilog" $args set filename $args - write_verilog_cmd $filename $sort + write_verilog_cmd $filename $sort $remove_cells } # sta namespace end diff --git a/verilog/VerilogWriter.cc b/verilog/VerilogWriter.cc index 52ffc0f4..36ed2093 100644 --- a/verilog/VerilogWriter.cc +++ b/verilog/VerilogWriter.cc @@ -32,6 +32,7 @@ class VerilogWriter public: VerilogWriter(const char *filename, bool sort, + vector *remove_cells, FILE *stream, Network *network); void writeModule(Instance *inst); @@ -54,6 +55,7 @@ protected: const char *filename_; bool sort_; + CellSet remove_cells_; FILE *stream_; Network *network_; @@ -65,12 +67,13 @@ protected: void writeVerilog(const char *filename, bool sort, + vector *remove_cells, Network *network) { if (network->topInstance()) { FILE *stream = fopen(filename, "w"); if (stream) { - VerilogWriter writer(filename, sort, stream, network); + VerilogWriter writer(filename, sort, remove_cells, stream, network); writer.writeModule(network->topInstance()); fclose(stream); } @@ -81,6 +84,7 @@ writeVerilog(const char *filename, VerilogWriter::VerilogWriter(const char *filename, bool sort, + vector *remove_cells, FILE *stream, Network *network) : filename_(filename), @@ -89,6 +93,10 @@ VerilogWriter::VerilogWriter(const char *filename, network_(network), unconnected_net_index_(1) { + if (remove_cells) { + for(LibertyCell *lib_cell : *remove_cells) + remove_cells_.insert(network->cell(lib_cell)); + } } void @@ -165,12 +173,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 @@ -197,23 +213,25 @@ void VerilogWriter::writeChild(Instance *child) { Cell *child_cell = network_->cell(child); - const char *child_name = network_->name(child); - const char *child_vname = instanceVerilogName(child_name, - network_->pathEscape()); - fprintf(stream_, " %s %s (", - network_->name(child_cell), - child_vname); - bool first_port = true; - CellPortIterator *port_iter = network_->portIterator(child_cell); - while (port_iter->hasNext()) { - Port *port = port_iter->next(); - if (network_->hasMembers(port)) - writeInstBusPin(child, port, first_port); - else - writeInstPin(child, port, first_port); + if (!remove_cells_.hasKey(child_cell)) { + const char *child_name = network_->name(child); + const char *child_vname = instanceVerilogName(child_name, + network_->pathEscape()); + fprintf(stream_, " %s %s (", + network_->name(child_cell), + child_vname); + bool first_port = true; + CellPortIterator *port_iter = network_->portIterator(child_cell); + while (port_iter->hasNext()) { + Port *port = port_iter->next(); + if (network_->hasMembers(port)) + writeInstBusPin(child, port, first_port); + else + writeInstPin(child, port, first_port); + } + delete port_iter; + fprintf(stream_, ");\n"); } - delete port_iter; - fprintf(stream_, ");\n"); } void