Merge pull request #388 from The-OpenROAD-Project-staging/sta_latest_0710

Sta latest 0710
This commit is contained in:
Matt Liberty 2026-07-22 00:04:31 +00:00 committed by GitHub
commit 31e8fffddc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 858 additions and 389 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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