Compare commits
8 Commits
b2129904cb
...
8280929182
| Author | SHA1 | Date |
|---|---|---|
|
|
8280929182 | |
|
|
254d090582 | |
|
|
8df87e07a1 | |
|
|
de0f5440a6 | |
|
|
8fb0cc305d | |
|
|
79ddebf153 | |
|
|
525c2efb3d | |
|
|
6e29fcb3f0 |
|
|
@ -594,7 +594,6 @@ Graph::deletePaths(Vertex *vertex)
|
|||
{
|
||||
vertex->setPaths(nullptr);
|
||||
vertex->tag_group_index_ = tag_group_index_max;
|
||||
vertex->crpr_path_pruning_disabled_ = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -998,7 +997,6 @@ Vertex::init(Pin *pin,
|
|||
visited1_ = false;
|
||||
visited2_ = false;
|
||||
bfs_in_queue_ = 0;
|
||||
crpr_path_pruning_disabled_ = false;
|
||||
}
|
||||
|
||||
Vertex::~Vertex()
|
||||
|
|
@ -1120,12 +1118,6 @@ Vertex::removeSlewAnnotated()
|
|||
slew_annotated_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Vertex::setCrprPathPruningDisabled(bool disabled)
|
||||
{
|
||||
crpr_path_pruning_disabled_ = disabled;
|
||||
}
|
||||
|
||||
TagGroupIndex
|
||||
Vertex::tagGroupIndex() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -304,8 +304,6 @@ public:
|
|||
bool bfsInQueue(BfsIndex index) const;
|
||||
void setBfsInQueue(BfsIndex index, bool value);
|
||||
bool isRegClk() const { return is_reg_clk_; }
|
||||
bool crprPathPruningDisabled() const { return crpr_path_pruning_disabled_;}
|
||||
void setCrprPathPruningDisabled(bool disabled);
|
||||
|
||||
// ObjectTable interface.
|
||||
ObjectIdx objectIdx() const { return object_idx_; }
|
||||
|
|
@ -353,7 +351,6 @@ protected:
|
|||
bool is_check_clk_:1;
|
||||
bool is_constrained_:1;
|
||||
bool has_downstream_clk_pin_:1;
|
||||
bool crpr_path_pruning_disabled_:1;
|
||||
bool visited1_:1;
|
||||
bool visited2_:1;
|
||||
|
||||
|
|
|
|||
|
|
@ -134,8 +134,12 @@ public:
|
|||
PathGroup *findPathGroup(const Clock *clock,
|
||||
const MinMax *min_max) const;
|
||||
PathGroup *pathGroup(const PathEnd *path_end) const;
|
||||
static bool isGroupPathName(const char *group_name);
|
||||
static std::string pathGroupName(const PathEnd *path_end,
|
||||
const StaState *sta);
|
||||
static const char *asyncPathGroupName() { return async_group_name_; }
|
||||
static const char *pathDelayGroupName() { return path_delay_group_name_; }
|
||||
static const char *gatedClkGroupName() { return gated_clk_group_name_; }
|
||||
static const char *unconstrainedGroupName() { return unconstrained_group_name_; }
|
||||
|
||||
protected:
|
||||
void makeGroupPathEnds(ExceptionTo *to,
|
||||
|
|
@ -175,7 +179,8 @@ protected:
|
|||
const MinMax *min_max);
|
||||
bool reportGroup(const char *group_name,
|
||||
PathGroupNameSet *group_names) const;
|
||||
GroupPath *groupPathTo(const PathEnd *path_end) const;
|
||||
static GroupPath *groupPathTo(const PathEnd *path_end,
|
||||
const StaState *sta);
|
||||
|
||||
int group_path_count_;
|
||||
int endpoint_path_count_;
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ typedef InstanceSeq::Iterator SlowDrvrIterator;
|
|||
typedef Vector<const char*> CheckError;
|
||||
typedef Vector<CheckError*> CheckErrorSeq;
|
||||
typedef Vector<Corner*> CornerSeq;
|
||||
typedef std::vector<std::string> StdStringSeq;
|
||||
|
||||
enum class CmdNamespace { sta, sdc };
|
||||
|
||||
|
|
@ -516,7 +517,10 @@ public:
|
|||
ExceptionThruSeq *thrus,
|
||||
ExceptionTo *to,
|
||||
const char *comment);
|
||||
bool isGroupPathName(const char *group_name);
|
||||
// Deprecated 10/24/2025
|
||||
bool isGroupPathName(const char *group_name) __attribute__ ((deprecated));
|
||||
bool isPathGroupName(const char *group_name) const;
|
||||
StdStringSeq pathGroupNames() const;
|
||||
void resetPath(ExceptionFrom *from,
|
||||
ExceptionThruSeq *thrus,
|
||||
ExceptionTo *to,
|
||||
|
|
@ -1002,6 +1006,10 @@ public:
|
|||
const MinMax *min_max);
|
||||
Slack pinSlack(const Pin *pin,
|
||||
const MinMax *min_max);
|
||||
// Worst slack for an endpoint in a path group.
|
||||
Slack endpointSlack(const Pin *pin,
|
||||
const std::string &path_group_name,
|
||||
const MinMax *min_max);
|
||||
Slack vertexSlack(Vertex *vertex,
|
||||
const MinMax *min_max);
|
||||
Slack vertexSlack(Vertex *vertex,
|
||||
|
|
@ -1437,8 +1445,6 @@ protected:
|
|||
Corner *corner,
|
||||
const MinMax *min_max);
|
||||
void powerPreamble();
|
||||
void disableFanoutCrprPruning(Vertex *vertex,
|
||||
int &fanou);
|
||||
virtual void replaceCell(Instance *inst,
|
||||
Cell *to_cell,
|
||||
LibertyCell *to_lib_cell);
|
||||
|
|
|
|||
|
|
@ -734,7 +734,7 @@ make_group_path(const char *name,
|
|||
bool
|
||||
is_path_group_name(const char *name)
|
||||
{
|
||||
return Sta::sta()->isGroupPathName(name);
|
||||
return Sta::sta()->isPathGroupName(name);
|
||||
}
|
||||
|
||||
ExceptionFrom *
|
||||
|
|
@ -863,7 +863,7 @@ set_clock_sense_cmd(PinSet *pins,
|
|||
else if (stop_propagation)
|
||||
sta->setClockSense(pins, clks, ClockSense::stop);
|
||||
else
|
||||
sta->report()->critical(1577, "unknown clock sense");
|
||||
sta->report()->critical(2123, "unknown clock sense");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1328,7 +1328,7 @@ filter_timing_arcs(const char *property,
|
|||
////////////////////////////////////////////////////////////////
|
||||
|
||||
StringSeq
|
||||
path_group_names()
|
||||
group_path_names()
|
||||
{
|
||||
StringSeq pg_names;
|
||||
for (auto const& [name, group] : Sta::sta()->sdc()->groupPaths())
|
||||
|
|
|
|||
|
|
@ -248,15 +248,6 @@ const char *PathGroups::gated_clk_group_name_ = "gated clock";
|
|||
const char *PathGroups::async_group_name_ = "asynchronous";
|
||||
const char *PathGroups::unconstrained_group_name_ = "unconstrained";
|
||||
|
||||
bool
|
||||
PathGroups::isGroupPathName(const char *group_name)
|
||||
{
|
||||
return stringEq(group_name, path_delay_group_name_)
|
||||
|| stringEq(group_name, gated_clk_group_name_)
|
||||
|| stringEq(group_name, async_group_name_)
|
||||
|| stringEq(group_name, unconstrained_group_name_);
|
||||
}
|
||||
|
||||
PathGroups::PathGroups(int group_path_count,
|
||||
int endpoint_path_count,
|
||||
bool unique_pins,
|
||||
|
|
@ -412,7 +403,7 @@ PathGroups::pathGroup(const PathEnd *path_end) const
|
|||
{
|
||||
const MinMax *min_max = path_end->minMax(this);
|
||||
int mm_index = min_max->index();
|
||||
GroupPath *group_path = groupPathTo(path_end);
|
||||
GroupPath *group_path = groupPathTo(path_end, this);
|
||||
if (path_end->isUnconstrained())
|
||||
return unconstrained_[mm_index];
|
||||
// GroupPaths have precedence.
|
||||
|
|
@ -455,16 +446,63 @@ PathGroups::pathGroup(const PathEnd *path_end) const
|
|||
}
|
||||
}
|
||||
|
||||
// Mirrors PathGroups::pathGroup.
|
||||
std::string
|
||||
PathGroups::pathGroupName(const PathEnd *path_end,
|
||||
const StaState *sta)
|
||||
{
|
||||
GroupPath *group_path = groupPathTo(path_end, sta);
|
||||
if (path_end->isUnconstrained())
|
||||
return unconstrained_group_name_;
|
||||
// GroupPaths have precedence.
|
||||
else if (group_path) {
|
||||
if (group_path->isDefault())
|
||||
return path_delay_group_name_;
|
||||
else
|
||||
return group_path->name();
|
||||
}
|
||||
else if (path_end->isCheck() || path_end->isLatchCheck()) {
|
||||
const TimingRole *check_role = path_end->checkRole(sta);
|
||||
const Clock *tgt_clk = path_end->targetClk(sta);
|
||||
if (check_role == TimingRole::removal()
|
||||
|| check_role == TimingRole::recovery())
|
||||
return async_group_name_;
|
||||
else
|
||||
return tgt_clk->name();
|
||||
}
|
||||
else if (path_end->isOutputDelay()
|
||||
|| path_end->isDataCheck())
|
||||
return path_end->targetClk(sta)->name();
|
||||
else if (path_end->isGatedClock())
|
||||
return gated_clk_group_name_;
|
||||
else if (path_end->isPathDelay()) {
|
||||
// Path delays that end at timing checks are part of the target clk group
|
||||
// unless -ignore_clock_latency is true.
|
||||
PathDelay *path_delay = path_end->pathDelay();
|
||||
const Clock *tgt_clk = path_end->targetClk(sta);
|
||||
if (tgt_clk
|
||||
&& !path_delay->ignoreClkLatency())
|
||||
return tgt_clk->name();
|
||||
else
|
||||
return path_delay_group_name_;
|
||||
}
|
||||
else {
|
||||
sta->report()->critical(1391, "unknown path end type");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
GroupPath *
|
||||
PathGroups::groupPathTo(const PathEnd *path_end) const
|
||||
PathGroups::groupPathTo(const PathEnd *path_end,
|
||||
const StaState *sta)
|
||||
{
|
||||
const Path *path = path_end->path();
|
||||
const Pin *pin = path->pin(this);
|
||||
const Pin *pin = path->pin(sta);
|
||||
ExceptionPath *exception =
|
||||
search_->exceptionTo(ExceptionPathType::group_path, path,
|
||||
pin, path->transition(this),
|
||||
path_end->targetClkEdge(this),
|
||||
path->minMax(this), false, false);
|
||||
sta->search()->exceptionTo(ExceptionPathType::group_path, path,
|
||||
pin, path->transition(sta),
|
||||
path_end->targetClkEdge(sta),
|
||||
path->minMax(sta), false, false);
|
||||
return dynamic_cast<GroupPath*>(exception);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1182,7 +1182,6 @@ ArrivalVisitor::visit(Vertex *vertex)
|
|||
visitFaninPaths(vertex);
|
||||
if (crpr_active_
|
||||
&& search_->crprPathPruningEnabled()
|
||||
&& !vertex->crprPathPruningDisabled()
|
||||
// No crpr for ideal clocks.
|
||||
&& tag_bldr_->hasPropagatedClk()
|
||||
&& !has_fanin_one_)
|
||||
|
|
|
|||
|
|
@ -251,6 +251,31 @@ vertex_worst_slack_path(Vertex *vertex,
|
|||
return sta->vertexWorstSlackPath(vertex, min_max);
|
||||
}
|
||||
|
||||
Slack
|
||||
endpoint_slack(const Pin *pin,
|
||||
const char *path_group_name,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
sta->ensureLibLinked();
|
||||
if (sta->isPathGroupName(path_group_name)) {
|
||||
Slack slack = sta->endpointSlack(pin, std::string(path_group_name), min_max);
|
||||
return sta->units()->timeUnit()->staToUser(slack);
|
||||
}
|
||||
else {
|
||||
sta->report()->error(1577, "%s is not a known path group name.",
|
||||
path_group_name);
|
||||
return INF;
|
||||
}
|
||||
}
|
||||
|
||||
StdStringSeq
|
||||
path_group_names()
|
||||
{
|
||||
Sta *sta = Sta::sta();
|
||||
return sta->pathGroupNames();
|
||||
}
|
||||
|
||||
int
|
||||
tag_group_count()
|
||||
{
|
||||
|
|
|
|||
143
search/Sta.cc
143
search/Sta.cc
|
|
@ -1990,9 +1990,35 @@ Sta::makeGroupPath(const char *name,
|
|||
bool
|
||||
Sta::isGroupPathName(const char *group_name)
|
||||
{
|
||||
return PathGroups::isGroupPathName(group_name)
|
||||
|| sdc_->findClock(group_name)
|
||||
|| sdc_->isGroupPathName(group_name);
|
||||
return isPathGroupName(group_name);
|
||||
}
|
||||
|
||||
bool
|
||||
Sta::isPathGroupName(const char *group_name) const
|
||||
{
|
||||
return sdc_->findClock(group_name)
|
||||
|| sdc_->isGroupPathName(group_name)
|
||||
|| stringEq(group_name, PathGroups::asyncPathGroupName())
|
||||
|| stringEq(group_name, PathGroups::pathDelayGroupName())
|
||||
|| stringEq(group_name, PathGroups::gatedClkGroupName())
|
||||
|| stringEq(group_name, PathGroups::unconstrainedGroupName());
|
||||
}
|
||||
|
||||
StdStringSeq
|
||||
Sta::pathGroupNames() const
|
||||
{
|
||||
StdStringSeq names;
|
||||
for (const Clock *clk : *sdc_->clocks())
|
||||
names.push_back(clk->name());
|
||||
|
||||
for (auto const &[name, group] : sdc_->groupPaths())
|
||||
names.push_back(name);
|
||||
|
||||
names.push_back(PathGroups::asyncPathGroupName());
|
||||
names.push_back(PathGroups::pathDelayGroupName());
|
||||
names.push_back(PathGroups::gatedClkGroupName());
|
||||
names.push_back(PathGroups::unconstrainedGroupName());
|
||||
return names;
|
||||
}
|
||||
|
||||
ExceptionFrom *
|
||||
|
|
@ -3004,13 +3030,78 @@ Sta::pinSlack(const Pin *pin,
|
|||
return slack;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class EndpointPathEndVisitor : public PathEndVisitor
|
||||
{
|
||||
public:
|
||||
EndpointPathEndVisitor(const std::string &path_group_name,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta);
|
||||
PathEndVisitor *copy() const;
|
||||
void visit(PathEnd *path_end);
|
||||
Slack slack() const { return slack_; }
|
||||
|
||||
private:
|
||||
const std::string &path_group_name_;
|
||||
const MinMax *min_max_;
|
||||
Slack slack_;
|
||||
const StaState *sta_;
|
||||
};
|
||||
|
||||
EndpointPathEndVisitor::EndpointPathEndVisitor(const std::string &path_group_name,
|
||||
const MinMax *min_max,
|
||||
const StaState *sta) :
|
||||
path_group_name_(path_group_name),
|
||||
min_max_(min_max),
|
||||
slack_(MinMax::min()->initValue()),
|
||||
sta_(sta)
|
||||
{
|
||||
}
|
||||
|
||||
PathEndVisitor *
|
||||
EndpointPathEndVisitor::copy() const
|
||||
{
|
||||
return new EndpointPathEndVisitor(path_group_name_, min_max_, sta_);
|
||||
}
|
||||
|
||||
void
|
||||
EndpointPathEndVisitor::visit(PathEnd *path_end)
|
||||
{
|
||||
if (path_end->minMax(sta_) == min_max_
|
||||
&& PathGroups::pathGroupName(path_end, sta_) == path_group_name_) {
|
||||
Slack end_slack = path_end->slack(sta_);
|
||||
if (delayLess(end_slack, slack_, sta_))
|
||||
slack_ = end_slack;
|
||||
}
|
||||
}
|
||||
|
||||
Slack
|
||||
Sta::endpointSlack(const Pin *pin,
|
||||
const std::string &path_group_name,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
ensureGraph();
|
||||
Vertex *vertex = graph_->pinLoadVertex(pin);
|
||||
if (vertex) {
|
||||
findRequired(vertex);
|
||||
VisitPathEnds visit_ends(this);
|
||||
EndpointPathEndVisitor path_end_visitor(path_group_name, min_max, this);
|
||||
visit_ends.visitPathEnds(vertex, &path_end_visitor);
|
||||
return path_end_visitor.slack();
|
||||
}
|
||||
else
|
||||
return INF;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
Slack
|
||||
Sta::vertexSlack(Vertex *vertex,
|
||||
const MinMax *min_max)
|
||||
{
|
||||
findRequired(vertex);
|
||||
const MinMax *min = MinMax::min();
|
||||
Slack slack = min->initValue();
|
||||
Slack slack = MinMax::min()->initValue();
|
||||
VertexPathIterator path_iter(vertex, this);
|
||||
while (path_iter.hasNext()) {
|
||||
Path *path = path_iter.next();
|
||||
|
|
@ -3200,48 +3291,8 @@ Sta::findRequired(Vertex *vertex)
|
|||
// Need to include downstream required times if there is fanout.
|
||||
&& !hasFanout(vertex, search_->searchAdj(), graph_))
|
||||
search_->seedRequired(vertex);
|
||||
else {
|
||||
else
|
||||
search_->findRequireds(vertex->level());
|
||||
if (variables_->crprEnabled()
|
||||
&& search_->crprPathPruningEnabled()
|
||||
&& !search_->crprApproxMissingRequireds()
|
||||
// Clocks invariably have requireds that are pruned but it isn't
|
||||
// worth finding arrivals and requireds all over again for
|
||||
// the entire fanout of the clock.
|
||||
&& !search_->isClock(vertex)) {
|
||||
// Invalidate arrivals and requireds and disable
|
||||
// path pruning on fanout vertices with DFS.
|
||||
int fanout = 0;
|
||||
disableFanoutCrprPruning(vertex, fanout);
|
||||
debugPrint(debug_, "search", 1, "resurrect pruned required %s fanout %d",
|
||||
vertex->to_string(this).c_str(),
|
||||
fanout);
|
||||
// Find fanout arrivals and requireds with pruning disabled.
|
||||
search_->findArrivals();
|
||||
search_->findRequireds(vertex->level());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Sta::disableFanoutCrprPruning(Vertex *vertex,
|
||||
int &fanout)
|
||||
{
|
||||
if (!vertex->crprPathPruningDisabled()) {
|
||||
search_->arrivalInvalid(vertex);
|
||||
search_->requiredInvalid(vertex);
|
||||
vertex->setCrprPathPruningDisabled(true);
|
||||
fanout++;
|
||||
SearchPred *pred = search_->searchAdj();
|
||||
VertexOutEdgeIterator edge_iter(vertex, graph_);
|
||||
while (edge_iter.hasNext()) {
|
||||
Edge *edge = edge_iter.next();
|
||||
Vertex *to_vertex = edge->to(graph_);
|
||||
if (pred->searchThru(edge)
|
||||
&& pred->searchTo(to_vertex))
|
||||
disableFanoutCrprPruning(to_vertex, fanout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Slack
|
||||
|
|
|
|||
|
|
@ -322,6 +322,16 @@ using namespace sta;
|
|||
Tcl_SetObjResult(interp, list);
|
||||
}
|
||||
|
||||
%typemap(out) StdStringSeq {
|
||||
StdStringSeq &strs = $1;
|
||||
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
||||
for (const std::string &str : strs) {
|
||||
Tcl_Obj *obj = Tcl_NewStringObj(str.c_str(), str.size());
|
||||
Tcl_ListObjAppendElement(interp, list, obj);
|
||||
}
|
||||
Tcl_SetObjResult(interp, list);
|
||||
}
|
||||
|
||||
%typemap(out) Library* {
|
||||
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
||||
Tcl_SetObjResult(interp, obj);
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
Initial path groups:
|
||||
Final path groups: In2Out In2Reg Reg2Out Reg2Reg
|
||||
Initial path groups: clk asynchronous {path delay} {gated clock} unconstrained
|
||||
Final path groups: clk In2Out In2Reg Reg2Out Reg2Reg asynchronous {path delay} {gated clock} unconstrained
|
||||
|
|
|
|||
Loading…
Reference in New Issue