report -min/max fanout, capacitance
This commit is contained in:
parent
6ff05e580b
commit
4c74fcfb65
|
|
@ -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}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ class ReportPath;
|
|||
class CheckTiming;
|
||||
class DcalcAnalysisPt;
|
||||
class CheckSlewLimits;
|
||||
class CheckFanoutLimits;
|
||||
class CheckCapacitanceLimits;
|
||||
class CheckMinPulseWidths;
|
||||
class CheckMinPeriods;
|
||||
class CheckMaxSkews;
|
||||
|
|
@ -612,6 +614,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,
|
||||
|
|
@ -636,6 +639,50 @@ public:
|
|||
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);
|
||||
void checkFanouts(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);
|
||||
void checkCapacitances(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 +1274,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 +1317,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 +1372,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_;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,306 @@
|
|||
// 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 "StaState.hh"
|
||||
#include "Corner.hh"
|
||||
#include "PortDirection.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::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()->capacitanceLimit(top_cell, min_max,
|
||||
top_limit, top_limit_exists);
|
||||
top_limit_= top_limit;
|
||||
top_limit_exists_ = top_limit_exists;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CheckCapacitanceLimits::findLimit(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &limit,
|
||||
bool &exists) const
|
||||
{
|
||||
exists = false;
|
||||
const Network *network = sta_->network();
|
||||
Sdc *sdc = sta_->sdc();
|
||||
if (network->isTopLevelPort(pin)) {
|
||||
Port *port = network->port(pin);
|
||||
sdc->capacitanceLimit(port, min_max, limit, exists);
|
||||
if (!exists) {
|
||||
limit = top_limit_;
|
||||
exists = top_limit_exists_;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Cell *cell = network->cell(network->instance(pin));
|
||||
sdc->capacitanceLimit(cell, min_max,
|
||||
limit, exists);
|
||||
if (!exists) {
|
||||
LibertyPort *port = network->libertyPort(pin);
|
||||
if (port) {
|
||||
port->capacitanceLimit(min_max, limit, exists);
|
||||
if (!exists
|
||||
&& port->direction()->isAnyOutput())
|
||||
port->libertyLibrary()->defaultMaxCapacitance(limit, exists);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
Sdc *sdc = sta_->sdc();
|
||||
float pin_cap, wire_cap, fanout;
|
||||
bool has_set_load;
|
||||
sdc->connectedCap(pin, rf1, op_cond, corner, min_max,
|
||||
pin_cap, wire_cap, fanout, has_set_load);
|
||||
float cap = pin_cap + wire_cap;
|
||||
|
||||
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)
|
||||
{
|
||||
init(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();
|
||||
InstancePinIterator *pin_iter = network->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
if (network->direction(pin)->isAnyOutput()) {
|
||||
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)
|
||||
violators->push_back(pin);
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
|
||||
Pin *
|
||||
CheckCapacitanceLimits::pinMinCapacitanceLimitSlack(const Corner *corner,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
init(min_max);
|
||||
const Network *network = sta_->network();
|
||||
Pin *min_slack_pin = 0;
|
||||
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();
|
||||
InstancePinIterator *pin_iter = network->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
const Corner *corner1;
|
||||
const RiseFall *rf;
|
||||
float capacitance, limit, slack;
|
||||
checkCapacitance(pin, corner, min_max, corner1, rf, capacitance, limit, slack);
|
||||
if (rf
|
||||
&& (min_slack_pin == 0
|
||||
|| slack < min_slack)) {
|
||||
min_slack_pin = pin;
|
||||
min_slack = slack;
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
// 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);
|
||||
void init(const MinMax *min_max);
|
||||
// Requires init().
|
||||
// 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);
|
||||
|
||||
float top_limit_;
|
||||
bool top_limit_exists_;
|
||||
const StaState *sta_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
// 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 "PortDirection.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::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()->fanoutLimit(top_cell, min_max,
|
||||
top_limit, top_limit_exists);
|
||||
top_limit_= top_limit;
|
||||
top_limit_exists_ = top_limit_exists;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CheckFanoutLimits::findLimit(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &limit,
|
||||
bool &exists) const
|
||||
{
|
||||
exists = false;
|
||||
const Network *network = sta_->network();
|
||||
Sdc *sdc = sta_->sdc();
|
||||
if (network->isTopLevelPort(pin)) {
|
||||
Port *port = network->port(pin);
|
||||
sdc->fanoutLimit(port, min_max, limit, exists);
|
||||
if (!exists) {
|
||||
limit = top_limit_;
|
||||
exists = top_limit_exists_;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Cell *cell = network->cell(network->instance(pin));
|
||||
sdc->fanoutLimit(cell, min_max,
|
||||
limit, exists);
|
||||
if (!exists) {
|
||||
LibertyPort *port = network->libertyPort(pin);
|
||||
if (port) {
|
||||
port->fanoutLimit(min_max, limit, exists);
|
||||
if (!exists
|
||||
&& port->direction()->isAnyOutput())
|
||||
port->libertyLibrary()->defaultMaxFanout(limit, exists);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CheckFanoutLimits::checkFanout(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
float limit1,
|
||||
// Return values.
|
||||
float &fanout,
|
||||
float &slack,
|
||||
float &limit) const
|
||||
{
|
||||
float fanout1 = this->fanout(pin);
|
||||
float slack1 = (min_max == MinMax::max())
|
||||
? limit1 - fanout1
|
||||
: fanout1 - limit1;
|
||||
if (fuzzyLessEqual(slack1, slack)) {
|
||||
fanout = fanout1;
|
||||
slack = slack1;
|
||||
limit = limit1;
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
CheckFanoutLimits::fanout(const Pin *pin) const
|
||||
{
|
||||
float fanout = 0;
|
||||
const Network *network = sta_->network();
|
||||
Net *net = network->net(pin);
|
||||
NetPinIterator *pin_iter = network->pinIterator(net);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
if (network->isLoad(pin))
|
||||
fanout++;
|
||||
}
|
||||
delete pin_iter;
|
||||
return fanout;
|
||||
}
|
||||
|
||||
PinSeq *
|
||||
CheckFanoutLimits::pinFanoutLimitViolations(const MinMax *min_max)
|
||||
{
|
||||
init(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();
|
||||
InstancePinIterator *pin_iter = network->pinIterator(inst);
|
||||
while (pin_iter->hasNext()) {
|
||||
Pin *pin = pin_iter->next();
|
||||
float fanout;
|
||||
float limit, slack;
|
||||
checkFanout(pin, min_max, fanout, limit, slack );
|
||||
if (slack < 0.0)
|
||||
violators->push_back(pin);
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
|
||||
Pin *
|
||||
CheckFanoutLimits::pinMinFanoutLimitSlack(const MinMax *min_max)
|
||||
{
|
||||
init(min_max);
|
||||
const Network *network = sta_->network();
|
||||
Pin *min_slack_pin = 0;
|
||||
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();
|
||||
float fanout;
|
||||
float limit, slack;
|
||||
checkFanout(pin, min_max, fanout, limit, slack);
|
||||
if (min_slack_pin == 0
|
||||
|| slack < min_slack) {
|
||||
min_slack_pin = pin;
|
||||
min_slack = slack;
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// 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 init(const MinMax *min_max);
|
||||
// Requires init().
|
||||
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 fanout(const Pin *pin) const;
|
||||
|
||||
float top_limit_;
|
||||
bool top_limit_exists_;
|
||||
const StaState *sta_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
@ -1549,21 +1549,22 @@ ReportPath::reportSkewClkPath(const char *arrival_msg,
|
|||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
ReportPath::reportSlewLimitShortHeader()
|
||||
ReportPath::reportLimitShortHeader(const char *what)
|
||||
{
|
||||
string result;
|
||||
reportSlewLimitShortHeader(result);
|
||||
reportLimitShortHeader(what, result);
|
||||
report_->print(result);
|
||||
}
|
||||
|
||||
void
|
||||
ReportPath::reportSlewLimitShortHeader(string &result)
|
||||
ReportPath::reportLimitShortHeader(const char *what,
|
||||
string &result)
|
||||
{
|
||||
reportDescription("Pin", result);
|
||||
result += ' ';
|
||||
reportField("Limit", field_slew_, result);
|
||||
result += ' ';
|
||||
reportField("Trans", field_slew_, result);
|
||||
reportField(what, field_slew_, result);
|
||||
result += ' ';
|
||||
reportField("Slack", field_slew_, result);
|
||||
reportEndOfLine(result);
|
||||
|
|
@ -1572,75 +1573,80 @@ ReportPath::reportSlewLimitShortHeader(string &result)
|
|||
}
|
||||
|
||||
void
|
||||
ReportPath::reportSlewLimitShort(Pin *pin,
|
||||
const RiseFall *rf,
|
||||
Slew slew,
|
||||
float limit,
|
||||
float slack)
|
||||
ReportPath::reportLimitShort(const char *what,
|
||||
Pin *pin,
|
||||
float value,
|
||||
float limit,
|
||||
float slack)
|
||||
{
|
||||
string result;
|
||||
reportSlewLimitShort(pin, rf, slew, limit, slack, result);
|
||||
reportLimitShort(what, 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 char *what,
|
||||
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);
|
||||
reportSpaceFieldDelay(value, EarlyLate::late(), result);
|
||||
reportSpaceSlack(slack, 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 char *what,
|
||||
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(what, 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 char *what,
|
||||
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 ";
|
||||
result += " ";
|
||||
result += what;
|
||||
result += " ";
|
||||
reportSpaceFieldTime(limit, result);
|
||||
reportEndOfLine(result);
|
||||
|
||||
result += "transition_time ";
|
||||
reportField(delayAsFloat(slew), field_slew_, result);
|
||||
result += what;
|
||||
result += " ";
|
||||
reportField(value, field_slew_, result);
|
||||
reportEndOfLine(result);
|
||||
|
||||
reportDashLine(strlen("transition_time") + field_slew_->width() + 1,
|
||||
result);
|
||||
reportDashLine(strlen(what) + field_slew_->width() + 6, result);
|
||||
|
||||
result += "Slack ";
|
||||
result += "Slack ";
|
||||
reportSpaceSlack(slack, result);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -137,34 +137,35 @@ 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 char *what);
|
||||
void reportLimitShortHeader(const char *what,
|
||||
string &result);
|
||||
void reportLimitShort(const char *what,
|
||||
Pin *pin,
|
||||
float value,
|
||||
float limit,
|
||||
float slack);
|
||||
void reportLimitShort(const char *what,
|
||||
Pin *pin,
|
||||
float value,
|
||||
float limit,
|
||||
float slack,
|
||||
string &result);
|
||||
void reportLimitVerbose(const char *what,
|
||||
Pin *pin,
|
||||
const RiseFall *rf,
|
||||
float value,
|
||||
float limit,
|
||||
float slack,
|
||||
const MinMax *min_max);
|
||||
void reportLimitVerbose(const char *what,
|
||||
Pin *pin,
|
||||
const RiseFall *rf,
|
||||
float value,
|
||||
float limit,
|
||||
float slack,
|
||||
const MinMax *min_max,
|
||||
string &result);
|
||||
|
||||
protected:
|
||||
void makeFields();
|
||||
|
|
|
|||
170
search/Sta.cc
170
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_;
|
||||
|
|
@ -4813,7 +4831,7 @@ 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();
|
||||
|
|
@ -4840,7 +4858,7 @@ Sta::pinSlewLimitViolations(const Corner *corner,
|
|||
void
|
||||
Sta::reportSlewLimitShortHeader()
|
||||
{
|
||||
report_path_->reportSlewLimitShortHeader();
|
||||
report_path_->reportLimitShortHeader("Slew");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4854,7 +4872,7 @@ Sta::reportSlewLimitShort(Pin *pin,
|
|||
float limit, slack;
|
||||
check_slew_limits_->checkSlews(pin, corner, min_max,
|
||||
corner1, rf, slew, limit, slack);
|
||||
report_path_->reportSlewLimitShort(pin, rf, slew, limit, slack);
|
||||
report_path_->reportLimitShort("slew", pin, delayAsFloat(slew), limit, slack);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4868,8 +4886,8 @@ Sta::reportSlewLimitVerbose(Pin *pin,
|
|||
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);
|
||||
report_path_->reportLimitVerbose("slew", pin, rf, delayAsFloat(slew),
|
||||
limit, slack, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -4891,6 +4909,148 @@ Sta::checkSlews(const Pin *pin,
|
|||
|
||||
////////////////////////////////////////////////////////////////'
|
||||
|
||||
void
|
||||
Sta::checkFanoutLimitPreamble()
|
||||
{
|
||||
if (check_fanout_limits_ == nullptr)
|
||||
makeCheckFanoutLimits();
|
||||
}
|
||||
|
||||
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("Fanout");
|
||||
}
|
||||
|
||||
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("fanout", 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("fanout", pin, nullptr, fanout,
|
||||
limit, slack, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::checkFanouts(const Pin *pin,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
float &fanout,
|
||||
float &limit,
|
||||
float &slack)
|
||||
{
|
||||
checkFanoutLimitPreamble();
|
||||
check_fanout_limits_->init(min_max);
|
||||
check_fanout_limits_->checkFanout(pin, min_max,
|
||||
fanout, limit, slack);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////'
|
||||
|
||||
void
|
||||
Sta::checkCapacitanceLimitPreamble()
|
||||
{
|
||||
if (check_capacitance_limits_ == nullptr)
|
||||
makeCheckCapacitanceLimits();
|
||||
}
|
||||
|
||||
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("Capacitance");
|
||||
}
|
||||
|
||||
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("capacitance", 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("capacitance", pin, rf,
|
||||
capacitance, limit, slack, min_max);
|
||||
}
|
||||
|
||||
void
|
||||
Sta::checkCapacitances(const Pin *pin,
|
||||
const Corner *corner,
|
||||
const MinMax *min_max,
|
||||
// Return values.
|
||||
const Corner *&corner1,
|
||||
const RiseFall *&rf,
|
||||
float &capacitance,
|
||||
float &limit,
|
||||
float &slack)
|
||||
{
|
||||
checkCapacitanceLimitPreamble();
|
||||
check_capacitance_limits_->init(min_max);
|
||||
check_capacitance_limits_->checkCapacitance(pin, corner, min_max,
|
||||
corner1, rf, capacitance,
|
||||
limit, slack);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////'
|
||||
|
||||
void
|
||||
Sta::minPulseWidthPreamble()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
34
tcl/Sta.tcl
34
tcl/Sta.tcl
|
|
@ -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,35 +360,47 @@ 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
|
||||
set max_skew 1
|
||||
set max_fanout 1
|
||||
set max_capacitance 1
|
||||
} else {
|
||||
parse_key_args "report_check_types" args keys {} \
|
||||
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 +418,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 +475,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]
|
||||
|
|
|
|||
78
tcl/StaTcl.i
78
tcl/StaTcl.i
|
|
@ -4613,6 +4613,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 +4655,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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue