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);
|
||||
else
|
||||
seedLoadSlew(vertex);
|
||||
iter_->enqueueAdjacentVertices(vertex);
|
||||
iter_->enqueueFanout(vertex);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -686,7 +686,11 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex,
|
|||
debugPrint(debug_, "delay_calc", 2, "find delays {} ({})",
|
||||
vertex->to_string(this),
|
||||
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);
|
||||
else {
|
||||
if (network_->isLeaf(pin)) {
|
||||
|
|
@ -703,7 +707,7 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex,
|
|||
// change when non-incremental to stride past annotations.
|
||||
if (!incremental_
|
||||
|| loadSlewsChanged(load_slews_prev, load_pin_index_map))
|
||||
iter_->enqueueAdjacentVertices(vertex);
|
||||
iter_->enqueueFanout(vertex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -711,14 +715,9 @@ GraphDelayCalc::findVertexDelay(Vertex *vertex,
|
|||
enqueueTimingChecksEdges(vertex);
|
||||
// Enqueue driver vertices from this input load.
|
||||
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 *&bidir_drvr_vertex)
|
||||
{
|
||||
vertex = nullptr;
|
||||
bidir_drvr_vertex = nullptr;
|
||||
PortDirection *dir = network_->direction(pin);
|
||||
if (!dir->isPowerGround()) {
|
||||
bool is_reg_clk = network_->isRegClkPin(pin);
|
||||
|
|
@ -427,8 +429,6 @@ Graph::makePinVertices(Pin *pin,
|
|||
bidir_drvr_vertex = makeVertex(pin, true, is_reg_clk);
|
||||
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)
|
||||
{
|
||||
if (pred->searchFrom(vertex)) {
|
||||
for (Edge *edge = this->edge(vertex->out_edges_);
|
||||
edge;
|
||||
edge = this->edge(edge->vertex_out_next_)) {
|
||||
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
Vertex *to_vertex = this->vertex(edge->to_);
|
||||
if (pred->searchThru(edge)
|
||||
&& pred->searchTo(to_vertex))
|
||||
|
|
@ -598,9 +598,9 @@ Graph::visitFanoutEdges(Vertex *vertex,
|
|||
const EdgeFn &fn)
|
||||
{
|
||||
if (pred->searchFrom(vertex)) {
|
||||
for (Edge *edge = this->edge(vertex->out_edges_);
|
||||
edge;
|
||||
edge = this->edge(edge->vertex_out_next_)) {
|
||||
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
Vertex *to_vertex = this->vertex(edge->to_);
|
||||
if (pred->searchThru(edge)
|
||||
&& pred->searchTo(to_vertex))
|
||||
|
|
@ -615,9 +615,9 @@ Graph::visitFanins(Vertex *vertex,
|
|||
const VertexFn &fn)
|
||||
{
|
||||
if (pred->searchFrom(vertex)) {
|
||||
for (Edge *edge = this->edge(vertex->in_edges_);
|
||||
edge;
|
||||
edge = this->edge(edge->vertex_in_next_)) {
|
||||
VertexInEdgeIterator edge_iter(vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
Vertex *from_vertex = this->vertex(edge->from_);
|
||||
if (pred->searchThru(edge)
|
||||
&& pred->searchFrom(from_vertex))
|
||||
|
|
@ -632,9 +632,9 @@ Graph::visitFaninEdges(Vertex *vertex,
|
|||
const EdgeFn &fn)
|
||||
{
|
||||
if (pred->searchFrom(vertex)) {
|
||||
for (Edge *edge = this->edge(vertex->in_edges_);
|
||||
edge;
|
||||
edge = this->edge(edge->vertex_in_next_)) {
|
||||
VertexInEdgeIterator edge_iter(vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
Vertex *from_vertex = this->vertex(edge->from_);
|
||||
if (pred->searchThru(edge)
|
||||
&& pred->searchFrom(from_vertex))
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -38,6 +39,8 @@ class SearchPred;
|
|||
class BfsFwdIterator;
|
||||
class BfsBkwdIterator;
|
||||
|
||||
using VertexFn = std::function<void(Vertex*)>;
|
||||
|
||||
// LevelQueue is a vector of vertex vectors indexed by logic level.
|
||||
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
|
||||
// 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.
|
||||
class BfsIterator : public StaState,
|
||||
public Iterator<Vertex*>
|
||||
class BfsIterator : public StaState
|
||||
{
|
||||
public:
|
||||
// Make sure that the BFS queue is deep enough for the max logic level.
|
||||
void ensureSize();
|
||||
// Reset to virgin state.
|
||||
void clear();
|
||||
// Apply fn to each vertex and clear.
|
||||
void clear(const VertexFn &fn);
|
||||
[[nodiscard]] bool empty() const;
|
||||
// Enqueue a vertex to search from.
|
||||
void enqueue(Vertex *vertex);
|
||||
// Enqueue vertices adjacent to a vertex.
|
||||
void enqueueAdjacentVertices(Vertex *vertex);
|
||||
virtual void enqueueAdjacentVertices(Vertex *vertex) = 0;
|
||||
virtual void enqueueAdjacentVertices(Vertex *vertex,
|
||||
const Mode *mode);
|
||||
virtual void enqueueAdjacentVertices(Vertex *vertex,
|
||||
SearchPred *search_pred,
|
||||
const Mode *mode) = 0;
|
||||
virtual void enqueueAdjacentVertices(Vertex *vertex,
|
||||
SearchPred *search_pred) = 0;
|
||||
|
||||
[[nodiscard]] bool inQueue(Vertex *vertex);
|
||||
void checkInQueue(Vertex *vertex);
|
||||
// Notify iterator that vertex will be deleted.
|
||||
|
|
@ -77,10 +77,6 @@ public:
|
|||
void remove(Vertex *vertex);
|
||||
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.
|
||||
// Returns the number of vertices that are visited.
|
||||
virtual int visit(Level to_level,
|
||||
|
|
@ -91,6 +87,10 @@ public:
|
|||
int visitParallel(Level to_level,
|
||||
VertexVisitor *visitor);
|
||||
|
||||
bool hasNext();
|
||||
bool hasNext(Level to_level);
|
||||
Vertex *next();
|
||||
|
||||
protected:
|
||||
BfsIterator(BfsIndex bfs_index,
|
||||
Level level_min,
|
||||
|
|
@ -104,10 +104,10 @@ protected:
|
|||
virtual bool levelLessOrEqual(Level level1,
|
||||
Level level2) const = 0;
|
||||
virtual void incrLevel(Level &level) const = 0;
|
||||
void findNext(Level to_level);
|
||||
void deleteEntries();
|
||||
void checkLevel(Vertex *vertex,
|
||||
Level level);
|
||||
void findNext(Level to_level);
|
||||
|
||||
BfsIndex bfs_index_;
|
||||
Level level_min_;
|
||||
|
|
@ -131,12 +131,13 @@ public:
|
|||
SearchPred *search_pred,
|
||||
StaState *sta);
|
||||
~BfsFwdIterator() override;
|
||||
void enqueueAdjacentVertices(Vertex *vertex) override;
|
||||
void enqueueAdjacentVertices(Vertex *vertex,
|
||||
SearchPred *search_pred) override;
|
||||
void enqueueAdjacentVertices(Vertex *vertex,
|
||||
SearchPred *search_pred,
|
||||
const Mode *mode) override;
|
||||
using BfsIterator::enqueueAdjacentVertices;
|
||||
void enqueueFanout(Vertex *vertex);
|
||||
void enqueueFanout(Vertex *vertex,
|
||||
const Mode *mode);
|
||||
|
||||
protected:
|
||||
bool levelLessOrEqual(Level level1,
|
||||
|
|
@ -153,14 +154,17 @@ public:
|
|||
SearchPred *search_pred,
|
||||
StaState *sta);
|
||||
~BfsBkwdIterator() override;
|
||||
void enqueueAdjacentVertices(Vertex *vertex) override;
|
||||
void enqueueAdjacentVertices(Vertex *vertex,
|
||||
SearchPred *search_pred) override;
|
||||
void enqueueAdjacentVertices(Vertex *vertex,
|
||||
SearchPred *search_pred,
|
||||
const Mode *mode) override;
|
||||
using BfsIterator::enqueueAdjacentVertices;
|
||||
void enqueueFanin(Vertex *vertex);
|
||||
void enqueueFanin(Vertex *vertex,
|
||||
const Mode *mode);
|
||||
|
||||
protected:
|
||||
void enqueueFanin(Vertex *vertex,
|
||||
SearchPred *search_pred);
|
||||
bool levelLessOrEqual(Level level1,
|
||||
Level level2) const override;
|
||||
bool levelLess(Level level1,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "GraphClass.hh"
|
||||
#include "NetworkClass.hh"
|
||||
#include "Scene.hh"
|
||||
#include "SdcClass.hh"
|
||||
#include "SearchClass.hh"
|
||||
#include "StringUtil.hh"
|
||||
|
|
@ -64,6 +65,16 @@ filterClocks(std::string_view filter_expression,
|
|||
ClockSeq *clks,
|
||||
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
|
||||
filterLibCells(std::string_view filter_expression,
|
||||
LibertyCellSeq *cells,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "LibertyClass.hh"
|
||||
#include "NetworkClass.hh"
|
||||
|
|
@ -61,109 +62,6 @@ private:
|
|||
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
|
||||
// value union (string values use std::string* so the union stays trivial)
|
||||
// enum Type
|
||||
|
|
@ -262,4 +160,151 @@ private:
|
|||
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
|
||||
|
|
|
|||
|
|
@ -286,8 +286,6 @@ public:
|
|||
TagGroupBldr *tag_bldr);
|
||||
void postponeLatchDataOutputs(Vertex *vertex);
|
||||
void postponeArrivals(Vertex *vertex);
|
||||
void enqueuePendingClkFanouts();
|
||||
void postponeClkFanouts(Vertex *vertex);
|
||||
void seedRequired(Vertex *vertex);
|
||||
void seedRequiredEnqueueFanin(Vertex *vertex);
|
||||
void seedInputDelayArrival(const Pin *pin,
|
||||
|
|
@ -503,12 +501,12 @@ protected:
|
|||
bool is_segment_start,
|
||||
const MinMax *min_max,
|
||||
Scene *scene);
|
||||
void seedClkVertexArrivals();
|
||||
void findClkArrivals1();
|
||||
void enqueueClkRoots();
|
||||
void enqueueInvalidClks();
|
||||
|
||||
void findAllArrivals(bool thru_latches,
|
||||
bool clks_only);
|
||||
void findAllArrivals(bool thru_latches);
|
||||
void findArrivals1(Level level);
|
||||
void findArrivals2(Level level);
|
||||
Tag *mutateTag(Tag *from_tag,
|
||||
const Pin *from_pin,
|
||||
const RiseFall *from_rf,
|
||||
|
|
@ -646,12 +644,9 @@ protected:
|
|||
std::vector<TagIndex> tag_group_free_indices_;
|
||||
std::mutex tag_group_lock_;
|
||||
|
||||
// Latches data outputs to queue on the next search pass.
|
||||
VertexSet postponed_arrivals_;
|
||||
std::mutex postponed_arrivals_lock_;
|
||||
// Clock network endpoints where arrival search was suppended by findClkArrivals().
|
||||
VertexSet postponed_clk_endpoints_;
|
||||
std::mutex postponed_clk_endpoints_lock_;
|
||||
// Arrivals to queue on the next search pass.
|
||||
VertexSet pending_arrivals_;
|
||||
std::mutex pending_arrivals_lock_;
|
||||
|
||||
VertexSet endpoints_;
|
||||
bool endpoints_initialized_{false};
|
||||
|
|
|
|||
|
|
@ -947,6 +947,11 @@ public:
|
|||
// from/thrus/to are owned and deleted by Search.
|
||||
// PathEnds in the returned PathEndSeq are owned by Search PathGroups
|
||||
// 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,
|
||||
ExceptionThruSeq *thrus,
|
||||
ExceptionTo *to,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "GraphCmp.hh"
|
||||
#include "Liberty.hh"
|
||||
#include "LibertyClass.hh"
|
||||
#include "Mode.hh"
|
||||
#include "Network.hh"
|
||||
#include "NetworkClass.hh"
|
||||
#include "PathEnd.hh"
|
||||
|
|
@ -497,6 +498,30 @@ filterClocks(std::string_view filter_expression,
|
|||
}, 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
|
||||
filterLibCells(std::string_view filter_expression,
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
filter_lib_cells(const char *filter_expression,
|
||||
LibertyCellSeq *cells)
|
||||
|
|
|
|||
205
search/Bfs.cc
205
search/Bfs.cc
|
|
@ -71,13 +71,21 @@ BfsIterator::ensureSize()
|
|||
|
||||
void
|
||||
BfsIterator::clear()
|
||||
{
|
||||
clear([] (Vertex *) {});
|
||||
}
|
||||
|
||||
void
|
||||
BfsIterator::clear(const VertexFn &fn)
|
||||
{
|
||||
Level level = first_level_;
|
||||
while (levelLessOrEqual(level, last_level_)) {
|
||||
VertexSeq &level_vertices = queue_[level];
|
||||
for (Vertex *vertex : level_vertices) {
|
||||
if (vertex)
|
||||
if (vertex) {
|
||||
vertex->setBfsInQueue(bfs_index_, false);
|
||||
fn(vertex);
|
||||
}
|
||||
}
|
||||
level_vertices.clear();
|
||||
incrLevel(level);
|
||||
|
|
@ -116,19 +124,6 @@ BfsIterator::empty() const
|
|||
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
|
||||
BfsIterator::visit(Level to_level,
|
||||
VertexVisitor *visitor)
|
||||
|
|
@ -218,50 +213,6 @@ BfsIterator::visitParallel(Level to_level,
|
|||
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
|
||||
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,
|
||||
SearchPred *search_pred,
|
||||
StaState *sta) :
|
||||
|
|
@ -376,15 +373,46 @@ BfsFwdIterator::levelLess(Level level1,
|
|||
}
|
||||
|
||||
void
|
||||
BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
||||
SearchPred *search_pred)
|
||||
BfsFwdIterator::enqueueFanout(Vertex *vertex)
|
||||
{
|
||||
if (search_pred->searchFrom(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))
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -392,16 +420,15 @@ BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
|||
|
||||
void
|
||||
BfsFwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
||||
SearchPred *search_pred,
|
||||
const Mode *mode)
|
||||
{
|
||||
if (search_pred->searchFrom(vertex, 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))
|
||||
if (search_pred_->searchThru(edge, mode)
|
||||
&& search_pred_->searchTo(to_vertex, mode))
|
||||
enqueue(to_vertex);
|
||||
}
|
||||
}
|
||||
|
|
@ -444,15 +471,15 @@ BfsBkwdIterator::levelLess(Level level1,
|
|||
}
|
||||
|
||||
void
|
||||
BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
||||
SearchPred *search_pred)
|
||||
BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex)
|
||||
{
|
||||
if (search_pred->searchTo(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))
|
||||
if (search_pred_->searchFrom(from_vertex)
|
||||
&& search_pred_->searchThru(edge))
|
||||
enqueue(from_vertex);
|
||||
}
|
||||
}
|
||||
|
|
@ -460,16 +487,46 @@ BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
|||
|
||||
void
|
||||
BfsBkwdIterator::enqueueAdjacentVertices(Vertex *vertex,
|
||||
SearchPred *search_pred,
|
||||
const Mode *mode)
|
||||
{
|
||||
if (search_pred->searchTo(vertex, 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))
|
||||
if (search_pred_->searchFrom(from_vertex, 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@
|
|||
|
||||
#include "ClkNetwork.hh"
|
||||
|
||||
#include "Bfs.hh"
|
||||
#include <queue>
|
||||
|
||||
#include "Debug.hh"
|
||||
#include "Graph.hh"
|
||||
#include "Mode.hh"
|
||||
|
|
@ -127,7 +128,6 @@ ClkNetwork::findClkPins(bool ideal_only,
|
|||
{
|
||||
const Sdc *sdc = mode_->sdc();
|
||||
ClkSearchPred srch_pred(this);
|
||||
BfsFwdIterator bfs(BfsIndex::other, &srch_pred, this);
|
||||
for (Clock *clk : sdc->clocks()) {
|
||||
if (!ideal_only
|
||||
|| !clk->isPropagated()) {
|
||||
|
|
@ -136,25 +136,39 @@ ClkNetwork::findClkPins(bool ideal_only,
|
|||
clk_pins = new PinSet(network_);
|
||||
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()) {
|
||||
if (!ideal_only
|
||||
|| !sdc->isPropagatedClock(pin)) {
|
||||
Vertex *vertex, *bidirect_drvr_vertex;
|
||||
graph_->pinVertices(pin, vertex, bidirect_drvr_vertex);
|
||||
bfs.enqueue(vertex);
|
||||
if (bidirect_drvr_vertex)
|
||||
bfs.enqueue(bidirect_drvr_vertex);
|
||||
enqueue(vertex);
|
||||
enqueue(bidirect_drvr_vertex);
|
||||
}
|
||||
}
|
||||
while (bfs.hasNext()) {
|
||||
Vertex *vertex = bfs.next();
|
||||
while (!queue.empty()) {
|
||||
Vertex *vertex = queue.front();
|
||||
queue.pop();
|
||||
const Pin *pin = vertex->pin();
|
||||
if (!ideal_only
|
||||
|| !sdc->isPropagatedClock(pin)) {
|
||||
clk_pins->insert(pin);
|
||||
ClockSet &pin_clks = pin_clks_map[pin];
|
||||
pin_clks.insert(clk);
|
||||
bfs.enqueueAdjacentVertices(vertex);
|
||||
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.
|
||||
GenClkMasterSearchPred srch_pred(this);
|
||||
VertexQueue master_queue;
|
||||
VertexSet visited = makeVertexSet(this);
|
||||
VertexSet src_vertices = makeVertexSet(this);
|
||||
gclk->srcPinVertices(src_vertices, network_, graph_);
|
||||
for (Vertex *vertex : src_vertices)
|
||||
|
|
@ -279,28 +278,25 @@ Genclks::ensureMaster(Clock *gclk,
|
|||
while (!master_queue.empty()) {
|
||||
Vertex *vertex = master_queue.front();
|
||||
master_queue.pop();
|
||||
if (!visited.contains(vertex)) {
|
||||
visited.insert(vertex);
|
||||
Pin *pin = vertex->pin();
|
||||
if (sdc->isLeafPinClock(pin)) {
|
||||
ClockSet *master_clks = sdc->findLeafPinClocks(pin);
|
||||
if (master_clks) {
|
||||
ClockSet::iterator master_iter = master_clks->begin();
|
||||
if (master_iter != master_clks->end()) {
|
||||
master_clk = *master_iter++;
|
||||
// Master source pin can actually be a clock source pin.
|
||||
if (master_clk != gclk) {
|
||||
gclk->setInferedMasterClk(master_clk);
|
||||
debugPrint(debug_, "genclk", 2, " {} master clk {}", gclk->name(),
|
||||
master_clk->name());
|
||||
master_clk_count++;
|
||||
break;
|
||||
}
|
||||
Pin *pin = vertex->pin();
|
||||
if (sdc->isLeafPinClock(pin)) {
|
||||
ClockSet *master_clks = sdc->findLeafPinClocks(pin);
|
||||
if (master_clks) {
|
||||
ClockSet::iterator master_iter = master_clks->begin();
|
||||
if (master_iter != master_clks->end()) {
|
||||
master_clk = *master_iter++;
|
||||
// Master source pin can actually be a clock source pin.
|
||||
if (master_clk != gclk) {
|
||||
gclk->setInferedMasterClk(master_clk);
|
||||
debugPrint(debug_, "genclk", 2, " {} master clk {}", gclk->name(),
|
||||
master_clk->name());
|
||||
master_clk_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
enqueueFanin(vertex, master_queue, srch_pred);
|
||||
}
|
||||
enqueueFanin(vertex, master_queue, srch_pred);
|
||||
}
|
||||
}
|
||||
if (master_clk_count > 1)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "Clock.hh"
|
||||
|
|
@ -1205,7 +1206,9 @@ Properties::getProperty(const Scene *scene,
|
|||
|| property == "full_name")
|
||||
return PropertyValue(scene->name());
|
||||
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")
|
||||
return PropertyValue(mode->name());
|
||||
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);
|
||||
}
|
||||
|
||||
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>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
%{
|
||||
|
||||
#include "Property.hh"
|
||||
#include "Report.hh"
|
||||
#include "Sta.hh"
|
||||
|
||||
using namespace sta;
|
||||
|
|
@ -137,6 +138,39 @@ mode_property(Mode *mode,
|
|||
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
|
||||
path_end_property(PathEnd *end,
|
||||
const char *property)
|
||||
|
|
|
|||
228
search/Search.cc
228
search/Search.cc
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "Bfs.hh"
|
||||
#include "ClkInfo.hh"
|
||||
#include "ClkNetwork.hh"
|
||||
#include "Clock.hh"
|
||||
#include "ContainerHelpers.hh"
|
||||
#include "Crpr.hh"
|
||||
|
|
@ -95,6 +96,8 @@ EvalPred::searchThru(Edge *edge,
|
|||
{
|
||||
const TimingRole *role = edge->role();
|
||||
return SearchPred0::searchThru(edge, mode)
|
||||
&& (sta_->variables()->dynamicLoopBreaking()
|
||||
|| !edge->isDisabledLoop())
|
||||
&& (search_thru_latches_
|
||||
|| role->isLatchDtoQ()
|
||||
|| sta_->latches()->latchDtoQState(edge, mode) == LatchEnableState::open);
|
||||
|
|
@ -263,8 +266,7 @@ Search::Search(StaState *sta) :
|
|||
tag_group_capacity_(tag_capacity_),
|
||||
tag_groups_(new TagGroup *[tag_group_capacity_]),
|
||||
tag_group_set_(new TagGroupSet(tag_group_capacity_)),
|
||||
postponed_arrivals_(makeVertexSet(this)),
|
||||
postponed_clk_endpoints_(makeVertexSet(this)),
|
||||
pending_arrivals_(makeVertexSet(this)),
|
||||
endpoints_(makeVertexSet(this)),
|
||||
invalid_endpoints_(makeVertexSet(this)),
|
||||
|
||||
|
|
@ -328,8 +330,7 @@ Search::clear()
|
|||
deletePathGroups();
|
||||
deletePaths();
|
||||
deleteTags();
|
||||
postponed_arrivals_.clear();
|
||||
postponed_clk_endpoints_.clear();
|
||||
pending_arrivals_.clear();
|
||||
deleteFilter();
|
||||
found_downstream_clk_pins_ = false;
|
||||
}
|
||||
|
|
@ -546,7 +547,7 @@ Search::findFilteredArrivals(ExceptionFrom *from,
|
|||
// These cases do not require filtered arrivals.
|
||||
// -from clocks
|
||||
// -to
|
||||
findAllArrivals(thru_latches, false);
|
||||
findAllArrivals(thru_latches);
|
||||
}
|
||||
|
||||
// From/thrus/to are used to make a filter exception. If the last
|
||||
|
|
@ -639,32 +640,36 @@ Search::deleteFilterClkInfos()
|
|||
void
|
||||
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
|
||||
// fanin startpoints to reach -thru/-to endpoints.
|
||||
arrival_visitor_->init(true, false, eval_pred_);
|
||||
enqueuePendingClkFanouts();
|
||||
bool have_pending_latch_outputs = false;
|
||||
// Iterate until data arrivals at all latches stop changing.
|
||||
arrival_iter_->ensureSize();
|
||||
|
||||
filtered_arrivals_.clear();
|
||||
findArrivalsSeed();
|
||||
seedFilterStarts();
|
||||
|
||||
Level max_level = levelize_->maxLevel();
|
||||
bool have_pending_arrivals = false;
|
||||
for (int pass = 1;
|
||||
pass == 1 || (thru_latches && have_pending_latch_outputs);
|
||||
pass == 1 || (thru_latches && have_pending_arrivals);
|
||||
pass++) {
|
||||
debugPrint(debug_, "search", 1, "find arrivals pass {}", pass);
|
||||
|
||||
int arrival_count = arrival_iter_->visitParallel(max_level, arrival_visitor_);
|
||||
debugPrint(debug_, "search", 1, "found {} arrivals", arrival_count);
|
||||
|
||||
have_pending_latch_outputs = !postponed_arrivals_.empty();
|
||||
for (Vertex *latch_output : postponed_arrivals_)
|
||||
arrival_visitor_->visit(latch_output, true);
|
||||
postponed_arrivals_.clear();
|
||||
// Latch D->Q and disabled loop edges have level discontinuities so their
|
||||
// eval. For latches the data path crpr clk path may be evaled in another
|
||||
// thread at the same time the latch D->Q edge.
|
||||
// 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();
|
||||
}
|
||||
arrivals_exist_ = true;
|
||||
}
|
||||
|
||||
// Delete stale tag arrarys.
|
||||
|
|
@ -860,14 +865,13 @@ void
|
|||
Search::levelsChangedBefore()
|
||||
{
|
||||
if (arrivals_exist_) {
|
||||
while (arrival_iter_->hasNext()) {
|
||||
Vertex *vertex = arrival_iter_->next();
|
||||
arrival_iter_->clear([this] (Vertex *vertex) {
|
||||
arrivalInvalid(vertex);
|
||||
}
|
||||
while (required_iter_->hasNext()) {
|
||||
Vertex *vertex = required_iter_->next();
|
||||
});
|
||||
|
||||
required_iter_->clear([this] (Vertex *vertex) {
|
||||
requiredInvalid(vertex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -939,11 +943,16 @@ Search::requiredInvalid(Vertex *vertex)
|
|||
void
|
||||
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
|
||||
Search::seedClkVertexArrivals()
|
||||
Search::enqueueClkRoots()
|
||||
{
|
||||
PinSet clk_pins(network_);
|
||||
findClkVertexPins(clk_pins);
|
||||
|
|
@ -954,6 +963,32 @@ Search::seedClkVertexArrivals()
|
|||
if (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
|
||||
|
|
@ -980,51 +1015,31 @@ Search::clockInsertion(const Clock *clk,
|
|||
void
|
||||
Search::findAllArrivals()
|
||||
{
|
||||
findAllArrivals(true, false);
|
||||
findAllArrivals(true);
|
||||
}
|
||||
|
||||
void
|
||||
Search::findAllArrivals(bool thru_latches,
|
||||
bool clks_only)
|
||||
Search::findAllArrivals(bool thru_latches)
|
||||
{
|
||||
if (!clks_only)
|
||||
enqueuePendingClkFanouts();
|
||||
arrival_visitor_->init(false, clks_only, eval_pred_);
|
||||
bool have_pending_latch_outputs = false;
|
||||
arrival_visitor_->init(false, false, eval_pred_);
|
||||
arrival_iter_->ensureSize();
|
||||
|
||||
bool have_pending_arrivals = false;
|
||||
// Iterate until data arrivals at all latches stop changing.
|
||||
for (int pass = 1;
|
||||
pass == 1 || (thru_latches && have_pending_latch_outputs);
|
||||
pass == 1 || (thru_latches && have_pending_arrivals);
|
||||
pass++) {
|
||||
debugPrint(debug_, "search", 1, "find arrivals pass {}", pass);
|
||||
|
||||
findArrivals1(levelize_->maxLevel());
|
||||
|
||||
have_pending_latch_outputs = !postponed_arrivals_.empty();
|
||||
for (Vertex *latch_output : postponed_arrivals_)
|
||||
arrival_visitor_->visit(latch_output, true);
|
||||
postponed_arrivals_.clear();
|
||||
have_pending_arrivals = !pending_arrivals_.empty();
|
||||
for (Vertex *vertex : pending_arrivals_)
|
||||
arrival_visitor_->visit(vertex, true);
|
||||
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
|
||||
Search::findArrivals()
|
||||
{
|
||||
|
|
@ -1035,6 +1050,7 @@ void
|
|||
Search::findArrivals(Level level)
|
||||
{
|
||||
arrival_visitor_->init(false, false, eval_pred_);
|
||||
arrival_iter_->ensureSize();
|
||||
findArrivals1(level);
|
||||
}
|
||||
|
||||
|
|
@ -1043,13 +1059,19 @@ Search::findArrivals1(Level level)
|
|||
{
|
||||
debugPrint(debug_, "search", 1, "find arrivals to level {}", level);
|
||||
findArrivalsSeed();
|
||||
findArrivals2(level);
|
||||
}
|
||||
|
||||
// Caller seeds arrival_iter_.
|
||||
void
|
||||
Search::findArrivals2(Level level)
|
||||
{
|
||||
Stats stats(debug_, report_);
|
||||
int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_);
|
||||
deleteTagsPrev();
|
||||
if (arrival_count > 0)
|
||||
deleteUnusedTagGroups();
|
||||
stats.report("Find arrivals");
|
||||
arrivals_exist_ = true;
|
||||
debugPrint(debug_, "search", 1, "found {} arrivals", arrival_count);
|
||||
}
|
||||
|
||||
|
|
@ -1059,15 +1081,9 @@ Search::findArrivalsSeed()
|
|||
if (!arrivals_seeded_) {
|
||||
for (const Mode *mode : modes_)
|
||||
mode->genclks()->ensureInsertionDelays();
|
||||
arrival_iter_->clear();
|
||||
required_iter_->clear();
|
||||
seedArrivals();
|
||||
arrivals_seeded_ = true;
|
||||
}
|
||||
else {
|
||||
arrival_iter_->ensureSize();
|
||||
required_iter_->ensureSize();
|
||||
}
|
||||
seedInvalidArrivals();
|
||||
}
|
||||
|
||||
|
|
@ -1173,22 +1189,18 @@ ArrivalVisitor::visit(Vertex *vertex,
|
|||
search_->postponeLatchDataOutputs(vertex);
|
||||
|
||||
if ((always_to_endpoints_ || arrivals_changed)) {
|
||||
if (clks_only_ && vertex->isRegClk()) {
|
||||
debugPrint(debug_, "search", 3, "postponing clk fanout");
|
||||
search_->postponeClkFanouts(vertex);
|
||||
}
|
||||
else {
|
||||
graph_->visitFanoutEdges(vertex, search_adj_,
|
||||
[this] (Edge *edge,
|
||||
Vertex *fanout) {
|
||||
if (edge->isDisabledLoop()) {
|
||||
if (hasPendingLoopPaths(edge))
|
||||
search_->postponeArrivals(fanout);
|
||||
}
|
||||
else
|
||||
search_->arrivalIterator()->enqueue(fanout);
|
||||
});
|
||||
}
|
||||
graph_->visitFanoutEdges(vertex, search_adj_,
|
||||
[this, vertex] (Edge *edge,
|
||||
Vertex *fanout) {
|
||||
if (edge->isDisabledLoop()) {
|
||||
if (hasPendingLoopPaths(edge))
|
||||
search_->postponeArrivals(fanout);
|
||||
}
|
||||
else if (clks_only_ && vertex->isRegClk())
|
||||
search_->arrivalInvalid(fanout);
|
||||
else
|
||||
search_->arrivalIterator()->enqueue(fanout);
|
||||
});
|
||||
}
|
||||
if (arrivals_changed) {
|
||||
debugPrint(debug_, "search", 4, "arrivals changed");
|
||||
|
|
@ -1425,8 +1437,8 @@ Search::postponeLatchDataOutputs(Vertex *latch_data)
|
|||
Edge *edge = edge_iter.next();
|
||||
if (edge->role() == TimingRole::latchDtoQ()) {
|
||||
Vertex *out_vertex = edge->to(graph_);
|
||||
LockGuard lock(postponed_arrivals_lock_);
|
||||
postponed_arrivals_.insert(out_vertex);
|
||||
LockGuard lock(pending_arrivals_lock_);
|
||||
pending_arrivals_.insert(out_vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1434,8 +1446,8 @@ Search::postponeLatchDataOutputs(Vertex *latch_data)
|
|||
void
|
||||
Search::postponeArrivals(Vertex *vertex)
|
||||
{
|
||||
LockGuard lock(postponed_arrivals_lock_);
|
||||
postponed_arrivals_.insert(vertex);
|
||||
LockGuard lock(pending_arrivals_lock_);
|
||||
pending_arrivals_.insert(vertex);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1448,6 +1460,7 @@ Search::seedArrivals()
|
|||
|
||||
for (Vertex *vertex : vertices)
|
||||
arrival_iter_->enqueue(vertex);
|
||||
arrivals_exist_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2764,14 +2777,14 @@ Search::reportArrivals(Vertex *vertex,
|
|||
for (const Path *path : paths) {
|
||||
const Tag *tag = path->tag(this);
|
||||
const RiseFall *rf = tag->transition();
|
||||
bool report_prev = false;
|
||||
bool report_prev = true;
|
||||
std::string prev_str;
|
||||
if (report_prev) {
|
||||
Path *prev_path = path->prevPath();
|
||||
if (prev_path) {
|
||||
const Edge *prev_edge = path->prevEdge(this);
|
||||
TimingArc *arc = path->prevArc(this);
|
||||
prev_str = sta::format("prev {} {} {} -> {} {}",
|
||||
prev_str = sta::format(" prev {} {} {} -> {} {}",
|
||||
prev_path->to_string(this),
|
||||
prev_edge->from(graph_)->to_string(this),
|
||||
arc->fromEdge()->to_string(),
|
||||
|
|
@ -2779,13 +2792,14 @@ Search::reportArrivals(Vertex *vertex,
|
|||
arc->toEdge()->to_string());
|
||||
}
|
||||
else
|
||||
prev_str = "prev NULL";
|
||||
prev_str = " prev NULL";
|
||||
}
|
||||
report_->report(" {} {} {} / {} {}{}", rf->shortName(),
|
||||
path->minMax(this)->to_string(),
|
||||
delayAsString(path->arrival(), 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
|
||||
|
|
@ -3146,6 +3160,7 @@ Search::findRequireds(Level level)
|
|||
Stats stats(debug_, report_);
|
||||
debugPrint(debug_, "search", 1, "find requireds to level {}", level);
|
||||
RequiredVisitor req_visitor(this);
|
||||
required_iter_->ensureSize();
|
||||
if (!requireds_seeded_)
|
||||
seedRequireds();
|
||||
seedInvalidRequireds();
|
||||
|
|
@ -3334,8 +3349,9 @@ Search::seedRequired(Vertex *vertex)
|
|||
required_cmp.requiredsInit(vertex, this);
|
||||
visit_path_ends_->visitPathEnds(vertex, &seeder);
|
||||
// Enqueue fanin vertices for back-propagating required times.
|
||||
required_iter_->ensureSize();
|
||||
if (required_cmp.requiredsSave(vertex, this))
|
||||
required_iter_->enqueueAdjacentVertices(vertex);
|
||||
required_iter_->enqueueFanin(vertex);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -3347,7 +3363,7 @@ Search::seedRequiredEnqueueFanin(Vertex *vertex)
|
|||
visit_path_ends_->visitPathEnds(vertex, &seeder);
|
||||
// Enqueue fanin vertices for back-propagating required times.
|
||||
required_cmp.requiredsSave(vertex, this);
|
||||
required_iter_->enqueueAdjacentVertices(vertex);
|
||||
required_iter_->enqueueFanin(vertex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -3455,7 +3471,7 @@ RequiredVisitor::visit(Vertex *vertex)
|
|||
search_->tnsInvalid(vertex);
|
||||
|
||||
if (changed)
|
||||
search_->requiredIterator()->enqueueAdjacentVertices(vertex);
|
||||
search_->requiredIterator()->enqueueFanin(vertex);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -3538,17 +3554,27 @@ void
|
|||
Search::ensureDownstreamClkPins()
|
||||
{
|
||||
if (!found_downstream_clk_pins_) {
|
||||
// Use backward BFS from register clk pins to mark upsteam pins
|
||||
// as having downstream clk pins.
|
||||
// Use backward DFS from register clk pins to mark upstream pins
|
||||
// as having downstream clk pins. hasDownstreamClkPin doubles as the
|
||||
// visited flag since its meaning is exactly "reached here".
|
||||
ClkTreeSearchPred pred(this);
|
||||
BfsBkwdIterator iter(BfsIndex::other, &pred, this);
|
||||
for (Vertex *vertex : graph_->regClkVertices())
|
||||
iter.enqueue(vertex);
|
||||
|
||||
while (iter.hasNext()) {
|
||||
Vertex *vertex = iter.next();
|
||||
vertex->setHasDownstreamClkPin(true);
|
||||
iter.enqueueAdjacentVertices(vertex);
|
||||
std::vector<Vertex*> stack;
|
||||
for (Vertex *vertex : graph_->regClkVertices()) {
|
||||
if (!vertex->hasDownstreamClkPin()) {
|
||||
vertex->setHasDownstreamClkPin(true);
|
||||
stack.push_back(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;
|
||||
|
|
|
|||
|
|
@ -4518,6 +4518,10 @@ Sta::makeInstanceAfter(const Instance *inst)
|
|||
if (pin) {
|
||||
Vertex *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);
|
||||
|
|
@ -4553,16 +4557,14 @@ Sta::replaceEquivCellBefore(const Instance *inst,
|
|||
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
Vertex *to_vertex = edge->to(graph_);
|
||||
if (network_->instance(to_vertex->pin()) == inst) {
|
||||
if (!edge->isWire()) {
|
||||
TimingArcSet *from_set = edge->timingArcSet();
|
||||
// Find corresponding timing arc set.
|
||||
TimingArcSet *to_set = to_cell->findTimingArcSet(from_set);
|
||||
if (to_set)
|
||||
edge->setTimingArcSet(to_set);
|
||||
else
|
||||
report_->critical(
|
||||
1556, "corresponding timing arc set not found in equiv cells");
|
||||
report_->critical(1563, "corresponding timing arc set not found in equiv cells");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4658,8 +4660,7 @@ Sta::replaceCellBefore(const Instance *inst,
|
|||
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
Vertex *to_vertex = edge->to(graph_);
|
||||
if (network_->instance(to_vertex->pin()) == inst)
|
||||
if (!edge->isWire())
|
||||
deleteEdge(edge);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,15 +258,15 @@ paths: 60
|
|||
--- report_tag_arrivals ---
|
||||
Vertex out1
|
||||
Group 2
|
||||
^ min 0.100 / -2.000 16 default clk ^ clk_src clk crpr_pin null
|
||||
v min 0.099 / -2.000 17 default clk ^ clk_src clk crpr_pin null
|
||||
^ max 0.100 / 8.000 18 default clk ^ clk_src clk crpr_pin null
|
||||
v max 0.099 / 8.000 19 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 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 prev buf2/Z ^ default/max 18 buf2/Z ^ -> out1 ^
|
||||
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
|
||||
^ min 0.100 / -2.000 default clk ^ clk_src clk crpr_pin null
|
||||
v min 0.099 / -2.000 default clk ^ clk_src clk crpr_pin null
|
||||
^ max 0.100 / 8.000 default clk ^ clk_src clk crpr_pin null
|
||||
v max 0.099 / 8.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 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 prev buf2/Z ^ default/max 18 buf2/Z ^ -> out1 ^
|
||||
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_required_entries ---
|
||||
Level 40
|
||||
|
|
|
|||
|
|
@ -68,15 +68,15 @@ worst_slack_path pin: out1
|
|||
worst_slack_path slack: 7.899713772019368e-9
|
||||
Vertex out1
|
||||
Group 2
|
||||
^ min 0.100 / -2.000 16 default clk ^ clk_src clk crpr_pin null
|
||||
v min 0.099 / -2.000 17 default clk ^ clk_src clk crpr_pin null
|
||||
^ max 0.100 / 8.000 18 default clk ^ clk_src clk crpr_pin null
|
||||
v max 0.099 / 8.000 19 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 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 prev buf2/Z ^ default/max 18 buf2/Z ^ -> out1 ^
|
||||
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
|
||||
^ min 0.100 / -2.000 default clk ^ clk_src clk crpr_pin null
|
||||
v min 0.099 / -2.000 default clk ^ clk_src clk crpr_pin null
|
||||
^ max 0.100 / 8.000 default clk ^ clk_src clk crpr_pin null
|
||||
v max 0.099 / 8.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 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 prev buf2/Z ^ default/max 18 buf2/Z ^ -> out1 ^
|
||||
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 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]
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
|
|
|||
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 } {
|
||||
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
|
||||
|
||||
if { [llength $args] == 0 } {
|
||||
|
|
@ -132,18 +132,34 @@ proc get_scenes { args } {
|
|||
}
|
||||
lappend modes $mode
|
||||
}
|
||||
return [find_mode_scenes_matching $scene_name $modes]
|
||||
set scenes [find_mode_scenes_matching $scene_name $modes]
|
||||
} 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 } {
|
||||
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);
|
||||
}
|
||||
|
||||
%typemap(in) ModeSeq* {
|
||||
$1 = tclListSeqPtr<Mode*>($input, SWIGTYPE_p_Mode, interp);
|
||||
}
|
||||
|
||||
%typemap(out) ModeSeq {
|
||||
seqTclList<ModeSeq, Mode>($1, SWIGTYPE_p_Mode, interp);
|
||||
}
|
||||
|
|
@ -1251,6 +1255,10 @@ using namespace sta;
|
|||
$1 = tclListSeq<Scene*>($input, SWIGTYPE_p_Scene, interp);
|
||||
}
|
||||
|
||||
%typemap(in) SceneSeq* {
|
||||
$1 = tclListSeqPtr<Scene*>($input, SWIGTYPE_p_Scene, interp);
|
||||
}
|
||||
|
||||
%typemap(out) SceneSeq {
|
||||
seqTclList<SceneSeq, Scene>($1, SWIGTYPE_p_Scene, interp);
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -4,3 +4,30 @@ scene2
|
|||
[get_modes *]
|
||||
mode1
|
||||
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 *]}
|
||||
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