ClkNetwork

This commit is contained in:
James Cherry 2020-08-08 18:44:19 -07:00
parent ff7557bb1f
commit 0db8d142d8
10 changed files with 364 additions and 158 deletions

View File

@ -158,6 +158,7 @@ set(STA_SOURCE
search/CheckSlewLimits.cc
search/CheckTiming.cc
search/ClkInfo.cc
search/ClkNetwork.cc
search/ClkSkew.cc
search/Corner.cc
search/Crpr.cc
@ -181,7 +182,6 @@ set(STA_SOURCE
search/ReportPath.cc
search/Search.cc
search/SearchPred.cc
search/FindClkPins.cc
search/Sim.cc
search/Sta.cc
search/StaState.cc

View File

@ -14,6 +14,8 @@
// 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 "GraphDelayCalc1.hh"
#include "Debug.hh"
#include "Stats.hh"
#include "MinMax.hh"
@ -34,7 +36,7 @@
#include "ArcDelayCalc.hh"
#include "DcalcAnalysisPt.hh"
#include "NetCaps.hh"
#include "GraphDelayCalc1.hh"
#include "ClkNetwork.hh"
namespace sta {
@ -1387,7 +1389,7 @@ GraphDelayCalc1::edgeFromSlew(const Vertex *from_vertex,
{
const TimingRole *role = edge->role();
if (role->genericRole() == TimingRole::regClkToQ()
&& isIdealClk(from_vertex))
&& clk_network_->isIdealClock(from_vertex->pin()))
return idealClkSlew(from_vertex, from_rf, dcalc_ap->slewMinMax());
else
return graph_->slew(from_vertex, from_rf, dcalc_ap->index());
@ -1399,7 +1401,7 @@ GraphDelayCalc1::idealClkSlew(const Vertex *vertex,
const MinMax *min_max)
{
float slew = min_max->initValue();
const ClockSet *clks = idealClks(vertex);
const ClockSet *clks = clk_network_->idealClocks(vertex->pin());
ClockSet::ConstIterator clk_iter(clks);
while (clk_iter.hasNext()) {
Clock *clk = clk_iter.next();
@ -1585,7 +1587,7 @@ GraphDelayCalc1::checkEdgeClkSlew(const Vertex *from_vertex,
const RiseFall *from_rf,
const DcalcAnalysisPt *dcalc_ap)
{
if (isIdealClk(from_vertex))
if (clk_network_->isIdealClock(from_vertex->pin()))
return idealClkSlew(from_vertex, from_rf, dcalc_ap->checkClkSlewMinMax());
else
return graph_->slew(from_vertex, from_rf, dcalc_ap->checkClkSlewIndex());
@ -1674,15 +1676,49 @@ GraphDelayCalc1::setIdealClks(const Vertex *vertex,
ClockSet *
GraphDelayCalc1::idealClks(const Vertex *vertex)
{
return ideal_clks_map_.findKey(vertex);
ClockSet *ideal_clks = ideal_clks_map_.findKey(vertex);
const ClockSet *ideal_clks2 = clk_network_->idealClocks(vertex->pin());
if (ideal_clks) {
for (Clock *clk : *ideal_clks) {
if (ideal_clks2) {
if (!ideal_clks2->findKey(clk))
printf("pin %s clk_net missing1 %s\n",
vertex->name(network_),
clk->name());
}
else
printf("pin %s clk_net missing2 %s\n",
vertex->name(network_),
clk->name());
}
if (ideal_clks2) {
for (Clock *clk : *ideal_clks2) {
if (ideal_clks) {
if (!ideal_clks->findKey(clk)) {
printf("pin %s dcalc missing3 %s\n",
vertex->name(network_),
clk->name());
}
}
else
printf("pin %s dcalc missing4 %s\n",
vertex->name(network_),
clk->name());
}
}
}
return ideal_clks;
}
bool
GraphDelayCalc1::isIdealClk(const Vertex *vertex)
{
const ClockSet *clks = idealClks(vertex);
return clks != 0
bool ideal = clks != 0
&& clks->size() > 0;
if (ideal != clk_network_->isIdealClock(vertex->pin()))
printf("ideal missmatch\n");
return ideal;
}
float
@ -1765,7 +1801,7 @@ GraphDelayCalc1::reportDelayCalc(Edge *edge,
const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, dcalc_ap);
int slew_index = dcalc_ap->checkDataSlewIndex();
const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index);
bool from_ideal_clk = isIdealClk(from_vertex);
bool from_ideal_clk = clk_network_->isIdealClock(from_vertex->pin());
const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr;
arc_delay_calc_->reportCheckDelay(cell, arc, from_slew, from_slew_annotation,
to_slew, related_out_cap, pvt, dcalc_ap,

View File

@ -18,6 +18,7 @@
#include <mutex>
#include "Delay.hh"
#include "GraphDelayCalc.hh"
namespace sta {

67
include/sta/ClkNetwork.hh Normal file
View File

@ -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 "Map.hh"
#include "Set.hh"
#include "StaState.hh"
#include "NetworkClass.hh"
#include "GraphClass.hh"
#include "SdcClass.hh"
namespace sta {
typedef Map<const Pin*, ClockSet> PinClksMap;
typedef Map<const Clock *, PinSet> ClkPinsMap;
class Sta;
// Find clock network pins.
// This is not as reliable as Search::isClock but is much cheaper.
class ClkNetwork : public StaState
{
public:
ClkNetwork(StaState *sta);
void ensureClkNetwork();
void clear();
bool isClock(const Pin *pin) const;
bool isIdealClock(const Pin *pin) const;
const ClockSet *clocks(const Pin *pin);
const ClockSet *idealClocks(const Pin *pin);
void clkPinsInvalid();
protected:
void deletePinBefore(const Pin *pin);
void connectPinAfter(const Pin *pin);
void disconnectPinBefore(const Pin *pin);
friend class Sta;
private:
void findClkPins();
void findClkPins(bool ideal_only,
PinClksMap &clk_pin_map);
bool clk_pins_valid_;
// pin -> clks
PinClksMap pin_clks_map_;
// pin -> ideal clks
PinClksMap pin_ideal_clks_map_;
// clock -> pins
ClkPinsMap clk_pins_map_;
};
} // namespace

View File

@ -1145,12 +1145,14 @@ public:
////////////////////////////////////////////////////////////////
void ensureClkPins();
bool isIdealClock(Pin *pin) const;
void ensureClkNetwork();
// Assumes ensureClkNetwork() has been called.
bool isClock(Pin *pin) const;
// Assumes ensureClkNetwork() has been called.
bool isIdealClock(Pin *pin) const;
void clkPinsInvalid();
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
void setTclInterp(Tcl_Interp *interp);
Tcl_Interp *tclInterp();
@ -1235,7 +1237,8 @@ protected:
virtual void makeGraphDelayCalc();
virtual void makeSim();
virtual void makeSearch();
virtual void makeLatches();
virtual void makeLatches();
virtual void makeClkNetwork();
virtual void makeCheckTiming();
virtual void makeCheckSlewLimits();
virtual void makeCheckFanoutLimits();
@ -1330,11 +1333,6 @@ protected:
void replaceCell(Instance *inst,
Cell *to_cell,
LibertyCell *to_lib_cell);
void clkPinsConnectPinAfter(Vertex *vertex);
void clkPinsDisconnectPinBefore(Vertex *vertex);
void findClkPins();
void findClkPins(bool ideal_only,
PinSet &clk_pins);
void sdcChangedGraph();
void ensureGraphSdcAnnotated();
@ -1356,10 +1354,6 @@ protected:
bool update_genclks_;
EquivCells *equiv_cells_;
bool graph_sdc_annotated_;
// findClkPins
PinSet clk_pins_;
PinSet ideal_clk_pins_;
bool clk_pins_valid_;
// Singleton sta used by tcl command interpreter.
static Sta *sta_;

View File

@ -36,6 +36,7 @@ class Parasitics;
class ArcDelayCalc;
class GraphDelayCalc;
class Latches;
class ClkNetwork;
class DispatchQueue;
// Most STA components use functionality in other components.
@ -114,6 +115,7 @@ protected:
Sim *sim_;
Search *search_;
Latches *latches_;
ClkNetwork *clk_network_;
int thread_count_;
DispatchQueue *dispatch_queue_;
bool pocv_enabled_;

183
search/ClkNetwork.cc Normal file
View File

@ -0,0 +1,183 @@
// 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 "ClkNetwork.hh"
#include "Debug.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Bfs.hh"
#include "Sdc.hh"
#include "SearchPred.hh"
#include "Search.hh"
namespace sta {
ClkNetwork::ClkNetwork(StaState *sta) :
StaState(sta),
clk_pins_valid_(false)
{
}
void
ClkNetwork::ensureClkNetwork()
{
if (!clk_pins_valid_)
findClkPins();
}
void
ClkNetwork::clear()
{
clk_pins_valid_ = false;
pin_clks_map_.clear();
clk_pins_map_.clear();
pin_ideal_clks_map_.clear();
}
void
ClkNetwork::clkPinsInvalid()
{
debugPrint0(debug_, "clk_network", 1, "clk network invalid\n");
clk_pins_valid_ = false;
}
void
ClkNetwork::deletePinBefore(const Pin *pin)
{
if (isClock(pin))
clkPinsInvalid();
}
void
ClkNetwork::disconnectPinBefore(const Pin *pin)
{
if (isClock(pin))
clkPinsInvalid();
}
void
ClkNetwork::connectPinAfter(const Pin *pin)
{
if (isClock(pin))
clkPinsInvalid();
}
class ClkSearchPred : public ClkTreeSearchPred
{
public:
ClkSearchPred(const StaState *sta);
virtual bool searchTo(const Vertex *to);
};
ClkSearchPred::ClkSearchPred(const StaState *sta) :
ClkTreeSearchPred(sta)
{
}
bool
ClkSearchPred::searchTo(const Vertex *to)
{
const Sdc *sdc = sta_->sdc();
return !sdc->isLeafPinClock(to->pin());
}
void
ClkNetwork::findClkPins()
{
debugPrint0(debug_, "clk_network", 1, "find clk network\n");
clear();
findClkPins(false, pin_clks_map_);
findClkPins(true, pin_ideal_clks_map_);
clk_pins_valid_ = true;
}
void
ClkNetwork::findClkPins(bool ideal_only,
PinClksMap &pin_clks_map)
{
ClkSearchPred srch_pred(this);
BfsFwdIterator bfs(BfsIndex::other, &srch_pred, this);
for (Clock *clk : sdc_->clks()) {
if (!ideal_only
|| !clk->isPropagated()) {
PinSet &clk_pins = clk_pins_map_[clk];
for (Pin *pin : clk->leafPins()) {
if (!ideal_only
|| !sdc_->isPropagatedClock(pin)) {
Vertex *vertex, *bidirect_drvr_vertex;
graph_->pinVertices(pin, vertex, bidirect_drvr_vertex);
bfs.enqueue(vertex);
if (bidirect_drvr_vertex)
bfs.enqueue(bidirect_drvr_vertex);
}
}
while (bfs.hasNext()) {
Vertex *vertex = bfs.next();
Pin *pin = vertex->pin();
if (!ideal_only
|| !sdc_->isPropagatedClock(pin)) {
clk_pins.insert(pin);
ClockSet &pin_clks = pin_clks_map[pin];
pin_clks.insert(clk);
bfs.enqueueAdjacentVertices(vertex);
}
}
}
}
}
bool
ClkNetwork::isClock(const Pin *pin) const
{
ClockSet clks;
bool exists;
pin_clks_map_.findKey(pin, clks, exists);
if (exists && clks.empty())
printf("luse empty clks\n");
return exists;
}
bool
ClkNetwork::isIdealClock(const Pin *pin) const
{
ClockSet clks;
bool exists;
pin_ideal_clks_map_.findKey(pin, clks, exists);
if (exists && clks.empty())
printf("luse empty clks\n");
return exists;
}
const ClockSet *
ClkNetwork::clocks(const Pin *pin)
{
if (pin_clks_map_.hasKey(pin))
return &pin_clks_map_[pin];
else
return nullptr;
}
const ClockSet *
ClkNetwork::idealClocks(const Pin *pin)
{
if (pin_ideal_clks_map_.hasKey(pin))
return &pin_ideal_clks_map_[pin];
else
return nullptr;
}
} // namespace

View File

@ -1,124 +0,0 @@
// 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 "Sta.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Bfs.hh"
#include "Sdc.hh"
#include "SearchPred.hh"
#include "Search.hh"
namespace sta {
void
Sta::ensureClkPins()
{
if (!clk_pins_valid_) {
ensureLevelized();
findClkPins();
clk_pins_valid_ = true;
}
}
void
Sta::clkPinsInvalid()
{
clk_pins_valid_ = false;
clk_pins_.clear();
ideal_clk_pins_.clear();
}
void
Sta::clkPinsDisconnectPinBefore(Vertex *vertex)
{
// If the pin is in the clock network but not a clock endpoint
// everything downstream is invalid.
if (clk_pins_.hasKey(vertex->pin())
&& !isClkEnd(vertex, graph_))
clk_pins_valid_ = false;
}
void
Sta::clkPinsConnectPinAfter(Vertex *vertex)
{
// If the pin fanin is part of the clock network
VertexInEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
Vertex *from = edge->from(graph_);
if (clk_pins_.hasKey(from->pin())) {
clk_pins_valid_ = false;
break;
}
}
}
// Find clock network pins.
// This is not as reliable as Search::isClock but is much cheaper.
void
Sta::findClkPins()
{
// Use two passes to find ideal and propagated clock network pins.
findClkPins(false, clk_pins_);
findClkPins(true, ideal_clk_pins_);
}
void
Sta::findClkPins(bool ideal_only,
PinSet &clk_pins)
{
ClkArrivalSearchPred srch_pred(this);
BfsFwdIterator bfs(BfsIndex::other, &srch_pred, this);
for (Clock *clk : sdc_->clks()) {
if (!ideal_only
|| !clk->isPropagated()) {
for (Pin *pin : clk->leafPins()) {
if (!ideal_only
|| !sdc_->isPropagatedClock(pin)) {
Vertex *vertex, *bidirect_drvr_vertex;
graph_->pinVertices(pin, vertex, bidirect_drvr_vertex);
bfs.enqueue(vertex);
if (bidirect_drvr_vertex)
bfs.enqueue(bidirect_drvr_vertex);
}
}
}
}
while (bfs.hasNext()) {
Vertex *vertex = bfs.next();
Pin *pin = vertex->pin();
if (!sdc_->isPropagatedClock(pin)) {
clk_pins.insert(pin);
bfs.enqueueAdjacentVertices(vertex);
}
}
}
bool
Sta::isClock(Pin *pin) const
{
return clk_pins_.hasKey(pin);
}
bool
Sta::isIdealClock(Pin *pin) const
{
return ideal_clk_pins_.hasKey(pin);
}
} // namespace

View File

@ -64,6 +64,7 @@
#include "ReportPath.hh"
#include "VisitPathGroupVertices.hh"
#include "Genclks.hh"
#include "ClkNetwork.hh"
#include "Power.hh"
namespace sta {
@ -268,8 +269,7 @@ Sta::Sta() :
link_make_black_boxes_(true),
update_genclks_(false),
equiv_cells_(nullptr),
graph_sdc_annotated_(false),
clk_pins_valid_(false)
graph_sdc_annotated_(false)
{
}
@ -289,6 +289,7 @@ Sta::makeComponents()
makeSim();
makeSearch();
makeLatches();
makeClkNetwork();
makeSdcNetwork();
makeReportPath();
makePower();
@ -348,6 +349,7 @@ Sta::updateComponentsState()
report_path_->copyState(this);
if (check_timing_)
check_timing_->copyState(this);
clk_network_->copyState(this);
if (power_)
power_->copyState(this);
}
@ -478,6 +480,12 @@ Sta::makeReportPath()
report_path_ = new ReportPath(this);
}
void
Sta::makeClkNetwork()
{
clk_network_ = new ClkNetwork(this);
}
void
Sta::makePower()
{
@ -525,6 +533,7 @@ Sta::~Sta()
delete debug_;
delete units_;
delete report_;
delete clk_network_;
delete power_;
delete equiv_cells_;
delete dispatch_queue_;
@ -2090,6 +2099,7 @@ Sta::removeConstraints()
if (graph_)
sdc_->removeGraphAnnotations();
sdc_->clear();
clk_network_->clear();
}
void
@ -3107,7 +3117,7 @@ Sta::findDelays(Level level)
void
Sta::delayCalcPreamble()
{
ensureLevelized();
ensureClkNetwork();
}
void
@ -3986,8 +3996,10 @@ Sta::connectPinAfter(Pin *pin)
EdgesThruHierPinIterator edge_iter(pin, network_, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->role()->isWire())
if (edge->role()->isWire()) {
connectDrvrPinAfter(edge->from(graph_));
connectLoadPinAfter(edge->to(graph_));
}
}
}
else {
@ -4034,12 +4046,13 @@ Sta::connectDrvrPinAfter(Vertex *vertex)
search_->endpointInvalid(to_vertex);
sdc_->clkHpinDisablesChanged(to_vertex->pin());
}
sdc_->clkHpinDisablesChanged(vertex->pin());
Pin *pin = vertex->pin();
sdc_->clkHpinDisablesChanged(pin);
graph_delay_calc_->delayInvalid(vertex);
search_->requiredInvalid(vertex);
search_->endpointInvalid(vertex);
clkPinsConnectPinAfter(vertex);
levelize_->invalidFrom(vertex);
clk_network_->connectPinAfter(pin);
}
void
@ -4054,12 +4067,13 @@ Sta::connectLoadPinAfter(Vertex *vertex)
search_->requiredInvalid(from_vertex);
sdc_->clkHpinDisablesChanged(from_vertex->pin());
}
sdc_->clkHpinDisablesChanged(vertex->pin());
Pin *pin = vertex->pin();
sdc_->clkHpinDisablesChanged(pin);
graph_delay_calc_->delayInvalid(vertex);
levelize_->invalidFrom(vertex);
search_->arrivalInvalid(vertex);
search_->endpointInvalid(vertex);
clkPinsConnectPinAfter(vertex);
clk_network_->connectPinAfter(pin);
}
void
@ -4079,7 +4093,7 @@ Sta::disconnectPinBefore(Pin *pin)
if (edge->role()->isWire())
deleteEdge(edge);
}
clkPinsDisconnectPinBefore(vertex);
clk_network_->disconnectPinBefore(pin);
}
}
if (network_->isLoad(pin)) {
@ -4092,7 +4106,7 @@ Sta::disconnectPinBefore(Pin *pin)
if (edge->role()->isWire())
deleteEdge(edge);
}
clkPinsDisconnectPinBefore(vertex);
clk_network_->disconnectPinBefore(pin);
}
}
if (network_->isHierarchical(pin)) {
@ -4100,8 +4114,10 @@ Sta::disconnectPinBefore(Pin *pin)
EdgesThruHierPinIterator edge_iter(pin, network_, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->role()->isWire())
if (edge->role()->isWire()) {
deleteEdge(edge);
clk_network_->disconnectPinBefore(edge->from(graph_)->pin());
}
}
}
}
@ -4229,6 +4245,7 @@ Sta::deletePinBefore(Pin *pin)
}
}
sim_->deletePinBefore(pin);
clk_network_->deletePinBefore(pin);
}
void
@ -4926,7 +4943,7 @@ Sta::checkFanoutLimitPreamble()
{
if (check_fanout_limits_ == nullptr)
makeCheckFanoutLimits();
ensureClkPins();
ensureClkNetwork();
}
Pin *
@ -4991,7 +5008,7 @@ Sta::checkCapacitanceLimitPreamble()
{
if (check_capacitance_limits_ == nullptr)
makeCheckCapacitanceLimits();
ensureClkPins();
ensureClkNetwork();
}
Pin *
@ -5244,4 +5261,31 @@ Sta::power(const Instance *inst,
power_->power(inst, corner, result);
}
////////////////////////////////////////////////////////////////
void
Sta::ensureClkNetwork()
{
ensureLevelized();
clk_network_->ensureClkNetwork();
}
bool
Sta::isClock(Pin *pin) const
{
return clk_network_->isClock(pin);
}
bool
Sta::isIdealClock(Pin *pin) const
{
return clk_network_->isIdealClock(pin);
}
void
Sta::clkPinsInvalid()
{
clk_network_->clkPinsInvalid();
}
} // namespace

View File

@ -39,6 +39,7 @@ StaState::StaState() :
sim_(nullptr),
search_(nullptr),
latches_(nullptr),
clk_network_(nullptr),
thread_count_(1),
dispatch_queue_(nullptr),
pocv_enabled_(false),
@ -63,6 +64,7 @@ StaState::StaState(const StaState *sta) :
sim_(sta->sim_),
search_(sta->search_),
latches_(sta->latches_),
clk_network_(sta->clk_network_),
thread_count_(sta->thread_count_),
dispatch_queue_(sta->dispatch_queue_),
pocv_enabled_(sta->pocv_enabled_),
@ -89,6 +91,7 @@ StaState::copyState(const StaState *sta)
sim_ = sta->sim_;
search_ = sta->search_;
latches_ = sta->latches_;
clk_network_ = sta->clk_network_;
thread_count_ = sta->thread_count_;
dispatch_queue_ = sta->dispatch_queue_;
pocv_enabled_ = sta->pocv_enabled_;