ClkNetwork
This commit is contained in:
parent
ff7557bb1f
commit
0db8d142d8
|
|
@ -158,6 +158,7 @@ set(STA_SOURCE
|
||||||
search/CheckSlewLimits.cc
|
search/CheckSlewLimits.cc
|
||||||
search/CheckTiming.cc
|
search/CheckTiming.cc
|
||||||
search/ClkInfo.cc
|
search/ClkInfo.cc
|
||||||
|
search/ClkNetwork.cc
|
||||||
search/ClkSkew.cc
|
search/ClkSkew.cc
|
||||||
search/Corner.cc
|
search/Corner.cc
|
||||||
search/Crpr.cc
|
search/Crpr.cc
|
||||||
|
|
@ -181,7 +182,6 @@ set(STA_SOURCE
|
||||||
search/ReportPath.cc
|
search/ReportPath.cc
|
||||||
search/Search.cc
|
search/Search.cc
|
||||||
search/SearchPred.cc
|
search/SearchPred.cc
|
||||||
search/FindClkPins.cc
|
|
||||||
search/Sim.cc
|
search/Sim.cc
|
||||||
search/Sta.cc
|
search/Sta.cc
|
||||||
search/StaState.cc
|
search/StaState.cc
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "GraphDelayCalc1.hh"
|
||||||
|
|
||||||
#include "Debug.hh"
|
#include "Debug.hh"
|
||||||
#include "Stats.hh"
|
#include "Stats.hh"
|
||||||
#include "MinMax.hh"
|
#include "MinMax.hh"
|
||||||
|
|
@ -34,7 +36,7 @@
|
||||||
#include "ArcDelayCalc.hh"
|
#include "ArcDelayCalc.hh"
|
||||||
#include "DcalcAnalysisPt.hh"
|
#include "DcalcAnalysisPt.hh"
|
||||||
#include "NetCaps.hh"
|
#include "NetCaps.hh"
|
||||||
#include "GraphDelayCalc1.hh"
|
#include "ClkNetwork.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -1387,7 +1389,7 @@ GraphDelayCalc1::edgeFromSlew(const Vertex *from_vertex,
|
||||||
{
|
{
|
||||||
const TimingRole *role = edge->role();
|
const TimingRole *role = edge->role();
|
||||||
if (role->genericRole() == TimingRole::regClkToQ()
|
if (role->genericRole() == TimingRole::regClkToQ()
|
||||||
&& isIdealClk(from_vertex))
|
&& clk_network_->isIdealClock(from_vertex->pin()))
|
||||||
return idealClkSlew(from_vertex, from_rf, dcalc_ap->slewMinMax());
|
return idealClkSlew(from_vertex, from_rf, dcalc_ap->slewMinMax());
|
||||||
else
|
else
|
||||||
return graph_->slew(from_vertex, from_rf, dcalc_ap->index());
|
return graph_->slew(from_vertex, from_rf, dcalc_ap->index());
|
||||||
|
|
@ -1399,7 +1401,7 @@ GraphDelayCalc1::idealClkSlew(const Vertex *vertex,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
float slew = min_max->initValue();
|
float slew = min_max->initValue();
|
||||||
const ClockSet *clks = idealClks(vertex);
|
const ClockSet *clks = clk_network_->idealClocks(vertex->pin());
|
||||||
ClockSet::ConstIterator clk_iter(clks);
|
ClockSet::ConstIterator clk_iter(clks);
|
||||||
while (clk_iter.hasNext()) {
|
while (clk_iter.hasNext()) {
|
||||||
Clock *clk = clk_iter.next();
|
Clock *clk = clk_iter.next();
|
||||||
|
|
@ -1585,7 +1587,7 @@ GraphDelayCalc1::checkEdgeClkSlew(const Vertex *from_vertex,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
const DcalcAnalysisPt *dcalc_ap)
|
const DcalcAnalysisPt *dcalc_ap)
|
||||||
{
|
{
|
||||||
if (isIdealClk(from_vertex))
|
if (clk_network_->isIdealClock(from_vertex->pin()))
|
||||||
return idealClkSlew(from_vertex, from_rf, dcalc_ap->checkClkSlewMinMax());
|
return idealClkSlew(from_vertex, from_rf, dcalc_ap->checkClkSlewMinMax());
|
||||||
else
|
else
|
||||||
return graph_->slew(from_vertex, from_rf, dcalc_ap->checkClkSlewIndex());
|
return graph_->slew(from_vertex, from_rf, dcalc_ap->checkClkSlewIndex());
|
||||||
|
|
@ -1674,15 +1676,49 @@ GraphDelayCalc1::setIdealClks(const Vertex *vertex,
|
||||||
ClockSet *
|
ClockSet *
|
||||||
GraphDelayCalc1::idealClks(const Vertex *vertex)
|
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
|
bool
|
||||||
GraphDelayCalc1::isIdealClk(const Vertex *vertex)
|
GraphDelayCalc1::isIdealClk(const Vertex *vertex)
|
||||||
{
|
{
|
||||||
const ClockSet *clks = idealClks(vertex);
|
const ClockSet *clks = idealClks(vertex);
|
||||||
return clks != 0
|
bool ideal = clks != 0
|
||||||
&& clks->size() > 0;
|
&& clks->size() > 0;
|
||||||
|
if (ideal != clk_network_->isIdealClock(vertex->pin()))
|
||||||
|
printf("ideal missmatch\n");
|
||||||
|
return ideal;
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -1765,7 +1801,7 @@ GraphDelayCalc1::reportDelayCalc(Edge *edge,
|
||||||
const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, dcalc_ap);
|
const Slew &from_slew = checkEdgeClkSlew(from_vertex, from_rf, dcalc_ap);
|
||||||
int slew_index = dcalc_ap->checkDataSlewIndex();
|
int slew_index = dcalc_ap->checkDataSlewIndex();
|
||||||
const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index);
|
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;
|
const char *from_slew_annotation = from_ideal_clk ? " (ideal clock)" : nullptr;
|
||||||
arc_delay_calc_->reportCheckDelay(cell, arc, from_slew, from_slew_annotation,
|
arc_delay_calc_->reportCheckDelay(cell, arc, from_slew, from_slew_annotation,
|
||||||
to_slew, related_out_cap, pvt, dcalc_ap,
|
to_slew, related_out_cap, pvt, dcalc_ap,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "Delay.hh"
|
||||||
#include "GraphDelayCalc.hh"
|
#include "GraphDelayCalc.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -1145,12 +1145,14 @@ public:
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void ensureClkPins();
|
void ensureClkNetwork();
|
||||||
bool isIdealClock(Pin *pin) const;
|
// Assumes ensureClkNetwork() has been called.
|
||||||
bool isClock(Pin *pin) const;
|
bool isClock(Pin *pin) const;
|
||||||
|
// Assumes ensureClkNetwork() has been called.
|
||||||
|
bool isIdealClock(Pin *pin) const;
|
||||||
void clkPinsInvalid();
|
void clkPinsInvalid();
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void setTclInterp(Tcl_Interp *interp);
|
void setTclInterp(Tcl_Interp *interp);
|
||||||
Tcl_Interp *tclInterp();
|
Tcl_Interp *tclInterp();
|
||||||
|
|
@ -1235,7 +1237,8 @@ protected:
|
||||||
virtual void makeGraphDelayCalc();
|
virtual void makeGraphDelayCalc();
|
||||||
virtual void makeSim();
|
virtual void makeSim();
|
||||||
virtual void makeSearch();
|
virtual void makeSearch();
|
||||||
virtual void makeLatches();
|
virtual void makeLatches();
|
||||||
|
virtual void makeClkNetwork();
|
||||||
virtual void makeCheckTiming();
|
virtual void makeCheckTiming();
|
||||||
virtual void makeCheckSlewLimits();
|
virtual void makeCheckSlewLimits();
|
||||||
virtual void makeCheckFanoutLimits();
|
virtual void makeCheckFanoutLimits();
|
||||||
|
|
@ -1330,11 +1333,6 @@ protected:
|
||||||
void replaceCell(Instance *inst,
|
void replaceCell(Instance *inst,
|
||||||
Cell *to_cell,
|
Cell *to_cell,
|
||||||
LibertyCell *to_lib_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 sdcChangedGraph();
|
||||||
void ensureGraphSdcAnnotated();
|
void ensureGraphSdcAnnotated();
|
||||||
|
|
||||||
|
|
@ -1356,10 +1354,6 @@ protected:
|
||||||
bool update_genclks_;
|
bool update_genclks_;
|
||||||
EquivCells *equiv_cells_;
|
EquivCells *equiv_cells_;
|
||||||
bool graph_sdc_annotated_;
|
bool graph_sdc_annotated_;
|
||||||
// findClkPins
|
|
||||||
PinSet clk_pins_;
|
|
||||||
PinSet ideal_clk_pins_;
|
|
||||||
bool clk_pins_valid_;
|
|
||||||
|
|
||||||
// Singleton sta used by tcl command interpreter.
|
// Singleton sta used by tcl command interpreter.
|
||||||
static Sta *sta_;
|
static Sta *sta_;
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ class Parasitics;
|
||||||
class ArcDelayCalc;
|
class ArcDelayCalc;
|
||||||
class GraphDelayCalc;
|
class GraphDelayCalc;
|
||||||
class Latches;
|
class Latches;
|
||||||
|
class ClkNetwork;
|
||||||
class DispatchQueue;
|
class DispatchQueue;
|
||||||
|
|
||||||
// Most STA components use functionality in other components.
|
// Most STA components use functionality in other components.
|
||||||
|
|
@ -114,6 +115,7 @@ protected:
|
||||||
Sim *sim_;
|
Sim *sim_;
|
||||||
Search *search_;
|
Search *search_;
|
||||||
Latches *latches_;
|
Latches *latches_;
|
||||||
|
ClkNetwork *clk_network_;
|
||||||
int thread_count_;
|
int thread_count_;
|
||||||
DispatchQueue *dispatch_queue_;
|
DispatchQueue *dispatch_queue_;
|
||||||
bool pocv_enabled_;
|
bool pocv_enabled_;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -64,6 +64,7 @@
|
||||||
#include "ReportPath.hh"
|
#include "ReportPath.hh"
|
||||||
#include "VisitPathGroupVertices.hh"
|
#include "VisitPathGroupVertices.hh"
|
||||||
#include "Genclks.hh"
|
#include "Genclks.hh"
|
||||||
|
#include "ClkNetwork.hh"
|
||||||
#include "Power.hh"
|
#include "Power.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
@ -268,8 +269,7 @@ Sta::Sta() :
|
||||||
link_make_black_boxes_(true),
|
link_make_black_boxes_(true),
|
||||||
update_genclks_(false),
|
update_genclks_(false),
|
||||||
equiv_cells_(nullptr),
|
equiv_cells_(nullptr),
|
||||||
graph_sdc_annotated_(false),
|
graph_sdc_annotated_(false)
|
||||||
clk_pins_valid_(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,6 +289,7 @@ Sta::makeComponents()
|
||||||
makeSim();
|
makeSim();
|
||||||
makeSearch();
|
makeSearch();
|
||||||
makeLatches();
|
makeLatches();
|
||||||
|
makeClkNetwork();
|
||||||
makeSdcNetwork();
|
makeSdcNetwork();
|
||||||
makeReportPath();
|
makeReportPath();
|
||||||
makePower();
|
makePower();
|
||||||
|
|
@ -348,6 +349,7 @@ Sta::updateComponentsState()
|
||||||
report_path_->copyState(this);
|
report_path_->copyState(this);
|
||||||
if (check_timing_)
|
if (check_timing_)
|
||||||
check_timing_->copyState(this);
|
check_timing_->copyState(this);
|
||||||
|
clk_network_->copyState(this);
|
||||||
if (power_)
|
if (power_)
|
||||||
power_->copyState(this);
|
power_->copyState(this);
|
||||||
}
|
}
|
||||||
|
|
@ -478,6 +480,12 @@ Sta::makeReportPath()
|
||||||
report_path_ = new ReportPath(this);
|
report_path_ = new ReportPath(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Sta::makeClkNetwork()
|
||||||
|
{
|
||||||
|
clk_network_ = new ClkNetwork(this);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Sta::makePower()
|
Sta::makePower()
|
||||||
{
|
{
|
||||||
|
|
@ -525,6 +533,7 @@ Sta::~Sta()
|
||||||
delete debug_;
|
delete debug_;
|
||||||
delete units_;
|
delete units_;
|
||||||
delete report_;
|
delete report_;
|
||||||
|
delete clk_network_;
|
||||||
delete power_;
|
delete power_;
|
||||||
delete equiv_cells_;
|
delete equiv_cells_;
|
||||||
delete dispatch_queue_;
|
delete dispatch_queue_;
|
||||||
|
|
@ -2090,6 +2099,7 @@ Sta::removeConstraints()
|
||||||
if (graph_)
|
if (graph_)
|
||||||
sdc_->removeGraphAnnotations();
|
sdc_->removeGraphAnnotations();
|
||||||
sdc_->clear();
|
sdc_->clear();
|
||||||
|
clk_network_->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -3107,7 +3117,7 @@ Sta::findDelays(Level level)
|
||||||
void
|
void
|
||||||
Sta::delayCalcPreamble()
|
Sta::delayCalcPreamble()
|
||||||
{
|
{
|
||||||
ensureLevelized();
|
ensureClkNetwork();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -3986,8 +3996,10 @@ Sta::connectPinAfter(Pin *pin)
|
||||||
EdgesThruHierPinIterator edge_iter(pin, network_, graph_);
|
EdgesThruHierPinIterator edge_iter(pin, network_, graph_);
|
||||||
while (edge_iter.hasNext()) {
|
while (edge_iter.hasNext()) {
|
||||||
Edge *edge = edge_iter.next();
|
Edge *edge = edge_iter.next();
|
||||||
if (edge->role()->isWire())
|
if (edge->role()->isWire()) {
|
||||||
connectDrvrPinAfter(edge->from(graph_));
|
connectDrvrPinAfter(edge->from(graph_));
|
||||||
|
connectLoadPinAfter(edge->to(graph_));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -4034,12 +4046,13 @@ Sta::connectDrvrPinAfter(Vertex *vertex)
|
||||||
search_->endpointInvalid(to_vertex);
|
search_->endpointInvalid(to_vertex);
|
||||||
sdc_->clkHpinDisablesChanged(to_vertex->pin());
|
sdc_->clkHpinDisablesChanged(to_vertex->pin());
|
||||||
}
|
}
|
||||||
sdc_->clkHpinDisablesChanged(vertex->pin());
|
Pin *pin = vertex->pin();
|
||||||
|
sdc_->clkHpinDisablesChanged(pin);
|
||||||
graph_delay_calc_->delayInvalid(vertex);
|
graph_delay_calc_->delayInvalid(vertex);
|
||||||
search_->requiredInvalid(vertex);
|
search_->requiredInvalid(vertex);
|
||||||
search_->endpointInvalid(vertex);
|
search_->endpointInvalid(vertex);
|
||||||
clkPinsConnectPinAfter(vertex);
|
|
||||||
levelize_->invalidFrom(vertex);
|
levelize_->invalidFrom(vertex);
|
||||||
|
clk_network_->connectPinAfter(pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -4054,12 +4067,13 @@ Sta::connectLoadPinAfter(Vertex *vertex)
|
||||||
search_->requiredInvalid(from_vertex);
|
search_->requiredInvalid(from_vertex);
|
||||||
sdc_->clkHpinDisablesChanged(from_vertex->pin());
|
sdc_->clkHpinDisablesChanged(from_vertex->pin());
|
||||||
}
|
}
|
||||||
sdc_->clkHpinDisablesChanged(vertex->pin());
|
Pin *pin = vertex->pin();
|
||||||
|
sdc_->clkHpinDisablesChanged(pin);
|
||||||
graph_delay_calc_->delayInvalid(vertex);
|
graph_delay_calc_->delayInvalid(vertex);
|
||||||
levelize_->invalidFrom(vertex);
|
levelize_->invalidFrom(vertex);
|
||||||
search_->arrivalInvalid(vertex);
|
search_->arrivalInvalid(vertex);
|
||||||
search_->endpointInvalid(vertex);
|
search_->endpointInvalid(vertex);
|
||||||
clkPinsConnectPinAfter(vertex);
|
clk_network_->connectPinAfter(pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -4079,7 +4093,7 @@ Sta::disconnectPinBefore(Pin *pin)
|
||||||
if (edge->role()->isWire())
|
if (edge->role()->isWire())
|
||||||
deleteEdge(edge);
|
deleteEdge(edge);
|
||||||
}
|
}
|
||||||
clkPinsDisconnectPinBefore(vertex);
|
clk_network_->disconnectPinBefore(pin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (network_->isLoad(pin)) {
|
if (network_->isLoad(pin)) {
|
||||||
|
|
@ -4092,7 +4106,7 @@ Sta::disconnectPinBefore(Pin *pin)
|
||||||
if (edge->role()->isWire())
|
if (edge->role()->isWire())
|
||||||
deleteEdge(edge);
|
deleteEdge(edge);
|
||||||
}
|
}
|
||||||
clkPinsDisconnectPinBefore(vertex);
|
clk_network_->disconnectPinBefore(pin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (network_->isHierarchical(pin)) {
|
if (network_->isHierarchical(pin)) {
|
||||||
|
|
@ -4100,8 +4114,10 @@ Sta::disconnectPinBefore(Pin *pin)
|
||||||
EdgesThruHierPinIterator edge_iter(pin, network_, graph_);
|
EdgesThruHierPinIterator edge_iter(pin, network_, graph_);
|
||||||
while (edge_iter.hasNext()) {
|
while (edge_iter.hasNext()) {
|
||||||
Edge *edge = edge_iter.next();
|
Edge *edge = edge_iter.next();
|
||||||
if (edge->role()->isWire())
|
if (edge->role()->isWire()) {
|
||||||
deleteEdge(edge);
|
deleteEdge(edge);
|
||||||
|
clk_network_->disconnectPinBefore(edge->from(graph_)->pin());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4229,6 +4245,7 @@ Sta::deletePinBefore(Pin *pin)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sim_->deletePinBefore(pin);
|
sim_->deletePinBefore(pin);
|
||||||
|
clk_network_->deletePinBefore(pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -4926,7 +4943,7 @@ Sta::checkFanoutLimitPreamble()
|
||||||
{
|
{
|
||||||
if (check_fanout_limits_ == nullptr)
|
if (check_fanout_limits_ == nullptr)
|
||||||
makeCheckFanoutLimits();
|
makeCheckFanoutLimits();
|
||||||
ensureClkPins();
|
ensureClkNetwork();
|
||||||
}
|
}
|
||||||
|
|
||||||
Pin *
|
Pin *
|
||||||
|
|
@ -4991,7 +5008,7 @@ Sta::checkCapacitanceLimitPreamble()
|
||||||
{
|
{
|
||||||
if (check_capacitance_limits_ == nullptr)
|
if (check_capacitance_limits_ == nullptr)
|
||||||
makeCheckCapacitanceLimits();
|
makeCheckCapacitanceLimits();
|
||||||
ensureClkPins();
|
ensureClkNetwork();
|
||||||
}
|
}
|
||||||
|
|
||||||
Pin *
|
Pin *
|
||||||
|
|
@ -5244,4 +5261,31 @@ Sta::power(const Instance *inst,
|
||||||
power_->power(inst, corner, result);
|
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
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ StaState::StaState() :
|
||||||
sim_(nullptr),
|
sim_(nullptr),
|
||||||
search_(nullptr),
|
search_(nullptr),
|
||||||
latches_(nullptr),
|
latches_(nullptr),
|
||||||
|
clk_network_(nullptr),
|
||||||
thread_count_(1),
|
thread_count_(1),
|
||||||
dispatch_queue_(nullptr),
|
dispatch_queue_(nullptr),
|
||||||
pocv_enabled_(false),
|
pocv_enabled_(false),
|
||||||
|
|
@ -63,6 +64,7 @@ StaState::StaState(const StaState *sta) :
|
||||||
sim_(sta->sim_),
|
sim_(sta->sim_),
|
||||||
search_(sta->search_),
|
search_(sta->search_),
|
||||||
latches_(sta->latches_),
|
latches_(sta->latches_),
|
||||||
|
clk_network_(sta->clk_network_),
|
||||||
thread_count_(sta->thread_count_),
|
thread_count_(sta->thread_count_),
|
||||||
dispatch_queue_(sta->dispatch_queue_),
|
dispatch_queue_(sta->dispatch_queue_),
|
||||||
pocv_enabled_(sta->pocv_enabled_),
|
pocv_enabled_(sta->pocv_enabled_),
|
||||||
|
|
@ -89,6 +91,7 @@ StaState::copyState(const StaState *sta)
|
||||||
sim_ = sta->sim_;
|
sim_ = sta->sim_;
|
||||||
search_ = sta->search_;
|
search_ = sta->search_;
|
||||||
latches_ = sta->latches_;
|
latches_ = sta->latches_;
|
||||||
|
clk_network_ = sta->clk_network_;
|
||||||
thread_count_ = sta->thread_count_;
|
thread_count_ = sta->thread_count_;
|
||||||
dispatch_queue_ = sta->dispatch_queue_;
|
dispatch_queue_ = sta->dispatch_queue_;
|
||||||
pocv_enabled_ = sta->pocv_enabled_;
|
pocv_enabled_ = sta->pocv_enabled_;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue