report paths in multiple matching groups resolves ascenium #145

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2025-10-30 08:53:36 -07:00
parent de0f5440a6
commit 98d801d7a6
14 changed files with 215 additions and 107 deletions

View File

@ -68,7 +68,7 @@ public:
path_delay path_delay
}; };
virtual PathEnd *copy() = 0; virtual PathEnd *copy() const = 0;
virtual ~PathEnd(); virtual ~PathEnd();
void deletePath(); void deletePath();
Path *path() { return path_; } Path *path() { return path_; }
@ -84,6 +84,8 @@ public:
PathAPIndex pathIndex(const StaState *sta) const; PathAPIndex pathIndex(const StaState *sta) const;
virtual void reportShort(const ReportPath *report) const = 0; virtual void reportShort(const ReportPath *report) const = 0;
virtual void reportFull(const ReportPath *report) const = 0; virtual void reportFull(const ReportPath *report) const = 0;
PathGroup *pathGroup() const { return path_group_; }
void setPathGroup(PathGroup *path_group);
// Predicates for PathEnd type. // Predicates for PathEnd type.
// Default methods overridden by respective types. // Default methods overridden by respective types.
@ -216,6 +218,7 @@ protected:
PathDelay *path_delay, PathDelay *path_delay,
const StaState *sta); const StaState *sta);
Path *path_; Path *path_;
PathGroup *path_group_;
}; };
class PathEndUnconstrained : public PathEnd class PathEndUnconstrained : public PathEnd
@ -224,7 +227,7 @@ public:
explicit PathEndUnconstrained(Path *path); explicit PathEndUnconstrained(Path *path);
virtual Type type() const; virtual Type type() const;
virtual const char *typeName() const; virtual const char *typeName() const;
virtual PathEnd *copy(); virtual PathEnd *copy() const;
virtual void reportShort(const ReportPath *report) const; virtual void reportShort(const ReportPath *report) const;
virtual void reportFull(const ReportPath *report) const; virtual void reportFull(const ReportPath *report) const;
virtual bool isUnconstrained() const; virtual bool isUnconstrained() const;
@ -321,7 +324,7 @@ public:
Path *clk_path, Path *clk_path,
MultiCyclePath *mcp, MultiCyclePath *mcp,
const StaState *sta); const StaState *sta);
virtual PathEnd *copy(); virtual PathEnd *copy() const;
virtual Type type() const; virtual Type type() const;
virtual const char *typeName() const; virtual const char *typeName() const;
virtual void reportShort(const ReportPath *report) const; virtual void reportShort(const ReportPath *report) const;
@ -367,7 +370,7 @@ public:
virtual bool isCheck() const { return false; } virtual bool isCheck() const { return false; }
virtual bool isLatchCheck() const { return true; } virtual bool isLatchCheck() const { return true; }
virtual PathDelay *pathDelay() const { return path_delay_; } virtual PathDelay *pathDelay() const { return path_delay_; }
virtual PathEnd *copy(); virtual PathEnd *copy() const;
Path *latchDisable(); Path *latchDisable();
const Path *latchDisable() const; const Path *latchDisable() const;
virtual void reportShort(const ReportPath *report) const; virtual void reportShort(const ReportPath *report) const;
@ -428,7 +431,7 @@ public:
Path *clk_path, Path *clk_path,
MultiCyclePath *mcp, MultiCyclePath *mcp,
const StaState *sta); const StaState *sta);
virtual PathEnd *copy(); virtual PathEnd *copy() const;
virtual Type type() const; virtual Type type() const;
virtual const char *typeName() const; virtual const char *typeName() const;
virtual void reportShort(const ReportPath *report) const; virtual void reportShort(const ReportPath *report) const;
@ -474,7 +477,7 @@ public:
MultiCyclePath *mcp, MultiCyclePath *mcp,
ArcDelay margin, ArcDelay margin,
const StaState *sta); const StaState *sta);
virtual PathEnd *copy(); virtual PathEnd *copy() const;
virtual Type type() const; virtual Type type() const;
virtual const char *typeName() const; virtual const char *typeName() const;
virtual void reportShort(const ReportPath *report) const; virtual void reportShort(const ReportPath *report) const;
@ -506,7 +509,7 @@ public:
Path *data_clk_path, Path *data_clk_path,
MultiCyclePath *mcp, MultiCyclePath *mcp,
const StaState *sta); const StaState *sta);
virtual PathEnd *copy(); virtual PathEnd *copy() const;
virtual Type type() const; virtual Type type() const;
virtual const char *typeName() const; virtual const char *typeName() const;
virtual void reportShort(const ReportPath *report) const; virtual void reportShort(const ReportPath *report) const;
@ -560,7 +563,7 @@ public:
Path *path, Path *path,
OutputDelay *output_delay, OutputDelay *output_delay,
const StaState *sta); const StaState *sta);
virtual PathEnd *copy(); virtual PathEnd *copy() const;
virtual Type type() const; virtual Type type() const;
virtual const char *typeName() const; virtual const char *typeName() const;
virtual void reportShort(const ReportPath *report) const; virtual void reportShort(const ReportPath *report) const;

