OpenSTA/search/PathGroup.cc

912 lines
24 KiB
C++
Raw Normal View History

2018-09-28 17:54:21 +02:00
// OpenSTA, Static Timing Analyzer
2020-03-07 03:50:37 +01:00
// Copyright (c) 2020, Parallax Software, Inc.
2018-09-28 17:54:21 +02:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2020-04-05 20:35:51 +02:00
#include "search/PathGroup.hh"
2018-09-28 17:54:21 +02:00
#include <algorithm>
#include <limits>
2020-04-05 20:35:51 +02:00
#include "util/Stats.hh"
#include "util/Debug.hh"
#include "util/Mutex.hh"
#include "util/Fuzzy.hh"
#include "util/MinMax.hh"
#include "util/DispatchQueue.hh"
#include "sdc/ExceptionPath.hh"
#include "sdc/Sdc.hh"
#include "graph/Graph.hh"
#include "search/PathEnd.hh"
#include "search/PathAnalysisPt.hh"
#include "search/Tag.hh"
#include "search/Corner.hh"
#include "search/Search.hh"
#include "search/VisitPathEnds.hh"
#include "search/PathEnum.hh"
2018-09-28 17:54:21 +02:00
namespace sta {
2019-02-16 21:07:59 +01:00
int PathGroup::group_count_max = std::numeric_limits<int>::max();
2018-09-28 17:54:21 +02:00
PathGroup *
PathGroup::makePathGroupSlack(const char *name,
2018-10-24 01:28:41 +02:00
int group_count,
int endpoint_count,
2018-09-28 17:54:21 +02:00
bool unique_pins,
float slack_min,
float slack_max,
const StaState *sta)
{
2018-10-24 01:28:41 +02:00
return new PathGroup(name, group_count, endpoint_count, unique_pins,
2018-09-28 17:54:21 +02:00
slack_min, slack_max, true, MinMax::min(), sta);
}
PathGroup *
PathGroup::makePathGroupArrival(const char *name,
2018-10-24 01:28:41 +02:00
int group_count,
int endpoint_count,
2018-09-28 17:54:21 +02:00
bool unique_pins,
const MinMax *min_max,
const StaState *sta)
{
2018-10-24 01:28:41 +02:00
return new PathGroup(name, group_count, endpoint_count, unique_pins,
2018-09-28 17:54:21 +02:00
0.0, 0.0, false, min_max, sta);
}
PathGroup::PathGroup(const char *name,
2018-10-24 01:28:41 +02:00
int group_count,
int endpoint_count,
2018-09-28 17:54:21 +02:00
bool unique_pins,
float slack_min,
float slack_max,
bool cmp_slack,
const MinMax *min_max,
const StaState *sta) :
name_(name),
2018-10-24 01:28:41 +02:00
group_count_(group_count),
endpoint_count_(endpoint_count),
2018-09-28 17:54:21 +02:00
unique_pins_(unique_pins),
slack_min_(slack_min),
slack_max_(slack_max),
min_max_(min_max),
compare_slack_(cmp_slack),
threshold_(min_max->initValue()),
sta_(sta)
{
}
PathGroup::~PathGroup()
{
path_ends_.deleteContents();
}
bool
PathGroup::savable(PathEnd *path_end)
{
bool savable = false;
if (compare_slack_) {
// Crpr increases the slack, so check the slack
// without crpr first because it is expensive to find.
Slack slack = path_end->slackNoCrpr(sta_);
if (!delayIsInitValue(slack, min_max_)
2019-03-13 01:25:53 +01:00
&& fuzzyLessEqual(slack, threshold_)
&& fuzzyLessEqual(slack, slack_max_)) {
2018-09-28 17:54:21 +02:00
// Now check with crpr.
slack = path_end->slack(sta_);
2019-03-13 01:25:53 +01:00
savable = fuzzyLessEqual(slack, threshold_)
&& fuzzyLessEqual(slack, slack_max_)
&& fuzzyGreaterEqual(slack, slack_min_);
2018-09-28 17:54:21 +02:00
}
}
else {
const Arrival &arrival = path_end->dataArrivalTime(sta_);
savable = !delayIsInitValue(arrival, min_max_)
2019-03-13 01:25:53 +01:00
&& fuzzyGreaterEqual(arrival, threshold_, min_max_);
2018-09-28 17:54:21 +02:00
}
return savable;
}
void
PathGroup::insert(PathEnd *path_end)
{
2019-03-13 01:25:53 +01:00
UniqueLock lock(lock_);
2018-09-28 17:54:21 +02:00
path_ends_.push_back(path_end);
2019-02-16 21:07:59 +01:00
if (group_count_ != group_count_max
2018-10-24 01:28:41 +02:00
&& static_cast<int>(path_ends_.size()) > group_count_ * 2)
2018-09-28 17:54:21 +02:00
prune();
}
void
PathGroup::prune()
{
sort();
VertexPathCountMap path_counts;
int end_count = 0;
for (unsigned i = 0; i < path_ends_.size(); i++) {
PathEnd *path_end = path_ends_[i];
Vertex *vertex = path_end->vertex(sta_);
2018-10-24 01:28:41 +02:00
// Squish up to endpoint_count path ends per vertex up to the front of path_ends_.
if (end_count < group_count_
&& path_counts[vertex] < endpoint_count_) {
2018-09-28 17:54:21 +02:00
path_ends_[end_count++] = path_end;
path_counts[vertex]++;
}
else
delete path_end;
}
path_ends_.resize(end_count);
// Set a threshold to the bottom of the sorted list that future
// inserts need to beat.
PathEnd *last_end = path_ends_[end_count - 1];
if (compare_slack_)
threshold_ = delayAsFloat(last_end->slack(sta_));
else
threshold_ = delayAsFloat(last_end->dataArrivalTime(sta_));
}
void
PathGroup::pushEnds(PathEndSeq *path_ends)
{
ensureSortedMaxPaths();
2020-01-07 04:36:04 +01:00
for (PathEnd *path_end : path_ends_)
2018-09-28 17:54:21 +02:00
path_ends->push_back(path_end);
}
PathGroupIterator *
PathGroup::iterator()
{
ensureSortedMaxPaths();
return new PathGroupIterator(path_ends_);
}
void
PathGroup::ensureSortedMaxPaths()
{
2018-10-24 01:28:41 +02:00
if (static_cast<int>(path_ends_.size()) > group_count_)
2018-09-28 17:54:21 +02:00
prune();
else
sort();
}
void
PathGroup::sort()
{
sta::sort(path_ends_, PathEndLess(sta_));
}
void
PathGroup::clear()
{
2019-03-13 01:25:53 +01:00
UniqueLock lock(lock_);
2018-09-28 17:54:21 +02:00
threshold_ = min_max_->initValue();
path_ends_.clear();
}
////////////////////////////////////////////////////////////////
const char *PathGroups::path_delay_group_name_ = "**default**";
const char *PathGroups::gated_clk_group_name_ = "**clock_gating_default**";
const char *PathGroups::async_group_name_ = "**async_default**";
const char *PathGroups::unconstrained_group_name_ = "(none)";
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_);
}
2018-10-24 01:28:41 +02:00
PathGroups::PathGroups(int group_count,
int endpoint_count,
2018-09-28 17:54:21 +02:00
bool unique_pins,
float slack_min,
float slack_max,
PathGroupNameSet *group_names,
bool setup,
bool hold,
bool recovery,
bool removal,
bool clk_gating_setup,
bool clk_gating_hold,
bool unconstrained,
const StaState *sta) :
StaState(sta),
2018-10-24 01:28:41 +02:00
group_count_(group_count),
endpoint_count_(endpoint_count),
2018-09-28 17:54:21 +02:00
unique_pins_(unique_pins),
slack_min_(slack_min),
slack_max_(slack_max)
{
2018-10-24 01:28:41 +02:00
makeGroups(group_count, endpoint_count, unique_pins, slack_min, slack_max, group_names,
2018-09-28 17:54:21 +02:00
setup, recovery, clk_gating_setup, unconstrained,
MinMax::max());
2018-10-24 01:28:41 +02:00
makeGroups(group_count, endpoint_count, unique_pins, slack_min, slack_max, group_names,
2018-09-28 17:54:21 +02:00
hold, removal, clk_gating_hold, unconstrained,
MinMax::min());
}
void
2018-10-24 01:28:41 +02:00
PathGroups::makeGroups(int group_count,
int endpoint_count,
2018-09-28 17:54:21 +02:00
bool unique_pins,
float slack_min,
float slack_max,
PathGroupNameSet *group_names,
bool setup_hold,
bool async,
bool gated_clk,
bool unconstrained,
const MinMax *min_max)
{
int mm_index = min_max->index();
if (setup_hold) {
2019-03-13 01:25:53 +01:00
GroupPathIterator group_path_iter(sdc_);
while (group_path_iter.hasNext()) {
2018-09-28 17:54:21 +02:00
const char *name;
GroupPathSet *groups;
2019-03-13 01:25:53 +01:00
group_path_iter.next(name, groups);
2018-09-28 17:54:21 +02:00
if (reportGroup(name, group_names)) {
2018-10-24 01:28:41 +02:00
PathGroup *group = PathGroup::makePathGroupSlack(name, group_count,
endpoint_count, unique_pins,
2018-09-28 17:54:21 +02:00
slack_min, slack_max,
this);
named_map_[mm_index][name] = group;
}
}
2019-03-13 01:25:53 +01:00
for (auto clk : sdc_->clks()) {
2018-09-28 17:54:21 +02:00
const char *clk_name = clk->name();
if (reportGroup(clk_name, group_names)) {
2018-10-24 01:28:41 +02:00
PathGroup *group = PathGroup::makePathGroupSlack(clk_name, group_count,
endpoint_count, unique_pins,
2018-09-28 17:54:21 +02:00
slack_min, slack_max,
this);
clk_map_[mm_index][clk] = group;
}
}
}
if (setup_hold
&& reportGroup(path_delay_group_name_, group_names))
path_delay_[mm_index] = PathGroup::makePathGroupSlack(path_delay_group_name_,
2018-10-24 01:28:41 +02:00
group_count, endpoint_count,
2018-09-28 17:54:21 +02:00
unique_pins,
slack_min, slack_max,
this);
else
2019-03-13 01:25:53 +01:00
path_delay_[mm_index] = nullptr;
2018-09-28 17:54:21 +02:00
if (gated_clk
&& reportGroup(gated_clk_group_name_, group_names))
gated_clk_[mm_index] = PathGroup::makePathGroupSlack(gated_clk_group_name_,
2018-10-24 01:28:41 +02:00
group_count, endpoint_count,
2018-09-28 17:54:21 +02:00
unique_pins,
slack_min, slack_max,
this);
else
2019-03-13 01:25:53 +01:00
gated_clk_[mm_index] = nullptr;
2018-09-28 17:54:21 +02:00
if (async
&& reportGroup(async_group_name_, group_names))
async_[mm_index] = PathGroup::makePathGroupSlack(async_group_name_,
2018-10-24 01:28:41 +02:00
group_count, endpoint_count,
2018-09-28 17:54:21 +02:00
unique_pins,
slack_min, slack_max,
this);
else
2019-03-13 01:25:53 +01:00
async_[mm_index] = nullptr;
2018-09-28 17:54:21 +02:00
if (unconstrained
&& reportGroup(unconstrained_group_name_, group_names))
unconstrained_[mm_index] =
PathGroup::makePathGroupArrival(unconstrained_group_name_,
2018-10-24 01:28:41 +02:00
group_count, endpoint_count, unique_pins,
2018-09-28 17:54:21 +02:00
min_max, this);
else
2019-03-13 01:25:53 +01:00
unconstrained_[mm_index] = nullptr;
2018-09-28 17:54:21 +02:00
}
PathGroups::~PathGroups()
{
2019-07-18 15:19:00 +02:00
for (auto mm_index : MinMax::rangeIndex()) {
2018-09-28 17:54:21 +02:00
named_map_[mm_index].deleteContents();
clk_map_[mm_index].deleteContents();
delete path_delay_[mm_index];
delete gated_clk_[mm_index];
delete async_[mm_index];
delete unconstrained_[mm_index];
}
}
PathGroup *
PathGroups::findPathGroup(const char *name,
const MinMax *min_max) const
{
return named_map_[min_max->index()].findKey(name);
}
PathGroup *
PathGroups::findPathGroup(const Clock *clock,
const MinMax *min_max) const
{
return clk_map_[min_max->index()].findKey(clock);
}
bool
PathGroups::reportGroup(const char *group_name,
PathGroupNameSet *group_names) const
{
2019-03-13 01:25:53 +01:00
return group_names == nullptr
2018-09-28 17:54:21 +02:00
|| group_names->empty()
|| group_names->hasKey(group_name);
}
PathGroup *
PathGroups::pathGroup(const PathEnd *path_end) const
{
const MinMax *min_max = path_end->minMax(this);
int mm_index = min_max->index();
// GroupPaths have precedence.
GroupPath *group_path = groupPathTo(path_end);
if (group_path) {
if (group_path->isDefault())
return path_delay_[mm_index];
else {
const char *group_name = group_path->name();
return findPathGroup(group_name, min_max);
}
}
else if (path_end->isCheck() || path_end->isLatchCheck()) {
const TimingRole *check_role = path_end->checkRole(this);
const Clock *tgt_clk = path_end->targetClk(this);
if (check_role == TimingRole::removal()
|| check_role == TimingRole::recovery())
return async_[mm_index];
else
return findPathGroup(tgt_clk, min_max);
}
else if (path_end->isOutputDelay()
|| path_end->isDataCheck())
return findPathGroup(path_end->targetClk(this), min_max);
else if (path_end->isGatedClock())
return gated_clk_[mm_index];
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();
Clock *tgt_clk = path_end->targetClk(this);
if (tgt_clk
&& !path_delay->ignoreClkLatency())
return findPathGroup(tgt_clk, min_max);
else
return path_delay_[mm_index];
}
else if (path_end->isUnconstrained())
return unconstrained_[mm_index];
else {
internalError("unknown path end type");
2019-03-13 01:25:53 +01:00
return nullptr;
2018-09-28 17:54:21 +02:00
}
}
GroupPath *
PathGroups::groupPathTo(const PathEnd *path_end) const
{
const Path *path = path_end->path();
const Pin *pin = path->pin(this);
ExceptionPath *exception =
2019-03-13 01:25:53 +01:00
search_->exceptionTo(ExceptionPathType::group_path, path,
2018-09-28 17:54:21 +02:00
pin, path->transition(this),
path_end->targetClkEdge(this),
path->minMax(this), false, false);
return dynamic_cast<GroupPath*>(exception);
}
void
PathGroups::pushGroupPathEnds(PathEndSeq *path_ends)
{
2019-07-18 15:19:00 +02:00
for (auto min_max : MinMax::range()) {
2018-09-28 17:54:21 +02:00
int mm_index = min_max->index();
2019-03-13 01:25:53 +01:00
GroupPathIterator group_path_iter(sdc_);
while (group_path_iter.hasNext()) {
2018-09-28 17:54:21 +02:00
const char *name;
GroupPathSet *groups;
2019-03-13 01:25:53 +01:00
group_path_iter.next(name, groups);
2018-09-28 17:54:21 +02:00
PathGroup *path_group = findPathGroup(name, min_max);
if (path_group)
path_group->pushEnds(path_ends);
}
if (async_[mm_index])
async_[mm_index]->pushEnds(path_ends);
if (gated_clk_[mm_index])
gated_clk_[mm_index]->pushEnds(path_ends);
if (path_delay_[mm_index])
path_delay_[mm_index]->pushEnds(path_ends);
ClockSeq clks;
sdc_->sortedClocks(clks);
ClockSeq::Iterator clk_iter(clks);
while (clk_iter.hasNext()) {
Clock *clk = clk_iter.next();
PathGroup *path_group = findPathGroup(clk, min_max);
if (path_group)
path_group->pushEnds(path_ends);
}
}
}
void
PathGroups::pushUnconstrainedPathEnds(PathEndSeq *path_ends,
const MinMaxAll *min_max)
{
Set<PathGroup *> groups;
2019-07-18 15:19:00 +02:00
for (auto path_ap : corners_->pathAnalysisPts()) {
2018-09-28 17:54:21 +02:00
const MinMax *path_min_max = path_ap->pathMinMax();
if (min_max->matches(path_min_max)) {
int mm_index = path_min_max->index();
PathGroup *group = unconstrained_[mm_index];
if (group
// For multiple corner path APs use the same group.
// Only report it once.
&& !groups.findKey(group)) {
group->pushEnds(path_ends);
groups.insert(group);
}
}
}
}
////////////////////////////////////////////////////////////////
typedef Map<PathGroup*, PathEnd*> PathGroupEndMap;
typedef Map<PathGroup*, PathEndSeq*> PathGroupEndsMap;
typedef Set<PathEnd*, PathEndNoCrprLess> PathEndNoCrprSet;
static bool
exceptionToEmpty(ExceptionTo *to);
PathEndSeq *
PathGroups::makePathEnds(ExceptionTo *to,
2019-01-06 01:09:27 +01:00
bool unconstrained_paths,
2018-09-28 17:54:21 +02:00
const Corner *corner,
const MinMaxAll *min_max,
bool sort_by_slack)
{
Stats stats(this->debug());
2019-01-06 01:09:27 +01:00
makeGroupPathEnds(to, group_count_, endpoint_count_, unique_pins_,
corner, min_max);
2018-09-28 17:54:21 +02:00
PathEndSeq *path_ends = new PathEndSeq;
pushGroupPathEnds(path_ends);
if (sort_by_slack) {
sort(path_ends, PathEndLess(this));
2018-10-24 01:28:41 +02:00
if (static_cast<int>(path_ends->size()) > group_count_)
path_ends->resize(group_count_);
2018-09-28 17:54:21 +02:00
}
2019-01-06 01:09:27 +01:00
if (unconstrained_paths
2018-09-28 17:54:21 +02:00
&& path_ends->empty())
// No constrained paths, so report unconstrained paths.
pushUnconstrainedPathEnds(path_ends, min_max);
stats.report("Make path ends");
return path_ends;
}
////////////////////////////////////////////////////////////////
// Visit each path end for a vertex and add the worst one in each
// path group to the group.
class MakePathEnds1 : public PathEndVisitor
{
public:
explicit MakePathEnds1(PathGroups *path_groups);
virtual PathEndVisitor *copy();
virtual void visit(PathEnd *path_end);
virtual void vertexEnd(Vertex *vertex);
private:
DISALLOW_COPY_AND_ASSIGN(MakePathEnds1);
void visitPathEnd(PathEnd *path_end,
PathGroup *group);
PathGroups *path_groups_;
PathGroupEndMap ends_;
PathEndLess cmp_;
};
MakePathEnds1::MakePathEnds1(PathGroups *path_groups) :
path_groups_(path_groups),
cmp_(path_groups){
}
PathEndVisitor *
MakePathEnds1::copy()
{
return new MakePathEnds1(path_groups_);
}
void
MakePathEnds1::visit(PathEnd *path_end)
{
PathGroup *group = path_groups_->pathGroup(path_end);
if (group)
visitPathEnd(path_end, group);
}
void
MakePathEnds1::visitPathEnd(PathEnd *path_end,
PathGroup *group)
{
if (group->savable(path_end)) {
// Only keep the path end with the smallest slack/latest arrival.
PathEnd *worst_end = ends_.findKey(group);
if (worst_end) {
if (cmp_(path_end, worst_end)) {
ends_[group] = path_end->copy();
delete worst_end;
}
}
else
ends_[group] = path_end->copy();
}
}
// Save the worst end for each path group.
void
MakePathEnds1::vertexEnd(Vertex *)
{
PathGroupEndMap::Iterator group_iter(ends_);
while (group_iter.hasNext()) {
PathGroup *group;
PathEnd *end;
group_iter.next(group, end);
// visitPathEnd already confirmed slack is savable.
if (end) {
group->insert(end);
// Clear ends_ for next vertex.
2019-03-13 01:25:53 +01:00
ends_[group] = nullptr;
2018-09-28 17:54:21 +02:00
}
}
}
////////////////////////////////////////////////////////////////
// Visit each path end and add it to the corresponding path group.
// After collecting the ends do parallel path enumeration to find the
// path ends for the group.
class MakePathEndsAll : public PathEndVisitor
{
public:
2018-10-24 01:28:41 +02:00
explicit MakePathEndsAll(int endpoint_count,
2018-09-28 17:54:21 +02:00
PathGroups *path_groups);
virtual ~MakePathEndsAll();
virtual PathEndVisitor *copy();
virtual void visit(PathEnd *path_end);
virtual void vertexEnd(Vertex *vertex);
private:
DISALLOW_COPY_AND_ASSIGN(MakePathEndsAll);
void visitPathEnd(PathEnd *path_end,
PathGroup *group);
2018-10-24 01:28:41 +02:00
int endpoint_count_;
2018-09-28 17:54:21 +02:00
PathGroups *path_groups_;
const StaState *sta_;
PathGroupEndsMap ends_;
PathEndSlackLess slack_cmp_;
PathEndNoCrprLess path_no_crpr_cmp_;
};
2018-10-24 01:28:41 +02:00
MakePathEndsAll::MakePathEndsAll(int endpoint_count,
2018-09-28 17:54:21 +02:00
PathGroups *path_groups) :
2018-10-24 01:28:41 +02:00
endpoint_count_(endpoint_count),
2018-09-28 17:54:21 +02:00
path_groups_(path_groups),
sta_(path_groups),
slack_cmp_(path_groups),
path_no_crpr_cmp_(path_groups)
{
}
PathEndVisitor *
MakePathEndsAll::copy()
{
2018-10-24 01:28:41 +02:00
return new MakePathEndsAll(endpoint_count_, path_groups_);
2018-09-28 17:54:21 +02:00
}
MakePathEndsAll::~MakePathEndsAll()
{
PathGroupEndsMap::Iterator group_iter(ends_);
while (group_iter.hasNext()) {
PathGroup *group;
PathEndSeq *ends;
group_iter.next(group, ends);
delete ends;
}
}
void
MakePathEndsAll::visit(PathEnd *path_end)
{
PathGroup *group = path_groups_->pathGroup(path_end);
if (group)
visitPathEnd(path_end, group);
}
void
MakePathEndsAll::visitPathEnd(PathEnd *path_end,
PathGroup *group)
{
PathEndSeq *ends = ends_.findKey(group);
2019-03-13 01:25:53 +01:00
if (ends == nullptr) {
2018-09-28 17:54:21 +02:00
ends = new PathEndSeq;
ends_[group] = ends;
}
ends->push_back(path_end->copy());
}
void
MakePathEndsAll::vertexEnd(Vertex *)
{
Debug *debug = sta_->debug();
Network *network = sta_->network();
PathGroupEndsMap::Iterator group_iter(ends_);
while (group_iter.hasNext()) {
PathGroup *group;
PathEndSeq *ends;
group_iter.next(group, ends);
if (ends) {
sort(ends, slack_cmp_);
PathEndNoCrprSet unique_ends(path_no_crpr_cmp_);
PathEndSeq::Iterator end_iter(ends);
int n = 0;
while (end_iter.hasNext()
2018-10-24 01:28:41 +02:00
&& n < endpoint_count_) {
2018-09-28 17:54:21 +02:00
PathEnd *path_end = end_iter.next();
// Only save the worst path end for each crpr tag.
// PathEnum will peel the others.
if (!unique_ends.hasKey(path_end)) {
debugPrint4(debug, "path_enum", 5, "insert %s %s %s %d\n",
path_end->vertex(sta_)->name(network),
2019-03-13 01:25:53 +01:00
path_end->typeName(),
2018-09-28 17:54:21 +02:00
path_end->transition(sta_)->asString(),
path_end->path()->tag(sta_)->index());
// Give the group a copy of the path end because
// it may delete it during pruning.
if (group->savable(path_end)) {
group->insert(path_end->copy());
unique_ends.insert(path_end);
n++;
}
}
else
debugPrint4(debug, "path_enum", 5, "prune %s %s %s %d\n",
path_end->vertex(sta_)->name(network),
2019-03-13 01:25:53 +01:00
path_end->typeName(),
2018-09-28 17:54:21 +02:00
path_end->transition(sta_)->asString(),
path_end->path()->tag(sta_)->index());
}
// Clear ends for next vertex.
PathEndSeq::Iterator end_iter2(ends);
while (end_iter2.hasNext()) {
PathEnd *path_end = end_iter2.next();
delete path_end;
}
ends->clear();
}
}
}
////////////////////////////////////////////////////////////////
void
PathGroups::makeGroupPathEnds(ExceptionTo *to,
2018-10-24 01:28:41 +02:00
int group_count,
int endpoint_count,
2018-09-28 17:54:21 +02:00
bool unique_pins,
const Corner *corner,
const MinMaxAll *min_max)
{
2018-10-24 01:28:41 +02:00
if (endpoint_count == 1) {
2018-09-28 17:54:21 +02:00
MakePathEnds1 make_path_ends(this);
makeGroupPathEnds(to, corner, min_max, &make_path_ends);
}
else {
2018-10-24 01:28:41 +02:00
MakePathEndsAll make_path_ends(endpoint_count, this);
2018-09-28 17:54:21 +02:00
makeGroupPathEnds(to, corner, min_max, &make_path_ends);
2019-07-18 15:19:00 +02:00
for (auto path_min_max : MinMax::range()) {
2018-09-28 17:54:21 +02:00
int mm_index = path_min_max->index();
2019-03-13 01:25:53 +01:00
GroupPathIterator group_path_iter(sdc_);
while (group_path_iter.hasNext()) {
2018-09-28 17:54:21 +02:00
const char *name;
GroupPathSet *groups;
2019-03-13 01:25:53 +01:00
group_path_iter.next(name, groups);
2018-09-28 17:54:21 +02:00
PathGroup *group = findPathGroup(name, path_min_max);
if (group)
2018-12-05 23:18:41 +01:00
enumPathEnds(group, group_count, endpoint_count, unique_pins, true);
2018-09-28 17:54:21 +02:00
}
2019-03-13 01:25:53 +01:00
for (auto clk : sdc_->clks()) {
2018-09-28 17:54:21 +02:00
PathGroup *group = findPathGroup(clk, path_min_max);
if (group)
2018-12-05 23:18:41 +01:00
enumPathEnds(group, group_count, endpoint_count, unique_pins, true);
2018-09-28 17:54:21 +02:00
}
PathGroup *group = unconstrained_[mm_index];
if (group)
2018-12-05 23:18:41 +01:00
enumPathEnds(group, group_count, endpoint_count, unique_pins, false);
2018-09-28 17:54:21 +02:00
group = path_delay_[mm_index];
if (group)
2018-12-05 23:18:41 +01:00
enumPathEnds(group, group_count, endpoint_count, unique_pins, true);
2018-09-28 17:54:21 +02:00
group = gated_clk_[mm_index];
if (group)
2018-12-05 23:18:41 +01:00
enumPathEnds(group, group_count, endpoint_count, unique_pins, true);
2018-09-28 17:54:21 +02:00
group = async_[mm_index];
if (group)
2018-12-05 23:18:41 +01:00
enumPathEnds(group, group_count, endpoint_count, unique_pins, true);
2018-09-28 17:54:21 +02:00
}
}
}
void
PathGroups::enumPathEnds(PathGroup *group,
2018-10-24 01:28:41 +02:00
int group_count,
int endpoint_count,
2018-09-28 17:54:21 +02:00
bool unique_pins,
2018-12-05 23:18:41 +01:00
bool cmp_slack)
2018-09-28 17:54:21 +02:00
{
// Insert the worst max_path path ends in the group into a path
// enumerator.
2018-12-05 23:18:41 +01:00
PathEnum path_enum(group_count, endpoint_count, unique_pins, cmp_slack, this);
2018-09-28 17:54:21 +02:00
PathGroupIterator *end_iter = group->iterator();
while (end_iter->hasNext()) {
PathEnd *end = end_iter->next();
if (group->savable(end))
path_enum.insert(end);
}
delete end_iter;
group->clear();
2018-10-24 01:28:41 +02:00
// Parallel path enumeratation to find the endpoint_count/max path ends.
for (int n = 0; path_enum.hasNext() && n < group_count; n++) {
2018-09-28 17:54:21 +02:00
PathEnd *end = path_enum.next();
group->insert(end);
}
}
void
PathGroups::makeGroupPathEnds(ExceptionTo *to,
const Corner *corner,
const MinMaxAll *min_max,
PathEndVisitor *visitor)
{
Network *network = this->network();
Graph *graph = this->graph();
Search *search = this->search();
if (exceptionToEmpty(to))
makeGroupPathEnds(search->endpoints(), corner, min_max, visitor);
else {
// Only visit -to filter pins.
VertexSet endpoints;
PinSet pins;
to->allPins(network, &pins);
PinSet::Iterator pin_iter(pins);
while (pin_iter.hasNext()) {
const Pin *pin = pin_iter.next();
Vertex *vertex, *bidirect_drvr_vertex;
graph->pinVertices(pin, vertex, bidirect_drvr_vertex);
if (vertex
&& search->isEndpoint(vertex))
endpoints.insert(vertex);
if (bidirect_drvr_vertex
&& search->isEndpoint(bidirect_drvr_vertex))
endpoints.insert(bidirect_drvr_vertex);
}
makeGroupPathEnds(&endpoints, corner, min_max, visitor);
}
}
static bool
exceptionToEmpty(ExceptionTo *to)
{
2019-03-13 01:25:53 +01:00
return to == nullptr
|| (to->pins() == nullptr
&& to->instances() == nullptr);
2018-09-28 17:54:21 +02:00
}
////////////////////////////////////////////////////////////////
class MakeEndpointPathEnds : public VertexVisitor
{
public:
MakeEndpointPathEnds(PathEndVisitor *path_end_visitor,
const Corner *corner,
const MinMaxAll *min_max,
const StaState *sta);
~MakeEndpointPathEnds();
virtual VertexVisitor *copy();
virtual void visit(Vertex *vertex);
private:
DISALLOW_COPY_AND_ASSIGN(MakeEndpointPathEnds);
VisitPathEnds *visit_path_ends_;
PathEndVisitor *path_end_visitor_;
const Corner *corner_;
const MinMaxAll *min_max_;
const StaState *sta_;
};
MakeEndpointPathEnds::MakeEndpointPathEnds(PathEndVisitor *path_end_visitor,
const Corner *corner,
const MinMaxAll *min_max,
const StaState *sta) :
visit_path_ends_(new VisitPathEnds(sta)),
path_end_visitor_(path_end_visitor->copy()),
corner_(corner),
min_max_(min_max),
sta_(sta)
{
}
MakeEndpointPathEnds::~MakeEndpointPathEnds()
{
delete visit_path_ends_;
delete path_end_visitor_;
}
VertexVisitor *
MakeEndpointPathEnds::copy()
{
return new MakeEndpointPathEnds(path_end_visitor_, corner_, min_max_, sta_);
}
void
MakeEndpointPathEnds::visit(Vertex *vertex)
{
visit_path_ends_->visitPathEnds(vertex, corner_, min_max_, true,
path_end_visitor_);
}
////////////////////////////////////////////////////////////////
void
PathGroups::makeGroupPathEnds(VertexSet *endpoints,
const Corner *corner,
const MinMaxAll *min_max,
PathEndVisitor *visitor)
{
2019-11-11 16:48:27 +01:00
Vector<MakeEndpointPathEnds*> visitors;
for (int i = 0; i < thread_count_; i++)
visitors.push_back(new MakeEndpointPathEnds(visitor, corner, min_max, this));
for (auto endpoint : *endpoints) {
dispatch_queue_->dispatch( [endpoint, &visitors](int i)
{ visitors[i]->visit(endpoint); } );
}
dispatch_queue_->finishTasks();
visitors.deleteContents();
2018-09-28 17:54:21 +02:00
}
} // namespace