2018-09-28 17:54:21 +02:00
|
|
|
// OpenSTA, Static Timing Analyzer
|
2025-01-22 02:54:33 +01:00
|
|
|
// Copyright (c) 2025, 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
|
2022-01-04 18:17:08 +01:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2018-09-28 17:54:21 +02:00
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2022-01-04 18:17:08 +01:00
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2025-01-22 02:54:33 +01:00
|
|
|
//
|
|
|
|
|
// The origin of this software must not be misrepresented; you must not
|
|
|
|
|
// claim that you wrote the original software.
|
|
|
|
|
//
|
|
|
|
|
// Altered source versions must be plainly marked as such, and must not be
|
|
|
|
|
// misrepresented as being the original software.
|
|
|
|
|
//
|
|
|
|
|
// This notice may not be removed or altered from any source distribution.
|
2018-09-28 17:54:21 +02:00
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "VisitPathGroupVertices.hh"
|
2020-04-05 20:35:51 +02:00
|
|
|
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "Debug.hh"
|
|
|
|
|
#include "Graph.hh"
|
|
|
|
|
#include "Bfs.hh"
|
|
|
|
|
#include "Search.hh"
|
2025-03-27 02:21:03 +01:00
|
|
|
#include "Path.hh"
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "PathEnd.hh"
|
|
|
|
|
#include "Tag.hh"
|
|
|
|
|
#include "VisitPathEnds.hh"
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
typedef Set<Path*, PathLess> PathSet;
|
|
|
|
|
typedef Map<Vertex*, PathSet*> VertexPathSetMap;
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
|
|
|
|
|
Vertex *vertex,
|
|
|
|
|
Tag *tag,
|
|
|
|
|
const StaState *sta);
|
|
|
|
|
|
|
|
|
|
// Visit each path end for a vertex and add the worst one in each
|
|
|
|
|
// path group to the group.
|
|
|
|
|
class VisitPathGroupEnds : public PathEndVisitor
|
|
|
|
|
{
|
|
|
|
|
public:
|
2021-12-16 01:21:57 +01:00
|
|
|
VisitPathGroupEnds(PathGroup *path_group,
|
|
|
|
|
VertexVisitor *vertex_visitor,
|
|
|
|
|
VertexPathSetMap *matching_path_map,
|
|
|
|
|
BfsBkwdIterator *bkwd_iter,
|
|
|
|
|
StaState *sta);
|
|
|
|
|
VisitPathGroupEnds(const VisitPathGroupEnds&) = default;
|
|
|
|
|
virtual PathEndVisitor *copy() const;
|
2018-09-28 17:54:21 +02:00
|
|
|
virtual void visit(PathEnd *path_end);
|
|
|
|
|
virtual void vertexBegin(Vertex *vertex);
|
|
|
|
|
virtual void vertexEnd(Vertex *vertex);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
PathGroup *path_group_;
|
|
|
|
|
VertexVisitor *vertex_visitor_;
|
|
|
|
|
BfsBkwdIterator *bkwd_iter_;
|
|
|
|
|
VertexPathSetMap *matching_path_map_;
|
|
|
|
|
bool vertex_matches_;
|
|
|
|
|
StaState *sta_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class PathGroupPathVisitor : public PathVisitor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
PathGroupPathVisitor(VertexVisitor *visitor,
|
|
|
|
|
BfsBkwdIterator *bkwd_iter,
|
|
|
|
|
VertexPathSetMap *matching_path_map,
|
|
|
|
|
const StaState *sta);
|
|
|
|
|
virtual ~PathGroupPathVisitor();
|
2021-12-16 03:35:02 +01:00
|
|
|
virtual VertexVisitor *copy() const;
|
2018-09-28 17:54:21 +02:00
|
|
|
virtual void visit(Vertex *vertex);
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
// Return false to stop visiting.
|
|
|
|
|
virtual bool visitFromToPath(const Pin *from_pin,
|
|
|
|
|
Vertex *from_vertex,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *from_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
Tag *from_tag,
|
2025-03-27 02:21:03 +01:00
|
|
|
Path *from_path,
|
2024-10-12 02:02:47 +02:00
|
|
|
const Arrival &from_arrival,
|
2018-09-28 17:54:21 +02:00
|
|
|
Edge *edge,
|
|
|
|
|
TimingArc *arc,
|
|
|
|
|
ArcDelay arc_delay,
|
|
|
|
|
Vertex *to_vertex,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *to_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
Tag *to_tag,
|
|
|
|
|
Arrival &to_arrival,
|
|
|
|
|
const MinMax *min_max,
|
|
|
|
|
const PathAnalysisPt *path_ap);
|
|
|
|
|
void fromMatches(Vertex *from_vertex,
|
2025-03-27 02:21:03 +01:00
|
|
|
Tag *from_tag);
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
VertexVisitor *visitor_;
|
|
|
|
|
BfsBkwdIterator *bkwd_iter_;
|
|
|
|
|
VertexPathSetMap *matching_path_map_;
|
|
|
|
|
bool vertex_matches_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// Visit the fanin vertices for the path group.
|
|
|
|
|
// Vertices in the clock network are NOT visited.
|
|
|
|
|
void
|
|
|
|
|
visitPathGroupVertices(PathGroup *path_group,
|
|
|
|
|
VertexVisitor *visitor,
|
|
|
|
|
StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
Search *search = sta->search();
|
|
|
|
|
VertexPathSetMap matching_path_map;
|
|
|
|
|
// Do not visit clock network.
|
|
|
|
|
SearchPredNonReg2 srch_non_reg(sta);
|
2019-03-13 01:25:53 +01:00
|
|
|
BfsBkwdIterator bkwd_iter(BfsIndex::other, &srch_non_reg, sta);
|
2018-09-28 17:54:21 +02:00
|
|
|
// Visit the path ends and filter by path_group to seed the backward search.
|
|
|
|
|
VisitPathGroupEnds end_visitor(path_group, visitor, &matching_path_map,
|
|
|
|
|
&bkwd_iter, sta);
|
|
|
|
|
VisitPathEnds visit_path_ends(sta);
|
2022-03-01 14:55:25 +01:00
|
|
|
for(Vertex *vertex : *search->endpoints())
|
2018-09-28 17:54:21 +02:00
|
|
|
visit_path_ends.visitPathEnds(vertex, &end_visitor);
|
|
|
|
|
|
|
|
|
|
// Search backward from the path ends thru vertices that have arrival tags
|
|
|
|
|
// that match path_group end paths.
|
|
|
|
|
PathGroupPathVisitor path_visitor(visitor, &bkwd_iter, &matching_path_map,
|
|
|
|
|
sta);
|
|
|
|
|
bkwd_iter.visit(0, &path_visitor);
|
|
|
|
|
|
|
|
|
|
// Cleanup.
|
|
|
|
|
VertexPathSetMap::Iterator matching_iter(matching_path_map);
|
|
|
|
|
while (matching_iter.hasNext()) {
|
2025-03-27 02:21:03 +01:00
|
|
|
PathSet *paths = matching_iter.next();
|
|
|
|
|
PathSet::Iterator path_iter(paths);
|
2018-09-28 17:54:21 +02:00
|
|
|
while (path_iter.hasNext()) {
|
2025-03-27 02:21:03 +01:00
|
|
|
Path *path = path_iter.next();
|
2018-09-28 17:54:21 +02:00
|
|
|
delete path;
|
|
|
|
|
}
|
|
|
|
|
delete paths;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
VisitPathGroupEnds::VisitPathGroupEnds(PathGroup *path_group,
|
|
|
|
|
VertexVisitor *vertex_visitor,
|
|
|
|
|
VertexPathSetMap *matching_path_map,
|
|
|
|
|
BfsBkwdIterator *bkwd_iter,
|
|
|
|
|
StaState *sta) :
|
|
|
|
|
path_group_(path_group),
|
|
|
|
|
vertex_visitor_(vertex_visitor),
|
|
|
|
|
bkwd_iter_(bkwd_iter),
|
|
|
|
|
matching_path_map_(matching_path_map),
|
|
|
|
|
sta_(sta)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PathEndVisitor *
|
2021-12-16 01:21:57 +01:00
|
|
|
VisitPathGroupEnds::copy() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2021-12-16 01:21:57 +01:00
|
|
|
return new VisitPathGroupEnds(*this);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VisitPathGroupEnds::vertexBegin(Vertex *)
|
|
|
|
|
{
|
|
|
|
|
vertex_matches_ = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VisitPathGroupEnds::visit(PathEnd *path_end)
|
|
|
|
|
{
|
2025-10-30 16:53:36 +01:00
|
|
|
PathGroupSeq groups = sta_->search()->pathGroups(path_end);
|
|
|
|
|
for (PathGroup *group : groups) {
|
|
|
|
|
if (group == path_group_) {
|
|
|
|
|
Path *path = path_end->path();
|
|
|
|
|
Vertex *vertex = path->vertex(sta_);
|
|
|
|
|
vertexPathSetMapInsertPath(matching_path_map_, vertex, path->tag(sta_), sta_);
|
|
|
|
|
vertex_matches_ = true;
|
|
|
|
|
}
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
|
|
|
|
|
Vertex *vertex,
|
|
|
|
|
Tag *tag,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
PathSet *matching_paths = matching_path_map->findKey(vertex);
|
2019-03-13 01:25:53 +01:00
|
|
|
if (matching_paths == nullptr) {
|
2018-09-28 17:54:21 +02:00
|
|
|
PathLess path_less(sta);
|
2025-03-27 02:21:03 +01:00
|
|
|
matching_paths = new PathSet(path_less);
|
2018-09-28 17:54:21 +02:00
|
|
|
(*matching_path_map)[vertex] = matching_paths;
|
|
|
|
|
}
|
2025-03-27 02:21:03 +01:00
|
|
|
Path *vpath = new Path(vertex, tag, sta);
|
2018-09-28 17:54:21 +02:00
|
|
|
matching_paths->insert(vpath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VisitPathGroupEnds::vertexEnd(Vertex *vertex)
|
|
|
|
|
{
|
|
|
|
|
if (vertex_matches_) {
|
|
|
|
|
vertex_visitor_->visit(vertex);
|
|
|
|
|
// Seed backward bfs fanin search.
|
|
|
|
|
bkwd_iter_->enqueueAdjacentVertices(vertex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
PathGroupPathVisitor::PathGroupPathVisitor(VertexVisitor *visitor,
|
|
|
|
|
BfsBkwdIterator *bkwd_iter,
|
|
|
|
|
VertexPathSetMap *matching_path_map,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
PathVisitor(sta),
|
|
|
|
|
visitor_(visitor),
|
|
|
|
|
bkwd_iter_(bkwd_iter),
|
|
|
|
|
matching_path_map_(matching_path_map)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PathGroupPathVisitor::~PathGroupPathVisitor()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VertexVisitor *
|
2021-12-16 03:35:02 +01:00
|
|
|
PathGroupPathVisitor::copy() const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2022-08-12 03:17:46 +02:00
|
|
|
return new PathGroupPathVisitor(visitor_, bkwd_iter_,
|
|
|
|
|
matching_path_map_, this);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PathGroupPathVisitor::visit(Vertex *vertex)
|
|
|
|
|
{
|
|
|
|
|
vertex_matches_ = false;
|
|
|
|
|
visitFanoutPaths(vertex);
|
|
|
|
|
if (vertex_matches_) {
|
2022-08-12 03:17:46 +02:00
|
|
|
debugPrint(debug_, "visit_path_group", 1, "visit %s",
|
2025-03-31 00:27:53 +02:00
|
|
|
vertex->to_string(this).c_str());
|
2018-09-28 17:54:21 +02:00
|
|
|
visitor_->visit(vertex);
|
|
|
|
|
bkwd_iter_->enqueueAdjacentVertices(vertex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PathGroupPathVisitor::visitFromToPath(const Pin *,
|
|
|
|
|
Vertex *from_vertex,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *,
|
2018-09-28 17:54:21 +02:00
|
|
|
Tag *from_tag,
|
2025-03-27 02:21:03 +01:00
|
|
|
Path *,
|
2024-10-12 02:02:47 +02:00
|
|
|
const Arrival &,
|
2018-09-28 17:54:21 +02:00
|
|
|
Edge *,
|
|
|
|
|
TimingArc *,
|
|
|
|
|
ArcDelay ,
|
|
|
|
|
Vertex *to_vertex,
|
2019-11-11 23:30:19 +01:00
|
|
|
const RiseFall *to_rf,
|
2018-09-28 17:54:21 +02:00
|
|
|
Tag *to_tag,
|
|
|
|
|
Arrival &,
|
|
|
|
|
const MinMax *,
|
|
|
|
|
const PathAnalysisPt *path_ap)
|
|
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
PathSet *matching_paths = matching_path_map_->findKey(to_vertex);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (matching_paths) {
|
2025-03-27 02:21:03 +01:00
|
|
|
Path to_path(to_vertex, to_tag, this);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (!to_path.isNull()) {
|
|
|
|
|
if (matching_paths->hasKey(&to_path)) {
|
2022-08-12 03:17:46 +02:00
|
|
|
debugPrint(debug_, "visit_path_group", 2, "match %s %s -> %s %s",
|
2025-03-31 00:27:53 +02:00
|
|
|
from_vertex->to_string(this).c_str(),
|
|
|
|
|
from_tag->to_string(this).c_str(),
|
|
|
|
|
to_vertex->to_string(this).c_str(),
|
|
|
|
|
to_tag->to_string(this).c_str());
|
2025-03-27 02:21:03 +01:00
|
|
|
fromMatches(from_vertex, from_tag);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2022-08-12 03:17:46 +02:00
|
|
|
VertexPathIterator to_iter(to_vertex, to_rf, path_ap, this);
|
2018-09-28 17:54:21 +02:00
|
|
|
while (to_iter.hasNext()) {
|
2025-03-27 02:21:03 +01:00
|
|
|
Path *to_path = to_iter.next();
|
2025-09-16 23:49:01 +02:00
|
|
|
if (Tag::matchNoCrpr(to_path->tag(this), to_tag)
|
2018-09-28 17:54:21 +02:00
|
|
|
&& matching_paths->hasKey(to_path)) {
|
2022-08-12 03:17:46 +02:00
|
|
|
debugPrint(debug_, "visit_path_group", 2,
|
2021-01-01 20:46:51 +01:00
|
|
|
"match crpr %s %s -> %s %s",
|
2025-03-31 00:27:53 +02:00
|
|
|
from_vertex->to_string(this).c_str(),
|
|
|
|
|
from_tag->to_string(this).c_str(),
|
|
|
|
|
to_vertex->to_string(this).c_str(),
|
|
|
|
|
to_tag->to_string(this).c_str());
|
2025-03-27 02:21:03 +01:00
|
|
|
fromMatches(from_vertex, from_tag);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PathGroupPathVisitor::fromMatches(Vertex *from_vertex,
|
2025-03-27 02:21:03 +01:00
|
|
|
Tag *from_tag)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
vertex_matches_ = true;
|
|
|
|
|
vertexPathSetMapInsertPath(matching_path_map_, from_vertex,
|
2025-03-27 02:21:03 +01:00
|
|
|
from_tag, this);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|