View File

@ -40,6 +40,8 @@ class PathEndVisitor;
typedef PathEndSeq::Iterator PathGroupIterator; typedef PathEndSeq::Iterator PathGroupIterator;
typedef Map<const Clock*, PathGroup*> PathGroupClkMap; typedef Map<const Clock*, PathGroup*> PathGroupClkMap;
typedef Map<const char*, PathGroup*, CharPtrLess> PathGroupNamedMap; typedef Map<const char*, PathGroup*, CharPtrLess> PathGroupNamedMap;
typedef std::vector<PathGroup*> PathGroupSeq;
typedef std::vector<std::string> StdStringSeq;
// A collection of PathEnds grouped and sorted for reporting. // A collection of PathEnds grouped and sorted for reporting.
class PathGroup class PathGroup
@ -133,9 +135,9 @@ public:
const MinMax *min_max) const; const MinMax *min_max) const;
PathGroup *findPathGroup(const Clock *clock, PathGroup *findPathGroup(const Clock *clock,
const MinMax *min_max) const; const MinMax *min_max) const;
PathGroup *pathGroup(const PathEnd *path_end) const; PathGroupSeq pathGroups(const PathEnd *path_end) const;
static std::string pathGroupName(const PathEnd *path_end, static StdStringSeq pathGroupNames(const PathEnd *path_end,
const StaState *sta); const StaState *sta);
static const char *asyncPathGroupName() { return async_group_name_; } static const char *asyncPathGroupName() { return async_group_name_; }
static const char *pathDelayGroupName() { return path_delay_group_name_; } static const char *pathDelayGroupName() { return path_delay_group_name_; }
static const char *gatedClkGroupName() { return gated_clk_group_name_; } static const char *gatedClkGroupName() { return gated_clk_group_name_; }
@ -179,8 +181,6 @@ protected:
const MinMax *min_max); const MinMax *min_max);
bool reportGroup(const char *group_name, bool reportGroup(const char *group_name,
PathGroupNameSet *group_names) const; PathGroupNameSet *group_names) const;
static GroupPath *groupPathTo(const PathEnd *path_end,
const StaState *sta);
int group_path_count_; int group_path_count_;
int endpoint_path_count_; int endpoint_path_count_;

View File

