Sta::endpointSlack

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2025-10-25 10:02:34 -07:00
parent 6e29fcb3f0
commit 525c2efb3d
7 changed files with 160 additions and 16 deletions

View File

@ -107,6 +107,7 @@ protected:
class PathGroups : public StaState
{
public:
PathGroups(const StaState *sta);
PathGroups(int group_path_count,
int endpoint_path_count,
bool unique_pins,
@ -134,8 +135,10 @@ 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 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,

View File

@ -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,

View File

@ -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())

View File

@ -248,13 +248,14 @@ 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)
PathGroups::PathGroups(const StaState *sta) :
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,

View File

@ -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->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
tag_group_count()
{

View File

@ -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::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 *
@ -3004,13 +3030,84 @@ Sta::pinSlack(const Pin *pin,
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
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();

View File

@ -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);