report paths in multiple matching groups resolves ascenium #145
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
de0f5440a6
commit
98d801d7a6
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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_;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
43
sdc/Sdc.cc
43
sdc/Sdc.cc
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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_,
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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_; }
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue