Merge pull request #388 from The-OpenROAD-Project-staging/sta_latest_0710
Sta latest 0710
This commit is contained in:
commit
31e8fffddc
|
|
@ -395,7 +395,7 @@ GraphDelayCalc::seedRootSlew(Vertex *vertex,
|
||||||
seedDrvrSlew(vertex, arc_delay_calc);
|
seedDrvrSlew(vertex, arc_delay_calc);
|
||||||
else
|
else
|
||||||
seedLoadSlew(vertex);
|
seedLoadSlew(vertex);
|
||||||
iter_->enqueueAdjacentVertices(vertex);
|
iter_->enqueueFanout(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -686,7 +686,11 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex,
|
||||||
debugPrint(debug_, "delay_calc", 2, "find delays {} ({})",
|
debugPrint(debug_, "delay_calc", 2, "find delays {} ({})",
|
||||||
vertex->to_string(this),
|
vertex->to_string(this),
|
||||||
network_->cellName(network_->instance(pin)));
|
network_->cellName(network_->instance(pin)));
|
||||||
if (vertex->isRoot())
|
if (vertex->isRoot()
|
||||||
|
// Bidirect port drivers are enqueued by their load vertex in
|
||||||
|
// annotateLoadDelays.
|
||||||
|
|| (vertex->isBidirectDriver()
|
||||||
|
&& network_->isTopLevelPort(pin)))
|
||||||
seedRootSlew(vertex, arc_delay_calc);
|
seedRootSlew(vertex, arc_delay_calc);
|
||||||
else {
|
else {
|
||||||
if (network_->isLeaf(pin)) {
|
if (network_->isLeaf(pin)) {
|
||||||
|
|
@ -703,7 +707,7 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex,
|
||||||
// change when non-incremental to stride past annotations.
|
// change when non-incremental to stride past annotations.
|
||||||
if (!incremental_
|
if (!incremental_
|
||||||
|| loadSlewsChanged(load_slews_prev, load_pin_index_map))
|
|| loadSlewsChanged(load_slews_prev, load_pin_index_map))
|
||||||
iter_->enqueueAdjacentVertices(vertex);
|
iter_->enqueueFanout(vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -711,14 +715,9 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex,
|
||||||
enqueueTimingChecksEdges(vertex);
|
enqueueTimingChecksEdges(vertex);
|
||||||
// Enqueue driver vertices from this input load.
|
// Enqueue driver vertices from this input load.
|
||||||
if (propagate)
|
if (propagate)
|
||||||
iter_->enqueueAdjacentVertices(vertex);
|
iter_->enqueueFanout(vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Bidirect port drivers are enqueued by their load vertex in
|
|
||||||
// annotateLoadDelays.
|
|
||||||
else if (vertex->isBidirectDriver()
|
|
||||||
&& network_->isTopLevelPort(pin))
|
|
||||||
seedRootSlew(vertex, arc_delay_calc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -418,6 +418,8 @@ Graph::makePinVertices(Pin *pin,
|
||||||
Vertex *&vertex,
|
Vertex *&vertex,
|
||||||
Vertex *&bidir_drvr_vertex)
|
Vertex *&bidir_drvr_vertex)
|
||||||
{
|
{
|
||||||
|
vertex = nullptr;
|
||||||
|
bidir_drvr_vertex = nullptr;
|
||||||
PortDirection *dir = network_->direction(pin);
|
PortDirection *dir = network_->direction(pin);
|
||||||
if (!dir->isPowerGround()) {
|
if (!dir->isPowerGround()) {
|
||||||
bool is_reg_clk = network_->isRegClkPin(pin);
|
bool is_reg_clk = network_->isRegClkPin(pin);
|
||||||
|
|
@ -427,8 +429,6 @@ Graph::makePinVertices(Pin *pin,
|
||||||
bidir_drvr_vertex = makeVertex(pin, true, is_reg_clk);
|
bidir_drvr_vertex = makeVertex(pin, true, is_reg_clk);
|
||||||
pin_bidirect_drvr_vertex_map_[pin] = bidir_drvr_vertex;
|
pin_bidirect_drvr_vertex_map_[pin] = bidir_drvr_vertex;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
bidir_drvr_vertex = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -581,9 +581,9 @@ Graph::visitFanouts(Vertex *vertex,
|
||||||
const VertexFn &fn)
|
const VertexFn &fn)
|
||||||
{
|
{
|
||||||
if (pred->searchFrom(vertex)) {
|
if (pred->searchFrom(vertex)) {
|
||||||
for (Edge *edge = this->edge(vertex->out_edges_);
|
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||||
edge;
|
while (edge_iter.hasNext()) {
|
||||||
edge = this->edge(edge->vertex_out_next_)) {
|
Edge *edge = edge_iter.next();
|
||||||
Vertex *to_vertex = this->vertex(edge->to_);
|
Vertex *to_vertex = this->vertex(edge->to_);
|
||||||
if (pred->searchThru(edge)
|
if (pred->searchThru(edge)
|
||||||
&& pred->searchTo(to_vertex))
|
&& pred->searchTo(to_vertex))
|
||||||
|
|
@ -598,9 +598,9 @@ Graph::visitFanoutEdges(Vertex *vertex,
|
||||||
const EdgeFn &fn)
|
const EdgeFn &fn)
|
||||||
{
|
{
|
||||||
if (pred->searchFrom(vertex)) {
|
if (pred->searchFrom(vertex)) {
|
||||||
for (Edge *edge = this->edge(vertex->out_edges_);
|
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||||
edge;
|
while (edge_iter.hasNext()) {
|
||||||
edge = this->edge(edge->vertex_out_next_)) {
|
Edge *edge = edge_iter.next();
|
||||||
Vertex *to_vertex = this->vertex(edge->to_);
|
Vertex *to_vertex = this->vertex(edge->to_);
|
||||||
if (pred->searchThru(edge)
|
if (pred->searchThru(edge)
|
||||||
&& pred->searchTo(to_vertex))
|
&& pred->searchTo(to_vertex))
|
||||||
|
|
@ -615,9 +615,9 @@ Graph::visitFanins(Vertex *vertex,
|
||||||
const VertexFn &fn)
|
const VertexFn &fn)
|
||||||
{
|
{
|
||||||
if (pred->searchFrom(vertex)) {
|
if (pred->searchFrom(vertex)) {
|
||||||
for (Edge *edge = this->edge(vertex->in_edges_);
|
VertexInEdgeIterator edge_iter(vertex, graph_);
|
||||||
edge;
|
while (edge_iter.hasNext()) {
|
||||||
edge = this->edge(edge->vertex_in_next_)) {
|
Edge *edge = edge_iter.next();
|
||||||
Vertex *from_vertex = this->vertex(edge->from_);
|
Vertex *from_vertex = this->vertex(edge->from_);
|
||||||
if (pred->searchThru(edge)
|
if (pred->searchThru(edge)
|
||||||
&& pred->searchFrom(from_vertex))
|
&& pred->searchFrom(from_vertex))
|
||||||
|
|
@ -632,9 +632,9 @@ Graph::visitFaninEdges(Vertex *vertex,
|
||||||
const EdgeFn &fn)
|
const EdgeFn &fn)
|
||||||
{
|
{
|
||||||
if (pred->searchFrom(vertex)) {
|
if (pred->searchFrom(vertex)) {
|
||||||
for (Edge *edge = this->edge(vertex->in_edges_);
|
VertexInEdgeIterator edge_iter(vertex, graph_);
|
||||||
edge;
|
while (edge_iter.hasNext()) {
|
||||||
edge = this->edge(edge->vertex_in_next_)) {
|
Edge *edge = edge_iter.next();
|
||||||
Vertex *from_vertex = this->vertex(edge->from_);
|
Vertex *from_vertex = this->vertex(edge->from_);
|
||||||
if (pred->searchThru(edge)
|
if (pred->searchThru(edge)
|
||||||
&& pred->searchFrom(from_vertex))
|
&& pred->searchFrom(from_vertex))
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -38,6 +39,8 @@ class SearchPred;
|
||||||
class BfsFwdIterator;
|
class BfsFwdIterator;
|
||||||
class BfsBkwdIterator;
|
class BfsBkwdIterator;
|
||||||
|
|
||||||
|
using VertexFn = std::function<void(Vertex*)>;
|
||||||
|
|
||||||
// LevelQueue is a vector of vertex vectors indexed by logic level.
|
// LevelQueue is a vector of vertex vectors indexed by logic level.
|
||||||
using LevelQueue = std::vector<VertexSeq>;
|
using LevelQueue = std::vector<VertexSeq>;
|
||||||
|
|
||||||
|
|
@ -50,26 +53,23 @@ using LevelQueue = std::vector<VertexSeq>;
|
||||||
// Vertices are marked as being in the queue by using a flag on
|
// Vertices are marked as being in the queue by using a flag on
|
||||||
// the vertex indexed by bfs_index. A unique flag is only needed
|
// the vertex indexed by bfs_index. A unique flag is only needed
|
||||||
// if the BFS in in use when other BFS's are simultaneously in use.
|
// if the BFS in in use when other BFS's are simultaneously in use.
|
||||||
class BfsIterator : public StaState,
|
class BfsIterator : public StaState
|
||||||
public Iterator<Vertex*>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Make sure that the BFS queue is deep enough for the max logic level.
|
// Make sure that the BFS queue is deep enough for the max logic level.
|
||||||
void ensureSize();
|
void ensureSize();
|
||||||
// Reset to virgin state.
|
// Reset to virgin state.
|
||||||
void clear();
|
void clear();
|
||||||
|
// Apply fn to each vertex and clear.
|
||||||
|
void clear(const VertexFn &fn);
|
||||||
[[nodiscard]] bool empty() const;
|
[[nodiscard]] bool empty() const;
|
||||||
// Enqueue a vertex to search from.
|
// Enqueue a vertex to search from.
|
||||||
void enqueue(Vertex *vertex);
|
void enqueue(Vertex *vertex);
|
||||||
// Enqueue vertices adjacent to a vertex.
|
// Enqueue vertices adjacent to a vertex.
|
||||||
void enqueueAdjacentVertices(Vertex *vertex);
|
virtual void enqueueAdjacentVertices(Vertex *vertex) = 0;
|
||||||
virtual void enqueueAdjacentVertices(Vertex *vertex,
|
virtual void enqueueAdjacentVertices(Vertex *vertex,
|
||||||
const Mode *mode);
|
|
||||||
virtual void enqueueAdjacentVertices(Vertex *vertex,
|
|
||||||
SearchPred *search_pred,
|
|
||||||
const Mode *mode) = 0;
|
const Mode *mode) = 0;
|
||||||
virtual void enqueueAdjacentVertices(Vertex *vertex,
|
|
||||||
SearchPred *search_pred) = 0;
|
|
||||||
[[nodiscard]] bool inQueue(Vertex *vertex);
|
[[nodiscard]] bool inQueue(Vertex *vertex);
|
||||||
void checkInQueue(Vertex *vertex);
|
void checkInQueue(Vertex *vertex);
|
||||||
// Notify iterator that vertex will be deleted.
|
// Notify iterator that vertex will be deleted.
|
||||||
|
|
@ -77,10 +77,6 @@ public:
|
||||||
void remove(Vertex *vertex);
|
void remove(Vertex *vertex);
|
||||||
void reportEntries() const;
|
void reportEntries() const;
|
||||||
|
|
||||||
bool hasNext() override;
|
|
||||||
bool hasNext(Level to_level);
|
|
||||||
Vertex *next() override;
|
|
||||||
|
|
||||||
// Apply visitor to all vertices in the queue in level order.
|
// Apply visitor to all vertices in the queue in level order.
|
||||||
// Returns the number of vertices that are visited.
|
// Returns the number of vertices that are visited.
|
||||||
virtual int visit(Level to_level,
|
virtual int visit(Level to_level,
|
||||||
|
|
@ -91,6 +87,10 @@ public:
|
||||||
int visitParallel(Level to_level,
|
int visitParallel(Level to_level,
|
||||||
VertexVisitor *visitor);
|
VertexVisitor *visitor);
|
||||||
|
|
||||||
|
bool hasNext();
|
||||||
|
bool hasNext(Level to_level);
|
||||||
|
Vertex *next();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BfsIterator(BfsIndex bfs_index,
|
BfsIterator(BfsIndex bfs_index,
|
||||||
Level level_min,
|
Level level_min,
|
||||||
|
|
@ -104,10 +104,10 @@ protected:
|
||||||
virtual bool levelLessOrEqual(Level level1,
|
virtual bool levelLessOrEqual(Level level1,
|
||||||
Level level2) const = 0;
|
Level level2) const = 0;
|
||||||
virtual void incrLevel(Level &level) const = 0;
|
virtual void incrLevel(Level &level) const = 0;
|
||||||
void findNext(Level to_level);
|
|
||||||
void deleteEntries();
|
void deleteEntries();
|
||||||
void checkLevel(Vertex *vertex,
|
void checkLevel(Vertex *vertex,
|
||||||
Level level);
|
Level level);
|
||||||
|
void findNext(Level to_level);
|
||||||
|
|
||||||
BfsIndex bfs_index_;
|
BfsIndex bfs_index_;
|
||||||
Level level_min_;
|
Level level_min_;
|
||||||
|
|
@ -131,12 +131,13 @@ public:
|
||||||
SearchPred *search_pred,
|
SearchPred *search_pred,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
~BfsFwdIterator() override;
|
~BfsFwdIterator() override;
|
||||||
|
void enqueueAdjacentVertices(Vertex *vertex) override;
|
||||||
void enqueueAdjacentVertices(Vertex *vertex,
|
void enqueueAdjacentVertices(Vertex *vertex,
|
||||||
SearchPred *search_pred) override;
|
|
||||||
void enqueueAdjacentVertices(Vertex *vertex,
|
|
||||||
SearchPred *search_pred,
|
|
||||||
const Mode *mode) override;
|
const Mode *mode) override;
|
||||||
using BfsIterator::enqueueAdjacentVertices;
|
using BfsIterator::enqueueAdjacentVertices;
|
||||||
|
void enqueueFanout(Vertex *vertex);
|
||||||
|
void enqueueFanout(Vertex *vertex,
|
||||||
|
const Mode *mode);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool levelLessOrEqual(Level level1,
|
bool levelLessOrEqual(Level level1,
|
||||||
|
|
@ -153,14 +154,17 @@ public:
|
||||||
SearchPred *search_pred,
|
SearchPred *search_pred,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
~BfsBkwdIterator() override;
|
~BfsBkwdIterator() override;
|
||||||
|
void enqueueAdjacentVertices(Vertex *vertex) override;
|
||||||
void enqueueAdjacentVertices(Vertex *vertex,
|
void enqueueAdjacentVertices(Vertex *vertex,
|
||||||
SearchPred *search_pred) override;
|
|
||||||
void enqueueAdjacentVertices(Vertex *vertex,
|
|
||||||
SearchPred *search_pred,
|
|
||||||
const Mode *mode) override;
|
const Mode *mode) override;
|
||||||
using BfsIterator::enqueueAdjacentVertices;
|
using BfsIterator::enqueueAdjacentVertices;
|
||||||
|
void enqueueFanin(Vertex *vertex);
|
||||||
|
void enqueueFanin(Vertex *vertex,
|
||||||
|
const Mode *mode);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void enqueueFanin(Vertex *vertex,
|
||||||
|
SearchPred *search_pred);
|
||||||
bool levelLessOrEqual(Level level1,
|
bool levelLessOrEqual(Level level1,
|
||||||
Level level2) const override;
|
Level level2) const override;
|
||||||
bool levelLess(Level level1,
|
bool levelLess(Level level1,
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "GraphClass.hh"
|
#include "GraphClass.hh"
|
||||||
#include "NetworkClass.hh"
|
#include "NetworkClass.hh"
|
||||||
|
#include "Scene.hh"
|
||||||
#include "SdcClass.hh"
|
#include "SdcClass.hh"
|
||||||
#include "SearchClass.hh"
|
#include "SearchClass.hh"
|
||||||
#include "StringUtil.hh"
|
#include "StringUtil.hh"
|
||||||
|
|
@ -64,6 +65,16 @@ filterClocks(std::string_view filter_expression,
|
||||||
ClockSeq *clks,
|
ClockSeq *clks,
|
||||||
Sta *sta);
|
Sta *sta);
|
||||||
|
|
||||||
|
SceneSeq
|
||||||
|
filterScenes(std::string_view filter_expression,
|
||||||
|
SceneSeq *scenes,
|
||||||
|
Sta *sta);
|
||||||
|
|
||||||
|
ModeSeq
|
||||||
|
filterModes(std::string_view filter_expression,
|
||||||
|
ModeSeq *modes,
|
||||||
|
Sta *sta);
|
||||||
|
|
||||||
LibertyCellSeq
|
LibertyCellSeq
|
||||||
filterLibCells(std::string_view filter_expression,
|
filterLibCells(std::string_view filter_expression,
|
||||||
LibertyCellSeq *cells,
|
LibertyCellSeq *cells,
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "LibertyClass.hh"
|
#include "LibertyClass.hh"
|
||||||
#include "NetworkClass.hh"
|
#include "NetworkClass.hh"
|
||||||
|
|
@ -61,109 +62,6 @@ private:
|
||||||
std::map<std::string, PropertyHandler, std::less<>> registry_;
|
std::map<std::string, PropertyHandler, std::less<>> registry_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Properties
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Properties(Sta *sta);
|
|
||||||
|
|
||||||
PropertyValue getProperty(const Library *lib,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(const LibertyLibrary *lib,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(const Cell *cell,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(const LibertyCell *cell,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(const Port *port,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(const LibertyPort *port,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(const Instance *inst,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(const Pin *pin,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(const Net *net,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(Edge *edge,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(const Clock *clk,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(const Scene *scene,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(const Mode *mode,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(PathEnd *end,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(Path *path,
|
|
||||||
std::string_view property);
|
|
||||||
PropertyValue getProperty(TimingArcSet *arc_set,
|
|
||||||
std::string_view property);
|
|
||||||
|
|
||||||
// Define handler for external property.
|
|
||||||
// properties->defineProperty("foo",
|
|
||||||
// [] (const Instance *, Sta *) -> PropertyValue {
|
|
||||||
// return PropertyValue("bar");
|
|
||||||
// });
|
|
||||||
void defineProperty(std::string_view property,
|
|
||||||
const PropertyRegistry<const Library *>::PropertyHandler &handler);
|
|
||||||
void defineProperty(std::string_view property,
|
|
||||||
const PropertyRegistry<const LibertyLibrary *>::PropertyHandler &handler);
|
|
||||||
void defineProperty(std::string_view property,
|
|
||||||
const PropertyRegistry<const Cell *>::PropertyHandler &handler);
|
|
||||||
void defineProperty(std::string_view property,
|
|
||||||
const PropertyRegistry<const LibertyCell *>::PropertyHandler &handler);
|
|
||||||
void defineProperty(std::string_view property,
|
|
||||||
const PropertyRegistry<const Port *>::PropertyHandler &handler);
|
|
||||||
void defineProperty(std::string_view property,
|
|
||||||
const PropertyRegistry<const LibertyPort *>::PropertyHandler &handler);
|
|
||||||
void defineProperty(std::string_view property,
|
|
||||||
const PropertyRegistry<const Instance *>::PropertyHandler &handler);
|
|
||||||
void defineProperty(std::string_view property,
|
|
||||||
const PropertyRegistry<const Pin *>::PropertyHandler &handler);
|
|
||||||
void defineProperty(std::string_view property,
|
|
||||||
const PropertyRegistry<const Net *>::PropertyHandler &handler);
|
|
||||||
void defineProperty(std::string_view property,
|
|
||||||
const PropertyRegistry<const Clock *>::PropertyHandler &handler);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
PropertyValue portSlew(const Port *port,
|
|
||||||
const RiseFallBoth *rf,
|
|
||||||
const MinMax *min_max);
|
|
||||||
PropertyValue portSlack(const Port *port,
|
|
||||||
const RiseFallBoth *rf,
|
|
||||||
const MinMax *min_max);
|
|
||||||
PropertyValue pinArrival(const Pin *pin,
|
|
||||||
const RiseFallBoth *rf,
|
|
||||||
const MinMax *min_max);
|
|
||||||
|
|
||||||
PropertyValue pinSlack(const Pin *pin,
|
|
||||||
const RiseFallBoth *rf,
|
|
||||||
const MinMax *min_max);
|
|
||||||
PropertyValue pinSlew(const Pin *pin,
|
|
||||||
const RiseFallBoth *rf,
|
|
||||||
const MinMax *min_max);
|
|
||||||
|
|
||||||
PropertyValue delayPropertyValue(Delay delay);
|
|
||||||
PropertyValue resistancePropertyValue(float res);
|
|
||||||
PropertyValue capacitancePropertyValue(float cap);
|
|
||||||
PropertyValue edgeDelay(Edge *edge,
|
|
||||||
const RiseFall *rf,
|
|
||||||
const MinMax *min_max);
|
|
||||||
|
|
||||||
PropertyRegistry<const Library*> registry_library_;
|
|
||||||
PropertyRegistry<const LibertyLibrary*> registry_liberty_library_;
|
|
||||||
PropertyRegistry<const Cell*> registry_cell_;
|
|
||||||
PropertyRegistry<const LibertyCell*> registry_liberty_cell_;
|
|
||||||
PropertyRegistry<const Port*> registry_port_;
|
|
||||||
PropertyRegistry<const LibertyPort*> registry_liberty_port_;
|
|
||||||
PropertyRegistry<const Instance*> registry_instance_;
|
|
||||||
PropertyRegistry<const Pin*> registry_pin_;
|
|
||||||
PropertyRegistry<const Net*> registry_net_;
|
|
||||||
PropertyRegistry<const Clock*> registry_clock_;
|
|
||||||
|
|
||||||
Sta *sta_;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Adding a new property type
|
// Adding a new property type
|
||||||
// value union (string values use std::string* so the union stays trivial)
|
// value union (string values use std::string* so the union stays trivial)
|
||||||
// enum Type
|
// enum Type
|
||||||
|
|
@ -262,4 +160,151 @@ private:
|
||||||
const Unit *unit_;
|
const Unit *unit_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Key for user-defined property values: the object instance and the
|
||||||
|
// property name.
|
||||||
|
class PropertyKey
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PropertyKey(const void *object,
|
||||||
|
std::string_view property);
|
||||||
|
bool operator<(const PropertyKey &key) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const void *object_;
|
||||||
|
std::string property_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Properties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Properties(Sta *sta);
|
||||||
|
|
||||||
|
PropertyValue getProperty(const Library *lib,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(const LibertyLibrary *lib,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(const Cell *cell,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(const LibertyCell *cell,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(const Port *port,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(const LibertyPort *port,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(const Instance *inst,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(const Pin *pin,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(const Net *net,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(Edge *edge,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(const Clock *clk,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(const Scene *scene,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(const Mode *mode,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(PathEnd *end,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(Path *path,
|
||||||
|
std::string_view property);
|
||||||
|
PropertyValue getProperty(TimingArcSet *arc_set,
|
||||||
|
std::string_view property);
|
||||||
|
|
||||||
|
// Define handler for external property.
|
||||||
|
// properties->defineProperty("foo",
|
||||||
|
// [] (const Instance *, Sta *) -> PropertyValue {
|
||||||
|
// return PropertyValue("bar");
|
||||||
|
// });
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const Library *>::PropertyHandler &handler);
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const LibertyLibrary *>::PropertyHandler &handler);
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const Cell *>::PropertyHandler &handler);
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const LibertyCell *>::PropertyHandler &handler);
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const Port *>::PropertyHandler &handler);
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const LibertyPort *>::PropertyHandler &handler);
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const Instance *>::PropertyHandler &handler);
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const Pin *>::PropertyHandler &handler);
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const Net *>::PropertyHandler &handler);
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const Clock *>::PropertyHandler &handler);
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const Scene *>::PropertyHandler &handler);
|
||||||
|
void defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const Mode *>::PropertyHandler &handler);
|
||||||
|
|
||||||
|
// User-defined, per-object mutable properties. defineProperty registers
|
||||||
|
// a property of the given value type ("bool", "float" or "string");
|
||||||
|
// setProperty sets the value on one object. Objects the property was never
|
||||||
|
// set on read back as an empty (none) value. The property is read through
|
||||||
|
// the same registry path as every other property so get_property /
|
||||||
|
// get_* -filter work unchanged.
|
||||||
|
template<class TYPE>
|
||||||
|
void defineProperty(std::string_view object_type,
|
||||||
|
std::string_view property,
|
||||||
|
std::string_view value_type);
|
||||||
|
void setProperty(const void *object,
|
||||||
|
std::string_view object_type,
|
||||||
|
std::string_view property,
|
||||||
|
std::string_view value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PropertyValue portSlew(const Port *port,
|
||||||
|
const RiseFallBoth *rf,
|
||||||
|
const MinMax *min_max);
|
||||||
|
PropertyValue portSlack(const Port *port,
|
||||||
|
const RiseFallBoth *rf,
|
||||||
|
const MinMax *min_max);
|
||||||
|
PropertyValue pinArrival(const Pin *pin,
|
||||||
|
const RiseFallBoth *rf,
|
||||||
|
const MinMax *min_max);
|
||||||
|
|
||||||
|
PropertyValue pinSlack(const Pin *pin,
|
||||||
|
const RiseFallBoth *rf,
|
||||||
|
const MinMax *min_max);
|
||||||
|
PropertyValue pinSlew(const Pin *pin,
|
||||||
|
const RiseFallBoth *rf,
|
||||||
|
const MinMax *min_max);
|
||||||
|
|
||||||
|
PropertyValue delayPropertyValue(Delay delay);
|
||||||
|
PropertyValue resistancePropertyValue(float res);
|
||||||
|
PropertyValue capacitancePropertyValue(float cap);
|
||||||
|
PropertyValue edgeDelay(Edge *edge,
|
||||||
|
const RiseFall *rf,
|
||||||
|
const MinMax *min_max);
|
||||||
|
PropertyValue::Type propertyType(std::string_view type);
|
||||||
|
PropertyValue coercePropertyValue(PropertyValue::Type type,
|
||||||
|
std::string_view value);
|
||||||
|
|
||||||
|
PropertyRegistry<const Library*> registry_library_;
|
||||||
|
PropertyRegistry<const LibertyLibrary*> registry_liberty_library_;
|
||||||
|
PropertyRegistry<const Cell*> registry_cell_;
|
||||||
|
PropertyRegistry<const LibertyCell*> registry_liberty_cell_;
|
||||||
|
PropertyRegistry<const Port*> registry_port_;
|
||||||
|
PropertyRegistry<const LibertyPort*> registry_liberty_port_;
|
||||||
|
PropertyRegistry<const Instance*> registry_instance_;
|
||||||
|
PropertyRegistry<const Pin*> registry_pin_;
|
||||||
|
PropertyRegistry<const Net*> registry_net_;
|
||||||
|
PropertyRegistry<const Clock*> registry_clock_;
|
||||||
|
PropertyRegistry<const Scene*> registry_scene_;
|
||||||
|
PropertyRegistry<const Mode*> registry_mode_;
|
||||||
|
|
||||||
|
// Value types of user-defined properties keyed by object type name and
|
||||||
|
// property name.
|
||||||
|
std::map<std::pair<std::string, std::string>, PropertyValue::Type> prop_types_;
|
||||||
|
// User-defined property values.
|
||||||
|
std::map<PropertyKey, PropertyValue> prop_values_;
|
||||||
|
|
||||||
|
Sta *sta_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace sta
|
} // namespace sta
|
||||||
|
|
|
||||||
|
|
@ -286,8 +286,6 @@ public:
|
||||||
TagGroupBldr *tag_bldr);
|
TagGroupBldr *tag_bldr);
|
||||||
void postponeLatchDataOutputs(Vertex *vertex);
|
void postponeLatchDataOutputs(Vertex *vertex);
|
||||||
void postponeArrivals(Vertex *vertex);
|
void postponeArrivals(Vertex *vertex);
|
||||||
void enqueuePendingClkFanouts();
|
|
||||||
void postponeClkFanouts(Vertex *vertex);
|
|
||||||
void seedRequired(Vertex *vertex);
|
void seedRequired(Vertex *vertex);
|
||||||
void seedRequiredEnqueueFanin(Vertex *vertex);
|
void seedRequiredEnqueueFanin(Vertex *vertex);
|
||||||
void seedInputDelayArrival(const Pin *pin,
|
void seedInputDelayArrival(const Pin *pin,
|
||||||
|
|
@ -503,12 +501,12 @@ protected:
|
||||||
bool is_segment_start,
|
bool is_segment_start,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
Scene *scene);
|
Scene *scene);
|
||||||
void seedClkVertexArrivals();
|
void enqueueClkRoots();
|
||||||
void findClkArrivals1();
|
void enqueueInvalidClks();
|
||||||
|
|
||||||
void findAllArrivals(bool thru_latches,
|
void findAllArrivals(bool thru_latches);
|
||||||
bool clks_only);
|
|
||||||
void findArrivals1(Level level);
|
void findArrivals1(Level level);
|
||||||
|
void findArrivals2(Level level);
|
||||||
Tag *mutateTag(Tag *from_tag,
|
Tag *mutateTag(Tag *from_tag,
|
||||||
const Pin *from_pin,
|
const Pin *from_pin,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
|
|
@ -646,12 +644,9 @@ protected:
|
||||||
std::vector<TagIndex> tag_group_free_indices_;
|
std::vector<TagIndex> tag_group_free_indices_;
|
||||||
std::mutex tag_group_lock_;
|
std::mutex tag_group_lock_;
|
||||||
|
|
||||||
// Latches data outputs to queue on the next search pass.
|
// Arrivals to queue on the next search pass.
|
||||||
VertexSet postponed_arrivals_;
|
VertexSet pending_arrivals_;
|
||||||
std::mutex postponed_arrivals_lock_;
|
std::mutex pending_arrivals_lock_;
|
||||||
// Clock network endpoints where arrival search was suppended by findClkArrivals().
|
|
||||||
VertexSet postponed_clk_endpoints_;
|
|
||||||
std::mutex postponed_clk_endpoints_lock_;
|
|
||||||
|
|
||||||
VertexSet endpoints_;
|
VertexSet endpoints_;
|
||||||
bool endpoints_initialized_{false};
|
bool endpoints_initialized_{false};
|
||||||
|
|
|
||||||
|
|
@ -947,6 +947,11 @@ public:
|
||||||
// from/thrus/to are owned and deleted by Search.
|
// from/thrus/to are owned and deleted by Search.
|
||||||
// PathEnds in the returned PathEndSeq are owned by Search PathGroups
|
// PathEnds in the returned PathEndSeq are owned by Search PathGroups
|
||||||
// and deleted on next call.
|
// and deleted on next call.
|
||||||
|
//
|
||||||
|
// IMPORTANT: THIS IS NOT THE DROID YOU ARE LOOKING FOR.
|
||||||
|
// This function is specifically designed to support the many options
|
||||||
|
// and results of timing reports. It is NOT a good option to find paths
|
||||||
|
// for optimization.
|
||||||
PathEndSeq findPathEnds(ExceptionFrom *from,
|
PathEndSeq findPathEnds(ExceptionFrom *from,
|
||||||
ExceptionThruSeq *thrus,
|
ExceptionThruSeq *thrus,
|
||||||
ExceptionTo *to,
|
ExceptionTo *to,
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
#include "GraphCmp.hh"
|
#include "GraphCmp.hh"
|
||||||
#include "Liberty.hh"
|
#include "Liberty.hh"
|
||||||
#include "LibertyClass.hh"
|
#include "LibertyClass.hh"
|
||||||
|
#include "Mode.hh"
|
||||||
#include "Network.hh"
|
#include "Network.hh"
|
||||||
#include "NetworkClass.hh"
|
#include "NetworkClass.hh"
|
||||||
#include "PathEnd.hh"
|
#include "PathEnd.hh"
|
||||||
|
|
@ -497,6 +498,30 @@ filterClocks(std::string_view filter_expression,
|
||||||
}, sta);
|
}, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SceneSeq
|
||||||
|
filterScenes(std::string_view filter_expression,
|
||||||
|
SceneSeq *scenes,
|
||||||
|
Sta *sta)
|
||||||
|
{
|
||||||
|
return filterObjects<Scene>(filter_expression, scenes,
|
||||||
|
[] (const Scene *scene1,
|
||||||
|
const Scene *scene2) {
|
||||||
|
return scene1->name() < scene2->name();
|
||||||
|
}, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModeSeq
|
||||||
|
filterModes(std::string_view filter_expression,
|
||||||
|
ModeSeq *modes,
|
||||||
|
Sta *sta)
|
||||||
|
{
|
||||||
|
return filterObjects<Mode>(filter_expression, modes,
|
||||||
|
[] (const Mode *mode1,
|
||||||
|
const Mode *mode2) {
|
||||||
|
return mode1->name() < mode2->name();
|
||||||
|
}, sta);
|
||||||
|
}
|
||||||
|
|
||||||
LibertyCellSeq
|
LibertyCellSeq
|
||||||
filterLibCells(std::string_view filter_expression,
|
filterLibCells(std::string_view filter_expression,
|
||||||
LibertyCellSeq *cells,
|
LibertyCellSeq *cells,
|
||||||
|
|
|
||||||
16
sdc/Sdc.i
16
sdc/Sdc.i
|
|
@ -1531,6 +1531,22 @@ filter_clocks(const char *filter_expression,
|
||||||
return filterClocks(filter_expression, clocks, sta);
|
return filterClocks(filter_expression, clocks, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SceneSeq
|
||||||
|
filter_scenes(const char *filter_expression,
|
||||||
|
SceneSeq *scenes)
|
||||||
|
{
|
||||||
|
sta::Sta *sta = Sta::sta();
|
||||||
|
return filterScenes(filter_expression, scenes, sta);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModeSeq
|
||||||
|
filter_modes(const char *filter_expression,
|
||||||
|
ModeSeq *modes)
|
||||||
|
{
|
||||||
|
sta::Sta *sta = Sta::sta();
|
||||||
|
return filterModes(filter_expression, modes, sta);
|
||||||
|
}
|
||||||
|
|
||||||
LibertyCellSeq
|
LibertyCellSeq
|
||||||
filter_lib_cells(const char *filter_expression,
|
filter_lib_cells(const char *filter_expression,
|
||||||
LibertyCellSeq *cells)
|
LibertyCellSeq *cells)
|
||||||
|
|
|
||||||
205
search/Bfs.cc
205
search/Bfs.cc
|
|
@ -71,13 +71,21 @@ BfsIterator::ensureSize()
|
||||||
|
|
||||||
void
|
void
|
||||||
BfsIterator::clear()
|
BfsIterator::clear()
|
||||||
|
{
|
||||||
|
clear([] (Vertex *) {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BfsIterator::clear(const VertexFn &fn)
|
||||||
{
|
{
|
||||||
Level level = first_level_;
|
Level level = first_level_;
|
||||||
while (levelLessOrEqual(level, last_level_)) {
|
while (levelLessOrEqual(level, last_level_)) {
|
||||||
VertexSeq &level_vertices = queue_[level];
|
VertexSeq &level_vertices = queue_[level];
|
||||||
for (Vertex *vertex : level_vertices) {
|
for (Vertex *vertex : level_vertices) {
|
||||||
if (vertex)
|
if (vertex) {
|
||||||
vertex->setBfsInQueue(bfs_index_, false);
|
vertex->setBfsInQueue(bfs_index_, false);
|
||||||
|
fn(vertex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
level_vertices.clear();
|
level_vertices.clear();
|
||||||
incrLevel(level);
|
incrLevel(level);
|
||||||
|
|
@ -116,19 +124,6 @@ BfsIterator::empty() const
|
||||||
return levelLess(last_level_, first_level_);
|
return levelLess(last_level_, first_level_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
BfsIterator::enqueueAdjacentVertices(Vertex *vertex)
|
|
||||||
{
|
|
||||||
enqueueAdjacentVertices(vertex, search_pred_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
BfsIterator::enqueueAdjacentVertices(Vertex *vertex,
|
|
||||||
const Mode *mode)
|
|
||||||
{
|
|
||||||
enqueueAdjacentVertices(vertex, search_pred_, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
BfsIterator::visit(Level to_level,
|
BfsIterator::visit(Level to_level,
|
||||||
VertexVisitor *visitor)
|
VertexVisitor *visitor)
|
||||||
|
|
@ -218,50 +213,6 @@ BfsIterator::visitParallel(Level to_level,
|
||||||
return visit_count;
|
return visit_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
BfsIterator::hasNext()
|
|
||||||
{
|
|
||||||
return hasNext(last_level_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
BfsIterator::hasNext(Level to_level)
|
|
||||||
{
|
|
||||||
findNext(to_level);
|
|
||||||
return levelLessOrEqual(first_level_, last_level_)
|
|
||||||
&& !queue_[first_level_].empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vertex *
|
|
||||||
BfsIterator::next()
|
|
||||||
{
|
|
||||||
VertexSeq &level_vertices = queue_[first_level_];
|
|
||||||
Vertex *vertex = level_vertices.back();
|
|
||||||
level_vertices.pop_back();
|
|
||||||
vertex->setBfsInQueue(bfs_index_, false);
|
|
||||||
return vertex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
BfsIterator::findNext(Level to_level)
|
|
||||||
{
|
|
||||||
while (levelLessOrEqual(first_level_, last_level_)
|
|
||||||
&& levelLessOrEqual(first_level_, to_level)) {
|
|
||||||
VertexSeq &level_vertices = queue_[first_level_];
|
|
||||||
// Skip null entries from deleted vertices.
|
|
||||||
while (!level_vertices.empty()) {
|
|
||||||
Vertex *vertex = level_vertices.back();
|
|
||||||
if (vertex == nullptr)
|
|
||||||
level_vertices.pop_back();
|
|
||||||
else {
|
|
||||||
checkLevel(vertex, first_level_);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
incrLevel(first_level_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BfsIterator::enqueue(Vertex *vertex)
|
BfsIterator::enqueue(Vertex *vertex)
|
||||||
{
|
{
|
||||||
|
|
@ -341,6 +292,52 @@ BfsIterator::remove(Vertex *vertex)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
bool
|
||||||
|
BfsIterator::hasNext()
|
||||||
|
{
|
||||||
|
return hasNext(last_level_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BfsIterator::hasNext(Level to_level)
|
||||||
|
{
|
||||||
|
findNext(to_level);
|
||||||
|
return levelLessOrEqual(first_level_, last_level_)
|
||||||
|
&& !queue_[first_level_].empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex *
|
||||||
|
BfsIterator::next()
|
||||||
|
{
|
||||||
|
VertexSeq &level_vertices = queue_[first_level_];
|
||||||
|
Vertex *vertex = level_vertices.back();
|
||||||
|
level_vertices.pop_back();
|
||||||
|
vertex->setBfsInQueue(bfs_index_, false);
|
||||||
|
return vertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BfsIterator::findNext(Level to_level)
|
||||||
|
{
|
||||||
|
while (levelLessOrEqual(first_level_, last_level_)
|
||||||
|
&& levelLessOrEqual(first_level_, to_level)) {
|
||||||
|
VertexSeq &level_vertices = queue_[first_level_];
|
||||||
|
// Skip null entries from deleted vertices.
|
||||||
|
while (!level_vertices.empty()) {
|
||||||
|
Vertex *vertex = level_vertices.back();
|
||||||
|
if (vertex == nullptr)
|
||||||
|
level_vertices.pop_back();
|
||||||
|
else {
|
||||||
|
checkLevel(vertex, first_level_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
incrLevel(first_level_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
BfsFwdIterator::BfsFwdIterator(BfsIndex bfs_index,
|
BfsFwdIterator::BfsFwdIterator(BfsIndex bfs_index,
|
||||||
SearchPred *search_pred,
|
SearchPred *search_pred,
|
||||||
StaState *sta) :
|
StaState *sta) :
|
||||||
|
|
@ -376,15 +373,46 @@ BfsFwdIterator::levelLess(Level level1,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
BfsFwdIterator::enqueueFanout(Vertex *vertex)
|
||||||
SearchPred *search_pred)
|
|
||||||
{
|
{
|
||||||
if (search_pred->searchFrom(vertex)) {
|
if (search_pred_->searchFrom(vertex)) {
|
||||||
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||||
while (edge_iter.hasNext()) {
|
while (edge_iter.hasNext()) {
|
||||||
Edge *edge = edge_iter.next();
|
Edge *edge = edge_iter.next();
|
||||||
Vertex *to_vertex = edge->to(graph_);
|
Vertex *to_vertex = edge->to(graph_);
|
||||||
if (search_pred->searchThru(edge) && search_pred->searchTo(to_vertex))
|
if (search_pred_->searchThru(edge)
|
||||||
|
&& search_pred_->searchTo(to_vertex))
|
||||||
|
enqueue(to_vertex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BfsFwdIterator::enqueueFanout(Vertex *vertex,
|
||||||
|
const Mode *mode)
|
||||||
|
{
|
||||||
|
if (search_pred_->searchFrom(vertex, mode)) {
|
||||||
|
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||||
|
while (edge_iter.hasNext()) {
|
||||||
|
Edge *edge = edge_iter.next();
|
||||||
|
Vertex *to_vertex = edge->to(graph_);
|
||||||
|
if (search_pred_->searchThru(edge, mode)
|
||||||
|
&& search_pred_->searchTo(to_vertex, mode))
|
||||||
|
enqueue(to_vertex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex)
|
||||||
|
{
|
||||||
|
if (search_pred_->searchFrom(vertex)) {
|
||||||
|
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||||
|
while (edge_iter.hasNext()) {
|
||||||
|
Edge *edge = edge_iter.next();
|
||||||
|
Vertex *to_vertex = edge->to(graph_);
|
||||||
|
if (search_pred_->searchThru(edge)
|
||||||
|
&& search_pred_->searchTo(to_vertex))
|
||||||
enqueue(to_vertex);
|
enqueue(to_vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -392,16 +420,15 @@ BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
||||||
|
|
||||||
void
|
void
|
||||||
BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
||||||
SearchPred *search_pred,
|
|
||||||
const Mode *mode)
|
const Mode *mode)
|
||||||
{
|
{
|
||||||
if (search_pred->searchFrom(vertex, mode)) {
|
if (search_pred_->searchFrom(vertex, mode)) {
|
||||||
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||||
while (edge_iter.hasNext()) {
|
while (edge_iter.hasNext()) {
|
||||||
Edge *edge = edge_iter.next();
|
Edge *edge = edge_iter.next();
|
||||||
Vertex *to_vertex = edge->to(graph_);
|
Vertex *to_vertex = edge->to(graph_);
|
||||||
if (search_pred->searchThru(edge, mode)
|
if (search_pred_->searchThru(edge, mode)
|
||||||
&& search_pred->searchTo(to_vertex, mode))
|
&& search_pred_->searchTo(to_vertex, mode))
|
||||||
enqueue(to_vertex);
|
enqueue(to_vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -444,15 +471,15 @@ BfsBkwdIterator::levelLess(Level level1,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex)
|
||||||
SearchPred *search_pred)
|
|
||||||
{
|
{
|
||||||
if (search_pred->searchTo(vertex)) {
|
if (search_pred_->searchTo(vertex)) {
|
||||||
VertexInEdgeIterator edge_iter(vertex, graph_);
|
VertexInEdgeIterator edge_iter(vertex, graph_);
|
||||||
while (edge_iter.hasNext()) {
|
while (edge_iter.hasNext()) {
|
||||||
Edge *edge = edge_iter.next();
|
Edge *edge = edge_iter.next();
|
||||||
Vertex *from_vertex = edge->from(graph_);
|
Vertex *from_vertex = edge->from(graph_);
|
||||||
if (search_pred->searchFrom(from_vertex) && search_pred->searchThru(edge))
|
if (search_pred_->searchFrom(from_vertex)
|
||||||
|
&& search_pred_->searchThru(edge))
|
||||||
enqueue(from_vertex);
|
enqueue(from_vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -460,16 +487,46 @@ BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
||||||
|
|
||||||
void
|
void
|
||||||
BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
||||||
SearchPred *search_pred,
|
|
||||||
const Mode *mode)
|
const Mode *mode)
|
||||||
{
|
{
|
||||||
if (search_pred->searchTo(vertex, mode)) {
|
if (search_pred_->searchTo(vertex, mode)) {
|
||||||
VertexInEdgeIterator edge_iter(vertex, graph_);
|
VertexInEdgeIterator edge_iter(vertex, graph_);
|
||||||
while (edge_iter.hasNext()) {
|
while (edge_iter.hasNext()) {
|
||||||
Edge *edge = edge_iter.next();
|
Edge *edge = edge_iter.next();
|
||||||
Vertex *from_vertex = edge->from(graph_);
|
Vertex *from_vertex = edge->from(graph_);
|
||||||
if (search_pred->searchFrom(from_vertex, mode)
|
if (search_pred_->searchFrom(from_vertex, mode)
|
||||||
&& search_pred->searchThru(edge, mode))
|
&& search_pred_->searchThru(edge, mode))
|
||||||
|
enqueue(from_vertex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BfsBkwdIterator::enqueueFanin(Vertex *vertex)
|
||||||
|
{
|
||||||
|
if (search_pred_->searchTo(vertex)) {
|
||||||
|
VertexInEdgeIterator edge_iter(vertex, graph_);
|
||||||
|
while (edge_iter.hasNext()) {
|
||||||
|
Edge *edge = edge_iter.next();
|
||||||
|
Vertex *from_vertex = edge->from(graph_);
|
||||||
|
if (search_pred_->searchFrom(from_vertex)
|
||||||
|
&& search_pred_->searchThru(edge))
|
||||||
|
enqueue(from_vertex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BfsBkwdIterator::enqueueFanin(Vertex *vertex,
|
||||||
|
const Mode *mode)
|
||||||
|
{
|
||||||
|
if (search_pred_->searchTo(vertex, mode)) {
|
||||||
|
VertexInEdgeIterator edge_iter(vertex, graph_);
|
||||||
|
while (edge_iter.hasNext()) {
|
||||||
|
Edge *edge = edge_iter.next();
|
||||||
|
Vertex *from_vertex = edge->from(graph_);
|
||||||
|
if (search_pred_->searchFrom(from_vertex, mode)
|
||||||
|
&& search_pred_->searchThru(edge, mode))
|
||||||
enqueue(from_vertex);
|
enqueue(from_vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@
|
||||||
|
|
||||||
#include "ClkNetwork.hh"
|
#include "ClkNetwork.hh"
|
||||||
|
|
||||||
#include "Bfs.hh"
|
#include <queue>
|
||||||
|
|
||||||
#include "Debug.hh"
|
#include "Debug.hh"
|
||||||
#include "Graph.hh"
|
#include "Graph.hh"
|
||||||
#include "Mode.hh"
|
#include "Mode.hh"
|
||||||
|
|
@ -127,7 +128,6 @@ ClkNetwork::findClkPins(bool ideal_only,
|
||||||
{
|
{
|
||||||
const Sdc *sdc = mode_->sdc();
|
const Sdc *sdc = mode_->sdc();
|
||||||
ClkSearchPred srch_pred(this);
|
ClkSearchPred srch_pred(this);
|
||||||
BfsFwdIterator bfs(BfsIndex::other, &srch_pred, this);
|
|
||||||
for (Clock *clk : sdc->clocks()) {
|
for (Clock *clk : sdc->clocks()) {
|
||||||
if (!ideal_only
|
if (!ideal_only
|
||||||
|| !clk->isPropagated()) {
|
|| !clk->isPropagated()) {
|
||||||
|
|
@ -136,25 +136,39 @@ ClkNetwork::findClkPins(bool ideal_only,
|
||||||
clk_pins = new PinSet(network_);
|
clk_pins = new PinSet(network_);
|
||||||
clk_pins_map_[clk] = clk_pins;
|
clk_pins_map_[clk] = clk_pins;
|
||||||
}
|
}
|
||||||
|
std::queue<Vertex *> queue;
|
||||||
|
VertexSet visited = makeVertexSet(this);
|
||||||
|
auto enqueue = [&queue, &visited] (Vertex *vertex) {
|
||||||
|
if (vertex && !visited.contains(vertex)) {
|
||||||
|
visited.insert(vertex);
|
||||||
|
queue.push(vertex);
|
||||||
|
}
|
||||||
|
};
|
||||||
for (const Pin *pin : clk->leafPins()) {
|
for (const Pin *pin : clk->leafPins()) {
|
||||||
if (!ideal_only
|
if (!ideal_only
|
||||||
|| !sdc->isPropagatedClock(pin)) {
|
|| !sdc->isPropagatedClock(pin)) {
|
||||||
Vertex *vertex, *bidirect_drvr_vertex;
|
Vertex *vertex, *bidirect_drvr_vertex;
|
||||||
graph_->pinVertices(pin, vertex, bidirect_drvr_vertex);
|
graph_->pinVertices(pin, vertex, bidirect_drvr_vertex);
|
||||||
bfs.enqueue(vertex);
|
enqueue(vertex);
|
||||||
if (bidirect_drvr_vertex)
|
enqueue(bidirect_drvr_vertex);
|
||||||
bfs.enqueue(bidirect_drvr_vertex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (bfs.hasNext()) {
|
while (!queue.empty()) {
|
||||||
Vertex *vertex = bfs.next();
|
Vertex *vertex = queue.front();
|
||||||
|
queue.pop();
|
||||||
const Pin *pin = vertex->pin();
|
const Pin *pin = vertex->pin();
|
||||||
if (!ideal_only
|
if (!ideal_only
|
||||||
|| !sdc->isPropagatedClock(pin)) {
|
|| !sdc->isPropagatedClock(pin)) {
|
||||||
clk_pins->insert(pin);
|
clk_pins->insert(pin);
|
||||||
ClockSet &pin_clks = pin_clks_map[pin];
|
ClockSet &pin_clks = pin_clks_map[pin];
|
||||||
pin_clks.insert(clk);
|
pin_clks.insert(clk);
|
||||||
bfs.enqueueAdjacentVertices(vertex);
|
graph_->visitFanouts(vertex, &srch_pred,
|
||||||
|
[&queue, &visited] (Vertex *fanout) {
|
||||||
|
if (!visited.contains(fanout)) {
|
||||||
|
visited.insert(fanout);
|
||||||
|
queue.push(fanout);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,6 @@ Genclks::ensureMaster(Clock *gclk,
|
||||||
// Search backward from generated clock source pin to a clock pin.
|
// Search backward from generated clock source pin to a clock pin.
|
||||||
GenClkMasterSearchPred srch_pred(this);
|
GenClkMasterSearchPred srch_pred(this);
|
||||||
VertexQueue master_queue;
|
VertexQueue master_queue;
|
||||||
VertexSet visited = makeVertexSet(this);
|
|
||||||
VertexSet src_vertices = makeVertexSet(this);
|
VertexSet src_vertices = makeVertexSet(this);
|
||||||
gclk->srcPinVertices(src_vertices, network_, graph_);
|
gclk->srcPinVertices(src_vertices, network_, graph_);
|
||||||
for (Vertex *vertex : src_vertices)
|
for (Vertex *vertex : src_vertices)
|
||||||
|
|
@ -279,28 +278,25 @@ Genclks::ensureMaster(Clock *gclk,
|
||||||
while (!master_queue.empty()) {
|
while (!master_queue.empty()) {
|
||||||
Vertex *vertex = master_queue.front();
|
Vertex *vertex = master_queue.front();
|
||||||
master_queue.pop();
|
master_queue.pop();
|
||||||
if (!visited.contains(vertex)) {
|
Pin *pin = vertex->pin();
|
||||||
visited.insert(vertex);
|
if (sdc->isLeafPinClock(pin)) {
|
||||||
Pin *pin = vertex->pin();
|
ClockSet *master_clks = sdc->findLeafPinClocks(pin);
|
||||||
if (sdc->isLeafPinClock(pin)) {
|
if (master_clks) {
|
||||||
ClockSet *master_clks = sdc->findLeafPinClocks(pin);
|
ClockSet::iterator master_iter = master_clks->begin();
|
||||||
if (master_clks) {
|
if (master_iter != master_clks->end()) {
|
||||||
ClockSet::iterator master_iter = master_clks->begin();
|
master_clk = *master_iter++;
|
||||||
if (master_iter != master_clks->end()) {
|
// Master source pin can actually be a clock source pin.
|
||||||
master_clk = *master_iter++;
|
if (master_clk != gclk) {
|
||||||
// Master source pin can actually be a clock source pin.
|
gclk->setInferedMasterClk(master_clk);
|
||||||
if (master_clk != gclk) {
|
debugPrint(debug_, "genclk", 2, " {} master clk {}", gclk->name(),
|
||||||
gclk->setInferedMasterClk(master_clk);
|
master_clk->name());
|
||||||
debugPrint(debug_, "genclk", 2, " {} master clk {}", gclk->name(),
|
master_clk_count++;
|
||||||
master_clk->name());
|
break;
|
||||||
master_clk_count++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enqueueFanin(vertex, master_queue, srch_pred);
|
|
||||||
}
|
}
|
||||||
|
enqueueFanin(vertex, master_queue, srch_pred);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (master_clk_count > 1)
|
if (master_clk_count > 1)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "Clock.hh"
|
#include "Clock.hh"
|
||||||
|
|
@ -1205,7 +1206,9 @@ Properties::getProperty(const Scene *scene,
|
||||||
|| property == "full_name")
|
|| property == "full_name")
|
||||||
return PropertyValue(scene->name());
|
return PropertyValue(scene->name());
|
||||||
else
|
else
|
||||||
throw PropertyUnknown("scene", property);
|
// Unknown properties throw PropertyUnknown; a user-defined property
|
||||||
|
// never set on this scene returns a none value.
|
||||||
|
return registry_scene_.getProperty(scene, property, "scene", sta_);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -1218,7 +1221,9 @@ Properties::getProperty(const Mode *mode,
|
||||||
|| property == "full_name")
|
|| property == "full_name")
|
||||||
return PropertyValue(mode->name());
|
return PropertyValue(mode->name());
|
||||||
else
|
else
|
||||||
throw PropertyUnknown("mode", property);
|
// Unknown properties throw PropertyUnknown; a user-defined property
|
||||||
|
// never set on this mode returns a none value.
|
||||||
|
return registry_mode_.getProperty(mode, property, "mode", sta_);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -1360,6 +1365,119 @@ Properties::defineProperty(std::string_view property,
|
||||||
registry_clock_.defineProperty(property, handler);
|
registry_clock_.defineProperty(property, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Properties::defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const Scene *>::PropertyHandler &handler)
|
||||||
|
{
|
||||||
|
registry_scene_.defineProperty(property, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Properties::defineProperty(std::string_view property,
|
||||||
|
const PropertyRegistry<const Mode *>::PropertyHandler &handler)
|
||||||
|
{
|
||||||
|
registry_mode_.defineProperty(property, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Value type from the define_property -type argument.
|
||||||
|
PropertyValue::Type
|
||||||
|
Properties::propertyType(std::string_view type)
|
||||||
|
{
|
||||||
|
if (type == "bool" || type == "boolean")
|
||||||
|
return PropertyValue::Type::bool_;
|
||||||
|
else if (type == "float" || type == "double" || type == "number")
|
||||||
|
return PropertyValue::Type::float_;
|
||||||
|
else if (type == "string")
|
||||||
|
return PropertyValue::Type::string;
|
||||||
|
else
|
||||||
|
sta_->report()->error(2210, "unknown property type '{}' (use bool, float or string).",
|
||||||
|
type);
|
||||||
|
return PropertyValue::Type::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyValue
|
||||||
|
Properties::coercePropertyValue(PropertyValue::Type type,
|
||||||
|
std::string_view value)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case PropertyValue::Type::bool_:
|
||||||
|
if (stringEqual(value, "true") || value == "1")
|
||||||
|
return PropertyValue(true);
|
||||||
|
if (stringEqual(value, "false") || value == "0")
|
||||||
|
return PropertyValue(false);
|
||||||
|
sta_->report()->error(2212, "'{}' is not a bool property value.", value);
|
||||||
|
return PropertyValue();
|
||||||
|
case PropertyValue::Type::float_: {
|
||||||
|
auto [number, valid] = stringFloat(std::string(value));
|
||||||
|
if (!valid)
|
||||||
|
sta_->report()->error(2215, "'{}' is not a float property value.", value);
|
||||||
|
return PropertyValue(number, sta_->units()->scalarUnit());
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return PropertyValue(std::string(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyKey::PropertyKey(const void *object,
|
||||||
|
std::string_view property) :
|
||||||
|
object_(object),
|
||||||
|
property_(property)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PropertyKey::operator<(const PropertyKey &key) const
|
||||||
|
{
|
||||||
|
return std::tie(object_, property_)
|
||||||
|
< std::tie(key.object_, key.property_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class TYPE>
|
||||||
|
void
|
||||||
|
Properties::defineProperty(std::string_view object_type,
|
||||||
|
std::string_view property,
|
||||||
|
std::string_view value_type)
|
||||||
|
{
|
||||||
|
prop_types_[{std::string(object_type), std::string(property)}] =
|
||||||
|
propertyType(value_type);
|
||||||
|
std::string name(property);
|
||||||
|
typename PropertyRegistry<const TYPE *>::PropertyHandler handler =
|
||||||
|
[this, name] (const TYPE *object,
|
||||||
|
Sta *) -> PropertyValue {
|
||||||
|
auto value_iter = prop_values_.find(PropertyKey(object, name));
|
||||||
|
if (value_iter != prop_values_.end())
|
||||||
|
return value_iter->second;
|
||||||
|
// Never set on this object.
|
||||||
|
return PropertyValue();
|
||||||
|
};
|
||||||
|
defineProperty(property, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object types the tcl interface exposes user properties on.
|
||||||
|
template void Properties::defineProperty<Scene>(std::string_view,
|
||||||
|
std::string_view,
|
||||||
|
std::string_view);
|
||||||
|
template void Properties::defineProperty<Mode>(std::string_view,
|
||||||
|
std::string_view,
|
||||||
|
std::string_view);
|
||||||
|
|
||||||
|
void
|
||||||
|
Properties::setProperty(const void *object,
|
||||||
|
std::string_view object_type,
|
||||||
|
std::string_view property,
|
||||||
|
std::string_view value)
|
||||||
|
{
|
||||||
|
auto type_iter = prop_types_.find({std::string(object_type),
|
||||||
|
std::string(property)});
|
||||||
|
if (type_iter == prop_types_.end())
|
||||||
|
sta_->report()->error(2211, "{} property '{}' is not defined.",
|
||||||
|
object_type, property);
|
||||||
|
prop_values_[PropertyKey(object, property)] =
|
||||||
|
coercePropertyValue(type_iter->second, value);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template<class TYPE>
|
template<class TYPE>
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
%{
|
%{
|
||||||
|
|
||||||
#include "Property.hh"
|
#include "Property.hh"
|
||||||
|
#include "Report.hh"
|
||||||
#include "Sta.hh"
|
#include "Sta.hh"
|
||||||
|
|
||||||
using namespace sta;
|
using namespace sta;
|
||||||
|
|
@ -137,6 +138,39 @@ mode_property(Mode *mode,
|
||||||
return properties.getProperty(mode, property);
|
return properties.getProperty(mode, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
define_property_cmd(const char *object_type,
|
||||||
|
const char *property,
|
||||||
|
const char *type)
|
||||||
|
{
|
||||||
|
Properties &properties = Sta::sta()->properties();
|
||||||
|
std::string_view object_type_view(object_type);
|
||||||
|
if (object_type_view == "scene")
|
||||||
|
properties.defineProperty<Scene>(object_type, property, type);
|
||||||
|
else if (object_type_view == "mode")
|
||||||
|
properties.defineProperty<Mode>(object_type, property, type);
|
||||||
|
else
|
||||||
|
Sta::sta()->report()->error(2209, "define_property -object_type {} not supported.",
|
||||||
|
object_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_property_cmd(void *object,
|
||||||
|
const char *object_type,
|
||||||
|
const char *property,
|
||||||
|
const char *value)
|
||||||
|
{
|
||||||
|
Properties &properties = Sta::sta()->properties();
|
||||||
|
std::string_view object_type_view(object_type);
|
||||||
|
if (object_type_view == "Scene")
|
||||||
|
properties.setProperty(object, "scene", property, value);
|
||||||
|
else if (object_type_view == "Mode")
|
||||||
|
properties.setProperty(object, "mode", property, value);
|
||||||
|
else
|
||||||
|
Sta::sta()->report()->error(2214, "set_property unsupported object type {}.",
|
||||||
|
object_type);
|
||||||
|
}
|
||||||
|
|
||||||
PropertyValue
|
PropertyValue
|
||||||
path_end_property(PathEnd *end,
|
path_end_property(PathEnd *end,
|
||||||
const char *property)
|
const char *property)
|
||||||
|
|
|
||||||
228
search/Search.cc
228
search/Search.cc
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "Bfs.hh"
|
#include "Bfs.hh"
|
||||||
#include "ClkInfo.hh"
|
#include "ClkInfo.hh"
|
||||||
|
#include "ClkNetwork.hh"
|
||||||
#include "Clock.hh"
|
#include "Clock.hh"
|
||||||
#include "ContainerHelpers.hh"
|
#include "ContainerHelpers.hh"
|
||||||
#include "Crpr.hh"
|
#include "Crpr.hh"
|
||||||
|
|
@ -95,6 +96,8 @@ EvalPred::searchThru(Edge *edge,
|
||||||
{
|
{
|
||||||
const TimingRole *role = edge->role();
|
const TimingRole *role = edge->role();
|
||||||
return SearchPred0::searchThru(edge, mode)
|
return SearchPred0::searchThru(edge, mode)
|
||||||
|
&& (sta_->variables()->dynamicLoopBreaking()
|
||||||
|
|| !edge->isDisabledLoop())
|
||||||
&& (search_thru_latches_
|
&& (search_thru_latches_
|
||||||
|| role->isLatchDtoQ()
|
|| role->isLatchDtoQ()
|
||||||
|| sta_->latches()->latchDtoQState(edge, mode) == LatchEnableState::open);
|
|| sta_->latches()->latchDtoQState(edge, mode) == LatchEnableState::open);
|
||||||
|
|
@ -263,8 +266,7 @@ Search::Search(StaState *sta) :
|
||||||
tag_group_capacity_(tag_capacity_),
|
tag_group_capacity_(tag_capacity_),
|
||||||
tag_groups_(new TagGroup *[tag_group_capacity_]),
|
tag_groups_(new TagGroup *[tag_group_capacity_]),
|
||||||
tag_group_set_(new TagGroupSet(tag_group_capacity_)),
|
tag_group_set_(new TagGroupSet(tag_group_capacity_)),
|
||||||
postponed_arrivals_(makeVertexSet(this)),
|
pending_arrivals_(makeVertexSet(this)),
|
||||||
postponed_clk_endpoints_(makeVertexSet(this)),
|
|
||||||
endpoints_(makeVertexSet(this)),
|
endpoints_(makeVertexSet(this)),
|
||||||
invalid_endpoints_(makeVertexSet(this)),
|
invalid_endpoints_(makeVertexSet(this)),
|
||||||
|
|
||||||
|
|
@ -328,8 +330,7 @@ Search::clear()
|
||||||
deletePathGroups();
|
deletePathGroups();
|
||||||
deletePaths();
|
deletePaths();
|
||||||
deleteTags();
|
deleteTags();
|
||||||
postponed_arrivals_.clear();
|
pending_arrivals_.clear();
|
||||||
postponed_clk_endpoints_.clear();
|
|
||||||
deleteFilter();
|
deleteFilter();
|
||||||
found_downstream_clk_pins_ = false;
|
found_downstream_clk_pins_ = false;
|
||||||
}
|
}
|
||||||
|
|
@ -546,7 +547,7 @@ Search::findFilteredArrivals(ExceptionFrom *from,
|
||||||
// These cases do not require filtered arrivals.
|
// These cases do not require filtered arrivals.
|
||||||
// -from clocks
|
// -from clocks
|
||||||
// -to
|
// -to
|
||||||
findAllArrivals(thru_latches, false);
|
findAllArrivals(thru_latches);
|
||||||
}
|
}
|
||||||
|
|
||||||
// From/thrus/to are used to make a filter exception. If the last
|
// From/thrus/to are used to make a filter exception. If the last
|
||||||
|
|
@ -639,32 +640,36 @@ Search::deleteFilterClkInfos()
|
||||||
void
|
void
|
||||||
Search::findFilteredArrivals(bool thru_latches)
|
Search::findFilteredArrivals(bool thru_latches)
|
||||||
{
|
{
|
||||||
filtered_arrivals_.clear();
|
|
||||||
findArrivalsSeed();
|
|
||||||
seedFilterStarts();
|
|
||||||
Level max_level = levelize_->maxLevel();
|
|
||||||
// Search always_to_endpoint to search from exisiting arrivals at
|
// Search always_to_endpoint to search from exisiting arrivals at
|
||||||
// fanin startpoints to reach -thru/-to endpoints.
|
// fanin startpoints to reach -thru/-to endpoints.
|
||||||
arrival_visitor_->init(true, false, eval_pred_);
|
arrival_visitor_->init(true, false, eval_pred_);
|
||||||
enqueuePendingClkFanouts();
|
arrival_iter_->ensureSize();
|
||||||
bool have_pending_latch_outputs = false;
|
|
||||||
// Iterate until data arrivals at all latches stop changing.
|
filtered_arrivals_.clear();
|
||||||
|
findArrivalsSeed();
|
||||||
|
seedFilterStarts();
|
||||||
|
|
||||||
|
Level max_level = levelize_->maxLevel();
|
||||||
|
bool have_pending_arrivals = false;
|
||||||
for (int pass = 1;
|
for (int pass = 1;
|
||||||
pass == 1 || (thru_latches && have_pending_latch_outputs);
|
pass == 1 || (thru_latches && have_pending_arrivals);
|
||||||
pass++) {
|
pass++) {
|
||||||
debugPrint(debug_, "search", 1, "find arrivals pass {}", pass);
|
debugPrint(debug_, "search", 1, "find arrivals pass {}", pass);
|
||||||
|
|
||||||
int arrival_count = arrival_iter_->visitParallel(max_level, arrival_visitor_);
|
int arrival_count = arrival_iter_->visitParallel(max_level, arrival_visitor_);
|
||||||
debugPrint(debug_, "search", 1, "found {} arrivals", arrival_count);
|
debugPrint(debug_, "search", 1, "found {} arrivals", arrival_count);
|
||||||
|
|
||||||
have_pending_latch_outputs = !postponed_arrivals_.empty();
|
// Latch D->Q and disabled loop edges have level discontinuities so their
|
||||||
for (Vertex *latch_output : postponed_arrivals_)
|
// eval. For latches the data path crpr clk path may be evaled in another
|
||||||
arrival_visitor_->visit(latch_output, true);
|
// thread at the same time the latch D->Q edge.
|
||||||
postponed_arrivals_.clear();
|
// Disabled loop edges propagate pending loop paths here.
|
||||||
|
have_pending_arrivals = !pending_arrivals_.empty();
|
||||||
|
for (Vertex *vertex : pending_arrivals_)
|
||||||
|
arrival_visitor_->visit(vertex, true);
|
||||||
|
pending_arrivals_.clear();
|
||||||
|
|
||||||
deleteTagsPrev();
|
deleteTagsPrev();
|
||||||
}
|
}
|
||||||
arrivals_exist_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete stale tag arrarys.
|
// Delete stale tag arrarys.
|
||||||
|
|
@ -860,14 +865,13 @@ void
|
||||||
Search::levelsChangedBefore()
|
Search::levelsChangedBefore()
|
||||||
{
|
{
|
||||||
if (arrivals_exist_) {
|
if (arrivals_exist_) {
|
||||||
while (arrival_iter_->hasNext()) {
|
arrival_iter_->clear([this] (Vertex *vertex) {
|
||||||
Vertex *vertex = arrival_iter_->next();
|
|
||||||
arrivalInvalid(vertex);
|
arrivalInvalid(vertex);
|
||||||
}
|
});
|
||||||
while (required_iter_->hasNext()) {
|
|
||||||
Vertex *vertex = required_iter_->next();
|
required_iter_->clear([this] (Vertex *vertex) {
|
||||||
requiredInvalid(vertex);
|
requiredInvalid(vertex);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -939,11 +943,16 @@ Search::requiredInvalid(Vertex *vertex)
|
||||||
void
|
void
|
||||||
Search::findClkArrivals()
|
Search::findClkArrivals()
|
||||||
{
|
{
|
||||||
findAllArrivals(false, true);
|
debugPrint(debug_, "search", 1, "find clk arrivals");
|
||||||
|
arrival_visitor_->init(false, true, eval_pred_);
|
||||||
|
arrival_iter_->ensureSize();
|
||||||
|
enqueueClkRoots();
|
||||||
|
enqueueInvalidClks();
|
||||||
|
findArrivals2(levelize_->maxLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Search::seedClkVertexArrivals()
|
Search::enqueueClkRoots()
|
||||||
{
|
{
|
||||||
PinSet clk_pins(network_);
|
PinSet clk_pins(network_);
|
||||||
findClkVertexPins(clk_pins);
|
findClkVertexPins(clk_pins);
|
||||||
|
|
@ -954,6 +963,32 @@ Search::seedClkVertexArrivals()
|
||||||
if (bidirect_drvr_vertex)
|
if (bidirect_drvr_vertex)
|
||||||
arrival_iter_->enqueue(bidirect_drvr_vertex);
|
arrival_iter_->enqueue(bidirect_drvr_vertex);
|
||||||
}
|
}
|
||||||
|
arrivals_exist_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Search::enqueueInvalidClks()
|
||||||
|
{
|
||||||
|
if (!invalid_arrivals_.empty()) {
|
||||||
|
for (Mode *mode : modes_)
|
||||||
|
mode->clkNetwork()->ensureClkNetwork();
|
||||||
|
for (auto itr = invalid_arrivals_.begin(); itr != invalid_arrivals_.end();) {
|
||||||
|
Vertex *vertex = *itr;
|
||||||
|
bool is_clk = false;
|
||||||
|
for (Mode *mode : modes_) {
|
||||||
|
if (mode->clkNetwork()->isClock(vertex)) {
|
||||||
|
is_clk = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_clk) {
|
||||||
|
arrival_iter_->enqueue(vertex);
|
||||||
|
itr = invalid_arrivals_.erase(itr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
itr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
|
|
@ -980,51 +1015,31 @@ Search::clockInsertion(const Clock *clk,
|
||||||
void
|
void
|
||||||
Search::findAllArrivals()
|
Search::findAllArrivals()
|
||||||
{
|
{
|
||||||
findAllArrivals(true, false);
|
findAllArrivals(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Search::findAllArrivals(bool thru_latches,
|
Search::findAllArrivals(bool thru_latches)
|
||||||
bool clks_only)
|
|
||||||
{
|
{
|
||||||
if (!clks_only)
|
arrival_visitor_->init(false, false, eval_pred_);
|
||||||
enqueuePendingClkFanouts();
|
arrival_iter_->ensureSize();
|
||||||
arrival_visitor_->init(false, clks_only, eval_pred_);
|
|
||||||
bool have_pending_latch_outputs = false;
|
bool have_pending_arrivals = false;
|
||||||
// Iterate until data arrivals at all latches stop changing.
|
// Iterate until data arrivals at all latches stop changing.
|
||||||
for (int pass = 1;
|
for (int pass = 1;
|
||||||
pass == 1 || (thru_latches && have_pending_latch_outputs);
|
pass == 1 || (thru_latches && have_pending_arrivals);
|
||||||
pass++) {
|
pass++) {
|
||||||
debugPrint(debug_, "search", 1, "find arrivals pass {}", pass);
|
debugPrint(debug_, "search", 1, "find arrivals pass {}", pass);
|
||||||
|
|
||||||
findArrivals1(levelize_->maxLevel());
|
findArrivals1(levelize_->maxLevel());
|
||||||
|
|
||||||
have_pending_latch_outputs = !postponed_arrivals_.empty();
|
have_pending_arrivals = !pending_arrivals_.empty();
|
||||||
for (Vertex *latch_output : postponed_arrivals_)
|
for (Vertex *vertex : pending_arrivals_)
|
||||||
arrival_visitor_->visit(latch_output, true);
|
arrival_visitor_->visit(vertex, true);
|
||||||
postponed_arrivals_.clear();
|
pending_arrivals_.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick up where the search stopped at the clock network boundary.
|
|
||||||
void
|
|
||||||
Search::enqueuePendingClkFanouts()
|
|
||||||
{
|
|
||||||
for (Vertex *vertex : postponed_clk_endpoints_) {
|
|
||||||
debugPrint(debug_, "search", 2, "enqueue clk fanout {}",
|
|
||||||
vertex->to_string(this));
|
|
||||||
arrival_iter_->enqueueAdjacentVertices(vertex, search_adj_);
|
|
||||||
}
|
|
||||||
postponed_clk_endpoints_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Search::postponeClkFanouts(Vertex *vertex)
|
|
||||||
{
|
|
||||||
LockGuard lock(postponed_clk_endpoints_lock_);
|
|
||||||
postponed_clk_endpoints_.insert(vertex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Search::findArrivals()
|
Search::findArrivals()
|
||||||
{
|
{
|
||||||
|
|
@ -1035,6 +1050,7 @@ void
|
||||||
Search::findArrivals(Level level)
|
Search::findArrivals(Level level)
|
||||||
{
|
{
|
||||||
arrival_visitor_->init(false, false, eval_pred_);
|
arrival_visitor_->init(false, false, eval_pred_);
|
||||||
|
arrival_iter_->ensureSize();
|
||||||
findArrivals1(level);
|
findArrivals1(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1043,13 +1059,19 @@ Search::findArrivals1(Level level)
|
||||||
{
|
{
|
||||||
debugPrint(debug_, "search", 1, "find arrivals to level {}", level);
|
debugPrint(debug_, "search", 1, "find arrivals to level {}", level);
|
||||||
findArrivalsSeed();
|
findArrivalsSeed();
|
||||||
|
findArrivals2(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Caller seeds arrival_iter_.
|
||||||
|
void
|
||||||
|
Search::findArrivals2(Level level)
|
||||||
|
{
|
||||||
Stats stats(debug_, report_);
|
Stats stats(debug_, report_);
|
||||||
int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_);
|
int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_);
|
||||||
deleteTagsPrev();
|
deleteTagsPrev();
|
||||||
if (arrival_count > 0)
|
if (arrival_count > 0)
|
||||||
deleteUnusedTagGroups();
|
deleteUnusedTagGroups();
|
||||||
stats.report("Find arrivals");
|
stats.report("Find arrivals");
|
||||||
arrivals_exist_ = true;
|
|
||||||
debugPrint(debug_, "search", 1, "found {} arrivals", arrival_count);
|
debugPrint(debug_, "search", 1, "found {} arrivals", arrival_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1059,15 +1081,9 @@ Search::findArrivalsSeed()
|
||||||
if (!arrivals_seeded_) {
|
if (!arrivals_seeded_) {
|
||||||
for (const Mode *mode : modes_)
|
for (const Mode *mode : modes_)
|
||||||
mode->genclks()->ensureInsertionDelays();
|
mode->genclks()->ensureInsertionDelays();
|
||||||
arrival_iter_->clear();
|
|
||||||
required_iter_->clear();
|
|
||||||
seedArrivals();
|
seedArrivals();
|
||||||
arrivals_seeded_ = true;
|
arrivals_seeded_ = true;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
arrival_iter_->ensureSize();
|
|
||||||
required_iter_->ensureSize();
|
|
||||||
}
|
|
||||||
seedInvalidArrivals();
|
seedInvalidArrivals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1173,22 +1189,18 @@ ArrivalVisitor::visit(Vertex *vertex,
|
||||||
search_->postponeLatchDataOutputs(vertex);
|
search_->postponeLatchDataOutputs(vertex);
|
||||||
|
|
||||||
if ((always_to_endpoints_ || arrivals_changed)) {
|
if ((always_to_endpoints_ || arrivals_changed)) {
|
||||||
if (clks_only_ && vertex->isRegClk()) {
|
graph_->visitFanoutEdges(vertex, search_adj_,
|
||||||
debugPrint(debug_, "search", 3, "postponing clk fanout");
|
[this, vertex] (Edge *edge,
|
||||||
search_->postponeClkFanouts(vertex);
|
Vertex *fanout) {
|
||||||
}
|
if (edge->isDisabledLoop()) {
|
||||||
else {
|
if (hasPendingLoopPaths(edge))
|
||||||
graph_->visitFanoutEdges(vertex, search_adj_,
|
search_->postponeArrivals(fanout);
|
||||||
[this] (Edge *edge,
|
}
|
||||||
Vertex *fanout) {
|
else if (clks_only_ && vertex->isRegClk())
|
||||||
if (edge->isDisabledLoop()) {
|
search_->arrivalInvalid(fanout);
|
||||||
if (hasPendingLoopPaths(edge))
|
else
|
||||||
search_->postponeArrivals(fanout);
|
search_->arrivalIterator()->enqueue(fanout);
|
||||||
}
|
});
|
||||||
else
|
|
||||||
search_->arrivalIterator()->enqueue(fanout);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (arrivals_changed) {
|
if (arrivals_changed) {
|
||||||
debugPrint(debug_, "search", 4, "arrivals changed");
|
debugPrint(debug_, "search", 4, "arrivals changed");
|
||||||
|
|
@ -1425,8 +1437,8 @@ Search::postponeLatchDataOutputs(Vertex *latch_data)
|
||||||
Edge *edge = edge_iter.next();
|
Edge *edge = edge_iter.next();
|
||||||
if (edge->role() == TimingRole::latchDtoQ()) {
|
if (edge->role() == TimingRole::latchDtoQ()) {
|
||||||
Vertex *out_vertex = edge->to(graph_);
|
Vertex *out_vertex = edge->to(graph_);
|
||||||
LockGuard lock(postponed_arrivals_lock_);
|
LockGuard lock(pending_arrivals_lock_);
|
||||||
postponed_arrivals_.insert(out_vertex);
|
pending_arrivals_.insert(out_vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1434,8 +1446,8 @@ Search::postponeLatchDataOutputs(Vertex *latch_data)
|
||||||
void
|
void
|
||||||
Search::postponeArrivals(Vertex *vertex)
|
Search::postponeArrivals(Vertex *vertex)
|
||||||
{
|
{
|
||||||
LockGuard lock(postponed_arrivals_lock_);
|
LockGuard lock(pending_arrivals_lock_);
|
||||||
postponed_arrivals_.insert(vertex);
|
pending_arrivals_.insert(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1448,6 +1460,7 @@ Search::seedArrivals()
|
||||||
|
|
||||||
for (Vertex *vertex : vertices)
|
for (Vertex *vertex : vertices)
|
||||||
arrival_iter_->enqueue(vertex);
|
arrival_iter_->enqueue(vertex);
|
||||||
|
arrivals_exist_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -2764,14 +2777,14 @@ Search::reportArrivals(Vertex *vertex,
|
||||||
for (const Path *path : paths) {
|
for (const Path *path : paths) {
|
||||||
const Tag *tag = path->tag(this);
|
const Tag *tag = path->tag(this);
|
||||||
const RiseFall *rf = tag->transition();
|
const RiseFall *rf = tag->transition();
|
||||||
bool report_prev = false;
|
bool report_prev = true;
|
||||||
std::string prev_str;
|
std::string prev_str;
|
||||||
if (report_prev) {
|
if (report_prev) {
|
||||||
Path *prev_path = path->prevPath();
|
Path *prev_path = path->prevPath();
|
||||||
if (prev_path) {
|
if (prev_path) {
|
||||||
const Edge *prev_edge = path->prevEdge(this);
|
const Edge *prev_edge = path->prevEdge(this);
|
||||||
TimingArc *arc = path->prevArc(this);
|
TimingArc *arc = path->prevArc(this);
|
||||||
prev_str = sta::format("prev {} {} {} -> {} {}",
|
prev_str = sta::format(" prev {} {} {} -> {} {}",
|
||||||
prev_path->to_string(this),
|
prev_path->to_string(this),
|
||||||
prev_edge->from(graph_)->to_string(this),
|
prev_edge->from(graph_)->to_string(this),
|
||||||
arc->fromEdge()->to_string(),
|
arc->fromEdge()->to_string(),
|
||||||
|
|
@ -2779,13 +2792,14 @@ Search::reportArrivals(Vertex *vertex,
|
||||||
arc->toEdge()->to_string());
|
arc->toEdge()->to_string());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
prev_str = "prev NULL";
|
prev_str = " prev NULL";
|
||||||
}
|
}
|
||||||
report_->report(" {} {} {} / {} {}{}", rf->shortName(),
|
report_->report(" {} {} {} / {} {}{}", rf->shortName(),
|
||||||
path->minMax(this)->to_string(),
|
path->minMax(this)->to_string(),
|
||||||
delayAsString(path->arrival(), digits, this),
|
delayAsString(path->arrival(), digits, this),
|
||||||
delayAsString(path->required(), digits, this),
|
delayAsString(path->required(), digits, this),
|
||||||
tag->to_string(report_tag_index, false, this), prev_str);
|
tag->to_string(report_tag_index, false, this),
|
||||||
|
prev_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -3146,6 +3160,7 @@ Search::findRequireds(Level level)
|
||||||
Stats stats(debug_, report_);
|
Stats stats(debug_, report_);
|
||||||
debugPrint(debug_, "search", 1, "find requireds to level {}", level);
|
debugPrint(debug_, "search", 1, "find requireds to level {}", level);
|
||||||
RequiredVisitor req_visitor(this);
|
RequiredVisitor req_visitor(this);
|
||||||
|
required_iter_->ensureSize();
|
||||||
if (!requireds_seeded_)
|
if (!requireds_seeded_)
|
||||||
seedRequireds();
|
seedRequireds();
|
||||||
seedInvalidRequireds();
|
seedInvalidRequireds();
|
||||||
|
|
@ -3334,8 +3349,9 @@ Search::seedRequired(Vertex *vertex)
|
||||||
required_cmp.requiredsInit(vertex, this);
|
required_cmp.requiredsInit(vertex, this);
|
||||||
visit_path_ends_->visitPathEnds(vertex, &seeder);
|
visit_path_ends_->visitPathEnds(vertex, &seeder);
|
||||||
// Enqueue fanin vertices for back-propagating required times.
|
// Enqueue fanin vertices for back-propagating required times.
|
||||||
|
required_iter_->ensureSize();
|
||||||
if (required_cmp.requiredsSave(vertex, this))
|
if (required_cmp.requiredsSave(vertex, this))
|
||||||
required_iter_->enqueueAdjacentVertices(vertex);
|
required_iter_->enqueueFanin(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -3347,7 +3363,7 @@ Search::seedRequiredEnqueueFanin(Vertex *vertex)
|
||||||
visit_path_ends_->visitPathEnds(vertex, &seeder);
|
visit_path_ends_->visitPathEnds(vertex, &seeder);
|
||||||
// Enqueue fanin vertices for back-propagating required times.
|
// Enqueue fanin vertices for back-propagating required times.
|
||||||
required_cmp.requiredsSave(vertex, this);
|
required_cmp.requiredsSave(vertex, this);
|
||||||
required_iter_->enqueueAdjacentVertices(vertex);
|
required_iter_->enqueueFanin(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -3455,7 +3471,7 @@ RequiredVisitor::visit(Vertex *vertex)
|
||||||
search_->tnsInvalid(vertex);
|
search_->tnsInvalid(vertex);
|
||||||
|
|
||||||
if (changed)
|
if (changed)
|
||||||
search_->requiredIterator()->enqueueAdjacentVertices(vertex);
|
search_->requiredIterator()->enqueueFanin(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -3538,17 +3554,27 @@ void
|
||||||
Search::ensureDownstreamClkPins()
|
Search::ensureDownstreamClkPins()
|
||||||
{
|
{
|
||||||
if (!found_downstream_clk_pins_) {
|
if (!found_downstream_clk_pins_) {
|
||||||
// Use backward BFS from register clk pins to mark upsteam pins
|
// Use backward DFS from register clk pins to mark upstream pins
|
||||||
// as having downstream clk pins.
|
// as having downstream clk pins. hasDownstreamClkPin doubles as the
|
||||||
|
// visited flag since its meaning is exactly "reached here".
|
||||||
ClkTreeSearchPred pred(this);
|
ClkTreeSearchPred pred(this);
|
||||||
BfsBkwdIterator iter(BfsIndex::other, &pred, this);
|
std::vector<Vertex*> stack;
|
||||||
for (Vertex *vertex : graph_->regClkVertices())
|
for (Vertex *vertex : graph_->regClkVertices()) {
|
||||||
iter.enqueue(vertex);
|
if (!vertex->hasDownstreamClkPin()) {
|
||||||
|
vertex->setHasDownstreamClkPin(true);
|
||||||
while (iter.hasNext()) {
|
stack.push_back(vertex);
|
||||||
Vertex *vertex = iter.next();
|
}
|
||||||
vertex->setHasDownstreamClkPin(true);
|
}
|
||||||
iter.enqueueAdjacentVertices(vertex);
|
while (!stack.empty()) {
|
||||||
|
Vertex *vertex = stack.back();
|
||||||
|
stack.pop_back();
|
||||||
|
graph_->visitFanins(vertex, &pred,
|
||||||
|
[&stack] (Vertex *fanin) {
|
||||||
|
if (!fanin->hasDownstreamClkPin()) {
|
||||||
|
fanin->setHasDownstreamClkPin(true);
|
||||||
|
stack.push_back(fanin);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
found_downstream_clk_pins_ = true;
|
found_downstream_clk_pins_ = true;
|
||||||
|
|
|
||||||
|
|
@ -4518,6 +4518,10 @@ Sta::makeInstanceAfter(const Instance *inst)
|
||||||
if (pin) {
|
if (pin) {
|
||||||
Vertex *vertex, *bidir_drvr_vertex;
|
Vertex *vertex, *bidir_drvr_vertex;
|
||||||
graph_->makePinVertices(pin, vertex, bidir_drvr_vertex);
|
graph_->makePinVertices(pin, vertex, bidir_drvr_vertex);
|
||||||
|
if (vertex)
|
||||||
|
search_->endpointInvalid(vertex);
|
||||||
|
if (bidir_drvr_vertex)
|
||||||
|
search_->endpointInvalid(bidir_drvr_vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
graph_->makeInstanceEdges(inst);
|
graph_->makeInstanceEdges(inst);
|
||||||
|
|
@ -4553,16 +4557,14 @@ Sta::replaceEquivCellBefore(const Instance *inst,
|
||||||
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||||
while (edge_iter.hasNext()) {
|
while (edge_iter.hasNext()) {
|
||||||
Edge *edge = edge_iter.next();
|
Edge *edge = edge_iter.next();
|
||||||
Vertex *to_vertex = edge->to(graph_);
|
if (!edge->isWire()) {
|
||||||
if (network_->instance(to_vertex->pin()) == inst) {
|
|
||||||
TimingArcSet *from_set = edge->timingArcSet();
|
TimingArcSet *from_set = edge->timingArcSet();
|
||||||
// Find corresponding timing arc set.
|
// Find corresponding timing arc set.
|
||||||
TimingArcSet *to_set = to_cell->findTimingArcSet(from_set);
|
TimingArcSet *to_set = to_cell->findTimingArcSet(from_set);
|
||||||
if (to_set)
|
if (to_set)
|
||||||
edge->setTimingArcSet(to_set);
|
edge->setTimingArcSet(to_set);
|
||||||
else
|
else
|
||||||
report_->critical(
|
report_->critical(1563, "corresponding timing arc set not found in equiv cells");
|
||||||
1556, "corresponding timing arc set not found in equiv cells");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4658,8 +4660,7 @@ Sta::replaceCellBefore(const Instance *inst,
|
||||||
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||||
while (edge_iter.hasNext()) {
|
while (edge_iter.hasNext()) {
|
||||||
Edge *edge = edge_iter.next();
|
Edge *edge = edge_iter.next();
|
||||||
Vertex *to_vertex = edge->to(graph_);
|
if (!edge->isWire())
|
||||||
if (network_->instance(to_vertex->pin()) == inst)
|
|
||||||
deleteEdge(edge);
|
deleteEdge(edge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -258,15 +258,15 @@ paths: 60
|
||||||
--- report_tag_arrivals ---
|
--- report_tag_arrivals ---
|
||||||
Vertex out1
|
Vertex out1
|
||||||
Group 2
|
Group 2
|
||||||
^ min 0.100 / -2.000 16 default clk ^ clk_src clk crpr_pin null
|
^ min 0.100 / -2.000 16 default clk ^ clk_src clk crpr_pin null prev buf2/Z ^ default/min 16 buf2/Z ^ -> out1 ^
|
||||||
v min 0.099 / -2.000 17 default clk ^ clk_src clk crpr_pin null
|
v min 0.099 / -2.000 17 default clk ^ clk_src clk crpr_pin null prev buf2/Z v default/min 17 buf2/Z v -> out1 v
|
||||||
^ max 0.100 / 8.000 18 default clk ^ clk_src clk crpr_pin null
|
^ max 0.100 / 8.000 18 default clk ^ clk_src clk crpr_pin null prev buf2/Z ^ default/max 18 buf2/Z ^ -> out1 ^
|
||||||
v max 0.099 / 8.000 19 default clk ^ clk_src clk crpr_pin null
|
v max 0.099 / 8.000 19 default clk ^ clk_src clk crpr_pin null prev buf2/Z v default/max 19 buf2/Z v -> out1 v
|
||||||
Vertex out1
|
Vertex out1
|
||||||
^ min 0.100 / -2.000 default clk ^ clk_src clk crpr_pin null
|
^ min 0.100 / -2.000 default clk ^ clk_src clk crpr_pin null prev buf2/Z ^ default/min 16 buf2/Z ^ -> out1 ^
|
||||||
v min 0.099 / -2.000 default clk ^ clk_src clk crpr_pin null
|
v min 0.099 / -2.000 default clk ^ clk_src clk crpr_pin null prev buf2/Z v default/min 17 buf2/Z v -> out1 v
|
||||||
^ max 0.100 / 8.000 default clk ^ clk_src clk crpr_pin null
|
^ max 0.100 / 8.000 default clk ^ clk_src clk crpr_pin null prev buf2/Z ^ default/max 18 buf2/Z ^ -> out1 ^
|
||||||
v max 0.099 / 8.000 default clk ^ clk_src clk crpr_pin null
|
v max 0.099 / 8.000 default clk ^ clk_src clk crpr_pin null prev buf2/Z v default/max 19 buf2/Z v -> out1 v
|
||||||
--- report_arrival_entries ---
|
--- report_arrival_entries ---
|
||||||
--- report_required_entries ---
|
--- report_required_entries ---
|
||||||
Level 40
|
Level 40
|
||||||
|
|
|
||||||
|
|
@ -68,15 +68,15 @@ worst_slack_path pin: out1
|
||||||
worst_slack_path slack: 7.899713772019368e-9
|
worst_slack_path slack: 7.899713772019368e-9
|
||||||
Vertex out1
|
Vertex out1
|
||||||
Group 2
|
Group 2
|
||||||
^ min 0.100 / -2.000 16 default clk ^ clk_src clk crpr_pin null
|
^ min 0.100 / -2.000 16 default clk ^ clk_src clk crpr_pin null prev buf2/Z ^ default/min 16 buf2/Z ^ -> out1 ^
|
||||||
v min 0.099 / -2.000 17 default clk ^ clk_src clk crpr_pin null
|
v min 0.099 / -2.000 17 default clk ^ clk_src clk crpr_pin null prev buf2/Z v default/min 17 buf2/Z v -> out1 v
|
||||||
^ max 0.100 / 8.000 18 default clk ^ clk_src clk crpr_pin null
|
^ max 0.100 / 8.000 18 default clk ^ clk_src clk crpr_pin null prev buf2/Z ^ default/max 18 buf2/Z ^ -> out1 ^
|
||||||
v max 0.099 / 8.000 19 default clk ^ clk_src clk crpr_pin null
|
v max 0.099 / 8.000 19 default clk ^ clk_src clk crpr_pin null prev buf2/Z v default/max 19 buf2/Z v -> out1 v
|
||||||
Vertex out1
|
Vertex out1
|
||||||
^ min 0.100 / -2.000 default clk ^ clk_src clk crpr_pin null
|
^ min 0.100 / -2.000 default clk ^ clk_src clk crpr_pin null prev buf2/Z ^ default/min 16 buf2/Z ^ -> out1 ^
|
||||||
v min 0.099 / -2.000 default clk ^ clk_src clk crpr_pin null
|
v min 0.099 / -2.000 default clk ^ clk_src clk crpr_pin null prev buf2/Z v default/min 17 buf2/Z v -> out1 v
|
||||||
^ max 0.100 / 8.000 default clk ^ clk_src clk crpr_pin null
|
^ max 0.100 / 8.000 default clk ^ clk_src clk crpr_pin null prev buf2/Z ^ default/max 18 buf2/Z ^ -> out1 ^
|
||||||
v max 0.099 / 8.000 default clk ^ clk_src clk crpr_pin null
|
v max 0.099 / 8.000 default clk ^ clk_src clk crpr_pin null prev buf2/Z v default/max 19 buf2/Z v -> out1 v
|
||||||
--- worst_slack_vertex min ---
|
--- worst_slack_vertex min ---
|
||||||
worst_slack_vertex min pin: reg1/D
|
worst_slack_vertex min pin: reg1/D
|
||||||
worst_arrival_path min pin: reg1/D
|
worst_arrival_path min pin: reg1/D
|
||||||
|
|
|
||||||
|
|
@ -120,5 +120,33 @@ proc get_property_object_type { object_type object_name quiet } {
|
||||||
return [lindex $object 0]
|
return [lindex $object 0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define_cmd_args "define_property" \
|
||||||
|
{-object_type scene|mode -type bool|float|string property}
|
||||||
|
|
||||||
|
proc define_property { args } {
|
||||||
|
parse_key_args "define_property" args keys {-object_type -type} flags {}
|
||||||
|
check_argc_eq1 "define_property" $args
|
||||||
|
if { ![info exists keys(-object_type)] } {
|
||||||
|
sta_error 2207 "define_property -object_type must be specified."
|
||||||
|
}
|
||||||
|
if { ![info exists keys(-type)] } {
|
||||||
|
sta_error 2208 "define_property -type must be specified."
|
||||||
|
}
|
||||||
|
define_property_cmd $keys(-object_type) [lindex $args 0] $keys(-type)
|
||||||
|
}
|
||||||
|
|
||||||
|
define_cmd_args "set_property" {object property value}
|
||||||
|
|
||||||
|
proc set_property { args } {
|
||||||
|
check_argc_eq3 "set_property" $args
|
||||||
|
set object [lindex $args 0]
|
||||||
|
set prop [lindex $args 1]
|
||||||
|
set value [lindex $args 2]
|
||||||
|
if { ![is_object $object] } {
|
||||||
|
sta_error 2213 "set_property $object is not an object."
|
||||||
|
}
|
||||||
|
set_property_cmd $object [object_type $object] $prop $value
|
||||||
|
}
|
||||||
|
|
||||||
# sta namespace end.
|
# sta namespace end.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
28
tcl/Sta.tcl
28
tcl/Sta.tcl
|
|
@ -112,10 +112,10 @@ proc set_scene { args } {
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
||||||
define_cmd_args "get_scenes" {[-modes mode_names] scene_names}
|
define_cmd_args "get_scenes" {[-modes mode_names] [-filter expr] scene_names}
|
||||||
|
|
||||||
proc get_scenes { args } {
|
proc get_scenes { args } {
|
||||||
parse_key_args "get_scenes" args keys {-modes} flags {}
|
parse_key_args "get_scenes" args keys {-modes -filter} flags {}
|
||||||
check_argc_eq0or1 "get_scenes" $args
|
check_argc_eq0or1 "get_scenes" $args
|
||||||
|
|
||||||
if { [llength $args] == 0 } {
|
if { [llength $args] == 0 } {
|
||||||
|
|
@ -132,18 +132,34 @@ proc get_scenes { args } {
|
||||||
}
|
}
|
||||||
lappend modes $mode
|
lappend modes $mode
|
||||||
}
|
}
|
||||||
return [find_mode_scenes_matching $scene_name $modes]
|
set scenes [find_mode_scenes_matching $scene_name $modes]
|
||||||
} else {
|
} else {
|
||||||
return [find_scenes_matching $scene_name]
|
set scenes [find_scenes_matching $scene_name]
|
||||||
}
|
}
|
||||||
|
if { [info exists keys(-filter)] } {
|
||||||
|
set scenes [filter_scenes $keys(-filter) $scenes]
|
||||||
|
}
|
||||||
|
return $scenes
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
||||||
define_cmd_args "get_modes" {mode_name}
|
define_cmd_args "get_modes" {[-filter expr] [mode_name]}
|
||||||
|
|
||||||
proc get_modes { args } {
|
proc get_modes { args } {
|
||||||
return [find_modes [lindex $args 0]]
|
parse_key_args "get_modes" args keys {-filter} flags {}
|
||||||
|
check_argc_eq0or1 "get_modes" $args
|
||||||
|
|
||||||
|
if { [llength $args] == 0 } {
|
||||||
|
set mode_name "*"
|
||||||
|
} else {
|
||||||
|
set mode_name [lindex $args 0]
|
||||||
|
}
|
||||||
|
set modes [find_modes $mode_name]
|
||||||
|
if { [info exists keys(-filter)] } {
|
||||||
|
set modes [filter_modes $keys(-filter) $modes]
|
||||||
|
}
|
||||||
|
return $modes
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
|
||||||
|
|
@ -1218,6 +1218,10 @@ using namespace sta;
|
||||||
$1 = tclListSeq<Mode*>($input, SWIGTYPE_p_Mode, interp);
|
$1 = tclListSeq<Mode*>($input, SWIGTYPE_p_Mode, interp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%typemap(in) ModeSeq* {
|
||||||
|
$1 = tclListSeqPtr<Mode*>($input, SWIGTYPE_p_Mode, interp);
|
||||||
|
}
|
||||||
|
|
||||||
%typemap(out) ModeSeq {
|
%typemap(out) ModeSeq {
|
||||||
seqTclList<ModeSeq, Mode>($1, SWIGTYPE_p_Mode, interp);
|
seqTclList<ModeSeq, Mode>($1, SWIGTYPE_p_Mode, interp);
|
||||||
}
|
}
|
||||||
|
|
@ -1251,6 +1255,10 @@ using namespace sta;
|
||||||
$1 = tclListSeq<Scene*>($input, SWIGTYPE_p_Scene, interp);
|
$1 = tclListSeq<Scene*>($input, SWIGTYPE_p_Scene, interp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
%typemap(in) SceneSeq* {
|
||||||
|
$1 = tclListSeqPtr<Scene*>($input, SWIGTYPE_p_Scene, interp);
|
||||||
|
}
|
||||||
|
|
||||||
%typemap(out) SceneSeq {
|
%typemap(out) SceneSeq {
|
||||||
seqTclList<SceneSeq, Scene>($1, SWIGTYPE_p_Scene, interp);
|
seqTclList<SceneSeq, Scene>($1, SWIGTYPE_p_Scene, interp);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -4,3 +4,30 @@ scene2
|
||||||
[get_modes *]
|
[get_modes *]
|
||||||
mode1
|
mode1
|
||||||
mode2
|
mode2
|
||||||
|
[get_scenes -filter {name == scene1}]
|
||||||
|
scene1
|
||||||
|
[get_scenes -filter {name =~ scene*}]
|
||||||
|
scene1
|
||||||
|
scene2
|
||||||
|
[get_scenes -filter {name != scene1}]
|
||||||
|
scene2
|
||||||
|
[get_modes -filter {name == mode2}]
|
||||||
|
mode2
|
||||||
|
[get_modes -filter {name =~ mode*}]
|
||||||
|
mode1
|
||||||
|
mode2
|
||||||
|
[get_property scene1 active]
|
||||||
|
1
|
||||||
|
[get_property scene2 active] (unset)
|
||||||
|
<>
|
||||||
|
[get_scenes -filter {active == true}]
|
||||||
|
scene1
|
||||||
|
[get_scenes -filter {active == false}] (scene2 unset)
|
||||||
|
[get_scenes -filter {active}]
|
||||||
|
scene1
|
||||||
|
[get_scenes -filter {!active}]
|
||||||
|
scene2
|
||||||
|
[get_property scene2 active] (set false)
|
||||||
|
0
|
||||||
|
[get_scenes -filter {active == false}] (scene2 set false)
|
||||||
|
scene2
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,47 @@ report_object_names [get_scenes *]
|
||||||
|
|
||||||
puts {[get_modes *]}
|
puts {[get_modes *]}
|
||||||
report_object_names [get_modes *]
|
report_object_names [get_modes *]
|
||||||
|
|
||||||
|
puts {[get_scenes -filter {name == scene1}]}
|
||||||
|
report_object_names [get_scenes -filter {name == scene1}]
|
||||||
|
|
||||||
|
puts {[get_scenes -filter {name =~ scene*}]}
|
||||||
|
report_object_names [get_scenes -filter {name =~ scene*}]
|
||||||
|
|
||||||
|
puts {[get_scenes -filter {name != scene1}]}
|
||||||
|
report_object_names [get_scenes -filter {name != scene1}]
|
||||||
|
|
||||||
|
puts {[get_modes -filter {name == mode2}]}
|
||||||
|
report_object_names [get_modes -filter {name == mode2}]
|
||||||
|
|
||||||
|
puts {[get_modes -filter {name =~ mode*}]}
|
||||||
|
report_object_names [get_modes -filter {name =~ mode*}]
|
||||||
|
|
||||||
|
# User-defined bool property. scene1 set active, scene2 left unset.
|
||||||
|
define_property -object_type scene -type bool active
|
||||||
|
set_property [get_scenes scene1] active true
|
||||||
|
|
||||||
|
puts {[get_property scene1 active]}
|
||||||
|
puts [get_property [get_scenes scene1] active]
|
||||||
|
puts {[get_property scene2 active] (unset)}
|
||||||
|
puts "<[get_property [get_scenes scene2] active]>"
|
||||||
|
|
||||||
|
puts {[get_scenes -filter {active == true}]}
|
||||||
|
report_object_names [get_scenes -filter {active == true}]
|
||||||
|
|
||||||
|
# Unset does not match false; only an explicitly set value does.
|
||||||
|
puts {[get_scenes -filter {active == false}] (scene2 unset)}
|
||||||
|
report_object_names [get_scenes -filter {active == false}]
|
||||||
|
|
||||||
|
puts {[get_scenes -filter {active}]}
|
||||||
|
report_object_names [get_scenes -filter {active}]
|
||||||
|
|
||||||
|
puts {[get_scenes -filter {!active}]}
|
||||||
|
report_object_names [get_scenes -filter {!active}]
|
||||||
|
|
||||||
|
set_property [get_scenes scene2] active false
|
||||||
|
puts {[get_property scene2 active] (set false)}
|
||||||
|
puts [get_property [get_scenes scene2] active]
|
||||||
|
|
||||||
|
puts {[get_scenes -filter {active == false}] (scene2 set false)}
|
||||||
|
report_object_names [get_scenes -filter {active == false}]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue