merge
This commit is contained in:
commit
57a12d9c66
|
|
@ -152,6 +152,8 @@ set(STA_SOURCE
|
|||
search/CheckMaxSkews.cc
|
||||
search/CheckMinPeriods.cc
|
||||
search/CheckMinPulseWidths.cc
|
||||
search/CheckCapacitanceLimits.cc
|
||||
search/CheckFanoutLimits.cc
|
||||
search/CheckSlewLimits.cc
|
||||
search/CheckTiming.cc
|
||||
search/ClkInfo.cc
|
||||
|
|
@ -511,6 +513,9 @@ install(DIRECTORY include/sta DESTINATION include)
|
|||
|
||||
################################################################
|
||||
|
||||
add_custom_target(tags etags -o TAGS ${STA_SOURCE} */*.hh include/sta/*.hh ${SWIG_TCL_FILES}
|
||||
add_custom_target(tags etags -o TAGS
|
||||
${STA_SOURCE}
|
||||
*/*.hh include/sta/*.hh
|
||||
${STA_TCL_FILES} ${SWIG_TCL_FILES}
|
||||
WORKING_DIRECTORY ${STA_HOME}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -244,7 +244,8 @@ DmpCeffTwoPoleDelayCalc::findParasitic(const Pin *drvr_pin,
|
|||
parasitic_ap);
|
||||
// Estimated parasitics are not recorded in the "database", so
|
||||
// it for deletion after the drvr pin delay calc is finished.
|
||||
unsaved_parasitics_.push_back(parasitic);
|
||||
if (parasitic)
|
||||
unsaved_parasitics_.push_back(parasitic);
|
||||
return parasitic;
|
||||
}
|
||||
}
|
||||
|
|
@ -346,7 +347,7 @@ DmpCeffTwoPoleDelayCalc::loadDelay(Parasitic *pole_residue,
|
|||
{
|
||||
ComplexFloat pole2, residue2;
|
||||
parasitics_->poleResidue(pole_residue, 1, pole2, residue2);
|
||||
if (!fuzzyZero(drvr_slew_)
|
||||
if (!delayZero(drvr_slew_)
|
||||
&& pole2.imag() == 0.0
|
||||
&& residue2.imag() == 0.0) {
|
||||
double p2 = pole2.real();
|
||||
|
|
|
|||
|
|
@ -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_)
|
||||
|
|
|
|||
|
|
@ -90,7 +90,8 @@ LumpedCapDelayCalc::findParasitic(const Pin *drvr_pin,
|
|||
parasitic_ap);
|
||||
// Estimated parasitics are not recorded in the "database", so
|
||||
// it for deletion after the drvr pin delay calc is finished.
|
||||
unsaved_parasitics_.push_back(parasitic);
|
||||
if (parasitic)
|
||||
unsaved_parasitics_.push_back(parasitic);
|
||||
return parasitic;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
|
|
@ -35,70 +35,6 @@ initDelayConstants()
|
|||
delay_init_values[MinMax::maxIndex()] = MinMax::max()->initValue();
|
||||
}
|
||||
|
||||
const Delay &
|
||||
delayInitValue(const MinMax *min_max)
|
||||
{
|
||||
return delay_init_values[min_max->index()];
|
||||
}
|
||||
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
return fuzzyEqual(delay, min_max->initValue());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyGreater(delay1, delay2);
|
||||
else
|
||||
return fuzzyLess(delay1, delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyGreaterEqual(delay1, delay2);
|
||||
else
|
||||
return fuzzyLessEqual(delay1, delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyLess(delay1, delay2);
|
||||
else
|
||||
return fuzzyGreater(delay1, delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyLessEqual(delay1, delay2);
|
||||
else
|
||||
return fuzzyGreaterEqual(delay1, delay2);
|
||||
}
|
||||
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return delay1 / delay2;
|
||||
}
|
||||
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta)
|
||||
|
|
@ -124,19 +60,130 @@ delayAsString(const Delay &delay,
|
|||
return unit->asString(delay, digits);
|
||||
}
|
||||
|
||||
float
|
||||
delayAsFloat(const Delay &delay,
|
||||
const EarlyLate *,
|
||||
const Delay &
|
||||
delayInitValue(const MinMax *min_max)
|
||||
{
|
||||
return delay_init_values[min_max->index()];
|
||||
}
|
||||
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
return fuzzyEqual(delay, min_max->initValue());
|
||||
}
|
||||
|
||||
bool
|
||||
delayZero(const Delay &delay)
|
||||
{
|
||||
return fuzzyZero(delay);
|
||||
}
|
||||
|
||||
bool
|
||||
delayInf(const Delay &delay)
|
||||
{
|
||||
return fuzzyInf(delay);
|
||||
}
|
||||
|
||||
bool
|
||||
delayEqual(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyEqual(delay1, delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *)
|
||||
{
|
||||
return fuzzyLess(delay1, delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyLess(delay1, delay2);
|
||||
else
|
||||
return fuzzyGreater(delay1, delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *)
|
||||
{
|
||||
return fuzzyLessEqual(delay1, delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyLessEqual(delay1, delay2);
|
||||
else
|
||||
return fuzzyGreaterEqual(delay1, delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *)
|
||||
{
|
||||
return delay;
|
||||
return fuzzyGreater(delay1, delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyGreater(delay1, delay2);
|
||||
else
|
||||
return fuzzyLess(delay1, delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *)
|
||||
{
|
||||
return fuzzyGreaterEqual(delay1, delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyGreaterEqual(delay1, delay2);
|
||||
else
|
||||
return fuzzyLessEqual(delay1, delay2);
|
||||
}
|
||||
|
||||
Delay
|
||||
delayRemove(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return delay1 - delay2;
|
||||
}
|
||||
|
||||
float
|
||||
delaySigma2(const Delay &,
|
||||
const EarlyLate *)
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return 0.0;
|
||||
return delay1 / delay2;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -162,32 +162,7 @@ Delay::operator-=(const Delay &delay)
|
|||
bool
|
||||
Delay::operator==(const Delay &delay) const
|
||||
{
|
||||
return mean_ == delay.mean_
|
||||
&& sigma2_ == delay.sigma2_;
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator>(const Delay &delay) const
|
||||
{
|
||||
return mean_ > delay.mean_;
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator>=(const Delay &delay) const
|
||||
{
|
||||
return mean_ >= delay.mean_;
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator<(const Delay &delay) const
|
||||
{
|
||||
return mean_ < delay.mean_;
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator<=(const Delay &delay) const
|
||||
{
|
||||
return mean_ <= delay.mean_;
|
||||
return delayEqual(*this, delay);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -208,166 +183,6 @@ makeDelay2(float delay,
|
|||
return Delay(delay, sigma2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
return fuzzyEqual(delay.mean(), min_max->initValue())
|
||||
&& delay.sigma2() == 0.0;
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyZero(const Delay &delay)
|
||||
{
|
||||
return fuzzyZero(delay.mean())
|
||||
&& fuzzyZero(delay.sigma2());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyInf(const Delay &delay)
|
||||
{
|
||||
return fuzzyInf(delay.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyEqual(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyEqual(delay1.mean(), delay2.mean())
|
||||
&& fuzzyEqual(delay1.sigma2(), delay2.sigma2());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyLess(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyLess(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyLessEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyLessEqual(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyLessEqual(delay1.mean(), delay2.mean());
|
||||
else
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyGreater(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyGreater(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyGreater(delay1.mean(), delay2.mean());
|
||||
else
|
||||
return fuzzyLess(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
|
||||
else
|
||||
return fuzzyLessEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyLess(delay1.mean(), delay2.mean());
|
||||
else
|
||||
return fuzzyGreater(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
Delay
|
||||
operator+(float delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1 + delay2.mean(),
|
||||
delay2.sigma2());
|
||||
}
|
||||
|
||||
Delay
|
||||
operator/(float delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1 / delay2.mean(),
|
||||
delay2.sigma2());
|
||||
}
|
||||
|
||||
Delay
|
||||
operator*(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return Delay(delay1.mean() * delay2,
|
||||
delay1.sigma2() * delay2 * delay2);
|
||||
}
|
||||
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return delay1.mean() / delay2.mean();
|
||||
}
|
||||
|
||||
float
|
||||
delayAsFloat(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
|
|
@ -425,6 +240,195 @@ delayAsString(const Delay &delay,
|
|||
return sta->units()->timeUnit()->asString(mean_sigma, digits);
|
||||
}
|
||||
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
return fuzzyEqual(delay.mean(), min_max->initValue())
|
||||
&& delay.sigma2() == 0.0;
|
||||
}
|
||||
|
||||
bool
|
||||
delayZero(const Delay &delay)
|
||||
{
|
||||
return fuzzyZero(delay.mean())
|
||||
&& fuzzyZero(delay.sigma2());
|
||||
}
|
||||
|
||||
bool
|
||||
delayInf(const Delay &delay)
|
||||
{
|
||||
return fuzzyInf(delay.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
delayEqual(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyEqual(delay1.mean(), delay2.mean())
|
||||
&& fuzzyEqual(delay1.sigma2(), delay2.sigma2());
|
||||
}
|
||||
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
|
||||
delayAsFloat(delay2, EarlyLate::early(), sta));
|
||||
}
|
||||
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
float delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
|
||||
delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return delayLess(delay1, delay2, sta);
|
||||
else
|
||||
return delayGreater(delay1, delay2, sta);
|
||||
}
|
||||
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
|
||||
delayAsFloat(delay2, EarlyLate::early(), sta));
|
||||
}
|
||||
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
float delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
|
||||
delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return delayLessEqual(delay1, delay2, sta);
|
||||
else
|
||||
return delayGreaterEqual(delay1, delay2, sta);
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta)
|
||||
|
||||
{
|
||||
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
|
||||
delayAsFloat(delay2, EarlyLate::late(), sta));
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
float delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
|
||||
delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
|
||||
delayAsFloat(delay2, EarlyLate::late(), sta));
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
float delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
|
||||
delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return delayGreater(delay1, delay2, sta);
|
||||
else
|
||||
return delayLess(delay1, delay2, sta);
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return delayGreaterEqual(delay1, delay2, sta);
|
||||
else
|
||||
return delayLessEqual(delay1, delay2, sta);
|
||||
}
|
||||
|
||||
Delay
|
||||
delayRemove(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1.mean() - delay2.mean(),
|
||||
delay1.sigma2() - delay2.sigma2());
|
||||
}
|
||||
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return delay1.mean() / delay2.mean();
|
||||
}
|
||||
|
||||
Delay
|
||||
operator+(float delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1 + delay2.mean(),
|
||||
delay2.sigma2());
|
||||
}
|
||||
|
||||
Delay
|
||||
operator/(float delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1 / delay2.mean(),
|
||||
delay2.sigma2());
|
||||
}
|
||||
|
||||
Delay
|
||||
operator*(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return Delay(delay1.mean() * delay2,
|
||||
delay1.sigma2() * delay2 * delay2);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // (SSTA == 1)
|
||||
|
|
|
|||
|
|
@ -187,30 +187,6 @@ Delay::operator==(const Delay &delay) const
|
|||
&& sigma2_[late_index] == delay.sigma2_[early_index];
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator>(const Delay &delay) const
|
||||
{
|
||||
return mean_ > delay.mean_;
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator>=(const Delay &delay) const
|
||||
{
|
||||
return mean_ >= delay.mean_;
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator<(const Delay &delay) const
|
||||
{
|
||||
return mean_ < delay.mean_;
|
||||
}
|
||||
|
||||
bool
|
||||
Delay::operator<=(const Delay &delay) const
|
||||
{
|
||||
return mean_ <= delay.mean_;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
Delay
|
||||
|
|
@ -234,12 +210,12 @@ delayIsInitValue(const Delay &delay,
|
|||
const MinMax *min_max)
|
||||
{
|
||||
return fuzzyEqual(delay.mean(), min_max->initValue())
|
||||
&& delay.sigma2Early() == 0.0
|
||||
&& delay.sigma2Late() == 0.0;
|
||||
&& fuzzyZero(delay.sigma2Early())
|
||||
&& fuzzyZero(delay.sigma2Late());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyZero(const Delay &delay)
|
||||
delayZero(const Delay &delay)
|
||||
{
|
||||
return fuzzyZero(delay.mean())
|
||||
&& fuzzyZero(delay.sigma2Early())
|
||||
|
|
@ -247,13 +223,13 @@ fuzzyZero(const Delay &delay)
|
|||
}
|
||||
|
||||
bool
|
||||
fuzzyInf(const Delay &delay)
|
||||
delayInf(const Delay &delay)
|
||||
{
|
||||
return fuzzyInf(delay.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyEqual(const Delay &delay1,
|
||||
delayEqual(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyEqual(delay1.mean(), delay2.mean())
|
||||
|
|
@ -262,137 +238,123 @@ fuzzyEqual(const Delay &delay1,
|
|||
}
|
||||
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyLess(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyLess(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyLessEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyLessEqual(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyLessEqual(delay1.mean(), delay2.mean());
|
||||
else
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyGreater(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyGreater(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyGreater(delay1.mean(), delay2.mean());
|
||||
else
|
||||
return fuzzyLess(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyGreaterEqual(delay1.mean(), delay2.mean());
|
||||
else
|
||||
return fuzzyLessEqual(delay1.mean(), delay2.mean());
|
||||
}
|
||||
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max)
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
|
||||
delayAsFloat(delay2, EarlyLate::early(), sta));
|
||||
}
|
||||
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
float delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyLess(delayAsFloat(delay1, EarlyLate::early(), sta),
|
||||
delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return fuzzyLess(delay1.mean(), delay2.mean());
|
||||
return delayLess(delay1, delay2, sta);
|
||||
else
|
||||
return fuzzyGreater(delay1.mean(), delay2.mean());
|
||||
return delayGreater(delay1, delay2, sta);
|
||||
}
|
||||
|
||||
Delay
|
||||
operator+(float delay1,
|
||||
const Delay &delay2)
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return Delay(delay1 + delay2.mean(),
|
||||
delay2.sigma2Early(),
|
||||
delay2.sigma2Late());
|
||||
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
|
||||
delayAsFloat(delay2, EarlyLate::early(), sta));
|
||||
}
|
||||
|
||||
Delay
|
||||
operator/(float delay1,
|
||||
const Delay &delay2)
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
float delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return Delay(delay1 / delay2.mean(),
|
||||
delay2.sigma2Early(),
|
||||
delay2.sigma2Late());
|
||||
return fuzzyLessEqual(delayAsFloat(delay1, EarlyLate::early(), sta),
|
||||
delay2);
|
||||
}
|
||||
|
||||
Delay
|
||||
operator*(const Delay &delay1,
|
||||
float delay2)
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta)
|
||||
{
|
||||
return Delay(delay1.mean() * delay2,
|
||||
delay1.sigma2Early() * delay2 * delay2,
|
||||
delay1.sigma2Late() * delay2 * delay2);
|
||||
if (min_max == MinMax::max())
|
||||
return delayLessEqual(delay1, delay2, sta);
|
||||
else
|
||||
return delayGreaterEqual(delay1, delay2, sta);
|
||||
}
|
||||
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return delay1.mean() / delay2.mean();
|
||||
return fuzzyGreater(delayAsFloat(delay1, EarlyLate::late(), sta),
|
||||
delayAsFloat(delay2, EarlyLate::late(), sta));
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
float delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
|
||||
delayAsFloat(delay2, EarlyLate::late(), sta));
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
|
||||
delayAsFloat(delay2, EarlyLate::late(), sta));
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
float delay2,
|
||||
const StaState *sta)
|
||||
{
|
||||
return fuzzyGreaterEqual(delayAsFloat(delay1, EarlyLate::late(), sta),
|
||||
delay2);
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return delayGreater(delay1, delay2, sta);
|
||||
else
|
||||
return delayLess(delay1, delay2, sta);
|
||||
}
|
||||
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta)
|
||||
{
|
||||
if (min_max == MinMax::max())
|
||||
return delayGreaterEqual(delay1, delay2, sta);
|
||||
else
|
||||
return delayLessEqual(delay1, delay2, sta);
|
||||
}
|
||||
|
||||
float
|
||||
|
|
@ -454,6 +416,49 @@ delayAsString(const Delay &delay,
|
|||
return sta->units()->timeUnit()->asString(mean_sigma, digits);
|
||||
}
|
||||
|
||||
Delay
|
||||
delayRemove(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1.mean() - delay2.mean(),
|
||||
delay1.sigma2Early() - delay2.sigma2Early(),
|
||||
delay1.sigma2Late() - delay2.sigma2Late());
|
||||
}
|
||||
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return delay1.mean() / delay2.mean();
|
||||
}
|
||||
|
||||
Delay
|
||||
operator+(float delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1 + delay2.mean(),
|
||||
delay2.sigma2Early(),
|
||||
delay2.sigma2Late());
|
||||
}
|
||||
|
||||
Delay
|
||||
operator/(float delay1,
|
||||
const Delay &delay2)
|
||||
{
|
||||
return Delay(delay1 / delay2.mean(),
|
||||
delay2.sigma2Early(),
|
||||
delay2.sigma2Late());
|
||||
}
|
||||
|
||||
Delay
|
||||
operator*(const Delay &delay1,
|
||||
float delay2)
|
||||
{
|
||||
return Delay(delay1.mean() * delay2,
|
||||
delay1.sigma2Early() * delay2 * delay2,
|
||||
delay1.sigma2Late() * delay2 * delay2);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // (SSTA == 2)
|
||||
|
|
|
|||
|
|
@ -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,46 +67,74 @@ delayAsFloat(const Delay &delay)
|
|||
}
|
||||
|
||||
// mean late+/early- sigma
|
||||
float
|
||||
inline float
|
||||
delayAsFloat(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const StaState *sta);
|
||||
float
|
||||
delaySigma2(const Delay &delay,
|
||||
const EarlyLate *early_late);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta,
|
||||
int digits);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const StaState *sta,
|
||||
int digits);
|
||||
const EarlyLate *,
|
||||
const StaState *)
|
||||
{
|
||||
return delay;
|
||||
}
|
||||
|
||||
inline float
|
||||
delaySigma2(const Delay &,
|
||||
const EarlyLate *)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
const Delay &
|
||||
delayInitValue(const MinMax *min_max);
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
delayZero(const Delay &delay);
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
delayInf(const Delay &delay);
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
delayEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
const StaState *sta);
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
|
||||
// delay1-delay2 subtracting sigma instead of addiing.
|
||||
Delay
|
||||
delayRemove(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
|
|
|
|||
|
|
@ -47,10 +47,6 @@ public:
|
|||
void operator-=(float delay);
|
||||
void operator-=(const Delay &delay);
|
||||
bool operator==(const Delay &delay) const;
|
||||
bool operator>(const Delay &delay) const;
|
||||
bool operator>=(const Delay &delay) const;
|
||||
bool operator<(const Delay &delay) const;
|
||||
bool operator<=(const Delay &delay) const;
|
||||
|
||||
private:
|
||||
float mean_;
|
||||
|
|
@ -63,6 +59,19 @@ const Delay delay_zero(0.0);
|
|||
void
|
||||
initDelayConstants();
|
||||
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta,
|
||||
int digits);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const StaState *sta,
|
||||
int digits);
|
||||
|
||||
Delay
|
||||
makeDelay(float delay,
|
||||
float sigma_early,
|
||||
|
|
@ -75,7 +84,74 @@ makeDelay2(float delay,
|
|||
float sigma_late);
|
||||
|
||||
inline float
|
||||
delayAsFloat(const Delay &delay) { return delay.mean(); }
|
||||
delayAsFloat(const Delay &delay)
|
||||
{
|
||||
return delay.mean();
|
||||
}
|
||||
|
||||
// mean late+/early- sigma
|
||||
float
|
||||
delayAsFloat(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const StaState *sta);
|
||||
float
|
||||
delaySigma2(const Delay &delay,
|
||||
const EarlyLate *early_late);
|
||||
const Delay &
|
||||
delayInitValue(const MinMax *min_max);
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayZero(const Delay &delay);
|
||||
bool
|
||||
delayInf(const Delay &delay);
|
||||
bool
|
||||
delayEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
|
||||
// delay1-delay2 subtracting sigma instead of addiing.
|
||||
Delay delayRemove(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
|
||||
// Most non-operator functions on Delay are not defined as member
|
||||
// functions so they can be defined on floats, where there is no class
|
||||
|
|
@ -90,68 +166,4 @@ Delay operator/(float delay1,
|
|||
Delay operator*(const Delay &delay1,
|
||||
float delay2);
|
||||
|
||||
// mean late+/early- sigma
|
||||
float
|
||||
delayAsFloat(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const StaState *sta);
|
||||
float
|
||||
delaySigma2(const Delay &delay,
|
||||
const EarlyLate *early_late);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta,
|
||||
int digits);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const StaState *sta,
|
||||
int digits);
|
||||
const Delay &
|
||||
delayInitValue(const MinMax *min_max);
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
fuzzyZero(const Delay &delay);
|
||||
bool
|
||||
fuzzyInf(const Delay &delay);
|
||||
bool
|
||||
fuzzyEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -50,10 +50,6 @@ public:
|
|||
void operator-=(float delay);
|
||||
void operator-=(const Delay &delay);
|
||||
bool operator==(const Delay &delay) const;
|
||||
bool operator>(const Delay &delay) const;
|
||||
bool operator>=(const Delay &delay) const;
|
||||
bool operator<(const Delay &delay) const;
|
||||
bool operator<=(const Delay &delay) const;
|
||||
|
||||
protected:
|
||||
static const int early_index = 0;
|
||||
|
|
@ -70,6 +66,19 @@ const Delay delay_zero(0.0);
|
|||
void
|
||||
initDelayConstants();
|
||||
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta,
|
||||
int digits);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const StaState *sta,
|
||||
int digits);
|
||||
|
||||
Delay
|
||||
makeDelay(float delay,
|
||||
float sigma_early,
|
||||
|
|
@ -82,7 +91,74 @@ makeDelay2(float delay,
|
|||
float sigma_late);
|
||||
|
||||
inline float
|
||||
delayAsFloat(const Delay &delay) { return delay.mean(); }
|
||||
delayAsFloat(const Delay &delay)
|
||||
{
|
||||
return delay.mean();
|
||||
}
|
||||
|
||||
// mean late+/early- sigma
|
||||
float
|
||||
delayAsFloat(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const StaState *sta);
|
||||
float
|
||||
delaySigma2(const Delay &delay,
|
||||
const EarlyLate *early_late);
|
||||
const Delay &
|
||||
delayInitValue(const MinMax *min_max);
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
delayZero(const Delay &delay);
|
||||
bool
|
||||
delayInf(const Delay &delay);
|
||||
bool
|
||||
delayEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
bool
|
||||
delayGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
|
||||
// delay1-delay2 subtracting sigma instead of addiing.
|
||||
Delay delayRemove(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
|
||||
// Most non-operator functions on Delay are not defined as member
|
||||
// functions so they can be defined on floats, where there is no class
|
||||
|
|
@ -97,68 +173,4 @@ Delay operator/(float delay1,
|
|||
Delay operator*(const Delay &delay1,
|
||||
float delay2);
|
||||
|
||||
// mean late+/early- sigma
|
||||
float
|
||||
delayAsFloat(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const StaState *sta);
|
||||
float
|
||||
delaySigma2(const Delay &delay,
|
||||
const EarlyLate *early_late);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const StaState *sta,
|
||||
int digits);
|
||||
const char *
|
||||
delayAsString(const Delay &delay,
|
||||
const EarlyLate *early_late,
|
||||
const StaState *sta,
|
||||
int digits);
|
||||
const Delay &
|
||||
delayInitValue(const MinMax *min_max);
|
||||
bool
|
||||
delayIsInitValue(const Delay &delay,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
fuzzyZero(const Delay &delay);
|
||||
bool
|
||||
fuzzyInf(const Delay &delay);
|
||||
bool
|
||||
fuzzyEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
fuzzyLess(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
fuzzyLessEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
bool
|
||||
fuzzyGreaterEqual(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
bool
|
||||
fuzzyGreater(const Delay &delay1,
|
||||
const Delay &delay2,
|
||||
const MinMax *min_max);
|
||||
float
|
||||
delayRatio(const Delay &delay1,
|
||||
const Delay &delay2);
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -202,7 +202,9 @@ public:
|
|||
void defaultMaxFanout(float &fanout,
|
||||
bool &exists) const;
|
||||
void setDefaultMaxFanout(float fanout);
|
||||
float defaultFanoutLoad() const { return default_fanout_load_; }
|
||||
void defaultFanoutLoad(// Return values.
|
||||
float &fanout,
|
||||
bool &exists) const;
|
||||
void setDefaultFanoutLoad(float load);
|
||||
|
||||
// Logic thresholds.
|
||||
|
|
@ -307,6 +309,7 @@ protected:
|
|||
RiseFallValues default_inout_pin_res_;
|
||||
RiseFallValues default_output_pin_res_;
|
||||
float default_fanout_load_;
|
||||
bool default_fanout_load_exists_;
|
||||
float default_max_cap_;
|
||||
bool default_max_cap_exists_;
|
||||
float default_max_fanout_;
|
||||
|
|
@ -402,6 +405,8 @@ public:
|
|||
void setDontUse(bool dont_use);
|
||||
bool isMacro() const { return is_macro_; }
|
||||
void setIsMacro(bool is_macro);
|
||||
bool isMemory() const { return is_memory_; }
|
||||
void setIsMemory(bool is_memory);
|
||||
bool isPad() const { return is_pad_; }
|
||||
void setIsPad(bool is_pad);
|
||||
bool interfaceTiming() const { return interface_timing_; }
|
||||
|
|
@ -488,6 +493,7 @@ public:
|
|||
Report *report,
|
||||
Debug *debug);
|
||||
bool isBuffer() const;
|
||||
bool isInverter() const;
|
||||
// Only valid when isBuffer() returns true.
|
||||
void bufferPorts(// Return values.
|
||||
LibertyPort *&input,
|
||||
|
|
@ -517,11 +523,14 @@ protected:
|
|||
void makeTimingArcPortMaps();
|
||||
bool hasBufferFunc(const LibertyPort *input,
|
||||
const LibertyPort *output) const;
|
||||
bool hasInverterFunc(const LibertyPort *input,
|
||||
const LibertyPort *output) const;
|
||||
|
||||
LibertyLibrary *liberty_library_;
|
||||
float area_;
|
||||
bool dont_use_;
|
||||
bool is_macro_;
|
||||
bool is_memory_;
|
||||
bool is_pad_;
|
||||
bool has_internal_ports_;
|
||||
bool interface_timing_;
|
||||
|
|
@ -623,6 +632,11 @@ public:
|
|||
LibertyLibrary *libertyLibrary() const { return liberty_cell_->libertyLibrary(); }
|
||||
LibertyPort *findLibertyMember(int index) const;
|
||||
LibertyPort *findLibertyBusBit(int index) const;
|
||||
void fanoutLoad(// Return values.
|
||||
float &fanout_load,
|
||||
bool &exists) const;
|
||||
void setFanoutLoad(float fanout_load);
|
||||
float capacitance() const;
|
||||
float capacitance(const RiseFall *rf,
|
||||
const MinMax *min_max) const;
|
||||
void capacitance(const RiseFall *rf,
|
||||
|
|
@ -748,6 +762,8 @@ protected:
|
|||
RiseFallMinMax capacitance_;
|
||||
MinMaxFloatValues slew_limit_; // inputs and outputs
|
||||
MinMaxFloatValues cap_limit_; // outputs
|
||||
float fanout_load_; // inputs
|
||||
bool fanout_load_exists_;
|
||||
MinMaxFloatValues fanout_limit_; // outputs
|
||||
float min_period_;
|
||||
float min_pulse_width_[RiseFall::index_count];
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -425,6 +425,7 @@ private:
|
|||
|
||||
// Path constrained by an output delay.
|
||||
// If there is a reference pin, clk_path_ is the reference pin clock.
|
||||
// If there is a path delay PathEndPathDelay is used instead of this.
|
||||
class PathEndOutputDelay : public PathEndClkConstrainedMcp
|
||||
{
|
||||
public:
|
||||
|
|
@ -555,6 +556,7 @@ private:
|
|||
|
||||
// Path constrained by set_min/max_delay.
|
||||
// "Clocked" when path delay ends at timing check pin.
|
||||
// May end at output with set_output_delay.
|
||||
class PathEndPathDelay : public PathEndClkConstrained
|
||||
{
|
||||
public:
|
||||
|
|
@ -587,6 +589,7 @@ public:
|
|||
virtual PathDelay *pathDelay() const { return path_delay_; }
|
||||
virtual ArcDelay margin(const StaState *sta) const;
|
||||
virtual float sourceClkOffset(const StaState *sta) const;
|
||||
virtual ClockEdge *targetClkEdge(const StaState *sta) const;
|
||||
virtual float targetClkTime(const StaState *sta) const;
|
||||
virtual Arrival targetClkArrivalNoCrpr(const StaState *sta) const;
|
||||
virtual float targetClkOffset(const StaState *sta) const;
|
||||
|
|
@ -594,6 +597,7 @@ public:
|
|||
virtual Required requiredTime(const StaState *sta) const;
|
||||
virtual int exceptPathCmp(const PathEnd *path_end,
|
||||
const StaState *sta) const;
|
||||
bool hasOutputDelay() const { return output_delay_ != nullptr; }
|
||||
|
||||
protected:
|
||||
PathEndPathDelay(PathDelay *path_delay,
|
||||
|
|
@ -610,8 +614,7 @@ protected:
|
|||
PathDelay *path_delay_;
|
||||
TimingArc *check_arc_;
|
||||
Edge *check_edge_;
|
||||
// Output delay is nullptr when there is no timing check or output
|
||||
// delay at the endpoint.
|
||||
// Output delay is nullptr when there is no output delay at the endpoint.
|
||||
OutputDelay *output_delay_;
|
||||
// Source clk arrival for set_min/max_delay -ignore_clk_latency.
|
||||
Arrival src_clk_arrival_;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -295,15 +295,6 @@ public:
|
|||
void setSlewLimit(Port *port,
|
||||
const MinMax *min_max,
|
||||
float slew);
|
||||
void slewLimit(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &slew,
|
||||
bool &exists);
|
||||
void setSlewLimit(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
float slew);
|
||||
void slewLimitPins(ConstPinSeq &pins);
|
||||
void slewLimit(Cell *cell,
|
||||
const MinMax *min_max,
|
||||
float &slew,
|
||||
|
|
@ -1329,7 +1320,6 @@ protected:
|
|||
OutputDelaysPinMap output_delay_leaf_pin_map_;
|
||||
|
||||
PortSlewLimitMap port_slew_limit_map_;
|
||||
PinSlewLimitMap pin_slew_limit_map_;
|
||||
CellSlewLimitMap cell_slew_limit_map_;
|
||||
bool have_clk_slew_limits_;
|
||||
CellCapLimitMap cell_cap_limit_map_;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ class ReportPath;
|
|||
class CheckTiming;
|
||||
class DcalcAnalysisPt;
|
||||
class CheckSlewLimits;
|
||||
class CheckFanoutLimits;
|
||||
class CheckCapacitanceLimits;
|
||||
class CheckMinPulseWidths;
|
||||
class CheckMinPeriods;
|
||||
class CheckMaxSkews;
|
||||
|
|
@ -245,9 +247,6 @@ public:
|
|||
void setSlewLimit(Port *port,
|
||||
const MinMax *min_max,
|
||||
float slew);
|
||||
void setSlewLimit(Pin *pin,
|
||||
const MinMax *min_max,
|
||||
float slew);
|
||||
void setSlewLimit(Cell *cell,
|
||||
const MinMax *min_max,
|
||||
float slew);
|
||||
|
|
@ -612,6 +611,7 @@ public:
|
|||
// Return value.
|
||||
ClockSet &clks);
|
||||
|
||||
void checkSlewLimitPreamble();
|
||||
// Return the pin with the min/max slew limit slack.
|
||||
// corner=nullptr checks all corners.
|
||||
Pin *pinMinSlewLimitSlack(const Corner *corner,
|
||||
|
|
@ -627,15 +627,63 @@ public:
|
|||
void reportSlewLimitVerbose(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
void checkSlews(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&tr,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack);
|
||||
// requires checkSlewLimitPreamble()
|
||||
void checkSlew(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
bool check_clks,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&tr,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack);
|
||||
|
||||
void checkFanoutLimitPreamble();
|
||||
// Return the pin with the min/max fanout limit slack.
|
||||
Pin *pinMinFanoutLimitSlack(const MinMax *min_max);
|
||||
// Return all pins with min/max fanout violations.
|
||||
PinSeq *pinFanoutLimitViolations(const MinMax *min_max);
|
||||
void reportFanoutLimitShortHeader();
|
||||
void reportFanoutLimitShort(Pin *pin,
|
||||
const MinMax *min_max);
|
||||
void reportFanoutLimitVerbose(Pin *pin,
|
||||
const MinMax *min_max);
|
||||
// requires checkFanoutLimitPreamble()
|
||||
void checkFanout(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &fanout,
|
||||
float &limit,
|
||||
float &slack);
|
||||
|
||||
void checkCapacitanceLimitPreamble();
|
||||
// Return the pin with the min/max capacitance limit slack.
|
||||
// corner=nullptr checks all corners.
|
||||
Pin *pinMinCapacitanceLimitSlack(const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
// Return all pins with min/max capacitance violations.
|
||||
// corner=nullptr checks all corners.
|
||||
PinSeq *pinCapacitanceLimitViolations(const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
void reportCapacitanceLimitShortHeader();
|
||||
void reportCapacitanceLimitShort(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
void reportCapacitanceLimitVerbose(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
// requires checkCapacitanceLimitPreamble()
|
||||
void checkCapacitance(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&tr,
|
||||
float &capacitance,
|
||||
float &limit,
|
||||
float &slack);
|
||||
|
||||
// Min pulse width check with the least slack.
|
||||
// corner=nullptr checks all corners.
|
||||
MinPulseWidthCheck *minPulseWidthSlack(const Corner *corner);
|
||||
|
|
@ -1227,6 +1275,8 @@ protected:
|
|||
virtual void makeLatches();
|
||||
virtual void makeCheckTiming();
|
||||
virtual void makeCheckSlewLimits();
|
||||
virtual void makeCheckFanoutLimits();
|
||||
virtual void makeCheckCapacitanceLimits();
|
||||
virtual void makeCheckMinPulseWidths();
|
||||
virtual void makeCheckMinPeriods();
|
||||
virtual void makeCheckMaxSkews();
|
||||
|
|
@ -1268,7 +1318,6 @@ protected:
|
|||
Edge *d_q_edge,
|
||||
const ClockEdge *en_clk_edge);
|
||||
void clockSlewChanged(Clock *clk);
|
||||
void checkSlewLimitPreamble();
|
||||
void minPulseWidthPreamble();
|
||||
void minPeriodPreamble();
|
||||
void maxSkewPreamble();
|
||||
|
|
@ -1324,6 +1373,8 @@ protected:
|
|||
Corner *cmd_corner_;
|
||||
CheckTiming *check_timing_;
|
||||
CheckSlewLimits *check_slew_limits_;
|
||||
CheckFanoutLimits *check_fanout_limits_;
|
||||
CheckCapacitanceLimits *check_capacitance_limits_;
|
||||
CheckMinPulseWidths *check_min_pulse_widths_;
|
||||
CheckMinPeriods *check_min_periods_;
|
||||
CheckMaxSkews *check_max_skews_;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace sta {
|
|||
class Unit
|
||||
{
|
||||
public:
|
||||
Unit();
|
||||
Unit(const char *suffix);
|
||||
~Unit();
|
||||
Unit(float scale,
|
||||
const char *suffix,
|
||||
|
|
@ -29,10 +29,12 @@ public:
|
|||
void operator=(const Unit &unit);
|
||||
float scale() const { return scale_; }
|
||||
void setScale(float scale);
|
||||
const char *scaleAbreviation();
|
||||
const char *suffix() const { return suffix_; }
|
||||
void setSuffix(const char *suffix);
|
||||
int digits() const { return digits_; }
|
||||
void setDigits(int digits);
|
||||
// Does not include suffix.
|
||||
int width() const;
|
||||
const char *asString(float value) const;
|
||||
const char *asString(double value) const;
|
||||
|
|
@ -50,7 +52,7 @@ private:
|
|||
class Units
|
||||
{
|
||||
public:
|
||||
Units() {}
|
||||
Units();
|
||||
Unit *find(const char *unit_name);
|
||||
void operator=(const Units &units);
|
||||
Unit *timeUnit() { return &time_unit_; }
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ LibertyLibrary::LibertyLibrary(const char *name,
|
|||
default_output_pin_cap_(0.0),
|
||||
default_bidirect_pin_cap_(0.0),
|
||||
default_fanout_load_(0.0),
|
||||
default_fanout_load_exists_(false),
|
||||
default_max_cap_(0.0),
|
||||
default_max_cap_exists_(false),
|
||||
default_max_fanout_(0.0),
|
||||
|
|
@ -425,10 +426,20 @@ LibertyLibrary::setDefaultMaxCapacitance(float cap)
|
|||
default_max_cap_exists_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyLibrary::defaultFanoutLoad(// Return values.
|
||||
float &fanout,
|
||||
bool &exists) const
|
||||
{
|
||||
fanout = default_fanout_load_;
|
||||
exists = default_fanout_load_exists_;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyLibrary::setDefaultFanoutLoad(float load)
|
||||
{
|
||||
default_fanout_load_ = load;
|
||||
default_fanout_load_exists_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -839,6 +850,7 @@ LibertyCell::LibertyCell(LibertyLibrary *library,
|
|||
area_(0.0),
|
||||
dont_use_(false),
|
||||
is_macro_(false),
|
||||
is_memory_(false),
|
||||
is_pad_(false),
|
||||
has_internal_ports_(false),
|
||||
interface_timing_(false),
|
||||
|
|
@ -984,6 +996,12 @@ LibertyCell::setIsMacro(bool is_macro)
|
|||
is_macro_ = is_macro;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyCell::setIsMemory(bool is_memory)
|
||||
{
|
||||
is_memory_ = is_memory;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyCell::LibertyCell::setIsPad(bool is_pad)
|
||||
{
|
||||
|
|
@ -1046,6 +1064,27 @@ LibertyCell::hasBufferFunc(const LibertyPort *input,
|
|||
&& func->port() == input;
|
||||
}
|
||||
|
||||
bool
|
||||
LibertyCell::isInverter() const
|
||||
{
|
||||
LibertyPort *input;
|
||||
LibertyPort *output;
|
||||
bufferPorts(input, output);
|
||||
return input && output
|
||||
&& hasInverterFunc(input, output);
|
||||
}
|
||||
|
||||
bool
|
||||
LibertyCell::hasInverterFunc(const LibertyPort *input,
|
||||
const LibertyPort *output) const
|
||||
{
|
||||
FuncExpr *func = output->function();
|
||||
return func
|
||||
&& func->op() == FuncExpr::op_not
|
||||
&& func->left()->op() == FuncExpr::op_port
|
||||
&& func->left()->port() == input;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyCell::bufferPorts(// Return values.
|
||||
LibertyPort *&input,
|
||||
|
|
@ -1811,8 +1850,8 @@ LibertyPort::LibertyPort(LibertyCell *cell,
|
|||
function_(nullptr),
|
||||
tristate_enable_(nullptr),
|
||||
scaled_ports_(nullptr),
|
||||
// capacitance_ intentionally not initialized so
|
||||
// liberty reader can apply default capacitance.
|
||||
fanout_load_(0.0),
|
||||
fanout_load_exists_(false),
|
||||
min_period_(0.0),
|
||||
pulse_clk_trigger_(nullptr),
|
||||
pulse_clk_sense_(nullptr),
|
||||
|
|
@ -1889,6 +1928,18 @@ LibertyPort::setCapacitance(const RiseFall *rf,
|
|||
}
|
||||
}
|
||||
|
||||
float
|
||||
LibertyPort::capacitance() const
|
||||
{
|
||||
float cap;
|
||||
bool exists;
|
||||
capacitance_.maxValue(cap, exists);
|
||||
if (exists)
|
||||
return cap;
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float
|
||||
LibertyPort::capacitance(const RiseFall *rf,
|
||||
const MinMax *min_max) const
|
||||
|
|
@ -2040,6 +2091,22 @@ LibertyPort::setCapacitanceLimit(float cap,
|
|||
cap_limit_.setValue(min_max, cap);
|
||||
}
|
||||
|
||||
void
|
||||
LibertyPort::fanoutLoad(// Return values.
|
||||
float &fanout_load,
|
||||
bool &exists) const
|
||||
{
|
||||
fanout_load = fanout_load_;
|
||||
exists = fanout_load_exists_;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyPort::setFanoutLoad(float fanout_load)
|
||||
{
|
||||
fanout_load_ = fanout_load;
|
||||
fanout_load_exists_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyPort::fanoutLimit(const MinMax *min_max,
|
||||
// Return values.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -286,6 +286,7 @@ LibertyReader::defineVisitors()
|
|||
defineAttrVisitor("area", &LibertyReader::visitArea);
|
||||
defineAttrVisitor("dont_use", &LibertyReader::visitDontUse);
|
||||
defineAttrVisitor("is_macro", &LibertyReader::visitIsMacro);
|
||||
defineAttrVisitor("is_memory", &LibertyReader::visitIsMemory);
|
||||
defineAttrVisitor("is_pad", &LibertyReader::visitIsPad);
|
||||
defineAttrVisitor("interface_timing", &LibertyReader::visitInterfaceTiming);
|
||||
defineAttrVisitor("scaling_factors", &LibertyReader::visitScalingFactors);
|
||||
|
|
@ -307,6 +308,7 @@ LibertyReader::defineVisitors()
|
|||
&LibertyReader::visitRiseCapRange);
|
||||
defineAttrVisitor("fall_capacitance_range",
|
||||
&LibertyReader::visitFallCapRange);
|
||||
defineAttrVisitor("fanout_load", &LibertyReader::visitFanoutLoad);
|
||||
defineAttrVisitor("max_fanout", &LibertyReader::visitMaxFanout);
|
||||
defineAttrVisitor("min_fanout", &LibertyReader::visitMinFanout);
|
||||
defineAttrVisitor("max_transition", &LibertyReader::visitMaxTransition);
|
||||
|
|
@ -2026,7 +2028,7 @@ LibertyReader::parseCellFuncs()
|
|||
while (func_iter.hasNext()) {
|
||||
LibertyFunc *func = func_iter.next();
|
||||
FuncExpr *expr = parseFunc(func->expr(), func->attrName(), func->line());
|
||||
if (func->invert()) {
|
||||
if (func->invert() && expr) {
|
||||
if (expr->op() == FuncExpr::op_not) {
|
||||
FuncExpr *inv = expr;
|
||||
expr = expr->left();
|
||||
|
|
@ -2425,6 +2427,17 @@ LibertyReader::visitIsMacro(LibertyAttr *attr)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitIsMemory(LibertyAttr *attr)
|
||||
{
|
||||
if (cell_) {
|
||||
bool is_memory, exists;
|
||||
getAttrBool(attr, is_memory, exists);
|
||||
if (exists)
|
||||
cell_->setIsMemory(is_memory);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitIsPad(LibertyAttr *attr)
|
||||
{
|
||||
|
|
@ -2967,6 +2980,21 @@ LibertyReader::defaultCap(LibertyPort *port)
|
|||
return cap;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitFanoutLoad(LibertyAttr *attr)
|
||||
{
|
||||
if (ports_) {
|
||||
float fanout;
|
||||
bool exists;
|
||||
getAttrFloat(attr, fanout, exists);
|
||||
if (exists) {
|
||||
visitPorts([&] (LibertyPort *port) {
|
||||
port->setFanoutLoad(fanout);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyReader::visitMaxFanout(LibertyAttr *attr)
|
||||
{
|
||||
|
|
@ -3906,7 +3934,7 @@ LibertyReader::makeFloatTable(LibertyAttr *attr,
|
|||
}
|
||||
else if (value->isFloat())
|
||||
// Scalar value.
|
||||
row->push_back(value->floatValue());
|
||||
row->push_back(value->floatValue() * scale);
|
||||
else
|
||||
libWarn(attr, "%s is not a list of floats.\n", attr->name());
|
||||
if (row->size() != cols) {
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ public:
|
|||
virtual void visitArea(LibertyAttr *attr);
|
||||
virtual void visitDontUse(LibertyAttr *attr);
|
||||
virtual void visitIsMacro(LibertyAttr *attr);
|
||||
virtual void visitIsMemory(LibertyAttr *attr);
|
||||
virtual void visitIsPad(LibertyAttr *attr);
|
||||
virtual void visitInterfaceTiming(LibertyAttr *attr);
|
||||
virtual void visitScalingFactors(LibertyAttr *attr);
|
||||
|
|
@ -206,6 +207,7 @@ public:
|
|||
virtual void visitFallCap(LibertyAttr *attr);
|
||||
virtual void visitRiseCapRange(LibertyAttr *attr);
|
||||
virtual void visitFallCapRange(LibertyAttr *attr);
|
||||
virtual void visitFanoutLoad(LibertyAttr *attr);
|
||||
virtual void visitMaxFanout(LibertyAttr *attr);
|
||||
virtual void visitMinFanout(LibertyAttr *attr);
|
||||
virtual void visitFanout(LibertyAttr *attr,
|
||||
|
|
|
|||
|
|
@ -21,15 +21,17 @@
|
|||
|
||||
#include "StringUtil.hh"
|
||||
#include "MinMax.hh" // INF
|
||||
#include "Fuzzy.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
using std::abs;
|
||||
|
||||
Unit::Unit() :
|
||||
|
||||
Unit::Unit(const char *suffix) :
|
||||
scale_(1.0),
|
||||
suffix_(stringCopy("")),
|
||||
digits_(4)
|
||||
suffix_(stringCopy(suffix)),
|
||||
digits_(3)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -62,6 +64,29 @@ Unit::setScale(float scale)
|
|||
scale_ = scale;
|
||||
}
|
||||
|
||||
const char *
|
||||
Unit::scaleAbreviation()
|
||||
{
|
||||
if (fuzzyEqual(scale_, 1E+6))
|
||||
return "M";
|
||||
else if (fuzzyEqual(scale_, 1E+3))
|
||||
return "k";
|
||||
if (fuzzyEqual(scale_, 1.0))
|
||||
return "";
|
||||
else if (fuzzyEqual(scale_, 1E-3))
|
||||
return "m";
|
||||
else if (fuzzyEqual(scale_, 1E-6))
|
||||
return "u";
|
||||
else if (fuzzyEqual(scale_, 1E-9))
|
||||
return "n";
|
||||
else if (fuzzyEqual(scale_, 1E-12))
|
||||
return "p";
|
||||
else if (fuzzyEqual(scale_, 1E-15))
|
||||
return "f";
|
||||
else
|
||||
return "?";
|
||||
}
|
||||
|
||||
void
|
||||
Unit::setSuffix(const char *suffix)
|
||||
{
|
||||
|
|
@ -78,7 +103,7 @@ Unit::setDigits(int digits)
|
|||
int
|
||||
Unit::width() const
|
||||
{
|
||||
return digits_ + (suffix_ ? strlen(suffix_) : 0) + 2;
|
||||
return digits_ + 2;
|
||||
}
|
||||
|
||||
const char *
|
||||
|
|
@ -105,12 +130,25 @@ Unit::asString(float value,
|
|||
// prevent "-0.00" on slowaris
|
||||
if (abs(scaled_value) < 1E-6)
|
||||
scaled_value = 0.0;
|
||||
return stringPrintTmp("%.*f%s", digits, scaled_value, suffix_);
|
||||
return stringPrintTmp("%.*f", digits, scaled_value);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
Units::Units() :
|
||||
time_unit_("s"),
|
||||
capacitance_unit_("F"),
|
||||
voltage_unit_("v"),
|
||||
resistance_unit_("ohm"),
|
||||
pulling_resistance_unit_("ohm"),
|
||||
current_unit_("A"),
|
||||
power_unit_("W"),
|
||||
distance_unit_("m"),
|
||||
scalar_unit_("")
|
||||
{
|
||||
}
|
||||
|
||||
Unit *
|
||||
Units::find(const char *unit_name)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1670,10 +1670,13 @@ ConcreteParasitics::estimatePiElmore(const Pin *drvr_pin,
|
|||
c2, rpi, c1,
|
||||
elmore_res, elmore_cap, elmore_use_load_cap);
|
||||
|
||||
return new ConcretePiElmoreEstimated(c2, rpi, c1, elmore_res, elmore_cap,
|
||||
elmore_use_load_cap,
|
||||
rf, op_cond, corner, min_max,
|
||||
sdc_);
|
||||
if (c1 > 0.0 || c2 > 0.0)
|
||||
return new ConcretePiElmoreEstimated(c2, rpi, c1, elmore_res, elmore_cap,
|
||||
elmore_use_load_cap,
|
||||
rf, op_cond, corner, min_max,
|
||||
sdc_);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -150,7 +150,8 @@ EstimateParasitics::estimatePiElmoreBalanced(const Pin *drvr_pin,
|
|||
float &elmore_cap,
|
||||
bool &elmore_use_load_cap)
|
||||
{
|
||||
if (wireload_res == 0.0) {
|
||||
if (wireload_res == 0.0
|
||||
|| fanout == 0) {
|
||||
// No resistance, so load is capacitance only.
|
||||
c2 = wireload_cap + net_pin_cap;
|
||||
rpi = 0.0;
|
||||
|
|
|
|||
|
|
@ -1931,8 +1931,8 @@ ExceptionThru::matches(const Pin *from_pin,
|
|||
EdgePins edge_pins(const_cast<Pin*>(from_pin), const_cast<Pin*>(to_pin));
|
||||
return ((pins_ && pins_->hasKey(const_cast<Pin*>(to_pin)))
|
||||
|| (edges_ && edges_->hasKey(&edge_pins))
|
||||
|| (nets_ && nets_->hasKey(network->net(to_pin)))
|
||||
|| (insts_ && insts_->hasKey(network->instance(to_pin))))
|
||||
|| (nets_ && to_pin && nets_->hasKey(network->net(to_pin)))
|
||||
|| (insts_ && to_pin && insts_->hasKey(network->instance(to_pin))))
|
||||
&& rf_->matches(to_rf);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
34
sdc/Sdc.cc
34
sdc/Sdc.cc
|
|
@ -807,40 +807,6 @@ Sdc::setSlewLimit(Port *port,
|
|||
values.setValue(min_max, slew);
|
||||
}
|
||||
|
||||
void
|
||||
Sdc::slewLimit(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
float &slew,
|
||||
bool &exists)
|
||||
{
|
||||
slew = 0.0;
|
||||
MinMaxFloatValues values;
|
||||
pin_slew_limit_map_.findKey(pin, values, exists);
|
||||
if (exists)
|
||||
values.value(min_max, slew, exists);
|
||||
}
|
||||
|
||||
void
|
||||
Sdc::setSlewLimit(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
float slew)
|
||||
{
|
||||
MinMaxFloatValues &values = pin_slew_limit_map_[pin];
|
||||
values.setValue(min_max, slew);
|
||||
}
|
||||
|
||||
void
|
||||
Sdc::slewLimitPins(ConstPinSeq &pins)
|
||||
{
|
||||
PinSlewLimitMap::Iterator iter(pin_slew_limit_map_);
|
||||
while (iter.hasNext()) {
|
||||
const Pin *pin;
|
||||
MinMaxFloatValues values;
|
||||
iter.next(pin, values);
|
||||
pins.push_back(pin);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Sdc::slewLimit(Cell *cell,
|
||||
const MinMax *min_max,
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
@ -2239,24 +2277,6 @@ WriteSdc::writeSlewLimits() const
|
|||
}
|
||||
delete port_iter;
|
||||
|
||||
ConstPinSeq pins;
|
||||
sdc_->slewLimitPins(pins);
|
||||
sort(pins, PinPathNameLess(network_));
|
||||
ConstPinSeq::Iterator pin_iter(pins);
|
||||
while (pin_iter.hasNext()) {
|
||||
const Pin *pin = pin_iter.next();
|
||||
float slew;
|
||||
bool exists;
|
||||
sdc_->slewLimit(pin, min_max, slew, exists);
|
||||
if (exists) {
|
||||
fprintf(stream_, "set_max_transition ");
|
||||
writeTime(slew);
|
||||
fprintf(stream_, " ");
|
||||
writeGetPin(pin, false);
|
||||
fprintf(stream_, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
writeClkSlewLimits();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,330 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2020, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "CheckCapacitanceLimits.hh"
|
||||
|
||||
#include "Fuzzy.hh"
|
||||
#include "Liberty.hh"
|
||||
#include "Network.hh"
|
||||
#include "Sdc.hh"
|
||||
#include "DcalcAnalysisPt.hh"
|
||||
#include "GraphDelayCalc.hh"
|
||||
#include "StaState.hh"
|
||||
#include "Corner.hh"
|
||||
#include "PortDirection.hh"
|
||||
#include "Sim.hh"
|
||||
#include "Graph.hh"
|
||||
#include "GraphDelayCalc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class PinCapacitanceLimitSlackLess
|
||||
{
|
||||
public:
|
||||
PinCapacitanceLimitSlackLess(const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
CheckCapacitanceLimits *check_capacitance_limit,
|
||||
const StaState *sta);
|
||||
bool operator()(Pin *pin1,
|
||||
Pin *pin2) const;
|
||||
|
||||
private:
|
||||
const Corner *corner_;
|
||||
const MinMax *min_max_;
|
||||
CheckCapacitanceLimits *check_capacitance_limit_;
|
||||
const StaState *sta_;
|
||||
|
||||
};
|
||||
|
||||
PinCapacitanceLimitSlackLess::PinCapacitanceLimitSlackLess(const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
CheckCapacitanceLimits *check_capacitance_limit,
|
||||
const StaState *sta) :
|
||||
corner_(corner),
|
||||
min_max_(min_max),
|
||||
check_capacitance_limit_(check_capacitance_limit),
|
||||
sta_(sta)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
PinCapacitanceLimitSlackLess::operator()(Pin *pin1,
|
||||
Pin *pin2) const
|
||||
{
|
||||
const Corner *corner1, *corner2;
|
||||
const RiseFall *rf1, *rf2;
|
||||
float capacitance1, capacitance2;
|
||||
float limit1, limit2, slack1, slack2;
|
||||
check_capacitance_limit_->checkCapacitance(pin1, corner_, min_max_,
|
||||
corner1, rf1, capacitance1,
|
||||
limit1, slack1);
|
||||
check_capacitance_limit_->checkCapacitance(pin2, corner_, min_max_,
|
||||
corner2, rf2, capacitance2,
|
||||
limit2, slack2);
|
||||
return fuzzyLess(slack1, slack2)
|
||||
|| (fuzzyEqual(slack1, slack2)
|
||||
// Break ties for the sake of regression stability.
|
||||
&& sta_->network()->pinLess(pin1, pin2));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
CheckCapacitanceLimits::CheckCapacitanceLimits(const StaState *sta) :
|
||||
sta_(sta)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CheckCapacitanceLimits::checkCapacitance(const Pin *pin,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
const RiseFall *&rf,
|
||||
float &capacitance,
|
||||
float &limit,
|
||||
float &slack) const
|
||||
{
|
||||
corner = nullptr;
|
||||
rf = nullptr;
|
||||
capacitance = 0.0;
|
||||
limit = 0.0;
|
||||
slack = MinMax::min()->initValue();
|
||||
if (corner1)
|
||||
checkCapacitance1(pin, corner1, min_max,
|
||||
corner, rf, capacitance, limit, slack);
|
||||
else {
|
||||
for (auto corner1 : *sta_->corners()) {
|
||||
checkCapacitance1(pin, corner1, min_max,
|
||||
corner, rf, capacitance, limit, slack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CheckCapacitanceLimits::checkCapacitance1(const Pin *pin,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
const RiseFall *&rf,
|
||||
float &capacitance,
|
||||
float &limit,
|
||||
float &slack) const
|
||||
{
|
||||
float limit1;
|
||||
bool limit1_exists;
|
||||
findLimit(pin, min_max, limit1, limit1_exists);
|
||||
if (limit1_exists) {
|
||||
for (auto rf1 : RiseFall::range()) {
|
||||
checkCapacitance(pin, corner1, min_max, rf1, limit1,
|
||||
corner, rf, capacitance, slack, limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return the tightest limit.
|
||||
void
|
||||
CheckCapacitanceLimits::findLimit(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &limit,
|
||||
bool &exists) const
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
Sdc *sdc = sta_->sdc();
|
||||
|
||||
// Default to top ("design") limit.
|
||||
Cell *top_cell = network->cell(network->topInstance());
|
||||
sdc->capacitanceLimit(top_cell, min_max,
|
||||
limit, exists);
|
||||
|
||||
float limit1;
|
||||
bool exists1;
|
||||
if (network->isTopLevelPort(pin)) {
|
||||
Port *port = network->port(pin);
|
||||
sdc->capacitanceLimit(port, min_max, limit1, exists1);
|
||||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Cell *cell = network->cell(network->instance(pin));
|
||||
sdc->capacitanceLimit(cell, min_max,
|
||||
limit1, exists1);
|
||||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
LibertyPort *port = network->libertyPort(pin);
|
||||
if (port) {
|
||||
port->capacitanceLimit(min_max, limit1, exists1);
|
||||
if (!exists1
|
||||
&& port->direction()->isAnyOutput())
|
||||
port->libertyLibrary()->defaultMaxCapacitance(limit1, exists1);
|
||||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CheckCapacitanceLimits::checkCapacitance(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
const RiseFall *rf1,
|
||||
float limit1,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
float &capacitance,
|
||||
float &slack,
|
||||
float &limit) const
|
||||
{
|
||||
const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
|
||||
const OperatingConditions *op_cond = dcalc_ap->operatingConditions();
|
||||
float cap = sta_->graphDelayCalc()->loadCap(pin, dcalc_ap);
|
||||
|
||||
float slack1 = (min_max == MinMax::max())
|
||||
? limit1 - cap : cap - limit1;
|
||||
if (corner == nullptr
|
||||
|| (slack1 < slack
|
||||
// Break ties for the sake of regression stability.
|
||||
|| (fuzzyEqual(slack1, slack)
|
||||
&& rf1->index() < rf->index()))) {
|
||||
corner1 = corner;
|
||||
rf = rf1;
|
||||
capacitance = cap;
|
||||
slack = slack1;
|
||||
limit = limit1;
|
||||
}
|
||||
}
|
||||
|
||||
PinSeq *
|
||||
CheckCapacitanceLimits::pinCapacitanceLimitViolations(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
PinSeq *violators = new PinSeq;
|
||||
LeafInstanceIterator *inst_iter = network->leafInstanceIterator();
|
||||
while (inst_iter->hasNext()) {
|
||||
Instance *inst = inst_iter->next();
|
||||
pinCapacitanceLimitViolations(inst, corner, min_max, violators);
|
||||
}
|
||||
delete inst_iter;
|
||||
// Check top level ports.
|
||||
pinCapacitanceLimitViolations(network->topInstance(), corner, min_max, violators);
|
||||
sort(violators, PinCapacitanceLimitSlackLess(corner, min_max, this, sta_));
|
||||
return violators;
|
||||
}
|
||||
|
||||
void
|
||||
CheckCapacitanceLimits::pinCapacitanceLimitViolations(Instance *inst,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
PinSeq *violators)
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
const Sim *sim = sta_->sim();
|
||||
InstancePinIterator *pin_iter = network->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
if (checkPin(pin)) {
|
||||
const Corner *corner1;
|
||||
const RiseFall *rf;
|
||||
float capacitance, limit, slack;
|
||||
checkCapacitance(pin, corner, min_max, corner1, rf, capacitance, limit, slack );
|
||||
if (rf && slack < 0.0 && !fuzzyInf(slack))
|
||||
violators->push_back(pin);
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
|
||||
Pin *
|
||||
CheckCapacitanceLimits::pinMinCapacitanceLimitSlack(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
Pin *min_slack_pin = nullptr;
|
||||
float min_slack = MinMax::min()->initValue();
|
||||
LeafInstanceIterator *inst_iter = network->leafInstanceIterator();
|
||||
while (inst_iter->hasNext()) {
|
||||
Instance *inst = inst_iter->next();
|
||||
pinMinCapacitanceLimitSlack(inst, corner, min_max, min_slack_pin, min_slack);
|
||||
}
|
||||
delete inst_iter;
|
||||
// Check top level ports.
|
||||
pinMinCapacitanceLimitSlack(network->topInstance(), corner, min_max,
|
||||
min_slack_pin, min_slack);
|
||||
return min_slack_pin;
|
||||
}
|
||||
|
||||
void
|
||||
CheckCapacitanceLimits::pinMinCapacitanceLimitSlack(Instance *inst,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
Pin *&min_slack_pin,
|
||||
float &min_slack)
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
const Sim *sim = sta_->sim();
|
||||
InstancePinIterator *pin_iter = network->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
if (checkPin(pin)) {
|
||||
const Corner *corner1;
|
||||
const RiseFall *rf;
|
||||
float capacitance, limit, slack;
|
||||
checkCapacitance(pin, corner, min_max, corner1, rf, capacitance, limit, slack);
|
||||
if (rf
|
||||
&& !fuzzyInf(slack)
|
||||
&& (min_slack_pin == nullptr
|
||||
|| slack < min_slack)) {
|
||||
min_slack_pin = pin;
|
||||
min_slack = slack;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
|
||||
bool
|
||||
CheckCapacitanceLimits::checkPin(const Pin *pin)
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
const Sim *sim = sta_->sim();
|
||||
const Sdc *sdc = sta_->sdc();
|
||||
const Graph *graph = sta_->graph();
|
||||
GraphDelayCalc *dcalc = sta_->graphDelayCalc();
|
||||
Vertex *vertex = graph->pinLoadVertex(pin);
|
||||
return network->direction(pin)->isAnyOutput()
|
||||
&& !sim->logicZeroOne(pin)
|
||||
&& !sdc->isDisabled(pin)
|
||||
&& !(vertex && sta_->graphDelayCalc()->isIdealClk(vertex));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2020, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MinMax.hh"
|
||||
#include "Transition.hh"
|
||||
#include "NetworkClass.hh"
|
||||
#include "SdcClass.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class StaState;
|
||||
class Corner;
|
||||
|
||||
class CheckCapacitanceLimits
|
||||
{
|
||||
public:
|
||||
CheckCapacitanceLimits(const StaState *sta);
|
||||
// corner=nullptr checks all corners.
|
||||
void checkCapacitance(const Pin *pin,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
// Corner is nullptr for no capacitance limit.
|
||||
const Corner *&corner,
|
||||
const RiseFall *&rf,
|
||||
float &capacitance,
|
||||
float &limit,
|
||||
float &slack) const;
|
||||
// corner=nullptr checks all corners.
|
||||
PinSeq *pinCapacitanceLimitViolations(const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
// corner=nullptr checks all corners.
|
||||
Pin *pinMinCapacitanceLimitSlack(const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
|
||||
protected:
|
||||
void checkCapacitance(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
const RiseFall *rf1,
|
||||
float limit1,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
float &capacitance,
|
||||
float &slack,
|
||||
float &limit) const;
|
||||
void checkCapacitance1(const Pin *pin,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
const RiseFall *&rf,
|
||||
float &capacitance,
|
||||
float &limit,
|
||||
float &slack) const;
|
||||
void findLimit(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &limit,
|
||||
bool &limit_exists) const;
|
||||
void pinCapacitanceLimitViolations(Instance *inst,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
PinSeq *violators);
|
||||
void pinMinCapacitanceLimitSlack(Instance *inst,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
Pin *&min_slack_pin,
|
||||
float &min_slack);
|
||||
bool checkPin(const Pin *pin);
|
||||
|
||||
const StaState *sta_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2020, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "CheckFanoutLimits.hh"
|
||||
|
||||
#include "Fuzzy.hh"
|
||||
#include "Liberty.hh"
|
||||
#include "Network.hh"
|
||||
#include "Sdc.hh"
|
||||
#include "Sim.hh"
|
||||
#include "PortDirection.hh"
|
||||
#include "Graph.hh"
|
||||
#include "GraphDelayCalc.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class PinFanoutLimitSlackLess
|
||||
{
|
||||
public:
|
||||
PinFanoutLimitSlackLess(const MinMax *min_max,
|
||||
CheckFanoutLimits *check_fanout_limit,
|
||||
const StaState *sta);
|
||||
bool operator()(Pin *pin1,
|
||||
Pin *pin2) const;
|
||||
|
||||
private:
|
||||
const MinMax *min_max_;
|
||||
CheckFanoutLimits *check_fanout_limit_;
|
||||
const StaState *sta_;
|
||||
|
||||
};
|
||||
|
||||
PinFanoutLimitSlackLess::PinFanoutLimitSlackLess(const MinMax *min_max,
|
||||
CheckFanoutLimits *check_fanout_limit,
|
||||
const StaState *sta) :
|
||||
min_max_(min_max),
|
||||
check_fanout_limit_(check_fanout_limit),
|
||||
sta_(sta)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
PinFanoutLimitSlackLess::operator()(Pin *pin1,
|
||||
Pin *pin2) const
|
||||
{
|
||||
float fanout1, fanout2;
|
||||
float limit1, limit2, slack1, slack2;
|
||||
check_fanout_limit_->checkFanout(pin1, min_max_,
|
||||
fanout1, limit1, slack1);
|
||||
check_fanout_limit_->checkFanout(pin2, min_max_,
|
||||
fanout2, limit2, slack2);
|
||||
return fuzzyLess(slack1, slack2)
|
||||
|| (fuzzyEqual(slack1, slack2)
|
||||
// Break ties for the sake of regression stability.
|
||||
&& sta_->network()->pinLess(pin1, pin2));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
CheckFanoutLimits::CheckFanoutLimits(const StaState *sta) :
|
||||
sta_(sta)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CheckFanoutLimits::checkFanout(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &fanout,
|
||||
float &limit,
|
||||
float &slack) const
|
||||
{
|
||||
fanout = 0.0;
|
||||
limit = 0.0;
|
||||
slack = MinMax::min()->initValue();
|
||||
|
||||
float limit1;
|
||||
bool limit1_exists;
|
||||
findLimit(pin, min_max, limit1, limit1_exists);
|
||||
if (limit1_exists)
|
||||
checkFanout(pin, min_max, limit1,
|
||||
fanout, slack, limit);
|
||||
}
|
||||
|
||||
// return the tightest limit.
|
||||
void
|
||||
CheckFanoutLimits::findLimit(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &limit,
|
||||
bool &exists) const
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
Sdc *sdc = sta_->sdc();
|
||||
|
||||
// Default to top ("design") limit.
|
||||
Cell *top_cell = network->cell(network->topInstance());
|
||||
sdc->fanoutLimit(top_cell, min_max,
|
||||
limit, exists);
|
||||
|
||||
float limit1;
|
||||
bool exists1;
|
||||
if (network->isTopLevelPort(pin)) {
|
||||
Port *port = network->port(pin);
|
||||
sdc->fanoutLimit(port, min_max, limit1, exists1);
|
||||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Cell *cell = network->cell(network->instance(pin));
|
||||
sdc->fanoutLimit(cell, min_max,
|
||||
limit1, exists1);
|
||||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
LibertyPort *port = network->libertyPort(pin);
|
||||
if (port) {
|
||||
port->fanoutLimit(min_max, limit1, exists1);
|
||||
if (!exists1
|
||||
&& min_max == MinMax::max()
|
||||
&& port->direction()->isAnyOutput())
|
||||
port->libertyLibrary()->defaultMaxFanout(limit1, exists1);
|
||||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CheckFanoutLimits::checkFanout(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
float limit1,
|
||||
// Return values.
|
||||
float &fanout,
|
||||
float &slack,
|
||||
float &limit) const
|
||||
{
|
||||
float fanout1 = fanoutLoad(pin);
|
||||
float slack1 = (min_max == MinMax::max())
|
||||
? limit1 - fanout1
|
||||
: fanout1 - limit1;
|
||||
if (fuzzyLessEqual(slack1, slack)) {
|
||||
fanout = fanout1;
|
||||
slack = slack1;
|
||||
limit = limit1;
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
CheckFanoutLimits::fanoutLoad(const Pin *pin) const
|
||||
{
|
||||
float fanout = 0;
|
||||
const Network *network = sta_->network();
|
||||
Net *net = network->net(pin);
|
||||
if (net) {
|
||||
NetPinIterator *pin_iter = network->pinIterator(net);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
if (network->isLoad(pin)) {
|
||||
LibertyPort *port = network->libertyPort(pin);
|
||||
if (port) {
|
||||
float fanout_load;
|
||||
bool exists;
|
||||
port->fanoutLoad(fanout_load, exists);
|
||||
if (!exists) {
|
||||
LibertyLibrary *lib = port->libertyLibrary();
|
||||
lib->defaultFanoutLoad(fanout_load, exists);
|
||||
}
|
||||
if (exists)
|
||||
fanout += fanout_load;
|
||||
}
|
||||
else
|
||||
fanout += 1;
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
return fanout;
|
||||
}
|
||||
|
||||
PinSeq *
|
||||
CheckFanoutLimits::pinFanoutLimitViolations(const MinMax *min_max)
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
PinSeq *violators = new PinSeq;
|
||||
LeafInstanceIterator *inst_iter = network->leafInstanceIterator();
|
||||
while (inst_iter->hasNext()) {
|
||||
Instance *inst = inst_iter->next();
|
||||
pinFanoutLimitViolations(inst, min_max, violators);
|
||||
}
|
||||
delete inst_iter;
|
||||
|
||||
// Check top level ports.
|
||||
pinFanoutLimitViolations(network->topInstance(), min_max, violators);
|
||||
sort(violators, PinFanoutLimitSlackLess(min_max, this, sta_));
|
||||
return violators;
|
||||
}
|
||||
|
||||
void
|
||||
CheckFanoutLimits::pinFanoutLimitViolations(Instance *inst,
|
||||
const MinMax *min_max,
|
||||
PinSeq *violators)
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
const Sim *sim = sta_->sim();
|
||||
InstancePinIterator *pin_iter = network->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
if (checkPin(pin)) {
|
||||
float fanout;
|
||||
float limit, slack;
|
||||
checkFanout(pin, min_max, fanout, limit, slack );
|
||||
if (slack < 0.0 && !fuzzyInf(slack))
|
||||
violators->push_back(pin);
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
|
||||
Pin *
|
||||
CheckFanoutLimits::pinMinFanoutLimitSlack(const MinMax *min_max)
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
Pin *min_slack_pin = nullptr;
|
||||
float min_slack = MinMax::min()->initValue();
|
||||
LeafInstanceIterator *inst_iter = network->leafInstanceIterator();
|
||||
while (inst_iter->hasNext()) {
|
||||
Instance *inst = inst_iter->next();
|
||||
pinMinFanoutLimitSlack(inst, min_max, min_slack_pin, min_slack);
|
||||
}
|
||||
delete inst_iter;
|
||||
// Check top level ports.
|
||||
pinMinFanoutLimitSlack(network->topInstance(), min_max,
|
||||
min_slack_pin, min_slack);
|
||||
return min_slack_pin;
|
||||
}
|
||||
|
||||
void
|
||||
CheckFanoutLimits::pinMinFanoutLimitSlack(Instance *inst,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
Pin *&min_slack_pin,
|
||||
float &min_slack)
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
InstancePinIterator *pin_iter = network->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
if (checkPin(pin)) {
|
||||
float fanout;
|
||||
float limit, slack;
|
||||
checkFanout(pin, min_max, fanout, limit, slack);
|
||||
if (!fuzzyInf(slack)
|
||||
&& (min_slack_pin == nullptr
|
||||
|| slack < min_slack)) {
|
||||
min_slack_pin = pin;
|
||||
min_slack = slack;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
|
||||
bool
|
||||
CheckFanoutLimits::checkPin(const Pin *pin)
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
const Sim *sim = sta_->sim();
|
||||
const Sdc *sdc = sta_->sdc();
|
||||
const Graph *graph = sta_->graph();
|
||||
GraphDelayCalc *dcalc = sta_->graphDelayCalc();
|
||||
Vertex *vertex = graph->pinLoadVertex(pin);
|
||||
return network->direction(pin)->isAnyOutput()
|
||||
&& !sim->logicZeroOne(pin)
|
||||
&& !sdc->isDisabled(pin)
|
||||
&& !(vertex && dcalc->isIdealClk(vertex));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
// OpenSTA, Static Timing Analyzer
|
||||
// Copyright (c) 2020, Parallax Software, Inc.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MinMax.hh"
|
||||
#include "NetworkClass.hh"
|
||||
#include "SdcClass.hh"
|
||||
|
||||
namespace sta {
|
||||
|
||||
class StaState;
|
||||
|
||||
class CheckFanoutLimits
|
||||
{
|
||||
public:
|
||||
CheckFanoutLimits(const StaState *sta);
|
||||
void checkFanout(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &fanout,
|
||||
float &limit,
|
||||
float &slack) const;
|
||||
PinSeq *pinFanoutLimitViolations(const MinMax *min_max);
|
||||
Pin *pinMinFanoutLimitSlack(const MinMax *min_max);
|
||||
|
||||
protected:
|
||||
void checkFanout(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
float limit1,
|
||||
// Return values.
|
||||
float &fanout,
|
||||
float &slack,
|
||||
float &limit) const;
|
||||
void findLimit(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &limit,
|
||||
bool &limit_exists) const;
|
||||
void pinFanoutLimitViolations(Instance *inst,
|
||||
const MinMax *min_max,
|
||||
PinSeq *violators);
|
||||
void pinMinFanoutLimitSlack(Instance *inst,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
Pin *&min_slack_pin,
|
||||
float &min_slack);
|
||||
float fanoutLoad(const Pin *pin) const;
|
||||
bool checkPin(const Pin *pin);
|
||||
|
||||
const StaState *sta_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -68,10 +68,10 @@ PinSlewLimitSlackLess::operator()(Pin *pin1,
|
|||
const RiseFall *rf1, *rf2;
|
||||
Slew slew1, slew2;
|
||||
float limit1, limit2, slack1, slack2;
|
||||
check_slew_limit_->checkSlews(pin1, corner_, min_max_,
|
||||
corner1, rf1, slew1, limit1, slack1);
|
||||
check_slew_limit_->checkSlews(pin2, corner_, min_max_,
|
||||
corner2, rf2, slew2, limit2, slack2);
|
||||
check_slew_limit_->checkSlew(pin1, corner_, min_max_, true,
|
||||
corner1, rf1, slew1, limit1, slack1);
|
||||
check_slew_limit_->checkSlew(pin2, corner_, min_max_, true,
|
||||
corner2, rf2, slew2, limit2, slack2);
|
||||
return fuzzyLess(slack1, slack2)
|
||||
|| (fuzzyEqual(slack1, slack2)
|
||||
// Break ties for the sake of regression stability.
|
||||
|
|
@ -86,28 +86,16 @@ CheckSlewLimits::CheckSlewLimits(const StaState *sta) :
|
|||
}
|
||||
|
||||
void
|
||||
CheckSlewLimits::init(const MinMax *min_max)
|
||||
{
|
||||
const Network *network = sta_->network();
|
||||
Cell *top_cell = network->cell(network->topInstance());
|
||||
float top_limit;
|
||||
bool top_limit_exists;
|
||||
sta_->sdc()->slewLimit(top_cell, min_max,
|
||||
top_limit, top_limit_exists);
|
||||
top_limit_= top_limit;
|
||||
top_limit_exists_ = top_limit_exists;
|
||||
}
|
||||
|
||||
void
|
||||
CheckSlewLimits::checkSlews(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack) const
|
||||
CheckSlewLimits::checkSlew(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
bool check_clks,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack) const
|
||||
{
|
||||
corner1 = nullptr;
|
||||
rf = nullptr;
|
||||
|
|
@ -115,11 +103,11 @@ CheckSlewLimits::checkSlews(const Pin *pin,
|
|||
limit = 0.0;
|
||||
slack = MinMax::min()->initValue();
|
||||
if (corner)
|
||||
checkSlews1(pin, corner, min_max,
|
||||
checkSlews1(pin, corner, min_max, check_clks,
|
||||
corner1, rf, slew, limit, slack);
|
||||
else {
|
||||
for (auto corner : *sta_->corners()) {
|
||||
checkSlews1(pin, corner, min_max,
|
||||
checkSlews1(pin, corner, min_max, check_clks,
|
||||
corner1, rf, slew, limit, slack);
|
||||
}
|
||||
}
|
||||
|
|
@ -129,6 +117,7 @@ void
|
|||
CheckSlewLimits::checkSlews1(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
bool check_clks,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
|
|
@ -138,13 +127,11 @@ CheckSlewLimits::checkSlews1(const Pin *pin,
|
|||
{
|
||||
Vertex *vertex, *bidirect_drvr_vertex;
|
||||
sta_->graph()->pinVertices(pin, vertex, bidirect_drvr_vertex);
|
||||
if (vertex
|
||||
&& !vertex->isDisabledConstraint())
|
||||
checkSlews1(vertex, corner, min_max,
|
||||
if (vertex)
|
||||
checkSlews1(vertex, corner, min_max, check_clks,
|
||||
corner1, rf, slew, limit, slack);
|
||||
if (bidirect_drvr_vertex
|
||||
&& !vertex->isDisabledConstraint())
|
||||
checkSlews1(bidirect_drvr_vertex, corner, min_max,
|
||||
if (bidirect_drvr_vertex)
|
||||
checkSlews1(bidirect_drvr_vertex, corner, min_max, check_clks,
|
||||
corner1, rf, slew, limit, slack);
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +139,7 @@ void
|
|||
CheckSlewLimits::checkSlews1(Vertex *vertex,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
bool check_clks,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
const RiseFall *&rf,
|
||||
|
|
@ -159,34 +147,46 @@ CheckSlewLimits::checkSlews1(Vertex *vertex,
|
|||
float &limit,
|
||||
float &slack) const
|
||||
{
|
||||
for (auto rf1 : RiseFall::range()) {
|
||||
float limit1;
|
||||
bool limit1_exists;
|
||||
findLimit(vertex->pin(), vertex, rf1, min_max, limit1, limit1_exists);
|
||||
if (limit1_exists) {
|
||||
checkSlew(vertex, corner1, min_max, rf1, limit1,
|
||||
corner, rf, slew, slack, limit);
|
||||
if (!vertex->isDisabledConstraint()
|
||||
&& !vertex->isConstant()
|
||||
&& !sta_->graphDelayCalc()->isIdealClk(vertex)) {
|
||||
for (auto rf1 : RiseFall::range()) {
|
||||
float limit1;
|
||||
bool limit1_exists;
|
||||
findLimit(vertex->pin(), vertex, rf1, min_max, check_clks,
|
||||
limit1, limit1_exists);
|
||||
if (limit1_exists) {
|
||||
checkSlew(vertex, corner1, rf1, min_max, limit1,
|
||||
corner, rf, slew, slack, limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return the tightest limit.
|
||||
void
|
||||
CheckSlewLimits::findLimit(const Pin *pin,
|
||||
const Vertex *vertex,
|
||||
const RiseFall *rf,
|
||||
const MinMax *min_max,
|
||||
bool check_clks,
|
||||
// Return values.
|
||||
float &limit,
|
||||
bool &exists) const
|
||||
{
|
||||
exists = false;
|
||||
if (!sta_->graphDelayCalc()->isIdealClk(vertex)) {
|
||||
const Network *network = sta_->network();
|
||||
Sdc *sdc = sta_->sdc();
|
||||
bool is_clk = sta_->search()->isClock(vertex);
|
||||
float limit1;
|
||||
bool exists1;
|
||||
const Network *network = sta_->network();
|
||||
Sdc *sdc = sta_->sdc();
|
||||
|
||||
// Default to top ("design") limit.
|
||||
Cell *top_cell = network->cell(network->topInstance());
|
||||
sdc->slewLimit(top_cell, min_max,
|
||||
limit, exists);
|
||||
float limit1;
|
||||
bool exists1;
|
||||
if (check_clks) {
|
||||
// Look for clock slew limits.
|
||||
bool is_clk = sta_->search()->isClock(vertex);
|
||||
ClockSet clks;
|
||||
clockDomains(vertex, clks);
|
||||
ClockSet::Iterator clk_iter(clks);
|
||||
|
|
@ -198,58 +198,34 @@ CheckSlewLimits::findLimit(const Pin *pin,
|
|||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
// Use the tightest clock limit.
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
if (!exists) {
|
||||
// Default to top ("design") limit.
|
||||
exists = top_limit_exists_;
|
||||
limit = top_limit_;
|
||||
if (network->isTopLevelPort(pin)) {
|
||||
Port *port = network->port(pin);
|
||||
sdc->slewLimit(port, min_max, limit1, exists1);
|
||||
// Use the tightest limit.
|
||||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sdc->slewLimit(pin, min_max,
|
||||
limit1, exists1);
|
||||
// Use the tightest limit.
|
||||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
LibertyPort *port = network->libertyPort(pin);
|
||||
if (port) {
|
||||
port->slewLimit(min_max, limit1, exists1);
|
||||
// Use the tightest limit.
|
||||
if (exists1) {
|
||||
if (!exists
|
||||
|| min_max->compare(limit, limit1)) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
else if (port->direction()->isAnyOutput()
|
||||
&& min_max == MinMax::max()) {
|
||||
port->libertyLibrary()->defaultMaxSlew(limit1, exists1);
|
||||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (network->isTopLevelPort(pin)) {
|
||||
Port *port = network->port(pin);
|
||||
sdc->slewLimit(port, min_max, limit1, exists1);
|
||||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LibertyPort *port = network->libertyPort(pin);
|
||||
if (port) {
|
||||
port->slewLimit(min_max, limit1, exists1);
|
||||
if (!exists1
|
||||
&& port->direction()->isAnyOutput()
|
||||
&& min_max == MinMax::max())
|
||||
port->libertyLibrary()->defaultMaxSlew(limit1, exists1);
|
||||
if (exists1
|
||||
&& (!exists
|
||||
|| min_max->compare(limit, limit1))) {
|
||||
limit = limit1;
|
||||
exists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -272,8 +248,8 @@ CheckSlewLimits::clockDomains(const Vertex *vertex,
|
|||
void
|
||||
CheckSlewLimits::checkSlew(Vertex *vertex,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
const RiseFall *rf1,
|
||||
const MinMax *min_max,
|
||||
float limit1,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
|
|
@ -304,7 +280,6 @@ PinSeq *
|
|||
CheckSlewLimits::pinSlewLimitViolations(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
init(min_max);
|
||||
const Network *network = sta_->network();
|
||||
PinSeq *violators = new PinSeq;
|
||||
LeafInstanceIterator *inst_iter = network->leafInstanceIterator();
|
||||
|
|
@ -333,8 +308,8 @@ CheckSlewLimits::pinSlewLimitViolations(Instance *inst,
|
|||
const RiseFall *rf;
|
||||
Slew slew;
|
||||
float limit, slack;
|
||||
checkSlews(pin, corner, min_max, corner1, rf, slew, limit, slack );
|
||||
if (rf && slack < 0.0)
|
||||
checkSlew(pin, corner, min_max, true, corner1, rf, slew, limit, slack);
|
||||
if (rf && slack < 0.0 && !fuzzyInf(slack))
|
||||
violators->push_back(pin);
|
||||
}
|
||||
delete pin_iter;
|
||||
|
|
@ -344,9 +319,8 @@ Pin *
|
|||
CheckSlewLimits::pinMinSlewLimitSlack(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
init(min_max);
|
||||
const Network *network = sta_->network();
|
||||
Pin *min_slack_pin = 0;
|
||||
Pin *min_slack_pin = nullptr;
|
||||
float min_slack = MinMax::min()->initValue();
|
||||
LeafInstanceIterator *inst_iter = network->leafInstanceIterator();
|
||||
while (inst_iter->hasNext()) {
|
||||
|
|
@ -376,9 +350,9 @@ CheckSlewLimits::pinMinSlewLimitSlack(Instance *inst,
|
|||
const RiseFall *rf;
|
||||
Slew slew;
|
||||
float limit, slack;
|
||||
checkSlews(pin, corner, min_max, corner1, rf, slew, limit, slack);
|
||||
checkSlew(pin, corner, min_max, true, corner1, rf, slew, limit, slack);
|
||||
if (rf
|
||||
&& (min_slack_pin == 0
|
||||
&& (min_slack_pin == nullptr
|
||||
|| slack < min_slack)) {
|
||||
min_slack_pin = pin;
|
||||
min_slack = slack;
|
||||
|
|
|
|||
|
|
@ -33,19 +33,18 @@ class CheckSlewLimits
|
|||
{
|
||||
public:
|
||||
CheckSlewLimits(const StaState *sta);
|
||||
void init(const MinMax *min_max);
|
||||
// Requires init().
|
||||
// corner=nullptr checks all corners.
|
||||
void checkSlews(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
// Corner is nullptr for no slew limit.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack) const;
|
||||
void checkSlew(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
bool check_clks,
|
||||
// Return values.
|
||||
// Corner is nullptr for no slew limit.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack) const;
|
||||
// corner=nullptr checks all corners.
|
||||
PinSeq *pinSlewLimitViolations(const Corner *corner,
|
||||
const MinMax *min_max);
|
||||
|
|
@ -57,6 +56,7 @@ protected:
|
|||
void checkSlews1(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
bool check_clks,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
|
|
@ -66,6 +66,7 @@ protected:
|
|||
void checkSlews1(Vertex *vertex,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
bool check_clks,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
const RiseFall *&rf,
|
||||
|
|
@ -74,8 +75,8 @@ protected:
|
|||
float &slack) const;
|
||||
void checkSlew(Vertex *vertex,
|
||||
const Corner *corner1,
|
||||
const MinMax *min_max,
|
||||
const RiseFall *rf1,
|
||||
const MinMax *min_max,
|
||||
float limit1,
|
||||
// Return values.
|
||||
const Corner *&corner,
|
||||
|
|
@ -87,6 +88,7 @@ protected:
|
|||
const Vertex *vertex,
|
||||
const RiseFall *rf,
|
||||
const MinMax *min_max,
|
||||
bool check_clks,
|
||||
// Return values.
|
||||
float &limit1,
|
||||
bool &limit1_exists) const;
|
||||
|
|
@ -104,8 +106,6 @@ protected:
|
|||
// Return value.
|
||||
ClockSet &clks) const;
|
||||
|
||||
float top_limit_;
|
||||
bool top_limit_exists_;
|
||||
const StaState *sta_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -302,6 +304,7 @@ CheckCrpr::findCrpr1(const PathVertex *src_clk_path,
|
|||
float tgt_clk_time = tgt_clk_path->clkEdge(this)->time();
|
||||
float crpr_mean = abs(delayAsFloat(src_arrival) - src_clk_time
|
||||
- (delayAsFloat(tgt_arrival) - tgt_clk_time));
|
||||
// Remove the sigma from both source and target path arrivals.
|
||||
float crpr_sigma2 = delaySigma2(src_arrival, src_el)
|
||||
+ delaySigma2(tgt_arrival, tgt_el);
|
||||
return makeDelay2(crpr_mean, -crpr_sigma2, -crpr_sigma2);
|
||||
|
|
@ -371,9 +374,12 @@ CheckCrpr::outputDelayCrpr1(const Path *src_path,
|
|||
{
|
||||
crpr = 0.0;
|
||||
crpr_pin = nullptr;
|
||||
ClkInfo *src_clk_info = src_path->tag(this)->clkInfo();
|
||||
Clock *tgt_clk = tgt_clk_edge->clock();
|
||||
Clock *src_clk = src_path->clock(this);
|
||||
if (tgt_clk->isGenerated()
|
||||
if (src_clk_info->isPropagated()
|
||||
&& tgt_clk->isGenerated()
|
||||
&& tgt_clk->isPropagated()
|
||||
&& crprPossible(src_clk, tgt_clk)) {
|
||||
PathVertex tgt_genclk_path;
|
||||
portClkPath(tgt_clk_edge, tgt_clk_edge->clock()->defaultPin(), tgt_path_ap,
|
||||
|
|
@ -392,7 +398,7 @@ CheckCrpr::crprPossible(Clock *clk1,
|
|||
return clk1 && clk2
|
||||
&& !clk1->isVirtual()
|
||||
&& !clk2->isVirtual()
|
||||
// Generated clock can have crpr in the source path.
|
||||
// Generated clocks can have crpr in the source path.
|
||||
&& (clk1 == clk2
|
||||
|| clk1->isGenerated()
|
||||
|| clk2->isGenerated()
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ Latches::latchRequired(const Path *data_path,
|
|||
network_->pathName(data_path->pin(this)),
|
||||
delayAsString(data_arrival, this),
|
||||
delayAsString(enable_arrival, this));
|
||||
if (data_arrival <= enable_arrival) {
|
||||
if (delayLessEqual(data_arrival, enable_arrival, this)) {
|
||||
// Data arrives before latch opens.
|
||||
required = enable_arrival;
|
||||
borrow = 0.0;
|
||||
|
|
@ -108,7 +108,7 @@ Latches::latchRequired(const Path *data_path,
|
|||
else {
|
||||
// Data arrives while latch is transparent.
|
||||
borrow = data_arrival - enable_arrival;
|
||||
if (borrow <= max_borrow)
|
||||
if (delayLessEqual(borrow, max_borrow, this))
|
||||
required = data_arrival;
|
||||
else {
|
||||
borrow = max_borrow;
|
||||
|
|
@ -332,7 +332,7 @@ Latches::latchOutArrival(Path *data_path,
|
|||
latchRequired(data_path, enable_path, &disable_path, path_ap,
|
||||
required, borrow, adjusted_data_arrival,
|
||||
time_given_to_startpoint);
|
||||
if (borrow > 0.0) {
|
||||
if (delayGreater(borrow, 0.0, this)) {
|
||||
// Latch is transparent when data arrives.
|
||||
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
|
||||
false, path_ap);
|
||||
|
|
|
|||
|
|
@ -361,10 +361,11 @@ PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path,
|
|||
if (clk_info->isPropagated()) {
|
||||
// Propagated clock. Propagated arrival is seeded with
|
||||
// early_late==path_min_max insertion delay.
|
||||
Arrival clk_arrival = tgt_clk_path->arrival(sta);
|
||||
Arrival path_insertion = search->clockInsertion(tgt_clk, tgt_src_pin,
|
||||
tgt_clk_rf, min_max,
|
||||
min_max, tgt_path_ap);
|
||||
latency=tgt_clk_path->arrival(sta)-tgt_clk_edge->time()-path_insertion;
|
||||
latency = delayRemove(clk_arrival - tgt_clk_edge->time(), path_insertion);
|
||||
}
|
||||
else
|
||||
// Ideal clock.
|
||||
|
|
@ -1243,7 +1244,7 @@ PathEndLatchCheck::targetClkWidth(const StaState *sta) const
|
|||
if (enable_clk_info->isPulseClk())
|
||||
return disable_arrival - enable_arrival;
|
||||
else {
|
||||
if (enable_arrival > disable_arrival) {
|
||||
if (delayGreater(enable_arrival, disable_arrival, sta)) {
|
||||
float period = enable_clk_info->clock()->period();
|
||||
disable_arrival += period;
|
||||
}
|
||||
|
|
@ -1844,6 +1845,17 @@ PathEnd::pathDelaySrcClkOffset(const PathRef &path,
|
|||
return offset;
|
||||
}
|
||||
|
||||
ClockEdge *
|
||||
PathEndPathDelay::targetClkEdge(const StaState *sta) const
|
||||
{
|
||||
if (!clk_path_.isNull())
|
||||
return clk_path_.clkEdge(sta);
|
||||
else if (output_delay_)
|
||||
return output_delay_->clkEdge();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
float
|
||||
PathEndPathDelay::targetClkTime(const StaState *sta) const
|
||||
{
|
||||
|
|
@ -1857,14 +1869,12 @@ PathEndPathDelay::targetClkTime(const StaState *sta) const
|
|||
Arrival
|
||||
PathEndPathDelay::targetClkArrivalNoCrpr(const StaState *sta) const
|
||||
{
|
||||
if (!clk_path_.isNull()) {
|
||||
ClockEdge *tgt_clk_edge = targetClkEdge(sta);
|
||||
if (tgt_clk_edge)
|
||||
return targetClkDelay(sta)
|
||||
+ targetClkUncertainty(sta);
|
||||
else
|
||||
return clk_path_.arrival(sta);
|
||||
}
|
||||
ClockEdge *tgt_clk_edge = targetClkEdge(sta);
|
||||
if (tgt_clk_edge)
|
||||
return targetClkDelay(sta)
|
||||
+ targetClkUncertainty(sta);
|
||||
else if (!clk_path_.isNull())
|
||||
return clk_path_.arrival(sta);
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
|
@ -1886,9 +1896,7 @@ PathEndPathDelay::requiredTime(const StaState *sta) const
|
|||
return src_clk_arrival_ + delay + margin(sta);
|
||||
}
|
||||
else {
|
||||
Arrival tgt_clk_arrival = 0.0;
|
||||
if (!clk_path_.isNull())
|
||||
tgt_clk_arrival = targetClkArrival(sta);
|
||||
Arrival tgt_clk_arrival = targetClkArrival(sta);
|
||||
float src_clk_offset = sourceClkOffset(sta);
|
||||
// Path delay includes target clk latency and timing check setup/hold
|
||||
// margin or external departure at target.
|
||||
|
|
@ -1981,24 +1989,24 @@ PathEnd::cmpSlack(const PathEnd *path_end1,
|
|||
{
|
||||
Slack slack1 = path_end1->slack(sta);
|
||||
Slack slack2 = path_end2->slack(sta);
|
||||
if (fuzzyZero(slack1)
|
||||
&& fuzzyZero(slack2)
|
||||
if (delayZero(slack1)
|
||||
&& delayZero(slack2)
|
||||
&& path_end1->isLatchCheck()
|
||||
&& path_end2->isLatchCheck()) {
|
||||
Arrival borrow1 = path_end1->borrow(sta);
|
||||
Arrival borrow2 = path_end2->borrow(sta);
|
||||
// Latch slack is zero if there is borrowing so break ties
|
||||
// based on borrow time.
|
||||
if (fuzzyEqual(borrow1, borrow2))
|
||||
if (delayEqual(borrow1, borrow2))
|
||||
return 0;
|
||||
else if (borrow1 > borrow2)
|
||||
else if (delayGreater(borrow1, borrow2, sta))
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
else if (fuzzyEqual(slack1, slack2))
|
||||
else if (delayEqual(slack1, slack2))
|
||||
return 0;
|
||||
else if (slack1 < slack2)
|
||||
else if (delayLess(slack1, slack2, sta))
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
|
|
@ -2012,9 +2020,9 @@ PathEnd::cmpArrival(const PathEnd *path_end1,
|
|||
Arrival arrival1 = path_end1->dataArrivalTime(sta);
|
||||
Arrival arrival2 = path_end2->dataArrivalTime(sta);
|
||||
const MinMax *min_max = path_end1->minMax(sta);
|
||||
if (fuzzyEqual(arrival1, arrival2))
|
||||
if (delayEqual(arrival1, arrival2))
|
||||
return 0;
|
||||
else if (fuzzyLess(arrival1, arrival2, min_max))
|
||||
else if (delayLess(arrival1, arrival2, min_max, sta))
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -154,7 +154,8 @@ Power::power(const Corner *corner,
|
|||
if (cell) {
|
||||
PowerResult inst_power;
|
||||
power(inst, corner, inst_power);
|
||||
if (cell->isMacro())
|
||||
if (cell->isMacro()
|
||||
|| cell->isMemory())
|
||||
macro.incr(inst_power);
|
||||
else if (cell->isPad())
|
||||
pad.incr(inst_power);
|
||||
|
|
@ -596,7 +597,7 @@ Power::findInputInternalPower(const Pin *pin,
|
|||
for (auto rf : RiseFall::range()) {
|
||||
float slew = delayAsFloat(graph_->slew(vertex, rf,
|
||||
dcalc_ap->index()));
|
||||
if (!fuzzyInf(slew)) {
|
||||
if (!delayInf(slew)) {
|
||||
float table_energy = pwr->power(rf, pvt, slew, load_cap);
|
||||
energy += table_energy;
|
||||
tr_count++;
|
||||
|
|
@ -621,7 +622,7 @@ Power::findInputInternalPower(const Pin *pin,
|
|||
float port_internal = energy * duty * activity.activity();
|
||||
debugPrint7(debug_, "power", 2, " %3s %6s %.2f %.2f %9.2e %9.2e %s\n",
|
||||
port->name(),
|
||||
when->asString(),
|
||||
when ? when->asString() : "",
|
||||
activity.activity() * 1e-9,
|
||||
duty,
|
||||
energy,
|
||||
|
|
@ -734,7 +735,7 @@ Power::findOutputInternalPower(const Pin *to_pin,
|
|||
? delayAsFloat(graph_->slew(from_vertex, from_rf,
|
||||
dcalc_ap->index()))
|
||||
: 0.0;
|
||||
if (!fuzzyInf(slew)) {
|
||||
if (!delayInf(slew)) {
|
||||
float table_energy = pwr->power(to_rf, pvt, slew, load_cap);
|
||||
energy += table_energy;
|
||||
tr_count++;
|
||||
|
|
@ -774,25 +775,26 @@ Power::findInputDuty(const Pin *to_pin,
|
|||
const LibertyPort *from_port = pwr->relatedPort();
|
||||
if (from_port) {
|
||||
const Pin *from_pin = network_->findPin(inst, from_port);
|
||||
FuncExpr *when = pwr->when();
|
||||
Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
|
||||
if (func && func->hasPort(from_port)) {
|
||||
PwrActivity from_activity = findActivity(from_pin);
|
||||
PwrActivity to_activity = findActivity(to_pin);
|
||||
float duty1 = evalActivityDifference(func, inst, from_port).duty();
|
||||
if (to_activity.activity() == 0.0)
|
||||
return 0.0;
|
||||
else
|
||||
return from_activity.activity() / to_activity.activity() * duty1;
|
||||
if (from_pin) {
|
||||
FuncExpr *when = pwr->when();
|
||||
Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
|
||||
if (func && func->hasPort(from_port)) {
|
||||
PwrActivity from_activity = findActivity(from_pin);
|
||||
PwrActivity to_activity = findActivity(to_pin);
|
||||
float duty1 = evalActivityDifference(func, inst, from_port).duty();
|
||||
if (to_activity.activity() == 0.0)
|
||||
return 0.0;
|
||||
else
|
||||
return from_activity.activity() / to_activity.activity() * duty1;
|
||||
}
|
||||
else if (when)
|
||||
return evalActivity(when, inst).duty();
|
||||
else if (search_->isClock(from_vertex))
|
||||
return 1.0;
|
||||
return 0.5;
|
||||
}
|
||||
else if (when)
|
||||
return evalActivity(when, inst).duty();
|
||||
else if (search_->isClock(from_vertex))
|
||||
return 1.0;
|
||||
return 0.5;
|
||||
}
|
||||
else
|
||||
return 0.0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
|
|||
|
|
@ -566,6 +566,8 @@ getProperty(const LibertyCell *cell,
|
|||
return PropertyValue(cell->libertyLibrary());
|
||||
else if (stringEqual(property, "is_buffer"))
|
||||
return PropertyValue(cell->isBuffer());
|
||||
else if (stringEqual(property, "is_inverter"))
|
||||
return PropertyValue(cell->isInverter());
|
||||
else if (stringEqual(property, "dont_use"))
|
||||
return PropertyValue(cell->dontUse());
|
||||
else
|
||||
|
|
@ -686,6 +688,8 @@ getProperty(const LibertyPort *port,
|
|||
float cap = port->capacitance(RiseFall::rise(), MinMax::max());
|
||||
return PropertyValue(sta->units()->capacitanceUnit()->asString(cap, 6));
|
||||
}
|
||||
else if (stringEqual(property, "is_register_clock"))
|
||||
return PropertyValue(port->isRegClk());
|
||||
else if (stringEqual(property, "drive_resistance_rise_min"))
|
||||
return PropertyValue(port->driveResistance(RiseFall::rise(),
|
||||
MinMax::min()));
|
||||
|
|
@ -732,13 +736,17 @@ getProperty(const Pin *pin,
|
|||
Sta *sta)
|
||||
{
|
||||
auto network = sta->cmdNetwork();
|
||||
if (stringEqual(property, "direction"))
|
||||
return PropertyValue(network->direction(pin)->name());
|
||||
else if (stringEqual(property, "name")
|
||||
|| stringEqual(property, "full_name"))
|
||||
return PropertyValue(network->pathName(pin));
|
||||
else if (stringEqual(property, "lib_pin_name"))
|
||||
if (stringEqual(property, "name")
|
||||
|| stringEqual(property, "lib_pin_name"))
|
||||
return PropertyValue(network->portName(pin));
|
||||
else if (stringEqual(property, "full_name"))
|
||||
return PropertyValue(network->pathName(pin));
|
||||
else if (stringEqual(property, "direction"))
|
||||
return PropertyValue(network->direction(pin)->name());
|
||||
else if (stringEqual(property, "is_register_clock")) {
|
||||
const LibertyPort *port = network->libertyPort(pin);
|
||||
return PropertyValue(port && port->isRegClk());
|
||||
}
|
||||
else if (stringEqual(property, "clocks")) {
|
||||
ClockSet clks;
|
||||
sta->clocks(pin, clks);
|
||||
|
|
@ -793,12 +801,12 @@ pinSlewProperty(const Pin *pin,
|
|||
Slew slew = min_max->initValue();
|
||||
if (vertex) {
|
||||
Slew vertex_slew = sta->vertexSlew(vertex, rf, min_max);
|
||||
if (fuzzyGreater(vertex_slew, slew, min_max))
|
||||
if (delayGreater(vertex_slew, slew, min_max, sta))
|
||||
slew = vertex_slew;
|
||||
}
|
||||
if (bidirect_drvr_vertex) {
|
||||
Slew vertex_slew = sta->vertexSlew(bidirect_drvr_vertex, rf, min_max);
|
||||
if (fuzzyGreater(vertex_slew, slew, min_max))
|
||||
if (delayGreater(vertex_slew, slew, min_max, sta))
|
||||
slew = vertex_slew;
|
||||
}
|
||||
return PropertyValue(delayPropertyValue(slew, sta));
|
||||
|
|
@ -871,9 +879,9 @@ edgeDelayProperty(Edge *edge,
|
|||
ArcDelay arc_delay = sta->arcDelay(edge, arc, dcalc_ap);
|
||||
if (!delay_exists
|
||||
|| ((min_max == MinMax::max()
|
||||
&& arc_delay > delay)
|
||||
&& delayGreater(arc_delay, delay, sta))
|
||||
|| (min_max == MinMax::min()
|
||||
&& arc_delay < delay)))
|
||||
&& delayLess(arc_delay, delay, sta))))
|
||||
delay = arc_delay;
|
||||
}
|
||||
}
|
||||
|
|
@ -916,7 +924,9 @@ getProperty(Clock *clk,
|
|||
else if (stringEqual(property, "sources"))
|
||||
return PropertyValue(&clk->pins());
|
||||
else if (stringEqual(property, "propagated"))
|
||||
return PropertyValue(clk->isPropagated() ? "1" : "0");
|
||||
return PropertyValue(clk->isPropagated());
|
||||
else if (stringEqual(property, "is_generated"))
|
||||
return PropertyValue(clk->isGenerated());
|
||||
else
|
||||
throw PropertyUnknown("clock", property);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ ReportPath::~ReportPath()
|
|||
void
|
||||
ReportPath::makeFields()
|
||||
{
|
||||
field_fanout_ = makeField("fanout", "Fanout", 5, false, nullptr, true);
|
||||
field_fanout_ = makeField("fanout", "Fanout", 6, false, nullptr, true);
|
||||
field_capacitance_ = makeField("capacitance", "Cap", 6, false,
|
||||
units_->capacitanceUnit(), true);
|
||||
field_slew_ = makeField("slew", "Slew", 6, false, units_->timeUnit(),
|
||||
|
|
@ -578,7 +578,7 @@ ReportPath::reportFull(const PathEndLatchCheck *end,
|
|||
else
|
||||
reportTgtClk(end, result);
|
||||
|
||||
if (borrow >= 0.0)
|
||||
if (delayGreaterEqual(borrow, 0.0, this))
|
||||
reportLine("time borrowed from endpoint", borrow, req_time,
|
||||
early_late, result);
|
||||
else
|
||||
|
|
@ -644,7 +644,7 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end,
|
|||
if (tgt_clk_path->clkInfo(search_)->isPropagated()) {
|
||||
auto width_msg = stdstrPrint("%s nominal pulse width", tgt_clk_name.c_str());
|
||||
reportLineTotal(width_msg.c_str(), nom_pulse_width, early_late, result);
|
||||
if (!fuzzyZero(latency_diff))
|
||||
if (!delayZero(latency_diff))
|
||||
reportLineTotalMinus("clock latency difference", latency_diff,
|
||||
early_late, result);
|
||||
}
|
||||
|
|
@ -655,19 +655,19 @@ ReportPath::reportBorrowing(const PathEndLatchCheck *end,
|
|||
ArcDelay margin = end->margin(this);
|
||||
reportLineTotalMinus("library setup time", margin, early_late, result);
|
||||
reportDashLineTotal(result);
|
||||
if (!fuzzyZero(crpr_diff))
|
||||
if (!delayZero(crpr_diff))
|
||||
reportLineTotalMinus("CRPR difference", crpr_diff, early_late, result);
|
||||
reportLineTotal("max time borrow", max_borrow, early_late, result);
|
||||
}
|
||||
if (fuzzyGreater(borrow, delay_zero)
|
||||
if (delayGreater(borrow, delay_zero, this)
|
||||
&& (!fuzzyZero(open_uncertainty)
|
||||
|| !fuzzyZero(open_crpr))) {
|
||||
|| !delayZero(open_crpr))) {
|
||||
reportDashLineTotal(result);
|
||||
reportLineTotal("actual time borrow", borrow, early_late, result);
|
||||
if (!fuzzyZero(open_uncertainty))
|
||||
reportLineTotal("open edge uncertainty", open_uncertainty,
|
||||
early_late, result);
|
||||
if (!fuzzyZero(open_crpr))
|
||||
if (!delayZero(open_crpr))
|
||||
reportLineTotal("open edge CRPR", open_crpr, early_late, result);
|
||||
reportDashLineTotal(result);
|
||||
reportLineTotal("time given to startpoint", time_given_to_startpoint,
|
||||
|
|
@ -705,12 +705,16 @@ void
|
|||
ReportPath::reportEndpoint(const PathEndPathDelay *end,
|
||||
string &result)
|
||||
{
|
||||
Instance *inst = network_->instance(end->vertex(this)->pin());
|
||||
const char *inst_name = cmd_network_->pathName(inst);
|
||||
string clk_name = tgtClkName(end);
|
||||
const char *reg_desc = clkRegLatchDesc(end);
|
||||
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
||||
reportEndpoint(inst_name, reason, result);
|
||||
if (end->hasOutputDelay())
|
||||
reportEndpointOutputDelay(end, result);
|
||||
else {
|
||||
Instance *inst = network_->instance(end->vertex(this)->pin());
|
||||
const char *inst_name = cmd_network_->pathName(inst);
|
||||
string clk_name = tgtClkName(end);
|
||||
const char *reg_desc = clkRegLatchDesc(end);
|
||||
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
||||
reportEndpoint(inst_name, reason, result);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -746,18 +750,16 @@ ReportPath::reportFull(const PathEndPathDelay *end,
|
|||
float delay = path_delay->delay();
|
||||
reportLine(delay_msg.c_str(), delay, delay, early_late, result);
|
||||
if (!path_delay->ignoreClkLatency()) {
|
||||
const Path *tgt_clk_path = end->targetClkPath();
|
||||
if (tgt_clk_path) {
|
||||
float delay = 0.0;
|
||||
if (path_delay)
|
||||
delay = path_delay->delay();
|
||||
Clock *tgt_clk = end->targetClk(this);
|
||||
if (tgt_clk) {
|
||||
const Path *tgt_clk_path = end->targetClkPath();
|
||||
if (reportClkPath()
|
||||
&& isPropagated(tgt_clk_path))
|
||||
&& isPropagated(tgt_clk_path, tgt_clk))
|
||||
reportTgtClk(end, delay, result);
|
||||
else {
|
||||
Arrival tgt_clk_delay = end->targetClkDelay(this);
|
||||
Arrival tgt_clk_arrival = delay + tgt_clk_delay;
|
||||
if (!fuzzyZero(tgt_clk_delay))
|
||||
if (!delayZero(tgt_clk_delay))
|
||||
reportLine(clkNetworkDelayIdealProp(isPropagated(tgt_clk_path)),
|
||||
tgt_clk_delay, tgt_clk_arrival, early_late, result);
|
||||
reportClkUncertainty(end, tgt_clk_arrival, result);
|
||||
|
|
@ -832,6 +834,13 @@ ReportPath::reportFull(const PathEndOutputDelay *end,
|
|||
void
|
||||
ReportPath::reportEndpoint(const PathEndOutputDelay *end,
|
||||
string &result)
|
||||
{
|
||||
reportEndpointOutputDelay(end, result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportEndpointOutputDelay(const PathEndClkConstrained *end,
|
||||
string &result)
|
||||
{
|
||||
Vertex *vertex = end->vertex(this);
|
||||
Pin *pin = vertex->pin();
|
||||
|
|
@ -851,6 +860,7 @@ ReportPath::reportEndpoint(const PathEndOutputDelay *end,
|
|||
if (tgt_clk) {
|
||||
string clk_name = tgtClkName(end);
|
||||
auto reason = stdstrPrint("internal path endpoint clocked by %s", clk_name.c_str());
|
||||
|
||||
reportEndpoint(pin_name, reason, result);
|
||||
}
|
||||
else
|
||||
|
|
@ -1367,8 +1377,8 @@ ReportPath::reportVerbose(MinPeriodCheck *check, string &result)
|
|||
result += pin_name;
|
||||
reportEndOfLine(result);
|
||||
|
||||
reportLine("Period", check->period(), EarlyLate::early(), result);
|
||||
reportLine("min_period", -check->minPeriod(this),
|
||||
reportLine("period", check->period(), EarlyLate::early(), result);
|
||||
reportLine("min period", -check->minPeriod(this),
|
||||
EarlyLate::early(), result);
|
||||
reportDashLine(result);
|
||||
reportSlack(check->slack(this), result);
|
||||
|
|
@ -1549,99 +1559,118 @@ ReportPath::reportSkewClkPath(const char *arrival_msg,
|
|||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
ReportPath::reportSlewLimitShortHeader()
|
||||
ReportPath::reportLimitShortHeader(const ReportField *field)
|
||||
{
|
||||
string result;
|
||||
reportSlewLimitShortHeader(result);
|
||||
reportLimitShortHeader(field, result);
|
||||
report_->print(result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportSlewLimitShortHeader(string &result)
|
||||
ReportPath::reportLimitShortHeader(const ReportField *field,
|
||||
string &result)
|
||||
{
|
||||
reportDescription("Pin", result);
|
||||
result += ' ';
|
||||
reportField("Limit", field_slew_, result);
|
||||
reportField("Limit", field, result);
|
||||
result += ' ';
|
||||
reportField("Trans", field_slew_, result);
|
||||
reportField(field->title(), field, result);
|
||||
result += ' ';
|
||||
reportField("Slack", field_slew_, result);
|
||||
reportField("Slack", field, result);
|
||||
reportEndOfLine(result);
|
||||
reportDashLine(field_description_->width() + field_slew_->width() * 3 + 3,
|
||||
reportDashLine(field_description_->width() + field->width() * 3 + 3,
|
||||
result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportSlewLimitShort(Pin *pin,
|
||||
const RiseFall *rf,
|
||||
Slew slew,
|
||||
float limit,
|
||||
float slack)
|
||||
ReportPath::reportLimitShort(const ReportField *field,
|
||||
Pin *pin,
|
||||
float value,
|
||||
float limit,
|
||||
float slack)
|
||||
{
|
||||
string result;
|
||||
reportSlewLimitShort(pin, rf, slew, limit, slack, result);
|
||||
reportLimitShort(field, pin, value, limit, slack, result);
|
||||
report_->print(result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportSlewLimitShort(Pin *pin,
|
||||
const RiseFall *,
|
||||
Slew slew,
|
||||
float limit,
|
||||
float slack,
|
||||
string &result)
|
||||
ReportPath::reportLimitShort(const ReportField *field,
|
||||
Pin *pin,
|
||||
float value,
|
||||
float limit,
|
||||
float slack,
|
||||
string &result)
|
||||
{
|
||||
const char *pin_name = cmd_network_->pathName(pin);
|
||||
reportDescription(pin_name, result);
|
||||
reportSpaceFieldTime(limit, result);
|
||||
reportSpaceFieldDelay(slew, EarlyLate::late(), result);
|
||||
reportSpaceSlack(slack, result);
|
||||
result += ' ';
|
||||
reportField(limit, field, result);
|
||||
result += ' ';
|
||||
reportField(value, field, result);
|
||||
result += ' ';
|
||||
reportField(slack, field, result);
|
||||
result += (slack >= 0.0)
|
||||
? " (MET)"
|
||||
: " (VIOLATED)";
|
||||
reportEndOfLine(result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportSlewLimitVerbose(Pin *pin,
|
||||
const Corner *corner,
|
||||
const RiseFall *rf,
|
||||
Slew slew,
|
||||
float limit,
|
||||
float slack,
|
||||
const MinMax *min_max)
|
||||
ReportPath::reportLimitVerbose(const ReportField *field,
|
||||
Pin *pin,
|
||||
const RiseFall *rf,
|
||||
float value,
|
||||
float limit,
|
||||
float slack,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
string result;
|
||||
reportSlewLimitVerbose(pin, corner, rf, slew, limit, slack, min_max, result);
|
||||
reportLimitVerbose(field, pin, rf, value, limit, slack, min_max, result);
|
||||
report_->print(result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportSlewLimitVerbose(Pin *pin,
|
||||
const Corner *,
|
||||
const RiseFall *rf,
|
||||
Slew slew,
|
||||
float limit,
|
||||
float slack,
|
||||
const MinMax *min_max,
|
||||
string &result)
|
||||
ReportPath::reportLimitVerbose(const ReportField *field,
|
||||
Pin *pin,
|
||||
const RiseFall *rf,
|
||||
float value,
|
||||
float limit,
|
||||
float slack,
|
||||
const MinMax *min_max,
|
||||
string &result)
|
||||
{
|
||||
result += "Pin ";
|
||||
result += cmd_network_->pathName(pin);
|
||||
result += ' ';
|
||||
result += rf->shortName();
|
||||
if (rf)
|
||||
result += rf->shortName();
|
||||
else
|
||||
result += ' ';
|
||||
reportEndOfLine(result);
|
||||
|
||||
result += min_max->asString();
|
||||
result += "_transition ";
|
||||
reportSpaceFieldTime(limit, result);
|
||||
result += ' ';
|
||||
result += field->name();
|
||||
result += ' ';
|
||||
reportField(limit, field, result);
|
||||
reportEndOfLine(result);
|
||||
|
||||
result += "transition_time ";
|
||||
reportField(delayAsFloat(slew), field_slew_, result);
|
||||
result += field->name();
|
||||
result += " ";
|
||||
reportField(value, field, result);
|
||||
reportEndOfLine(result);
|
||||
int name_width = strlen(field->name()) + 5;
|
||||
reportDashLine(name_width + field->width(), result);
|
||||
|
||||
reportDashLine(strlen("transition_time") + field_slew_->width() + 1,
|
||||
result);
|
||||
|
||||
result += "Slack ";
|
||||
reportSpaceSlack(slack, result);
|
||||
result += "Slack";
|
||||
for (int i = strlen("Slack"); i < name_width; i++)
|
||||
result += ' ';
|
||||
reportField(slack, field, result);
|
||||
result += (slack >= 0.0)
|
||||
? " (MET)"
|
||||
: " (VIOLATED)";
|
||||
reportEndOfLine(result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -2021,13 +2050,24 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
|||
else if (clk_used_as_data) {
|
||||
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time,
|
||||
early_late, result);
|
||||
if (clk_insertion > 0.0)
|
||||
if (delayGreater(clk_insertion, 0.0, this))
|
||||
reportClkSrcLatency(clk_insertion, clk_time, early_late, result);
|
||||
reportPath1(path, expanded, true, time_offset, result);
|
||||
if (reportClkPath())
|
||||
reportPath1(path, expanded, true, time_offset, result);
|
||||
else {
|
||||
Arrival clk_arrival = clk_end_time;
|
||||
Arrival end_arrival = path->arrival(this) + time_offset;
|
||||
Delay clk_delay = end_arrival - clk_arrival;
|
||||
reportLine("clock network delay", clk_delay,
|
||||
end_arrival, early_late, result);
|
||||
Vertex *end_vertex = path->vertex(this);
|
||||
reportLine(descriptionField(end_vertex).c_str(),
|
||||
end_arrival, early_late, clk_end_rf, result);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (is_path_delay) {
|
||||
if (clk_delay > 0.0)
|
||||
if (delayGreater(clk_delay, 0.0, this))
|
||||
reportLine(clkNetworkDelayIdealProp(is_prop), clk_delay,
|
||||
clk_end_time, early_late, result);
|
||||
}
|
||||
|
|
@ -2167,10 +2207,10 @@ ReportPath::pathFromGenPropClk(const Path *clk_path,
|
|||
float insertion;
|
||||
bool exists;
|
||||
sdc_->clockInsertion(clk, clk_info->clkSrc(),
|
||||
clk_edge->transition(),
|
||||
clk_path->minMax(this),
|
||||
early_late,
|
||||
insertion, exists);
|
||||
clk_edge->transition(),
|
||||
clk_path->minMax(this),
|
||||
early_late,
|
||||
insertion, exists);
|
||||
return !exists
|
||||
&& clk->isGeneratedWithPropagatedMaster();
|
||||
}
|
||||
|
|
@ -2187,8 +2227,8 @@ ReportPath::isGenPropClk(const Clock *clk,
|
|||
float insertion;
|
||||
bool exists;
|
||||
sdc_->clockInsertion(clk, clk->srcPin(), clk_rf,
|
||||
min_max, early_late,
|
||||
insertion, exists);
|
||||
min_max, early_late,
|
||||
insertion, exists);
|
||||
return !exists
|
||||
&& clk->isGeneratedWithPropagatedMaster();
|
||||
}
|
||||
|
|
@ -2474,6 +2514,27 @@ ReportPath::reportPath(const PathEnd *end,
|
|||
void
|
||||
ReportPath::reportPath(const Path *path,
|
||||
string &result)
|
||||
{
|
||||
switch (format_) {
|
||||
case ReportPathFormat::full:
|
||||
case ReportPathFormat::full_clock:
|
||||
case ReportPathFormat::full_clock_expanded:
|
||||
reportPathFull(path, result);
|
||||
break;
|
||||
case ReportPathFormat::json:
|
||||
reportPathJson(path, result);
|
||||
break;
|
||||
case ReportPathFormat::summary:
|
||||
case ReportPathFormat::slack_only:
|
||||
default:
|
||||
internalError("unsupported path type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportPathFull(const Path *path,
|
||||
string &result)
|
||||
{
|
||||
reportPathHeader(result);
|
||||
PathExpanded expanded(path, this);
|
||||
|
|
@ -2481,6 +2542,50 @@ ReportPath::reportPath(const Path *path,
|
|||
false, result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportPathJson(const Path *path,
|
||||
string &result)
|
||||
{
|
||||
result += "{ \"path\": [\n";
|
||||
PathExpanded expanded(path, this);
|
||||
for (auto i = expanded.startIndex(); i < expanded.size(); i++) {
|
||||
PathRef *path = expanded.path(i);
|
||||
const Pin *pin = path->vertex(this)->pin();
|
||||
result += " {\n";
|
||||
result += " \"pin\": \"";
|
||||
result += network_->pathName(pin);
|
||||
result += "\",\n";
|
||||
|
||||
double x, y;
|
||||
bool exists;
|
||||
string tmp;
|
||||
network_->location(pin, x, y, exists);
|
||||
if (exists) {
|
||||
result += " \"x\": ";
|
||||
stringPrint(tmp, "%.9f", x);
|
||||
result += tmp + ",\n";
|
||||
result += " \"y\": ";
|
||||
stringPrint(tmp, "%.9f", y);
|
||||
result += tmp + ",\n";
|
||||
}
|
||||
|
||||
result += " \"arrival\": ";
|
||||
stringPrint(tmp, "%.3e", delayAsFloat(path->arrival(this)));
|
||||
result += tmp + ",\n";
|
||||
|
||||
result += " \"slew\": ";
|
||||
stringPrint(tmp, "%.3e", delayAsFloat(path->slew(this)));
|
||||
result += tmp + "\n";
|
||||
|
||||
result += " }";
|
||||
if (i < expanded.size() - 1)
|
||||
result += ",";
|
||||
result += "\n";
|
||||
}
|
||||
result += " ]\n";
|
||||
result += "}\n";
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportPath1(const Path *path,
|
||||
PathExpanded &expanded,
|
||||
|
|
@ -2508,7 +2613,7 @@ ReportPath::reportPath1(const Path *path,
|
|||
}
|
||||
Arrival time = latch_enable_time + latch_time_given;
|
||||
Arrival incr = latch_time_given;
|
||||
if (incr >= 0.0)
|
||||
if (delayGreaterEqual(incr, 0.0, this))
|
||||
reportLine("time given to startpoint", incr, time, early_late, result);
|
||||
else
|
||||
reportLine("time borrowed from startpoint", incr, time,
|
||||
|
|
@ -2608,7 +2713,7 @@ ReportPath::reportPath5(const Path *path,
|
|||
Vertex *vertex = path1->vertex(this);
|
||||
Pin *pin = vertex->pin();
|
||||
Arrival time = path1->arrival(this) + time_offset;
|
||||
float incr = 0.0;
|
||||
Delay incr = 0.0;
|
||||
const char *line_case = nullptr;
|
||||
bool is_clk_start = network_->isRegClkPin(pin);
|
||||
bool is_clk = path1->isClock(search_);
|
||||
|
|
@ -2633,8 +2738,7 @@ ReportPath::reportPath5(const Path *path,
|
|||
// from the input to the loads. Report the wire delay on the
|
||||
// input pin instead.
|
||||
Arrival next_time = next_path->arrival(this) + time_offset;
|
||||
incr = delayAsFloat(next_time, min_max, this)
|
||||
- delayAsFloat(time, min_max, this);
|
||||
incr = delayIncr(next_time, time, min_max);
|
||||
time = next_time;
|
||||
line_case = "input_drive";
|
||||
}
|
||||
|
|
@ -2681,13 +2785,11 @@ ReportPath::reportPath5(const Path *path,
|
|||
line_case = "clk_ideal";
|
||||
}
|
||||
else if (is_clk && !is_clk_start) {
|
||||
incr = delayAsFloat(time, min_max, this)
|
||||
- delayAsFloat(prev_time, min_max, this);
|
||||
incr = delayIncr(time, prev_time, min_max);
|
||||
line_case = "clk_prop";
|
||||
}
|
||||
else {
|
||||
incr = delayAsFloat(time, min_max, this)
|
||||
- delayAsFloat(prev_time, min_max, this);
|
||||
incr = delayIncr(time, prev_time, min_max);
|
||||
line_case = "normal";
|
||||
}
|
||||
if (report_input_pin_
|
||||
|
|
@ -2739,6 +2841,17 @@ ReportPath::reportPath5(const Path *path,
|
|||
}
|
||||
}
|
||||
|
||||
Delay
|
||||
ReportPath::delayIncr(Delay time,
|
||||
Delay prev,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
if (report_sigmas_)
|
||||
return delayRemove(time, prev);
|
||||
else
|
||||
return delayAsFloat(time, min_max, this) - delayAsFloat(prev, min_max, this);
|
||||
}
|
||||
|
||||
bool
|
||||
ReportPath::nextArcAnnotated(const PathRef *next_path,
|
||||
size_t next_index,
|
||||
|
|
@ -2884,7 +2997,9 @@ ReportPath::loadCap(Pin *drvr_pin,
|
|||
Parasitic *parasitic = nullptr;
|
||||
if (arc_delay_calc_)
|
||||
parasitic = arc_delay_calc_->findParasitic(drvr_pin, rf, dcalc_ap);
|
||||
return graph_delay_calc_->loadCap(drvr_pin, parasitic, rf, dcalc_ap);
|
||||
float load_cap = graph_delay_calc_->loadCap(drvr_pin, parasitic, rf, dcalc_ap);
|
||||
arc_delay_calc_->finishDrvrPin();
|
||||
return load_cap;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -3177,8 +3292,8 @@ ReportPath::reportFieldDelayMinus(Delay value,
|
|||
else {
|
||||
const char *str = report_sigmas_
|
||||
? delayAsString(-value, this, digits_)
|
||||
// : delayAsString(-value, early_late, this, digits_);
|
||||
: units_->timeUnit()->asString(-delayAsFloat(value, early_late, this), digits_);
|
||||
// Opposite min/max for negative value.
|
||||
: delayAsString(-value, early_late->opposite(), this, digits_);
|
||||
if (stringEq(str, plus_zero_))
|
||||
// Force leading minus sign.
|
||||
str = minus_zero_;
|
||||
|
|
@ -3207,20 +3322,24 @@ ReportPath::reportFieldDelay(Delay value,
|
|||
|
||||
void
|
||||
ReportPath::reportField(float value,
|
||||
ReportField *field,
|
||||
const ReportField *field,
|
||||
string &result)
|
||||
{
|
||||
if (value == field_blank_)
|
||||
reportFieldBlank(field, result);
|
||||
else {
|
||||
const char *value_str = field->unit()->asString(value, digits_);
|
||||
Unit *unit = field->unit();
|
||||
const char *value_str = (unit)
|
||||
? unit->asString(value, digits_)
|
||||
// fanout
|
||||
: stringPrintTmp("%.0f", value);
|
||||
reportField(value_str, field, result);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportField(const char *value,
|
||||
ReportField *field,
|
||||
const ReportField *field,
|
||||
string &result)
|
||||
{
|
||||
if (field->leftJustify())
|
||||
|
|
@ -3232,7 +3351,7 @@ ReportPath::reportField(const char *value,
|
|||
}
|
||||
|
||||
void
|
||||
ReportPath::reportFieldBlank(ReportField *field,
|
||||
ReportPath::reportFieldBlank(const ReportField *field,
|
||||
string &result)
|
||||
{
|
||||
result += field->blank();
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ public:
|
|||
void reportPathEnd(PathEnd *end,
|
||||
PathEnd *prev_end);
|
||||
void reportPathEnds(PathEndSeq *ends);
|
||||
// for debugging
|
||||
void reportPath(const Path *path);
|
||||
|
||||
void reportShort(const PathEndUnconstrained *end,
|
||||
|
|
@ -137,34 +138,38 @@ public:
|
|||
void reportVerbose(MaxSkewCheck *check,
|
||||
string &result);
|
||||
|
||||
void reportSlewLimitShortHeader();
|
||||
void reportSlewLimitShortHeader(string &result);
|
||||
void reportSlewLimitShort(Pin *pin,
|
||||
const RiseFall *rf,
|
||||
Slew slew,
|
||||
float limit,
|
||||
float slack);
|
||||
void reportSlewLimitShort(Pin *pin, const
|
||||
RiseFall *rf,
|
||||
Slew slew,
|
||||
float limit,
|
||||
float slack,
|
||||
string &result);
|
||||
void reportSlewLimitVerbose(Pin *pin,
|
||||
const Corner *corner,
|
||||
const RiseFall *rf,
|
||||
Slew slew,
|
||||
float limit,
|
||||
float slack,
|
||||
const MinMax *min_max);
|
||||
void reportSlewLimitVerbose(Pin *pin,
|
||||
const Corner *corner,
|
||||
const RiseFall *rf,
|
||||
Slew slew,
|
||||
float limit,
|
||||
float slack,
|
||||
const MinMax *min_max,
|
||||
void reportLimitShortHeader(const ReportField *field);
|
||||
void reportLimitShortHeader(const ReportField *field,
|
||||
string &result);
|
||||
void reportLimitShort(const ReportField *field,
|
||||
Pin *pin,
|
||||
float value,
|
||||
float limit,
|
||||
float slack);
|
||||
void reportLimitShort(const ReportField *field,
|
||||
Pin *pin,
|
||||
float value,
|
||||
float limit,
|
||||
float slack,
|
||||
string &result);
|
||||
void reportLimitVerbose(const ReportField *field,
|
||||
Pin *pin,
|
||||
const RiseFall *rf,
|
||||
float value,
|
||||
float limit,
|
||||
float slack,
|
||||
const MinMax *min_max);
|
||||
void reportLimitVerbose(const ReportField *field,
|
||||
Pin *pin,
|
||||
const RiseFall *rf,
|
||||
float value,
|
||||
float limit,
|
||||
float slack,
|
||||
const MinMax *min_max,
|
||||
string &result);
|
||||
ReportField *fieldSlew() const { return field_slew_; }
|
||||
ReportField *fieldFanout() const { return field_fanout_; }
|
||||
ReportField *fieldCapacitance() const { return field_capacitance_; }
|
||||
|
||||
protected:
|
||||
void makeFields();
|
||||
|
|
@ -199,6 +204,8 @@ protected:
|
|||
string &result);
|
||||
void reportEndpoint(const PathEndOutputDelay *end,
|
||||
string &result);
|
||||
void reportEndpointOutputDelay(const PathEndClkConstrained *end,
|
||||
string &result);
|
||||
void reportEndpoint(const PathEndPathDelay *end,
|
||||
string &result);
|
||||
void reportEndpoint(const PathEndGatedClock *end,
|
||||
|
|
@ -335,6 +342,10 @@ protected:
|
|||
string &result);
|
||||
void reportPath(const Path *path,
|
||||
string &result);
|
||||
void reportPathFull(const Path *path,
|
||||
string &result);
|
||||
void reportPathJson(const Path *path,
|
||||
string &result);
|
||||
void reportPathHeader(string &result);
|
||||
void reportPath1(const Path *path,
|
||||
PathExpanded &expanded,
|
||||
|
|
@ -453,12 +464,12 @@ protected:
|
|||
ReportField *field,
|
||||
string &result);
|
||||
void reportField(float value,
|
||||
ReportField *field,
|
||||
const ReportField *field,
|
||||
string &result);
|
||||
void reportField(const char *value,
|
||||
ReportField *field,
|
||||
const ReportField *field,
|
||||
string &result);
|
||||
void reportFieldBlank(ReportField *field,
|
||||
void reportFieldBlank(const ReportField *field,
|
||||
string &result);
|
||||
void reportDashLine(string &result);
|
||||
void reportDashLine(int line_width,
|
||||
|
|
@ -514,6 +525,9 @@ protected:
|
|||
PathRef &ref_path);
|
||||
const char *asRisingFalling(const RiseFall *rf);
|
||||
const char *asRiseFall(const RiseFall *rf);
|
||||
Delay delayIncr(Delay time,
|
||||
Delay prev,
|
||||
const MinMax *min_max);
|
||||
|
||||
// Path options.
|
||||
ReportPathFormat format_;
|
||||
|
|
@ -564,7 +578,7 @@ public:
|
|||
void setWidth(int width);
|
||||
bool leftJustify() const { return left_justify_; }
|
||||
Unit *unit() const { return unit_; }
|
||||
const char *blank() { return blank_; }
|
||||
const char *blank() const { return blank_; }
|
||||
void setEnabled(bool enabled);
|
||||
bool enabled() const { return enabled_; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1194,7 +1194,7 @@ Search::arrivalsChanged(Vertex *vertex,
|
|||
bool arrival_exists2;
|
||||
tag_bldr->tagArrival(tag1, arrival2, arrival_exists2);
|
||||
if (!arrival_exists2
|
||||
|| !fuzzyEqual(arrival1, arrival2))
|
||||
|| !delayEqual(arrival1, arrival2))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -1238,7 +1238,7 @@ ArrivalVisitor::visitFromToPath(const Pin *,
|
|||
Tag *tag_match;
|
||||
tag_bldr_->tagMatchArrival(to_tag, tag_match, arrival, arrival_index);
|
||||
if (tag_match == nullptr
|
||||
|| fuzzyGreater(to_arrival, arrival, min_max)) {
|
||||
|| delayGreater(to_arrival, arrival, min_max, sta_)) {
|
||||
debugPrint5(debug, "search", 3, " %s + %s = %s %s %s\n",
|
||||
delayAsString(from_path->arrival(sta_), sta_),
|
||||
delayAsString(arc_delay, sta_),
|
||||
|
|
@ -1258,7 +1258,7 @@ ArrivalVisitor::visitFromToPath(const Pin *,
|
|||
tag_bldr_no_crpr_->tagMatchArrival(to_tag, tag_match,
|
||||
arrival, arrival_index);
|
||||
if (tag_match == nullptr
|
||||
|| fuzzyGreater(to_arrival, arrival, min_max)) {
|
||||
|| delayGreater(to_arrival, arrival, min_max, sta_)) {
|
||||
tag_bldr_no_crpr_->setMatchArrival(to_tag, tag_match,
|
||||
to_arrival, arrival_index,
|
||||
&prev_path);
|
||||
|
|
@ -1300,7 +1300,7 @@ ArrivalVisitor::pruneCrprArrivals()
|
|||
delayAsString(max_crpr, sta_),
|
||||
delayAsString(max_arrival_max_crpr, sta_));
|
||||
Arrival arrival = tag_bldr_->arrival(arrival_index);
|
||||
if (fuzzyGreater(max_arrival_max_crpr, arrival, min_max)) {
|
||||
if (delayGreater(max_arrival_max_crpr, arrival, min_max, sta_)) {
|
||||
debugPrint1(debug, "search", 3, " pruned %s\n",
|
||||
tag->asString(sta_));
|
||||
tag_bldr_->deleteArrival(tag);
|
||||
|
|
@ -2207,7 +2207,7 @@ PathVisitor::visitFromPath(const Pin *from_pin,
|
|||
}
|
||||
else {
|
||||
arc_delay = search->deratedDelay(from_vertex, arc, edge, false, path_ap);
|
||||
if (!fuzzyEqual(arc_delay, min_max->initValue())) {
|
||||
if (!delayEqual(arc_delay, min_max->initValue())) {
|
||||
to_arrival = from_arrival + arc_delay;
|
||||
to_tag = search->thruTag(from_tag, edge, to_rf, min_max, path_ap);
|
||||
}
|
||||
|
|
@ -2262,8 +2262,13 @@ Search::pathClkPathArrival(const Path *path) const
|
|||
pathClkPathArrival1(path, src_clk_path);
|
||||
if (!src_clk_path.isNull())
|
||||
return clkPathArrival(&src_clk_path);
|
||||
else
|
||||
return 0.0;
|
||||
else {
|
||||
// Check for input arrival clock.
|
||||
ClockEdge *clk_edge = path->clkEdge(this);
|
||||
if (clk_edge)
|
||||
return clk_edge->time();
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// PathExpanded::expand() and PathExpanded::clkPath().
|
||||
|
|
@ -3249,7 +3254,7 @@ FindEndRequiredVisitor::visit(PathEnd *path_end)
|
|||
bool arrival_exists;
|
||||
path.arrivalIndex(arrival_index, arrival_exists);
|
||||
Required required = path_end->requiredTime(sta_);
|
||||
required_cmp_->requiredSet(arrival_index, required, req_min);
|
||||
required_cmp_->requiredSet(arrival_index, required, req_min, sta_);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3314,9 +3319,10 @@ RequiredCmp::requiredsInit(Vertex *vertex,
|
|||
void
|
||||
RequiredCmp::requiredSet(int arrival_index,
|
||||
Required required,
|
||||
const MinMax *min_max)
|
||||
const MinMax *min_max,
|
||||
const StaState *sta)
|
||||
{
|
||||
if (fuzzyGreater(required, requireds_[arrival_index], min_max)) {
|
||||
if (delayGreater(required, requireds_[arrival_index], min_max, sta)) {
|
||||
requireds_[arrival_index] = required;
|
||||
have_requireds_ = true;
|
||||
}
|
||||
|
|
@ -3341,7 +3347,7 @@ RequiredCmp::requiredsSave(Vertex *vertex,
|
|||
Required req = requireds_[arrival_index];
|
||||
if (prev_reqs) {
|
||||
Required prev_req = path->required(sta);
|
||||
if (!fuzzyEqual(prev_req, req)) {
|
||||
if (!delayEqual(prev_req, req)) {
|
||||
debugPrint2(debug, "search", 3, "required save %s -> %s\n",
|
||||
delayAsString(prev_req, sta),
|
||||
delayAsString(req, sta));
|
||||
|
|
@ -3445,7 +3451,7 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
|||
const MinMax *req_min = min_max->opposite();
|
||||
TagGroup *to_tag_group = sta_->search()->tagGroup(to_vertex);
|
||||
// Check to see if to_tag was pruned.
|
||||
if (to_tag_group->hasTag(to_tag)) {
|
||||
if (to_tag_group && to_tag_group->hasTag(to_tag)) {
|
||||
PathVertex to_path(to_vertex, to_tag, sta_);
|
||||
Required to_required = to_path.required(sta_);
|
||||
Required from_required = to_required - arc_delay;
|
||||
|
|
@ -3458,7 +3464,7 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
|||
delayAsString(from_required, sta_),
|
||||
min_max == MinMax::max() ? "<" : ">",
|
||||
delayAsString(required_cmp_->required(arrival_index), sta_));
|
||||
required_cmp_->requiredSet(arrival_index, from_required, req_min);
|
||||
required_cmp_->requiredSet(arrival_index, from_required, req_min, sta_);
|
||||
}
|
||||
else {
|
||||
if (sta_->search()->crprApproxMissingRequireds()) {
|
||||
|
|
@ -3482,7 +3488,7 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
|||
min_max == MinMax::max() ? "<" : ">",
|
||||
delayAsString(required_cmp_->required(arrival_index),
|
||||
sta_));
|
||||
required_cmp_->requiredSet(arrival_index, from_required, req_min);
|
||||
required_cmp_->requiredSet(arrival_index, from_required, req_min, sta_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -3635,7 +3641,7 @@ Search::totalNegativeSlack(const MinMax *min_max)
|
|||
for (Corner *corner : *corners_) {
|
||||
PathAPIndex path_ap_index = corner->findPathAnalysisPt(min_max)->index();
|
||||
Slack tns1 = tns_[path_ap_index];
|
||||
if (tns1 < tns)
|
||||
if (delayLess(tns1, tns, this))
|
||||
tns = tns1;
|
||||
}
|
||||
return tns;
|
||||
|
|
@ -3730,7 +3736,7 @@ Search::tnsIncr(Vertex *vertex,
|
|||
Slack slack,
|
||||
PathAPIndex path_ap_index)
|
||||
{
|
||||
if (fuzzyLess(slack, 0.0)) {
|
||||
if (delayLess(slack, 0.0, this)) {
|
||||
debugPrint2(debug_, "tns", 3, "tns+ %s %s\n",
|
||||
delayAsString(slack, this),
|
||||
vertex->name(sdc_network_));
|
||||
|
|
@ -3749,7 +3755,7 @@ Search::tnsDecr(Vertex *vertex,
|
|||
bool found;
|
||||
tns_slacks_[path_ap_index].findKey(vertex, slack, found);
|
||||
if (found
|
||||
&& fuzzyLess(slack, 0.0)) {
|
||||
&& delayLess(slack, 0.0, this)) {
|
||||
debugPrint2(debug_, "tns", 3, "tns- %s %s\n",
|
||||
delayAsString(slack, this),
|
||||
vertex->name(sdc_network_));
|
||||
|
|
@ -3875,7 +3881,7 @@ FindEndSlackVisitor::visit(PathEnd *path_end)
|
|||
PathRef &path = path_end->pathRef();
|
||||
PathAPIndex path_ap_index = path.pathAnalysisPtIndex(sta_);
|
||||
Slack slack = path_end->slack(sta_);
|
||||
if (fuzzyLess(slack, slacks_[path_ap_index]))
|
||||
if (delayLess(slack, slacks_[path_ap_index], sta_))
|
||||
slacks_[path_ap_index] = slack;
|
||||
}
|
||||
}
|
||||
|
|
@ -3902,7 +3908,7 @@ Search::wnsSlacks(Vertex *vertex,
|
|||
PathAPIndex path_ap_index = path->pathAnalysisPtIndex(this);
|
||||
const Slack path_slack = path->slack(this);
|
||||
if (!path->tag(this)->isFilter()
|
||||
&& fuzzyLess(path_slack, slacks[path_ap_index]))
|
||||
&& delayLess(path_slack, slacks[path_ap_index], this))
|
||||
slacks[path_ap_index] = path_slack;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -837,8 +837,12 @@ Sim::removePropagatedValue(const Pin *pin)
|
|||
if (!exists) {
|
||||
debugPrint1(debug_, "sim", 2, "pin %s remove prop constant\n",
|
||||
network_->pathName(pin));
|
||||
Vertex *vertex = graph_->pinLoadVertex(pin);
|
||||
setSimValue(vertex, LogicValue::unknown);
|
||||
Vertex *vertex, *bidirect_drvr_vertex;
|
||||
graph_->pinVertices(pin, vertex, bidirect_drvr_vertex);
|
||||
if (vertex)
|
||||
setSimValue(vertex, LogicValue::unknown);
|
||||
if (bidirect_drvr_vertex)
|
||||
setSimValue(bidirect_drvr_vertex, LogicValue::unknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
266
search/Sta.cc
266
search/Sta.cc
|
|
@ -55,6 +55,8 @@
|
|||
#include "PathGroup.hh"
|
||||
#include "CheckTiming.hh"
|
||||
#include "CheckSlewLimits.hh"
|
||||
#include "CheckFanoutLimits.hh"
|
||||
#include "CheckCapacitanceLimits.hh"
|
||||
#include "CheckMinPulseWidths.hh"
|
||||
#include "CheckMinPeriods.hh"
|
||||
#include "CheckMaxSkews.hh"
|
||||
|
|
@ -256,6 +258,8 @@ Sta::Sta() :
|
|||
current_instance_(nullptr),
|
||||
check_timing_(nullptr),
|
||||
check_slew_limits_(nullptr),
|
||||
check_fanout_limits_(nullptr),
|
||||
check_capacitance_limits_(nullptr),
|
||||
check_min_pulse_widths_(nullptr),
|
||||
check_min_periods_(nullptr),
|
||||
check_max_skews_(nullptr),
|
||||
|
|
@ -437,6 +441,18 @@ Sta::makeCheckSlewLimits()
|
|||
check_slew_limits_ = new CheckSlewLimits(this);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::makeCheckFanoutLimits()
|
||||
{
|
||||
check_fanout_limits_ = new CheckFanoutLimits(this);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::makeCheckCapacitanceLimits()
|
||||
{
|
||||
check_capacitance_limits_ = new CheckCapacitanceLimits(this);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::makeCheckMinPulseWidths()
|
||||
{
|
||||
|
|
@ -483,6 +499,8 @@ Sta::~Sta()
|
|||
{
|
||||
// Delete "top down" to minimize chance of referencing deleted memory.
|
||||
delete check_slew_limits_;
|
||||
delete check_fanout_limits_;
|
||||
delete check_capacitance_limits_;
|
||||
delete check_min_pulse_widths_;
|
||||
delete check_min_periods_;
|
||||
delete check_max_skews_;
|
||||
|
|
@ -537,8 +555,6 @@ Sta::clear()
|
|||
void
|
||||
Sta::networkChanged()
|
||||
{
|
||||
// Remove sdc graph annotations.
|
||||
sdc_->annotateGraph(false);
|
||||
// Everything else from clear().
|
||||
search_->clear();
|
||||
levelize_->clear();
|
||||
|
|
@ -982,14 +998,6 @@ Sta::setSlewLimit(Port *port,
|
|||
sdc_->setSlewLimit(port, min_max, slew);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::setSlewLimit(Pin *pin,
|
||||
const MinMax *min_max,
|
||||
float slew)
|
||||
{
|
||||
sdc_->setSlewLimit(pin, min_max, slew);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::setSlewLimit(Cell *cell,
|
||||
const MinMax *min_max,
|
||||
|
|
@ -2675,7 +2683,7 @@ Sta::vertexWorstArrivalPath(Vertex *vertex,
|
|||
PathVertex *path = path_iter.next();
|
||||
Arrival arrival = path->arrival(this);
|
||||
if (!path->tag(this)->isGenClkSrcPath()
|
||||
&& fuzzyGreater(arrival, worst_arrival, min_max)) {
|
||||
&& delayGreater(arrival, worst_arrival, min_max, this)) {
|
||||
worst_arrival = arrival;
|
||||
worst_path.init(path);
|
||||
}
|
||||
|
|
@ -2695,7 +2703,7 @@ Sta::vertexWorstArrivalPath(Vertex *vertex,
|
|||
Arrival arrival = path->arrival(this);
|
||||
if (path->minMax(this) == min_max
|
||||
&& !path->tag(this)->isGenClkSrcPath()
|
||||
&& fuzzyGreater(arrival, worst_arrival, min_max)) {
|
||||
&& delayGreater(arrival, worst_arrival, min_max, this)) {
|
||||
worst_arrival = arrival;
|
||||
worst_path.init(path);
|
||||
}
|
||||
|
|
@ -2715,7 +2723,7 @@ Sta::vertexWorstSlackPath(Vertex *vertex,
|
|||
PathVertex *path = path_iter.next();
|
||||
Slack slack = path->slack(this);
|
||||
if (!path->tag(this)->isGenClkSrcPath()
|
||||
&& slack < min_slack) {
|
||||
&& delayLess(slack, min_slack, this)) {
|
||||
min_slack = slack;
|
||||
worst_path.init(path);
|
||||
}
|
||||
|
|
@ -2736,7 +2744,7 @@ Sta::vertexWorstSlackPath(Vertex *vertex,
|
|||
if (path->minMax(this) == min_max
|
||||
&& !path->tag(this)->isGenClkSrcPath()) {
|
||||
Slack slack = path->slack(this);
|
||||
if (fuzzyLess(slack, min_slack)) {
|
||||
if (delayLess(slack, min_slack, this)) {
|
||||
min_slack = slack;
|
||||
worst_path.init(path);
|
||||
}
|
||||
|
|
@ -2770,7 +2778,7 @@ Sta::vertexArrival(Vertex *vertex,
|
|||
if ((clk_edge == clk_edge_wildcard
|
||||
|| clk_info->clkEdge() == clk_edge)
|
||||
&& !clk_info->isGenClkSrcPath()
|
||||
&& fuzzyGreater(path->arrival(this), arrival, min_max))
|
||||
&& delayGreater(path->arrival(this), arrival, min_max, this))
|
||||
arrival = path_arrival;
|
||||
}
|
||||
return arrival;
|
||||
|
|
@ -2788,7 +2796,7 @@ Sta::vertexRequired(Vertex *vertex,
|
|||
const Path *path = path_iter.next();
|
||||
if (path->minMax(this) == min_max) {
|
||||
const Required path_required = path->required(this);
|
||||
if (fuzzyGreater(path_required, required, req_min_max))
|
||||
if (delayGreater(path_required, required, req_min_max, this))
|
||||
required = path_required;
|
||||
}
|
||||
}
|
||||
|
|
@ -2818,7 +2826,7 @@ Sta::vertexRequired(Vertex *vertex,
|
|||
const Required path_required = path->required(this);
|
||||
if ((clk_edge == clk_edge_wildcard
|
||||
|| path->clkEdge(search_) == clk_edge)
|
||||
&& fuzzyGreater(path_required, required, min_max))
|
||||
&& delayGreater(path_required, required, min_max, this))
|
||||
required = path_required;
|
||||
}
|
||||
return required;
|
||||
|
|
@ -2836,7 +2844,8 @@ Sta::netSlack(const Net *net,
|
|||
if (network_->isLoad(pin)) {
|
||||
Vertex *vertex = graph_->pinLoadVertex(pin);
|
||||
Slack pin_slack = vertexSlack(vertex, min_max);
|
||||
slack = min(slack, pin_slack);
|
||||
if (delayLess(pin_slack, slack, this))
|
||||
slack = pin_slack;
|
||||
}
|
||||
}
|
||||
return slack;
|
||||
|
|
@ -2852,8 +2861,11 @@ Sta::pinSlack(const Pin *pin,
|
|||
Slack slack = MinMax::min()->initValue();
|
||||
if (vertex)
|
||||
slack = vertexSlack(vertex, min_max);
|
||||
if (bidirect_drvr_vertex)
|
||||
slack = min(slack, vertexSlack(bidirect_drvr_vertex, min_max));
|
||||
if (bidirect_drvr_vertex) {
|
||||
Slack slack1 = vertexSlack(bidirect_drvr_vertex, min_max);
|
||||
if (delayLess(slack1, slack, this))
|
||||
slack = slack1;
|
||||
}
|
||||
return slack;
|
||||
}
|
||||
|
||||
|
|
@ -2868,8 +2880,11 @@ Sta::pinSlack(const Pin *pin,
|
|||
Slack slack = MinMax::min()->initValue();
|
||||
if (vertex)
|
||||
slack = vertexSlack(vertex, rf, min_max);
|
||||
if (bidirect_drvr_vertex)
|
||||
slack = min(slack, vertexSlack(bidirect_drvr_vertex, rf, min_max));
|
||||
if (bidirect_drvr_vertex) {
|
||||
Slack slack1 = vertexSlack(bidirect_drvr_vertex, rf, min_max);
|
||||
if (delayLess(slack1, slack, this))
|
||||
slack = slack1;
|
||||
}
|
||||
return slack;
|
||||
}
|
||||
|
||||
|
|
@ -2885,7 +2900,7 @@ Sta::vertexSlack(Vertex *vertex,
|
|||
Path *path = path_iter.next();
|
||||
if (path->minMax(this) == min_max) {
|
||||
Slack path_slack = path->slack(this);
|
||||
if (path_slack < slack)
|
||||
if (delayLess(path_slack, slack, this))
|
||||
slack = path_slack;
|
||||
}
|
||||
}
|
||||
|
|
@ -2903,7 +2918,7 @@ Sta::vertexSlack(Vertex *vertex,
|
|||
while (path_iter.hasNext()) {
|
||||
Path *path = path_iter.next();
|
||||
Slack path_slack = path->slack(this);
|
||||
if (path_slack < slack)
|
||||
if (delayLess(path_slack, slack, this))
|
||||
slack = path_slack;
|
||||
}
|
||||
return slack;
|
||||
|
|
@ -2942,7 +2957,7 @@ Sta::vertexSlack1(Vertex *vertex,
|
|||
Slack path_slack = path->slack(this);
|
||||
if ((clk_edge == clk_edge_wildcard
|
||||
|| path->clkEdge(search_) == clk_edge)
|
||||
&& path_slack < slack)
|
||||
&& delayLess(path_slack, slack, this))
|
||||
slack = path_slack;
|
||||
}
|
||||
return slack;
|
||||
|
|
@ -2964,7 +2979,7 @@ Sta::vertexSlacks(Vertex *vertex,
|
|||
Slack path_slack = path->slack(this);
|
||||
int rf_index = path->rfIndex(this);
|
||||
int mm_index = path->minMax(this)->index();
|
||||
if (path_slack < slacks[rf_index][mm_index])
|
||||
if (delayLess(path_slack, slacks[rf_index][mm_index], this))
|
||||
slacks[rf_index][mm_index] = path_slack;
|
||||
}
|
||||
}
|
||||
|
|
@ -3159,7 +3174,7 @@ Sta::vertexSlew(Vertex *vertex,
|
|||
Slew mm_slew = min_max->initValue();
|
||||
for (DcalcAnalysisPt *dcalc_ap : corners_->dcalcAnalysisPts()) {
|
||||
Slew slew = graph_->slew(vertex, rf, dcalc_ap->index());
|
||||
if (fuzzyGreater(slew, mm_slew, min_max))
|
||||
if (delayGreater(slew, mm_slew, min_max, this))
|
||||
mm_slew = slew;
|
||||
}
|
||||
return mm_slew;
|
||||
|
|
@ -4781,7 +4796,7 @@ bool
|
|||
InstanceMaxSlewGreater::operator()(const Instance *inst1,
|
||||
const Instance *inst2) const
|
||||
{
|
||||
return instMaxSlew(inst1) > instMaxSlew(inst2);
|
||||
return delayGreater(instMaxSlew(inst1), instMaxSlew(inst2), sta_);
|
||||
}
|
||||
|
||||
Slew
|
||||
|
|
@ -4798,7 +4813,7 @@ InstanceMaxSlewGreater::instMaxSlew(const Instance *inst) const
|
|||
for (RiseFall *rf : RiseFall::range()) {
|
||||
for (DcalcAnalysisPt *dcalc_ap : sta_->corners()->dcalcAnalysisPts()) {
|
||||
Slew slew = graph->slew(vertex, rf, dcalc_ap->index());
|
||||
if (slew > max_slew)
|
||||
if (delayGreater(slew, max_slew, sta_))
|
||||
max_slew = slew;
|
||||
}
|
||||
}
|
||||
|
|
@ -4823,13 +4838,13 @@ Sta::slowDrvrIterator()
|
|||
return new SlowDrvrIterator(insts);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////'
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
Sta::checkSlewLimitPreamble()
|
||||
{
|
||||
if (sdc_->haveClkSlewLimits())
|
||||
// Arrivals are needed to know what pin clock domains.
|
||||
// Arrivals are needed to know pin clock domains.
|
||||
updateTiming(false);
|
||||
else
|
||||
findDelays();
|
||||
|
|
@ -4856,7 +4871,7 @@ Sta::pinSlewLimitViolations(const Corner *corner,
|
|||
void
|
||||
Sta::reportSlewLimitShortHeader()
|
||||
{
|
||||
report_path_->reportSlewLimitShortHeader();
|
||||
report_path_->reportLimitShortHeader(report_path_->fieldSlew());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4868,9 +4883,10 @@ Sta::reportSlewLimitShort(Pin *pin,
|
|||
const RiseFall *rf;
|
||||
Slew slew;
|
||||
float limit, slack;
|
||||
check_slew_limits_->checkSlews(pin, corner, min_max,
|
||||
corner1, rf, slew, limit, slack);
|
||||
report_path_->reportSlewLimitShort(pin, rf, slew, limit, slack);
|
||||
check_slew_limits_->checkSlew(pin, corner, min_max, true,
|
||||
corner1, rf, slew, limit, slack);
|
||||
report_path_->reportLimitShort(report_path_->fieldSlew(), pin,
|
||||
delayAsFloat(slew), limit, slack);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4882,31 +4898,177 @@ Sta::reportSlewLimitVerbose(Pin *pin,
|
|||
const RiseFall *rf;
|
||||
Slew slew;
|
||||
float limit, slack;
|
||||
check_slew_limits_->checkSlews(pin, corner, min_max,
|
||||
corner1, rf, slew, limit, slack);
|
||||
report_path_->reportSlewLimitVerbose(pin, corner1, rf, slew,
|
||||
limit, slack, min_max);
|
||||
check_slew_limits_->checkSlew(pin, corner, min_max, true,
|
||||
corner1, rf, slew, limit, slack);
|
||||
report_path_->reportLimitVerbose(report_path_->fieldSlew(), pin, rf,
|
||||
delayAsFloat(slew),
|
||||
limit, slack, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::checkSlews(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack)
|
||||
Sta::checkSlew(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
bool check_clks,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
Slew &slew,
|
||||
float &limit,
|
||||
float &slack)
|
||||
{
|
||||
checkSlewLimitPreamble();
|
||||
check_slew_limits_->init(min_max);
|
||||
check_slew_limits_->checkSlews(pin, corner, min_max,
|
||||
corner1, rf, slew, limit, slack);
|
||||
check_slew_limits_->checkSlew(pin, corner, min_max, check_clks,
|
||||
corner1, rf, slew, limit, slack);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////'
|
||||
|
||||
void
|
||||
Sta::checkFanoutLimitPreamble()
|
||||
{
|
||||
if (check_fanout_limits_ == nullptr)
|
||||
makeCheckFanoutLimits();
|
||||
// For sim values and ideal clocks.
|
||||
findDelays();
|
||||
}
|
||||
|
||||
Pin *
|
||||
Sta::pinMinFanoutLimitSlack(const MinMax *min_max)
|
||||
{
|
||||
checkFanoutLimitPreamble();
|
||||
return check_fanout_limits_->pinMinFanoutLimitSlack(min_max);
|
||||
}
|
||||
|
||||
PinSeq *
|
||||
Sta::pinFanoutLimitViolations(const MinMax *min_max)
|
||||
{
|
||||
checkFanoutLimitPreamble();
|
||||
return check_fanout_limits_->pinFanoutLimitViolations(min_max);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportFanoutLimitShortHeader()
|
||||
{
|
||||
report_path_->reportLimitShortHeader(report_path_->fieldFanout());
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportFanoutLimitShort(Pin *pin,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
float fanout, limit, slack;
|
||||
check_fanout_limits_->checkFanout(pin, min_max,
|
||||
fanout, limit, slack);
|
||||
report_path_->reportLimitShort(report_path_->fieldFanout(),
|
||||
pin, fanout, limit, slack);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportFanoutLimitVerbose(Pin *pin,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
float fanout, limit, slack;
|
||||
check_fanout_limits_->checkFanout(pin, min_max,
|
||||
fanout, limit, slack);
|
||||
report_path_->reportLimitVerbose(report_path_->fieldFanout(),
|
||||
pin, nullptr, fanout,
|
||||
limit, slack, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::checkFanout(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &fanout,
|
||||
float &limit,
|
||||
float &slack)
|
||||
{
|
||||
check_fanout_limits_->checkFanout(pin, min_max,
|
||||
fanout, limit, slack);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////'
|
||||
|
||||
void
|
||||
Sta::checkCapacitanceLimitPreamble()
|
||||
{
|
||||
if (check_capacitance_limits_ == nullptr)
|
||||
makeCheckCapacitanceLimits();
|
||||
// For sim values and ideal clocks.
|
||||
findDelays();
|
||||
}
|
||||
|
||||
Pin *
|
||||
Sta::pinMinCapacitanceLimitSlack(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
checkCapacitanceLimitPreamble();
|
||||
return check_capacitance_limits_->pinMinCapacitanceLimitSlack(corner, min_max);
|
||||
}
|
||||
|
||||
PinSeq *
|
||||
Sta::pinCapacitanceLimitViolations(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
checkCapacitanceLimitPreamble();
|
||||
return check_capacitance_limits_->pinCapacitanceLimitViolations(corner, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportCapacitanceLimitShortHeader()
|
||||
{
|
||||
report_path_->reportLimitShortHeader(report_path_->fieldCapacitance());
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportCapacitanceLimitShort(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
const Corner *corner1;
|
||||
const RiseFall *rf;
|
||||
float capacitance, limit, slack;
|
||||
check_capacitance_limits_->checkCapacitance(pin, corner, min_max,
|
||||
corner1, rf, capacitance,
|
||||
limit, slack);
|
||||
report_path_->reportLimitShort(report_path_->fieldCapacitance(),
|
||||
pin, capacitance, limit, slack);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::reportCapacitanceLimitVerbose(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
const Corner *corner1;
|
||||
const RiseFall *rf;
|
||||
float capacitance, limit, slack;
|
||||
check_capacitance_limits_->checkCapacitance(pin, corner, min_max,
|
||||
corner1, rf, capacitance,
|
||||
limit, slack);
|
||||
report_path_->reportLimitVerbose(report_path_->fieldCapacitance(),
|
||||
pin, rf, capacitance,
|
||||
limit, slack, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::checkCapacitance(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
float &capacitance,
|
||||
float &limit,
|
||||
float &slack)
|
||||
{
|
||||
check_capacitance_limits_->checkCapacitance(pin, corner, min_max,
|
||||
corner1, rf, capacitance,
|
||||
limit, slack);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
Sta::minPulseWidthPreamble()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -331,7 +331,8 @@ proc report_net_caps { net pins corner digits } {
|
|||
}
|
||||
if [$pin is_driver] {
|
||||
incr driver_count
|
||||
} elseif [$pin is_load] {
|
||||
}
|
||||
if [$pin is_load] {
|
||||
incr load_count
|
||||
}
|
||||
}
|
||||
|
|
@ -381,7 +382,7 @@ proc report_net_pin { pin verbose corner digits } {
|
|||
puts -nonewline [port_capacitance_str $liberty_port $digits]
|
||||
}
|
||||
}
|
||||
puts ""
|
||||
puts "[pin_location_str $pin]"
|
||||
} elseif [$pin is_top_level_port] {
|
||||
puts -nonewline " [get_full_name $pin] [pin_direction $pin] port"
|
||||
if { $verbose } {
|
||||
|
|
@ -403,12 +404,23 @@ proc report_net_pin { pin verbose corner digits } {
|
|||
puts -nonewline " pin [capacitances_str $cap_r_min $cap_r_max $cap_f_min $cap_f_max $digits]"
|
||||
}
|
||||
}
|
||||
puts ""
|
||||
puts "[pin_location_str $pin]"
|
||||
} elseif [$pin is_hierarchical] {
|
||||
puts " [get_full_name $pin] [pin_direction $pin]"
|
||||
}
|
||||
}
|
||||
|
||||
# Used by report_net
|
||||
proc pin_location_str { pin } {
|
||||
set loc [pin_location $pin]
|
||||
if { $loc != "" } {
|
||||
lassign $loc x y
|
||||
return " ([format_distance $x 0], [format_distance $y 0])"
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
proc report_pin_ { pin } {
|
||||
|
|
|
|||
27
tcl/Sdc.tcl
27
tcl/Sdc.tcl
|
|
@ -297,6 +297,11 @@ proc set_unit_values { unit key unit_name key_var } {
|
|||
} else {
|
||||
set prefix [string index $value 0]
|
||||
set suffix [string range $value 1 end]
|
||||
# unit includes "1" prefix
|
||||
if { [string is digit $prefix] } {
|
||||
set prefix [string index $value 1]
|
||||
set suffix [string range $value 2 end]
|
||||
}
|
||||
if { [string equal -nocase $suffix $unit_name] } {
|
||||
set scale [unit_prefix_scale $unit $prefix]
|
||||
set_cmd_unit_scale $unit $scale
|
||||
|
|
@ -497,9 +502,16 @@ proc get_cells { args } {
|
|||
if { $args != {} } {
|
||||
sta_warn "patterns argument not supported with -of_objects."
|
||||
}
|
||||
parse_pin_net_args $keys(-of_objects) pins nets
|
||||
parse_port_pin_net_arg $keys(-of_objects) pins nets
|
||||
foreach pin $pins {
|
||||
lappend insts [$pin instance]
|
||||
if { [$pin is_top_level_port] } {
|
||||
set net [get_nets [get_name $pin]]
|
||||
if { $net != "NULL" } {
|
||||
lappend nets $net
|
||||
}
|
||||
} else {
|
||||
lappend insts [$pin instance]
|
||||
}
|
||||
}
|
||||
foreach net $nets {
|
||||
set pin_iter [$net pin_iterator]
|
||||
|
|
@ -992,7 +1004,7 @@ proc get_ports { args } {
|
|||
return $ports
|
||||
}
|
||||
|
||||
variable filter_regexp1 {@?([a-zA-Z_]+) +(==|=~) +([0-9a-zA-Z_\*]+)}
|
||||
variable filter_regexp1 {@?([a-zA-Z_]+) *(==|=~) *([0-9a-zA-Z_\*]+)}
|
||||
variable filter_or_regexp "($filter_regexp1) +\\|\\| +($filter_regexp1)"
|
||||
variable filter_and_regexp "($filter_regexp1) +&& +($filter_regexp1)"
|
||||
|
||||
|
|
@ -2600,7 +2612,7 @@ proc set_max_transition { args } {
|
|||
set slew [time_ui_sta $slew]
|
||||
|
||||
set objects [lindex $args 1]
|
||||
parse_clk_cell_port_pin_args $objects clks cells ports pins
|
||||
parse_clk_cell_port_args $objects clks cells ports
|
||||
|
||||
set tr [parse_rise_fall_flags flags]
|
||||
|
||||
|
|
@ -2617,12 +2629,12 @@ proc set_max_transition { args } {
|
|||
lappend path_types "data"
|
||||
}
|
||||
|
||||
if { ($ports != {} || $pins != {} || $cells != {}) \
|
||||
if { ($ports != {} || $cells != {}) \
|
||||
&& ([info exists flags(-clock_path)] \
|
||||
|| [info exists flags(-data_path)]
|
||||
|| [info exists flags(-rise)]
|
||||
|| [info exists flags(-fall)]) } {
|
||||
sta_warn "-data_path, -clock_path, -rise, -fall ignored for ports, pins and designs."
|
||||
sta_warn "-data_path, -clock_path, -rise, -fall ignored for ports and designs."
|
||||
}
|
||||
|
||||
# -clock_path/-data_path and transition only apply to clock objects.
|
||||
|
|
@ -2637,9 +2649,6 @@ proc set_max_transition { args } {
|
|||
foreach port $ports {
|
||||
set_slew_limit_port $port "max" $slew
|
||||
}
|
||||
foreach pin $pins {
|
||||
set_slew_limit_pin $pin "max" $slew
|
||||
}
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ proc parse_report_path_options { cmd args_var default_format
|
|||
if [info exists path_options(-format)] {
|
||||
set format $path_options(-format)
|
||||
set formats {full full_clock full_clock_expanded short \
|
||||
end slack_only summary}
|
||||
end slack_only summary json}
|
||||
if { [lsearch $formats $format] == -1 } {
|
||||
sta_error "-format $format not recognized."
|
||||
}
|
||||
|
|
@ -247,7 +247,7 @@ proc parse_report_path_options { cmd args_var default_format
|
|||
|
||||
set path_options(num_fmt) "%.${digits}f"
|
||||
set_report_path_digits $digits
|
||||
# Numberic field width expands with digits.
|
||||
# Numeric field width expands with digits.
|
||||
set field_width [expr $digits + $report_path_field_width_extra]
|
||||
if { $report_sigmas } {
|
||||
set delay_field_width [expr $field_width * 3 + $report_path_field_width_extra]
|
||||
|
|
@ -386,7 +386,7 @@ proc report_slew_limits { corner min_max all_violators verbose nosplit } {
|
|||
if { $all_violators } {
|
||||
set violators [pin_slew_limit_violations $corner $min_max]
|
||||
if { $violators != {} } {
|
||||
puts "${min_max}_transition"
|
||||
puts "${min_max} slew"
|
||||
puts ""
|
||||
if { $verbose } {
|
||||
foreach pin $violators {
|
||||
|
|
@ -404,7 +404,7 @@ proc report_slew_limits { corner min_max all_violators verbose nosplit } {
|
|||
} else {
|
||||
set pin [pin_min_slew_limit_slack $corner $min_max]
|
||||
if { $pin != "NULL" } {
|
||||
puts "${min_max}_transition"
|
||||
puts "${min_max} slew"
|
||||
puts ""
|
||||
if { $verbose } {
|
||||
report_slew_limit_verbose $pin $corner $min_max
|
||||
|
|
@ -418,6 +418,80 @@ proc report_slew_limits { corner min_max all_violators verbose nosplit } {
|
|||
}
|
||||
}
|
||||
|
||||
proc report_fanout_limits { min_max all_violators verbose nosplit } {
|
||||
if { $all_violators } {
|
||||
set violators [pin_fanout_limit_violations $min_max]
|
||||
if { $violators != {} } {
|
||||
puts "${min_max} fanout"
|
||||
puts ""
|
||||
if { $verbose } {
|
||||
foreach pin $violators {
|
||||
report_fanout_limit_verbose $pin $min_max
|
||||
puts ""
|
||||
}
|
||||
} else {
|
||||
report_fanout_limit_short_header
|
||||
foreach pin $violators {
|
||||
report_fanout_limit_short $pin $min_max
|
||||
}
|
||||
puts ""
|
||||
}
|
||||
}
|
||||
} else {
|
||||
set pin [pin_min_fanout_limit_slack $min_max]
|
||||
if { $pin != "NULL" } {
|
||||
puts "${min_max} fanout"
|
||||
puts ""
|
||||
if { $verbose } {
|
||||
report_fanout_limit_verbose $pin $min_max
|
||||
puts ""
|
||||
} else {
|
||||
report_fanout_limit_short_header
|
||||
report_fanout_limit_short $pin $min_max
|
||||
puts ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc report_capacitance_limits { corner min_max all_violators verbose nosplit } {
|
||||
if { $all_violators } {
|
||||
set violators [pin_capacitance_limit_violations $corner $min_max]
|
||||
if { $violators != {} } {
|
||||
puts "${min_max} capacitance"
|
||||
puts ""
|
||||
if { $verbose } {
|
||||
foreach pin $violators {
|
||||
report_capacitance_limit_verbose $pin $corner $min_max
|
||||
puts ""
|
||||
}
|
||||
} else {
|
||||
report_capacitance_limit_short_header
|
||||
foreach pin $violators {
|
||||
report_capacitance_limit_short $pin $corner $min_max
|
||||
}
|
||||
puts ""
|
||||
}
|
||||
}
|
||||
} else {
|
||||
set pin [pin_min_capacitance_limit_slack $corner $min_max]
|
||||
if { $pin != "NULL" } {
|
||||
puts "${min_max} capacitance"
|
||||
puts ""
|
||||
if { $verbose } {
|
||||
report_capacitance_limit_verbose $pin $corner $min_max
|
||||
puts ""
|
||||
} else {
|
||||
report_capacitance_limit_short_header
|
||||
report_capacitance_limit_short $pin $corner $min_max
|
||||
puts ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
proc report_path_ends { path_ends } {
|
||||
report_path_end_header
|
||||
set prev_end "NULL"
|
||||
|
|
|
|||
45
tcl/Sta.tcl
45
tcl/Sta.tcl
|
|
@ -46,7 +46,7 @@ proc define_report_path_fields {} {
|
|||
set_report_path_field_properties "incr" "Delay" $width 0
|
||||
set_report_path_field_properties "capacitance" "Cap" $width 0
|
||||
set_report_path_field_properties "slew" "Slew" $width 0
|
||||
set_report_path_field_properties "fanout" "Fanout" 5 0
|
||||
set_report_path_field_properties "fanout" "Fanout" 6 0
|
||||
set_report_path_field_properties "edge" " " 1 0
|
||||
set_report_path_field_properties "case" " " 11 0
|
||||
}
|
||||
|
|
@ -319,6 +319,8 @@ define_sta_cmd_args "report_check_types" \
|
|||
[-recovery] [-removal]\
|
||||
[-clock_gating_setup] [-clock_gating_hold]\
|
||||
[-max_slew] [-min_slew]\
|
||||
[-max_fanout] [-min_fanout]\
|
||||
[-max_capacitance] [-min_capacitance]\
|
||||
[-min_pulse_width] [-min_period] [-max_skew]\
|
||||
[-digits digits] [-no_line_splits]\
|
||||
[> filename] [>> filename]}
|
||||
|
|
@ -358,23 +360,31 @@ proc_redirect report_check_types {
|
|||
set recovery 1
|
||||
set clk_gating_setup 1
|
||||
set max_slew 1
|
||||
set max_fanout 1
|
||||
set max_capacitance 1
|
||||
} else {
|
||||
set setup 0
|
||||
set recovery 0
|
||||
set clk_gating_setup 0
|
||||
set max_slew 0
|
||||
set max_fanout 0
|
||||
set max_capacitance 0
|
||||
}
|
||||
if { $min_max == "min" || $min_max == "min_max" } {
|
||||
set hold 1
|
||||
set removal 1
|
||||
set clk_gating_hold 1
|
||||
set min_slew 1
|
||||
set min_fanout 1
|
||||
set min_capacitance 1
|
||||
} else {
|
||||
set hold 0
|
||||
set min_delay 0
|
||||
set removal 0
|
||||
set clk_gating_hold 0
|
||||
set min_slew 0
|
||||
set min_fanout 0
|
||||
set min_capacitance 0
|
||||
}
|
||||
set min_pulse_width 1
|
||||
set min_period 1
|
||||
|
|
@ -384,9 +394,11 @@ proc_redirect report_check_types {
|
|||
flags {-max_delay -min_delay -recovery -removal \
|
||||
-clock_gating_setup -clock_gating_hold \
|
||||
-max_slew -min_slew \
|
||||
-max_transition -min_transition \
|
||||
-max_fanout -min_fanout \
|
||||
-max_capacitance -min_capacitance \
|
||||
-min_pulse_width \
|
||||
-min_period -max_skew} 1
|
||||
-min_period -max_skew \
|
||||
-max_transition -min_transition } 1
|
||||
|
||||
set setup [info exists flags(-max_delay)]
|
||||
set hold [info exists flags(-min_delay)]
|
||||
|
|
@ -404,6 +416,10 @@ proc_redirect report_check_types {
|
|||
sta_warn "-min_transition deprecated. Use -min_slew."
|
||||
set min_slew 1
|
||||
}
|
||||
set max_fanout [info exists flags(-max_fanout)]
|
||||
set min_fanout [info exists flags(-min_fanout)]
|
||||
set max_capacitance [info exists flags(-max_capacitance)]
|
||||
set min_capacitance [info exists flags(-min_capacitance)]
|
||||
set min_pulse_width [info exists flags(-min_pulse_width)]
|
||||
set min_period [info exists flags(-min_period)]
|
||||
set max_skew [info exists flags(-max_skew)]
|
||||
|
|
@ -457,6 +473,18 @@ proc_redirect report_check_types {
|
|||
if { $min_slew } {
|
||||
report_slew_limits $corner "min" $violators $verbose $nosplit
|
||||
}
|
||||
if { $max_fanout } {
|
||||
report_fanout_limits "max" $violators $verbose $nosplit
|
||||
}
|
||||
if { $min_fanout } {
|
||||
report_fanout_limits "min" $violators $verbose $nosplit
|
||||
}
|
||||
if { $max_capacitance } {
|
||||
report_capacitance_limits $corner "max" $violators $verbose $nosplit
|
||||
}
|
||||
if { $min_capacitance } {
|
||||
report_capacitance_limits $corner "min" $violators $verbose $nosplit
|
||||
}
|
||||
if { $min_pulse_width } {
|
||||
if { $violators } {
|
||||
set checks [min_pulse_width_violations $corner]
|
||||
|
|
@ -1076,6 +1104,17 @@ proc report_object_names { args } {
|
|||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "report_units" {}
|
||||
|
||||
proc report_units { args } {
|
||||
check_argc_eq0 "report_units" $args
|
||||
foreach unit {"time" "capacitance" "resistance" "voltage" "current" "power" "distance"} {
|
||||
puts " $unit 1[unit_scale_abreviation $unit][unit_suffix $unit]"
|
||||
}
|
||||
}
|
||||
|
||||
################################################################
|
||||
|
||||
define_sta_cmd_args "with_output_to_variable" { var { cmds }}
|
||||
|
||||
# with_output_to_variable variable { command args... }
|
||||
|
|
|
|||
130
tcl/StaTcl.i
130
tcl/StaTcl.i
|
|
@ -1065,6 +1065,8 @@ using namespace sta;
|
|||
$1 = ReportPathFormat::summary;
|
||||
else if (stringEq(arg, "slack_only"))
|
||||
$1 = ReportPathFormat::slack_only;
|
||||
else if (stringEq(arg, "json"))
|
||||
$1 = ReportPathFormat::json;
|
||||
else {
|
||||
tclError(interp, "Error: unknown path type %s.", arg);
|
||||
return TCL_ERROR;
|
||||
|
|
@ -3516,15 +3518,6 @@ set_slew_limit_port(Port *port,
|
|||
Sta::sta()->setSlewLimit(port, min_max, slew);
|
||||
}
|
||||
|
||||
void
|
||||
set_slew_limit_pin(Pin *pin,
|
||||
const MinMax *min_max,
|
||||
float slew)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
Sta::sta()->setSlewLimit(pin, min_max, slew);
|
||||
}
|
||||
|
||||
void
|
||||
set_slew_limit_cell(Cell *cell,
|
||||
const MinMax *min_max,
|
||||
|
|
@ -3958,6 +3951,26 @@ set_cmd_unit_suffix(const char *unit_name,
|
|||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
unit_scale_abreviation(const char *unit_name)
|
||||
{
|
||||
Unit *unit = Sta::sta()->units()->find(unit_name);
|
||||
if (unit)
|
||||
return unit->scaleAbreviation();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
const char *
|
||||
unit_suffix(const char *unit_name)
|
||||
{
|
||||
Unit *unit = Sta::sta()->units()->find(unit_name);
|
||||
if (unit)
|
||||
return unit->suffix();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
VertexIterator *
|
||||
|
|
@ -4613,6 +4626,8 @@ report_delay_calc_cmd(Edge *edge,
|
|||
return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
Pin *
|
||||
pin_min_slew_limit_slack(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
|
|
@ -4653,6 +4668,82 @@ report_slew_limit_verbose(Pin *pin,
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
Pin *
|
||||
pin_min_fanout_limit_slack(const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->pinMinFanoutLimitSlack(min_max);
|
||||
}
|
||||
|
||||
PinSeq *
|
||||
pin_fanout_limit_violations(const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->pinFanoutLimitViolations(min_max);
|
||||
}
|
||||
|
||||
void
|
||||
report_fanout_limit_short_header()
|
||||
{
|
||||
Sta::sta()->reportFanoutLimitShortHeader();
|
||||
}
|
||||
|
||||
void
|
||||
report_fanout_limit_short(Pin *pin,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
Sta::sta()->reportFanoutLimitShort(pin, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
report_fanout_limit_verbose(Pin *pin,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
Sta::sta()->reportFanoutLimitVerbose(pin, min_max);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
Pin *
|
||||
pin_min_capacitance_limit_slack(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->pinMinCapacitanceLimitSlack(corner, min_max);
|
||||
}
|
||||
|
||||
PinSeq *
|
||||
pin_capacitance_limit_violations(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return Sta::sta()->pinCapacitanceLimitViolations(corner, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
report_capacitance_limit_short_header()
|
||||
{
|
||||
Sta::sta()->reportCapacitanceLimitShortHeader();
|
||||
}
|
||||
|
||||
void
|
||||
report_capacitance_limit_short(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
Sta::sta()->reportCapacitanceLimitShort(pin, corner, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
report_capacitance_limit_verbose(Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
Sta::sta()->reportCapacitanceLimitVerbose(pin, corner, min_max);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
TmpFloatSeq *
|
||||
design_power(const Corner *corner)
|
||||
{
|
||||
|
|
@ -5213,6 +5304,27 @@ arrivals_invalid()
|
|||
sta->arrivalsInvalid();
|
||||
}
|
||||
|
||||
void
|
||||
delays_invalid()
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
sta->delaysInvalid();
|
||||
}
|
||||
|
||||
const char *
|
||||
pin_location(Pin *pin)
|
||||
{
|
||||
Network *network = cmdNetwork();
|
||||
double x, y;
|
||||
bool exists;
|
||||
network->location(pin, x, y, exists);
|
||||
// return x/y as tcl list
|
||||
if (exists)
|
||||
return sta::stringPrintTmp("%f %f", x, y);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
%} // inline
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -165,12 +165,20 @@ VerilogWriter::verilogPortDir(PortDirection *dir)
|
|||
return "input";
|
||||
else if (dir == PortDirection::output())
|
||||
return "output";
|
||||
else if (dir == PortDirection::bidirect())
|
||||
return "inout";
|
||||
else if (dir == PortDirection::tristate())
|
||||
return "output";
|
||||
else
|
||||
else if (dir == PortDirection::bidirect())
|
||||
return "inout";
|
||||
else if (dir == PortDirection::power())
|
||||
return "input";
|
||||
else if (dir == PortDirection::ground())
|
||||
return "input";
|
||||
else if (dir == PortDirection::internal())
|
||||
return nullptr;
|
||||
else {
|
||||
internalError("unknown port direction");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
Loading…
Reference in New Issue