report -min/max fanout, capacitance

This commit is contained in:
James Cherry 2020-06-02 11:08:48 -07:00
parent 6ff05e580b
commit 4c74fcfb65
12 changed files with 1211 additions and 78 deletions

View File

@ -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}
)

View File

@ -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_;

View File

@ -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

View File

@ -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

258
search/CheckFanoutLimits.cc Normal file
View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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();

View File

@ -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()
{

View File

@ -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"

View File

@ -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]

View File

@ -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)
{