@ -996,6 +996,12 @@ public:
const MinMax *min_max, const MinMax *min_max,
bool match_min_max_exactly, bool match_min_max_exactly,
bool require_to_pin) const; bool require_to_pin) const;
void groupPathsTo(const Pin *pin,
const RiseFall *rf,
const ClockEdge *clk_edge,
const MinMax *min_max,
// Return value.
ExceptionPathSeq &group_paths) const;
bool isCompleteTo(ExceptionState *state, bool isCompleteTo(ExceptionState *state,
const Pin *pin, const Pin *pin,
const RiseFall *rf, const RiseFall *rf,
@ -1164,6 +1170,13 @@ protected:
// Return values. // Return values.
ExceptionPath *&hi_priority_exception, ExceptionPath *&hi_priority_exception,
int &hi_priority) const; int &hi_priority) const;
void groupPathsTo(const ExceptionPathSet *to_exceptions,
const Pin *pin,
const RiseFall *rf,
const ClockEdge *clk_edge,
const MinMax *min_max,
// Return value.
ExceptionPathSeq &group_paths) const;
void makeLoopPath(ExceptionThruSeq *thrus); void makeLoopPath(ExceptionThruSeq *thrus);
void makeLoopException(const Pin *loop_input_pin, void makeLoopException(const Pin *loop_input_pin,
const Pin *loop_pin, const Pin *loop_pin,

View File

@ -71,6 +71,8 @@ typedef Map<Vertex*, Slack> VertexSlackMap;
typedef Vector<VertexSlackMap> VertexSlackMapSeq; typedef Vector<VertexSlackMap> VertexSlackMapSeq;
typedef Vector<WorstSlacks> WorstSlacksSeq; typedef Vector<WorstSlacks> WorstSlacksSeq;
typedef std::vector<DelayDbl> DelayDblSeq; typedef std::vector<DelayDbl> DelayDblSeq;
typedef Vector<ExceptionPath*> ExceptionPathSeq;
typedef std::vector<PathGroup*> PathGroupSeq;
class Search : public StaState class Search : public StaState
{ {
@ -165,7 +167,7 @@ public:
// Clock arrival at the path source/launch point. // Clock arrival at the path source/launch point.
Arrival pathClkPathArrival(const Path *path) const; Arrival pathClkPathArrival(const Path *path) const;
PathGroup *pathGroup(const PathEnd *path_end) const; PathGroupSeq pathGroups(const PathEnd *path_end) const;
void deletePathGroups(); void deletePathGroups();
void makePathGroups(int group_path_count, void makePathGroups(int group_path_count,
int endpoint_path_count, int endpoint_path_count,
@ -187,6 +189,7 @@ public:
const MinMax *min_max, const MinMax *min_max,
bool match_min_max_exactly, bool match_min_max_exactly,
bool require_to_pin) const; bool require_to_pin) const;
ExceptionPathSeq groupPathsTo(const PathEnd *path_end) const;
FilterPath *filter() const { return filter_; } FilterPath *filter() const { return filter_; }
void deleteFilter(); void deleteFilter();
void deleteFilteredArrivals(); void deleteFilteredArrivals();

View File

@ -5362,6 +5362,8 @@ Sdc::exceptionThruStates(const ExceptionPathSet *exceptions,
} }
} }
////////////////////////////////////////////////////////////////
void void
Sdc::exceptionTo(ExceptionPathType type, Sdc::exceptionTo(ExceptionPathType type,
const Pin *pin, const Pin *pin,
@ -5484,6 +5486,47 @@ Sdc::isCompleteTo(ExceptionState *state,
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
void
Sdc::groupPathsTo(const Pin *pin,
const RiseFall *rf,
const ClockEdge *clk_edge,
const MinMax *min_max,
// Return value.
ExceptionPathSeq &group_paths) const
{
if (!first_to_inst_exceptions_.empty()) {
Instance *inst = network_->instance(pin);
groupPathsTo(first_to_inst_exceptions_.findKey(inst), pin, rf,
clk_edge, min_max, group_paths);
}
if (!first_to_pin_exceptions_.empty())
groupPathsTo(first_to_pin_exceptions_.findKey(pin), pin, rf,
clk_edge, min_max, group_paths);
if (clk_edge && !first_to_clk_exceptions_.empty())
groupPathsTo(first_to_clk_exceptions_.findKey(clk_edge->clock()),
pin, rf, clk_edge, min_max, group_paths);
}
void
Sdc::groupPathsTo(const ExceptionPathSet *to_exceptions,
const Pin *pin,
const RiseFall *rf,
const ClockEdge *clk_edge,
const MinMax *min_max,
// Return value.
ExceptionPathSeq &group_paths) const
{
if (to_exceptions) {
for (ExceptionPath *exception : *to_exceptions) {
if (exception->isGroupPath()
&& exceptionMatchesTo(exception, pin, rf, clk_edge, min_max, true, false))
group_paths.push_back(exception);
}
}
}
////////////////////////////////////////////////////////////////
Wireload * Wireload *
Sdc::wireload(const MinMax *min_max) Sdc::wireload(const MinMax *min_max)
{ {

View File

@ -306,7 +306,7 @@ Path::isClock(const StaState *sta) const
const MinMax * const MinMax *
Path::minMax(const StaState *sta) const Path::minMax(const StaState *sta) const
{ {
return pathAnalysisPt(sta)->pathMinMax(); return tag(sta)->minMax(sta);
} }
PathAPIndex PathAPIndex

View File

@ -49,7 +49,8 @@
namespace sta { namespace sta {
PathEnd::PathEnd(Path *path) : PathEnd::PathEnd(Path *path) :
path_(path) path_(path),
path_group_(nullptr)
{ {
} }
@ -65,6 +66,12 @@ PathEnd::setPath(Path *path)
path_ = path; path_ = path;
} }
void
PathEnd::setPathGroup(PathGroup *path_group)
{
path_group_ = path_group;
}
Vertex * Vertex *
PathEnd::vertex(const StaState *sta) const PathEnd::vertex(const StaState *sta) const
{ {
@ -454,7 +461,7 @@ PathEndUnconstrained::PathEndUnconstrained(Path *path) :
} }
PathEnd * PathEnd *
PathEndUnconstrained::copy() PathEndUnconstrained::copy() const
{ {
return new PathEndUnconstrained(path_); return new PathEndUnconstrained(path_);
} }
@ -955,7 +962,7 @@ PathEndCheck::PathEndCheck(Path *path,
} }
PathEnd * PathEnd *
PathEndCheck::copy() PathEndCheck::copy() const
{ {
return new PathEndCheck(path_, check_arc_, check_edge_, return new PathEndCheck(path_, check_arc_, check_edge_,
clk_path_, mcp_, crpr_, crpr_valid_); clk_path_, mcp_, crpr_, crpr_valid_);
@ -1126,7 +1133,7 @@ PathEndLatchCheck::PathEndLatchCheck(Path *path,
} }
PathEnd * PathEnd *
PathEndLatchCheck::copy() PathEndLatchCheck::copy() const
{ {
return new PathEndLatchCheck(path_, check_arc_, check_edge_, return new PathEndLatchCheck(path_, check_arc_, check_edge_,
clk_path_, disable_path_, mcp_, path_delay_, clk_path_, disable_path_, mcp_, path_delay_,
@ -1346,7 +1353,7 @@ PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
} }
PathEnd * PathEnd *
PathEndOutputDelay::copy() PathEndOutputDelay::copy() const
{ {
return new PathEndOutputDelay(output_delay_, path_, clk_path_, return new PathEndOutputDelay(output_delay_, path_, clk_path_,
mcp_, crpr_, crpr_valid_); mcp_, crpr_, crpr_valid_);
@ -1552,7 +1559,7 @@ PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
} }
PathEnd * PathEnd *
PathEndGatedClock::copy() PathEndGatedClock::copy() const
{ {
return new PathEndGatedClock(path_, clk_path_, check_role_, return new PathEndGatedClock(path_, clk_path_, check_role_,
mcp_, margin_, crpr_, crpr_valid_); mcp_, margin_, crpr_, crpr_valid_);
@ -1668,7 +1675,7 @@ PathEndDataCheck::PathEndDataCheck(DataCheck *check,
} }
PathEnd * PathEnd *
PathEndDataCheck::copy() PathEndDataCheck::copy() const
{ {
return new PathEndDataCheck(check_, path_, data_clk_path_, return new PathEndDataCheck(check_, path_, data_clk_path_,
clk_path_, mcp_, crpr_, crpr_valid_); clk_path_, mcp_, crpr_, crpr_valid_);
@ -1825,7 +1832,7 @@ PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
} }
PathEnd * PathEnd *
PathEndPathDelay::copy() PathEndPathDelay::copy() const
{ {
return new PathEndPathDelay(path_delay_, path_, clk_path_, return new PathEndPathDelay(path_delay_, path_, clk_path_,
check_arc_, check_edge_, output_delay_, check_arc_, check_edge_, output_delay_,

View File

@ -168,6 +168,7 @@ PathGroup::insert(PathEnd *path_end)
{ {
LockGuard lock(lock_); LockGuard lock(lock_);
path_ends_.push_back(path_end); path_ends_.push_back(path_end);
path_end->setPathGroup(this);
if (group_path_count_ != group_path_count_max if (group_path_count_ != group_path_count_max
&& path_ends_.size() > group_path_count_ * 2) && path_ends_.size() > group_path_count_ * 2)
prune(); prune();
@ -398,37 +399,43 @@ PathGroups::reportGroup(const char *group_name,
|| group_names->hasKey(group_name); || group_names->hasKey(group_name);
} }
PathGroup * PathGroupSeq
PathGroups::pathGroup(const PathEnd *path_end) const PathGroups::pathGroups(const PathEnd *path_end) const
{ {
PathGroupSeq path_groups;
PathGroup *path_group = nullptr;
ExceptionPathSeq group_paths = search_->groupPathsTo(path_end);
const MinMax *min_max = path_end->minMax(this); const MinMax *min_max = path_end->minMax(this);
int mm_index = min_max->index(); int mm_index = min_max->index();
GroupPath *group_path = groupPathTo(path_end, this);
if (path_end->isUnconstrained()) if (path_end->isUnconstrained())
return unconstrained_[mm_index]; path_group = unconstrained_[mm_index];
// GroupPaths have precedence. // GroupPaths have precedence.
else if (group_path) { else if (!group_paths.empty()) {
if (group_path->isDefault()) for (ExceptionPath *group_path : group_paths) {
return path_delay_[mm_index]; if (group_path->isDefault())
else { path_groups.push_back(path_delay_[mm_index]);
const char *group_name = group_path->name(); else {
return findPathGroup(group_name, min_max); const char *group_name = group_path->name();
} PathGroup *group = findPathGroup(group_name, min_max);
if (group)
path_groups.push_back(group);
}
}
} }
else if (path_end->isCheck() || path_end->isLatchCheck()) { else if (path_end->isCheck() || path_end->isLatchCheck()) {
const TimingRole *check_role = path_end->checkRole(this); const TimingRole *check_role = path_end->checkRole(this);
const Clock *tgt_clk = path_end->targetClk(this); const Clock *tgt_clk = path_end->targetClk(this);
if (check_role == TimingRole::removal() if (check_role == TimingRole::removal()
|| check_role == TimingRole::recovery()) || check_role == TimingRole::recovery())
return async_[mm_index]; path_group = async_[mm_index];
else else
return findPathGroup(tgt_clk, min_max); path_group = findPathGroup(tgt_clk, min_max);
} }
else if (path_end->isOutputDelay() else if (path_end->isOutputDelay()
|| path_end->isDataCheck()) || path_end->isDataCheck())
return findPathGroup(path_end->targetClk(this), min_max); path_group = findPathGroup(path_end->targetClk(this), min_max);
else if (path_end->isGatedClock()) else if (path_end->isGatedClock())
return gated_clk_[mm_index]; path_group = gated_clk_[mm_index];
else if (path_end->isPathDelay()) { else if (path_end->isPathDelay()) {
// Path delays that end at timing checks are part of the target clk group // Path delays that end at timing checks are part of the target clk group
// unless -ignore_clock_latency is true. // unless -ignore_clock_latency is true.
@ -436,45 +443,52 @@ PathGroups::pathGroup(const PathEnd *path_end) const
const Clock *tgt_clk = path_end->targetClk(this); const Clock *tgt_clk = path_end->targetClk(this);
if (tgt_clk if (tgt_clk
&& !path_delay->ignoreClkLatency()) && !path_delay->ignoreClkLatency())
return findPathGroup(tgt_clk, min_max); path_group = findPathGroup(tgt_clk, min_max);
else else
return path_delay_[mm_index]; path_group = path_delay_[mm_index];
}
else {
report_->critical(1390, "unknown path end type");
return nullptr;
} }
if (path_group)
path_groups.push_back(path_group);
return path_groups;
} }
// Mirrors PathGroups::pathGroup. // Mirrors PathGroups::pathGroup.
std::string StdStringSeq
PathGroups::pathGroupName(const PathEnd *path_end, PathGroups::pathGroupNames(const PathEnd *path_end,
const StaState *sta) const StaState *sta)
{ {
GroupPath *group_path = groupPathTo(path_end, sta); StdStringSeq group_names;
const char *group_name = nullptr;
const Search *search = sta->search();
ExceptionPathSeq group_paths = search->groupPathsTo(path_end);
if (path_end->isUnconstrained()) if (path_end->isUnconstrained())
return unconstrained_group_name_; group_name = unconstrained_group_name_;
// GroupPaths have precedence. else if (!group_paths.empty()) {
else if (group_path) { // GroupPaths have precedence.
if (group_path->isDefault()) for (ExceptionPath *group_path : group_paths) {
return path_delay_group_name_; if (group_path->isDefault())
else group_names.push_back(path_delay_group_name_);
return group_path->name(); else
group_names.push_back(group_path->name());
}
} }
else if (path_end->isCheck() || path_end->isLatchCheck()) { else if (path_end->isCheck() || path_end->isLatchCheck()) {
const TimingRole *check_role = path_end->checkRole(sta); const TimingRole *check_role = path_end->checkRole(sta);
const Clock *tgt_clk = path_end->targetClk(sta); const Clock *tgt_clk = path_end->targetClk(sta);
if (check_role == TimingRole::removal() if (check_role == TimingRole::removal()
|| check_role == TimingRole::recovery()) || check_role == TimingRole::recovery())
return async_group_name_; group_name = async_group_name_;
else else
return tgt_clk->name(); group_name = tgt_clk->name();
} }
else if (path_end->isOutputDelay() else if (path_end->isOutputDelay()
|| path_end->isDataCheck()) || path_end->isDataCheck()) {
return path_end->targetClk(sta)->name(); const Clock *tgt_clk = path_end->targetClk(sta);
if (tgt_clk)
group_name = tgt_clk->name();
}
else if (path_end->isGatedClock()) else if (path_end->isGatedClock())
return gated_clk_group_name_; group_name = gated_clk_group_name_;
else if (path_end->isPathDelay()) { else if (path_end->isPathDelay()) {
// Path delays that end at timing checks are part of the target clk group // Path delays that end at timing checks are part of the target clk group
// unless -ignore_clock_latency is true. // unless -ignore_clock_latency is true.
@ -482,28 +496,13 @@ PathGroups::pathGroupName(const PathEnd *path_end,
const Clock *tgt_clk = path_end->targetClk(sta); const Clock *tgt_clk = path_end->targetClk(sta);
if (tgt_clk if (tgt_clk
&& !path_delay->ignoreClkLatency()) && !path_delay->ignoreClkLatency())
return tgt_clk->name(); group_name = tgt_clk->name();
else else
return path_delay_group_name_; group_name = path_delay_group_name_;
} }
else { if (group_name)
sta->report()->critical(1391, "unknown path end type"); group_names.push_back(group_name);
return nullptr; return group_names;
}
}
GroupPath *
PathGroups::groupPathTo(const PathEnd *path_end,
const StaState *sta)
{
const Path *path = path_end->path();
const Pin *pin = path->pin(sta);
ExceptionPath *exception =
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);
} }
void void
@ -632,8 +631,7 @@ MakePathEnds1::copy() const
void void
MakePathEnds1::visit(PathEnd *path_end) MakePathEnds1::visit(PathEnd *path_end)
{ {
PathGroup *group = path_groups_->pathGroup(path_end); for (PathGroup *group : path_groups_->pathGroups(path_end))
if (group)
visitPathEnd(path_end, group); visitPathEnd(path_end, group);
} }
@ -644,14 +642,15 @@ MakePathEnds1::visitPathEnd(PathEnd *path_end,
if (group->saveable(path_end)) { if (group->saveable(path_end)) {
// Only keep the path end with the smallest slack/latest arrival. // Only keep the path end with the smallest slack/latest arrival.
PathEnd *worst_end = ends_.findKey(group); PathEnd *worst_end = ends_.findKey(group);
PathEnd *copy = path_end->copy();
if (worst_end) { if (worst_end) {
if (cmp_(path_end, worst_end)) { if (cmp_(path_end, worst_end)) {
ends_[group] = path_end->copy(); ends_[group] = copy;
delete worst_end; delete worst_end;
} }
} }
else else
ends_[group] = path_end->copy(); ends_[group] = copy;
} }
} }
@ -732,8 +731,7 @@ MakePathEndsAll::~MakePathEndsAll()
void void
MakePathEndsAll::visit(PathEnd *path_end) MakePathEndsAll::visit(PathEnd *path_end)
{ {
PathGroup *group = path_groups_->pathGroup(path_end); for (PathGroup *group : path_groups_->pathGroups(path_end))
if (group)
visitPathEnd(path_end, group); visitPathEnd(path_end, group);
} }

View File

@ -401,8 +401,8 @@ ReportPath::reportEndpointHeader(const PathEnd *end,
{ {
PathGroup *prev_group = nullptr; PathGroup *prev_group = nullptr;
if (prev_end) if (prev_end)
prev_group = search_->pathGroup(prev_end); prev_group = prev_end->pathGroup();
PathGroup *group = search_->pathGroup(end); PathGroup *group = end->pathGroup();
if (group && group != prev_group) { if (group && group != prev_group) {
if (prev_group) if (prev_group)
reportBlankLine(); reportBlankLine();
@ -1086,7 +1086,7 @@ ReportPath::reportJson(const PathEnd *end,
result += "{\n"; result += "{\n";
stringAppend(result, " \"type\": \"%s\",\n", end->typeName()); stringAppend(result, " \"type\": \"%s\",\n", end->typeName());
stringAppend(result, " \"path_group\": \"%s\",\n", stringAppend(result, " \"path_group\": \"%s\",\n",
search_->pathGroup(end)->name()); end->pathGroup()->name());
stringAppend(result, " \"path_type\": \"%s\",\n", stringAppend(result, " \"path_type\": \"%s\",\n",
end->minMax(this)->to_string().c_str()); end->minMax(this)->to_string().c_str());
@ -1273,7 +1273,7 @@ ReportPath::reportSlackOnly(const PathEnd *end) const
{ {
string line; string line;
const EarlyLate *early_late = end->pathEarlyLate(this); const EarlyLate *early_late = end->pathEarlyLate(this);
reportDescription(search_->pathGroup(end)->name(), line); reportDescription(end->pathGroup()->name(), line);
if (end->isUnconstrained()) if (end->isUnconstrained())
reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line); reportSpaceFieldDelay(end->dataArrivalTimeOffset(this), early_late, line);
else else
@ -1939,7 +1939,7 @@ ReportPath::reportGroup(const PathEnd *end) const
{ {
string line; string line;
line = "Path Group: "; line = "Path Group: ";
PathGroup *group = search_->pathGroup(end); PathGroup *group = end->pathGroup();
line += group ? group->name() : "(none)"; line += group ? group->name() : "(none)";
report_->reportLineString(line); report_->reportLineString(line);

View File

@ -3767,6 +3767,34 @@ Search::exceptionTo(ExceptionPathType type,
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// Find group paths that end at the path.
ExceptionPathSeq
Search::groupPathsTo(const PathEnd *path_end) const
{
ExceptionPathSeq group_paths;
const Path *path = path_end->path();
const Pin *pin = path->pin(this);
const Tag *tag = path->tag(this);
const RiseFall *rf = tag->transition();
const ClockEdge *clk_edge = path_end->targetClkEdge(this);
const MinMax *min_max = tag->minMax(this);
const ExceptionStateSet *states = path->tag(this)->states();
if (states) {
for (auto state : *states) {
ExceptionPath *exception = state->exception();
if (exception->isGroupPath()
&& sdc_->exceptionMatchesTo(exception, pin, rf, clk_edge, min_max,
false, false))
group_paths.push_back(exception);
}
}
// Check for group_path -to exceptions originating at the end pin or target clock.
sdc_->groupPathsTo(pin, rf, clk_edge, min_max, group_paths);
return group_paths;
}
////////////////////////////////////////////////////////////////
Slack Slack
Search::totalNegativeSlack(const MinMax *min_max) Search::totalNegativeSlack(const MinMax *min_max)
{ {
@ -4095,13 +4123,13 @@ Search::deletePathGroups()
path_groups_ = nullptr; path_groups_ = nullptr;
} }
PathGroup * PathGroupSeq
Search::pathGroup(const PathEnd *path_end) const Search::pathGroups(const PathEnd *path_end) const
{ {
if (path_groups_) if (path_groups_)
return path_groups_->pathGroup(path_end); return path_groups_->pathGroups(path_end);
else else
return nullptr; return PathGroupSeq();
} }
bool bool

View File

@ -3068,11 +3068,15 @@ EndpointPathEndVisitor::copy() const
void void
EndpointPathEndVisitor::visit(PathEnd *path_end) EndpointPathEndVisitor::visit(PathEnd *path_end)
{ {
if (path_end->minMax(sta_) == min_max_ if (path_end->minMax(sta_) == min_max_) {
&& PathGroups::pathGroupName(path_end, sta_) == path_group_name_) { StdStringSeq group_names = PathGroups::pathGroupNames(path_end, sta_);
Slack end_slack = path_end->slack(sta_); for (std::string &group_name : group_names) {
if (delayLess(end_slack, slack_, sta_)) if (group_name == path_group_name_) {
slack_ = end_slack; Slack end_slack = path_end->slack(sta_);
if (delayLess(end_slack, slack_, sta_))
slack_ = end_slack;
}
}
} }
} }

View File

@ -181,6 +181,12 @@ Tag::transition() const
return RiseFall::find(rf_index_); return RiseFall::find(rf_index_);
} }
const MinMax *
Tag::minMax(const StaState *sta) const
{
return pathAnalysisPt(sta)->pathMinMax();
}
PathAnalysisPt * PathAnalysisPt *
Tag::pathAnalysisPt(const StaState *sta) const Tag::pathAnalysisPt(const StaState *sta) const
{ {

View File

@ -73,6 +73,7 @@ public:
const Pin *clkSrc() const; const Pin *clkSrc() const;
int rfIndex() const { return rf_index_; } int rfIndex() const { return rf_index_; }
const RiseFall *transition() const; const RiseFall *transition() const;
const MinMax *minMax(const StaState *sta) const;
PathAnalysisPt *pathAnalysisPt(const StaState *sta) const; PathAnalysisPt *pathAnalysisPt(const StaState *sta) const;
PathAPIndex pathAPIndex() const { return path_ap_index_; } PathAPIndex pathAPIndex() const { return path_ap_index_; }
TagIndex index() const { return index_; } TagIndex index() const { return index_; }

View File

@ -177,12 +177,14 @@ VisitPathGroupEnds::vertexBegin(Vertex *)
void void
VisitPathGroupEnds::visit(PathEnd *path_end) VisitPathGroupEnds::visit(PathEnd *path_end)
{ {
PathGroup *group = sta_->search()->pathGroup(path_end); PathGroupSeq groups = sta_->search()->pathGroups(path_end);
if (group == path_group_) { for (PathGroup *group : groups) {
Path *path = path_end->path(); if (group == path_group_) {
Vertex *vertex = path->vertex(sta_); Path *path = path_end->path();
vertexPathSetMapInsertPath(matching_path_map_, vertex, path->tag(sta_), sta_); Vertex *vertex = path->vertex(sta_);
vertex_matches_ = true; vertexPathSetMapInsertPath(matching_path_map_, vertex, path->tag(sta_), sta_);
vertex_matches_ = true;
}
} }
} }