merge
This commit is contained in:
commit
ff7557bb1f
|
|
@ -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}
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include <tcl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "util/Machine.hh"
|
||||
#include "StringUtil.hh"
|
||||
#include "Vector.hh"
|
||||
#include "Sta.hh"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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_)
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "Machine.hh"
|
||||
#include "DisallowCopyAssign.hh"
|
||||
#include "Map.hh"
|
||||
#include "StringUtil.hh"
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "StaConfig.hh"
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "StaConfig.hh"
|
||||
|
||||
#if (SSTA == 1)
|
||||
// Delays are Normal PDFs.
|
||||
#include "DelayNormal1.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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#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
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
#include "NetworkClass.hh"
|
||||
#include "SearchClass.hh"
|
||||
#include "SdcClass.hh"
|
||||
#include "Power.hh"
|
||||
#include "PowerClass.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include "Machine.hh"
|
||||
#include "DisallowCopyAssign.hh"
|
||||
|
||||
struct Tcl_Interp;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -119,7 +119,8 @@ enum class ReportPathFormat { full,
|
|||
shorter,
|
||||
endpoint,
|
||||
summary,
|
||||
slack_only
|
||||
slack_only,
|
||||
json
|
||||
};
|
||||
|
||||
static const int tag_index_bits = 24;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#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_;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include "Machine.hh"
|
||||
#include "Vector.hh"
|
||||
|
||||
namespace sta {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Machine.hh"
|
||||
#include "DisallowCopyAssign.hh"
|
||||
#include "Vector.hh"
|
||||
#include "Transition.hh"
|
||||
|
|
|
|||
|
|
@ -16,13 +16,19 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace sta {
|
||||
|
||||
using std::vector;
|
||||
|
||||
class Network;
|
||||
class LibertyCell;
|
||||
|
||||
void
|
||||
writeVerilog(const char *filename,
|
||||
bool sort,
|
||||
vector<LibertyCell*> *remove_cells,
|
||||
Network *network);
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "FuncExpr.hh"
|
||||
|
||||
#include <algorithm> // 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;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <functional>
|
||||
|
||||
#include "Machine.hh"
|
||||
#include "DisallowCopyAssign.hh"
|
||||
#include "Vector.hh"
|
||||
#include "Map.hh"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Machine.hh"
|
||||
#include "Zlib.hh"
|
||||
#include "Map.hh"
|
||||
#include "StringSeq.hh"
|
||||
|
|
|
|||
|
|
@ -699,9 +699,4 @@ sortClockSet(ClockSet *set,
|
|||
sort(clks, ClockNameLess());
|
||||
}
|
||||
|
||||
ClockPinIterator::ClockPinIterator(Clock *clk) :
|
||||
PinSet::Iterator(clk->pins())
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -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<RiseFall::index_count;rf_index++) {
|
||||
for (int mm_index = 0; mm_index < MinMax::index_count; mm_index++) {
|
||||
if (exists_[rf_index][mm_index]) {
|
||||
max_value = std::max(max_value, values_[rf_index][mm_index]);
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RiseFallMinMax::empty() const
|
||||
{
|
||||
|
|
|
|||
481
sdc/Sdc.cc
481
sdc/Sdc.cc
|
|
@ -31,7 +31,6 @@
|
|||
#include "Transition.hh"
|
||||
#include "PortDirection.hh"
|
||||
#include "Network.hh"
|
||||
#include "HpinDrvrLoad.hh"
|
||||
#include "RiseFallMinMax.hh"
|
||||
#include "Clock.hh"
|
||||
#include "ClockLatency.hh"
|
||||
|
|
@ -46,9 +45,10 @@
|
|||
#include "ClockGatingCheck.hh"
|
||||
#include "ClockGroups.hh"
|
||||
#include "DeratingFactors.hh"
|
||||
#include "Graph.hh"
|
||||
#include "HpinDrvrLoad.hh"
|
||||
#include "search/Levelize.hh"
|
||||
#include "Corner.hh"
|
||||
#include "Graph.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
|
|
@ -77,11 +77,6 @@ typedef Set<Pvt*> 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
|
||||
|
|
|
|||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#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
|
||||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
241
search/Power.cc
241
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_;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,58 +16,47 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Sta.hh"
|
||||
#include <utility>
|
||||
|
||||
#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<const Pin*,PwrActivity> PwrActivityMap;
|
||||
typedef std::pair<const Instance*, LibertyPort*> 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<const Pin*,PwrActivity> PwrActivityMap;
|
||||
typedef UnorderedMap<SeqPin, PwrActivity,
|
||||
SeqPinHash, SeqPinEqual> 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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
119
search/Sta.cc
119
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);
|
||||
|
|
|
|||
|
|
@ -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<MultiCyclePath*>(exception);
|
||||
PathEndDataCheck path_end(check, path, tgt_clk_path, mcp, this);
|
||||
visitor->visit(&path_end);
|
||||
is_constrained = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
15
tcl/Cmds.tcl
15
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
|
||||
|
|
|
|||
|
|
@ -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 } {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
13
tcl/Sdc.tcl
13
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)"
|
||||
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
}
|
||||
|
|
|
|||
57
tcl/StaTcl.i
57
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 <class TYPE>
|
||||
vector<TYPE> *
|
||||
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<TYPE> *seq = new vector<TYPE>;
|
||||
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<TYPE>(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<LibertyLibrary*>(source, SWIGTYPE_p_LibertyLibrary, interp);
|
||||
}
|
||||
|
||||
LibertyCellSeq *
|
||||
vector<LibertyCell*> *
|
||||
tclListSeqLibertyCell(Tcl_Obj *const source,
|
||||
Tcl_Interp *interp)
|
||||
{
|
||||
return tclListSeq<LibertyCell*>(source, SWIGTYPE_p_LibertyCell, interp);
|
||||
return tclListStdSeq<LibertyCell*>(source, SWIGTYPE_p_LibertyCell, interp);
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
|
|
@ -442,6 +467,10 @@ using namespace sta;
|
|||
delete cells;
|
||||
}
|
||||
|
||||
%typemap(in) vector<LibertyCell*> * {
|
||||
$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
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include <algorithm> // min
|
||||
|
||||
#include "Error.hh"
|
||||
#include "Machine.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@
|
|||
|
||||
#include "Stats.hh"
|
||||
|
||||
#include "Machine.hh"
|
||||
#include "StringUtil.hh"
|
||||
#include "Debug.hh"
|
||||
#include "Machine.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@
|
|||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Mutex.hh"
|
||||
#include "Machine.hh"
|
||||
#include "Mutex.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
|
|
|
|||
|
|
@ -51,13 +51,14 @@ delete_verilog_reader()
|
|||
|
||||
void
|
||||
write_verilog_cmd(const char *filename,
|
||||
bool sort)
|
||||
bool sort,
|
||||
vector<LibertyCell*> *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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class VerilogWriter
|
|||
public:
|
||||
VerilogWriter(const char *filename,
|
||||
bool sort,
|
||||
vector<LibertyCell*> *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<LibertyCell*> *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<LibertyCell*> *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
|
||||
|
|
|
|||
Loading…
Reference in New Issue