Sta::endpointSlack
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
6e29fcb3f0
commit
525c2efb3d
|
|
@ -107,6 +107,7 @@ protected:
|
||||||
class PathGroups : public StaState
|
class PathGroups : public StaState
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
PathGroups(const StaState *sta);
|
||||||
PathGroups(int group_path_count,
|
PathGroups(int group_path_count,
|
||||||
int endpoint_path_count,
|
int endpoint_path_count,
|
||||||
bool unique_pins,
|
bool unique_pins,
|
||||||
|
|
@ -134,8 +135,10 @@ public:
|
||||||
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;
|
PathGroup *pathGroup(const PathEnd *path_end) const;
|
||||||
static bool isGroupPathName(const char *group_name);
|
|
||||||
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 *gatedClkGroupName() { return gated_clk_group_name_; }
|
||||||
|
static const char *unconstrainedGroupName() { return unconstrained_group_name_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void makeGroupPathEnds(ExceptionTo *to,
|
void makeGroupPathEnds(ExceptionTo *to,
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ typedef InstanceSeq::Iterator SlowDrvrIterator;
|
||||||
typedef Vector<const char*> CheckError;
|
typedef Vector<const char*> CheckError;
|
||||||
typedef Vector<CheckError*> CheckErrorSeq;
|
typedef Vector<CheckError*> CheckErrorSeq;
|
||||||
typedef Vector<Corner*> CornerSeq;
|
typedef Vector<Corner*> CornerSeq;
|
||||||
|
typedef std::vector<std::string> StdStringSeq;
|
||||||
|
|
||||||
enum class CmdNamespace { sta, sdc };
|
enum class CmdNamespace { sta, sdc };
|
||||||
|
|
||||||
|
|
@ -516,7 +517,10 @@ public:
|
||||||
ExceptionThruSeq *thrus,
|
ExceptionThruSeq *thrus,
|
||||||
ExceptionTo *to,
|
ExceptionTo *to,
|
||||||
const char *comment);
|
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,
|
void resetPath(ExceptionFrom *from,
|
||||||
ExceptionThruSeq *thrus,
|
ExceptionThruSeq *thrus,
|
||||||
ExceptionTo *to,
|
ExceptionTo *to,
|
||||||
|
|
@ -1002,6 +1006,10 @@ public:
|
||||||
const MinMax *min_max);
|
const MinMax *min_max);
|
||||||
Slack pinSlack(const Pin *pin,
|
Slack pinSlack(const Pin *pin,
|
||||||
const MinMax *min_max);
|
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,
|
Slack vertexSlack(Vertex *vertex,
|
||||||
const MinMax *min_max);
|
const MinMax *min_max);
|
||||||
Slack vertexSlack(Vertex *vertex,
|
Slack vertexSlack(Vertex *vertex,
|
||||||
|
|
|
||||||
|
|
@ -734,7 +734,7 @@ make_group_path(const char *name,
|
||||||
bool
|
bool
|
||||||
is_path_group_name(const char *name)
|
is_path_group_name(const char *name)
|
||||||
{
|
{
|
||||||
return Sta::sta()->isGroupPathName(name);
|
return Sta::sta()->isPathGroupName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExceptionFrom *
|
ExceptionFrom *
|
||||||
|
|
@ -863,7 +863,7 @@ set_clock_sense_cmd(PinSet *pins,
|
||||||
else if (stop_propagation)
|
else if (stop_propagation)
|
||||||
sta->setClockSense(pins, clks, ClockSense::stop);
|
sta->setClockSense(pins, clks, ClockSense::stop);
|
||||||
else
|
else
|
||||||
sta->report()->critical(1577, "unknown clock sense");
|
sta->report()->critical(2123, "unknown clock sense");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1328,7 +1328,7 @@ filter_timing_arcs(const char *property,
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
StringSeq
|
StringSeq
|
||||||
path_group_names()
|
group_path_names()
|
||||||
{
|
{
|
||||||
StringSeq pg_names;
|
StringSeq pg_names;
|
||||||
for (auto const& [name, group] : Sta::sta()->sdc()->groupPaths())
|
for (auto const& [name, group] : Sta::sta()->sdc()->groupPaths())
|
||||||
|
|
|
||||||
|
|
@ -248,13 +248,14 @@ const char *PathGroups::gated_clk_group_name_ = "gated clock";
|
||||||
const char *PathGroups::async_group_name_ = "asynchronous";
|
const char *PathGroups::async_group_name_ = "asynchronous";
|
||||||
const char *PathGroups::unconstrained_group_name_ = "unconstrained";
|
const char *PathGroups::unconstrained_group_name_ = "unconstrained";
|
||||||
|
|
||||||
bool
|
PathGroups::PathGroups(const StaState *sta) :
|
||||||
PathGroups::isGroupPathName(const char *group_name)
|
StaState(sta),
|
||||||
|
group_path_count_(0),
|
||||||
|
endpoint_path_count_(0),
|
||||||
|
unique_pins_(false),
|
||||||
|
slack_min_(-INF),
|
||||||
|
slack_max_(INF)
|
||||||
{
|
{
|
||||||
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,
|
PathGroups::PathGroups(int group_path_count,
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,31 @@ vertex_worst_slack_path(Vertex *vertex,
|
||||||
return sta->vertexWorstSlackPath(vertex, min_max);
|
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->isGroupPathName(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
|
int
|
||||||
tag_group_count()
|
tag_group_count()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
107
search/Sta.cc
107
search/Sta.cc
|
|
@ -1990,9 +1990,35 @@ Sta::makeGroupPath(const char *name,
|
||||||
bool
|
bool
|
||||||
Sta::isGroupPathName(const char *group_name)
|
Sta::isGroupPathName(const char *group_name)
|
||||||
{
|
{
|
||||||
return PathGroups::isGroupPathName(group_name)
|
return isPathGroupName(group_name);
|
||||||
|| sdc_->findClock(group_name)
|
}
|
||||||
|| sdc_->isGroupPathName(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::asyncPathGroupName());
|
||||||
|
}
|
||||||
|
|
||||||
|
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 *
|
ExceptionFrom *
|
||||||
|
|
@ -3004,13 +3030,84 @@ Sta::pinSlack(const Pin *pin,
|
||||||
return slack;
|
return slack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class EndpointPathEndVisitor : public PathEndVisitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EndpointPathEndVisitor(const std::string &path_group_name,
|
||||||
|
const PathGroups &path_groups,
|
||||||
|
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 PathGroups &path_groups_;
|
||||||
|
const MinMax *min_max_;
|
||||||
|
Slack slack_;
|
||||||
|
const StaState *sta_;
|
||||||
|
};
|
||||||
|
|
||||||
|
EndpointPathEndVisitor::EndpointPathEndVisitor(const std::string &path_group_name,
|
||||||
|
const PathGroups &path_groups,
|
||||||
|
const MinMax *min_max,
|
||||||
|
const StaState *sta) :
|
||||||
|
path_group_name_(path_group_name),
|
||||||
|
path_groups_(path_groups),
|
||||||
|
min_max_(min_max),
|
||||||
|
slack_(MinMax::min()->initValue()),
|
||||||
|
sta_(sta)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PathEndVisitor *
|
||||||
|
EndpointPathEndVisitor::copy() const
|
||||||
|
{
|
||||||
|
return new EndpointPathEndVisitor(path_group_name_, path_groups_, min_max_, sta_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EndpointPathEndVisitor::visit(PathEnd *path_end)
|
||||||
|
{
|
||||||
|
if (path_end->minMax(sta_) == min_max_
|
||||||
|
&& path_groups_.pathGroup(path_end)->name() == 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);
|
||||||
|
// Make path groups to use PathGroups::pathGroup(PathEnd).
|
||||||
|
PathGroups path_groups(this);
|
||||||
|
VisitPathEnds visit_ends(this);
|
||||||
|
EndpointPathEndVisitor path_end_visitor(path_group_name, path_groups, min_max, this);
|
||||||
|
visit_ends.visitPathEnds(vertex, &path_end_visitor);
|
||||||
|
return path_end_visitor.slack();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return INF;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Slack
|
Slack
|
||||||
Sta::vertexSlack(Vertex *vertex,
|
Sta::vertexSlack(Vertex *vertex,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
findRequired(vertex);
|
findRequired(vertex);
|
||||||
const MinMax *min = MinMax::min();
|
Slack slack = MinMax::min()->initValue();
|
||||||
Slack slack = min->initValue();
|
|
||||||
VertexPathIterator path_iter(vertex, this);
|
VertexPathIterator path_iter(vertex, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
Path *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
|
|
|
||||||
|
|
@ -322,6 +322,16 @@ using namespace sta;
|
||||||
Tcl_SetObjResult(interp, list);
|
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* {
|
%typemap(out) Library* {
|
||||||
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
||||||
Tcl_SetObjResult(interp, obj);
|
Tcl_SetObjResult(interp, obj);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue