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 "Path.hh"
|
2020-04-05 20:35:51 +02:00
|
|
|
|
2023-12-07 18:27:45 +01:00
|
|
|
#include "TimingRole.hh"
|
2020-04-05 23:53:44 +02:00
|
|
|
#include "TimingArc.hh"
|
|
|
|
|
#include "Network.hh"
|
|
|
|
|
#include "Graph.hh"
|
|
|
|
|
#include "Clock.hh"
|
|
|
|
|
#include "DcalcAnalysisPt.hh"
|
|
|
|
|
#include "Corner.hh"
|
|
|
|
|
#include "PathAnalysisPt.hh"
|
|
|
|
|
#include "Tag.hh"
|
2025-03-27 02:21:03 +01:00
|
|
|
#include "TagGroup.hh"
|
|
|
|
|
#include "Search.hh"
|
2018-09-28 17:54:21 +02:00
|
|
|
|
|
|
|
|
namespace sta {
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
Path::Path() :
|
|
|
|
|
prev_path_(nullptr),
|
|
|
|
|
arrival_(0.0),
|
|
|
|
|
required_(0.0),
|
|
|
|
|
vertex_id_(vertex_id_null),
|
|
|
|
|
tag_index_(tag_index_null),
|
|
|
|
|
is_enum_(false),
|
|
|
|
|
prev_arc_idx_(0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Path::Path(Path *path) :
|
|
|
|
|
prev_path_(path ? path->prev_path_ : nullptr),
|
|
|
|
|
arrival_(path ? path->arrival_ : 0.0),
|
|
|
|
|
required_(path ? path->required_ : 0.0),
|
|
|
|
|
vertex_id_(path ? path->vertex_id_ : vertex_id_null),
|
|
|
|
|
tag_index_(path ? path->tag_index_ : tag_index_null),
|
|
|
|
|
is_enum_(path ? path->is_enum_ : false),
|
|
|
|
|
prev_arc_idx_(path ? path->prev_arc_idx_ : 0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Path::Path(Vertex *vertex,
|
|
|
|
|
Tag *tag,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
prev_path_(nullptr),
|
|
|
|
|
arrival_(0.0),
|
|
|
|
|
required_(0.0),
|
|
|
|
|
tag_index_(tag->index()),
|
|
|
|
|
is_enum_(false),
|
|
|
|
|
prev_arc_idx_(0)
|
|
|
|
|
{
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
vertex_id_ = graph->id(vertex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Path::Path(Vertex *vertex,
|
|
|
|
|
Tag *tag,
|
|
|
|
|
Arrival arrival,
|
|
|
|
|
Path *prev_path,
|
|
|
|
|
Edge *prev_edge,
|
|
|
|
|
TimingArc *prev_arc,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
prev_path_(prev_path),
|
|
|
|
|
arrival_(arrival),
|
|
|
|
|
required_(0.0),
|
|
|
|
|
tag_index_(tag->index()),
|
|
|
|
|
is_enum_(false)
|
|
|
|
|
{
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
if (prev_path) {
|
|
|
|
|
prev_edge_id_ = graph->id(prev_edge);
|
|
|
|
|
prev_arc_idx_ = prev_arc->index();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
vertex_id_ = graph->id(vertex);
|
|
|
|
|
prev_arc_idx_ = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Path::Path(Vertex *vertex,
|
|
|
|
|
Tag *tag,
|
|
|
|
|
Arrival arrival,
|
|
|
|
|
Path *prev_path,
|
|
|
|
|
Edge *prev_edge,
|
|
|
|
|
TimingArc *prev_arc,
|
|
|
|
|
bool is_enum,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
prev_path_(prev_path),
|
|
|
|
|
arrival_(arrival),
|
|
|
|
|
required_(0.0),
|
|
|
|
|
tag_index_(tag->index()),
|
|
|
|
|
is_enum_(is_enum)
|
|
|
|
|
{
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
if (prev_path) {
|
|
|
|
|
prev_edge_id_ = graph->id(prev_edge);
|
|
|
|
|
prev_arc_idx_ = prev_arc->index();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
vertex_id_ = graph->id(vertex);
|
|
|
|
|
prev_arc_idx_ = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Path:: ~Path()
|
|
|
|
|
{
|
|
|
|
|
if (is_enum_ && prev_path_ && prev_path_->is_enum_)
|
|
|
|
|
delete prev_path_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Path::init(Vertex *vertex,
|
|
|
|
|
Arrival arrival,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
vertex_id_ = graph->id(vertex);
|
|
|
|
|
tag_index_ = tag_index_null,
|
|
|
|
|
prev_path_ = nullptr;
|
|
|
|
|
prev_arc_idx_ = 0;
|
|
|
|
|
arrival_ = arrival;
|
|
|
|
|
required_ = 0.0;
|
|
|
|
|
is_enum_ = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Path::init(Vertex *vertex,
|
|
|
|
|
Tag *tag,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
vertex_id_ = graph->id(vertex);
|
|
|
|
|
tag_index_ = tag->index(),
|
|
|
|
|
prev_path_ = nullptr;
|
|
|
|
|
prev_arc_idx_ = 0;
|
|
|
|
|
arrival_ = 0.0;
|
|
|
|
|
required_ = 0.0;
|
|
|
|
|
is_enum_ = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Path::init(Vertex *vertex,
|
|
|
|
|
Tag *tag,
|
|
|
|
|
Arrival arrival,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
vertex_id_ = graph->id(vertex);
|
|
|
|
|
tag_index_ = tag->index(),
|
|
|
|
|
prev_path_ = nullptr;
|
|
|
|
|
prev_arc_idx_ = 0;
|
|
|
|
|
arrival_ = arrival;
|
|
|
|
|
required_ = 0.0;
|
|
|
|
|
is_enum_ = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Path::init(Vertex *vertex,
|
|
|
|
|
Tag *tag,
|
|
|
|
|
Arrival arrival,
|
|
|
|
|
Path *prev_path,
|
|
|
|
|
Edge *prev_edge,
|
|
|
|
|
TimingArc *prev_arc,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
tag_index_ = tag->index(),
|
|
|
|
|
prev_path_ = prev_path;
|
|
|
|
|
if (prev_path) {
|
|
|
|
|
prev_edge_id_ = graph->id(prev_edge);
|
|
|
|
|
prev_arc_idx_ = prev_arc->index();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
vertex_id_ = graph->id(vertex);
|
|
|
|
|
prev_arc_idx_ = 0;
|
|
|
|
|
}
|
|
|
|
|
arrival_ = arrival;
|
|
|
|
|
required_ = 0.0;
|
|
|
|
|
is_enum_ = false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *
|
|
|
|
|
Path::name(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
const Network *network = sta->network();
|
2025-03-27 02:21:03 +01:00
|
|
|
Vertex *vertex = this->vertex(sta);
|
|
|
|
|
if (vertex) {
|
|
|
|
|
const char *vertex_name = vertex->name(network);
|
2018-09-28 17:54:21 +02:00
|
|
|
const char *tr_str = transition(sta)->asString();
|
|
|
|
|
const PathAnalysisPt *path_ap = pathAnalysisPt(sta);
|
|
|
|
|
int ap_index = path_ap->index();
|
|
|
|
|
const char *min_max = path_ap->pathMinMax()->asString();
|
|
|
|
|
TagIndex tag_index = tagIndex(sta);
|
2019-01-17 00:37:31 +01:00
|
|
|
return stringPrintTmp("%s %s %s/%d %d",
|
2018-09-28 17:54:21 +02:00
|
|
|
vertex_name, tr_str, min_max,
|
|
|
|
|
ap_index, tag_index);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return "NULL";
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
bool
|
|
|
|
|
Path::isNull() const
|
|
|
|
|
{
|
|
|
|
|
return vertex_id_ == vertex_id_null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vertex *
|
|
|
|
|
Path::vertex(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
if (prev_path_) {
|
|
|
|
|
const Edge *edge = graph->edge(prev_edge_id_);
|
|
|
|
|
return edge->to(graph);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return graph->vertex(vertex_id_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VertexId
|
|
|
|
|
Path::vertexId(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
if (prev_path_) {
|
|
|
|
|
const Edge *edge = graph->edge(prev_edge_id_);
|
|
|
|
|
return edge->to();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return vertex_id_;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
Pin *
|
|
|
|
|
Path::pin(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
return vertex(sta)->pin();
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
Tag *
|
|
|
|
|
Path::tag(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
const Search *search = sta->search();
|
|
|
|
|
return search->tag(tag_index_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Path::setTag(Tag *tag)
|
|
|
|
|
{
|
|
|
|
|
tag_index_ = tag->index();
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
TagIndex
|
2025-03-27 02:21:03 +01:00
|
|
|
Path::tagIndex(const StaState *) const
|
|
|
|
|
{
|
|
|
|
|
return tag_index_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
Path::pathIndex(const StaState *sta) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
Vertex *vertex = this->vertex(sta);
|
|
|
|
|
Path *paths = vertex->paths();
|
|
|
|
|
return this - paths;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClkInfo *
|
|
|
|
|
Path::clkInfo(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
return tag(sta)->clkInfo();
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *
|
2018-09-28 17:54:21 +02:00
|
|
|
Path::clkEdge(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
return tag(sta)->clkEdge();
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-19 19:23:45 +01:00
|
|
|
const Clock *
|
2018-09-28 17:54:21 +02:00
|
|
|
Path::clock(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
return tag(sta)->clock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
Path::isClock(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
return tag(sta)->isClock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const MinMax *
|
|
|
|
|
Path::minMax(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
return pathAnalysisPt(sta)->pathMinMax();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PathAPIndex
|
|
|
|
|
Path::pathAnalysisPtIndex(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
return pathAnalysisPt(sta)->index();
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-21 07:41:54 +01:00
|
|
|
DcalcAnalysisPt *
|
|
|
|
|
Path::dcalcAnalysisPt(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
return pathAnalysisPt(sta)->dcalcAnalysisPt();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Slew
|
|
|
|
|
Path::slew(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
return sta->graph()->slew(vertex(sta), transition(sta),
|
|
|
|
|
dcalcAnalysisPt(sta)->index());
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
const RiseFall *
|
|
|
|
|
Path::transition(const StaState *sta) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
return tag(sta)->transition();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
int
|
|
|
|
|
Path::rfIndex(const StaState *sta) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
return transition(sta)->index();
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
PathAnalysisPt *
|
|
|
|
|
Path::pathAnalysisPt(const StaState *sta) const
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
return tag(sta)->pathAnalysisPt(sta);
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-03-27 02:21:03 +01:00
|
|
|
Path::setArrival(Arrival arrival)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
arrival_ = arrival;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
void
|
|
|
|
|
Path::setRequired(const Required &required)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
required_ = required;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Slack
|
|
|
|
|
Path::slack(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
if (minMax(sta) == MinMax::max())
|
2025-03-27 02:21:03 +01:00
|
|
|
return required_ - arrival_;
|
2018-09-28 17:54:21 +02:00
|
|
|
else
|
2025-03-27 02:21:03 +01:00
|
|
|
return arrival_ - required_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Path *
|
|
|
|
|
Path::prevPath() const
|
|
|
|
|
{
|
|
|
|
|
return prev_path_;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2025-03-27 02:21:03 +01:00
|
|
|
Path::setPrevPath(Path *prev_path)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
prev_path_ = prev_path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Path::clearPrevPath(const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
// Preserve vertex ID for path when prev edge is no longer valid.
|
|
|
|
|
if (prev_path_) {
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
const Edge *prev_edge = graph->edge(prev_edge_id_);
|
|
|
|
|
vertex_id_ = prev_edge->to();
|
|
|
|
|
prev_arc_idx_ = 0;
|
|
|
|
|
}
|
|
|
|
|
prev_path_ = nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TimingArc *
|
|
|
|
|
Path::prevArc(const StaState *sta) const
|
|
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
if (prev_path_) {
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
const Edge *edge = graph->edge(prev_edge_id_);
|
|
|
|
|
TimingArcSet *arc_set = edge->timingArcSet();
|
|
|
|
|
return arc_set->findTimingArc(prev_arc_idx_);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return nullptr;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Edge *
|
2025-03-27 02:21:03 +01:00
|
|
|
Path::prevEdge(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
if (prev_path_) {
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
return graph->edge(prev_edge_id_);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Vertex *
|
|
|
|
|
Path::prevVertex(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
if (prev_path_) {
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
return graph->edge(prev_edge_id_)->from(graph);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Path::setPrevEdgeArc(Edge *prev_edge,
|
|
|
|
|
TimingArc *prev_arc,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
if (prev_edge) {
|
|
|
|
|
const Graph *graph = sta->graph();
|
|
|
|
|
prev_edge_id_ = graph->id(prev_edge);
|
|
|
|
|
prev_arc_idx_ = prev_arc->index();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
prev_arc_idx_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Path::checkPrevPaths(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
const Path *path = this;
|
|
|
|
|
while (path) {
|
|
|
|
|
path->checkPrevPath(sta);
|
|
|
|
|
path = path->prevPath();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Path::checkPrevPath(const StaState *sta) const
|
|
|
|
|
{
|
|
|
|
|
if (prev_path_ && !prev_path_->isNull()) {
|
|
|
|
|
Graph *graph = sta->graph();
|
|
|
|
|
Edge *edge = prevEdge(sta);
|
|
|
|
|
Vertex *prev_vertex = prev_path_->vertex(sta);
|
|
|
|
|
Vertex *prev_edge_vertex = edge->from(graph);
|
|
|
|
|
if (prev_vertex != prev_edge_vertex) {
|
|
|
|
|
Network *network = sta->network();
|
|
|
|
|
sta->report()->reportLine("path %s prev path corrupted %s vs %s.",
|
|
|
|
|
name(sta),
|
|
|
|
|
prev_vertex->name(network),
|
|
|
|
|
prev_edge_vertex->name(network));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
2025-03-27 02:21:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Path::setIsEnum(bool is_enum)
|
|
|
|
|
{
|
|
|
|
|
is_enum_ = is_enum;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
Path *
|
|
|
|
|
Path::vertexPath(const Path &path,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
if (!path.isNull()) {
|
|
|
|
|
Vertex *vertex = path.vertex(sta);
|
|
|
|
|
Tag *tag = path.tag(sta);
|
|
|
|
|
return vertexPath(vertex, tag, sta);
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Path *
|
|
|
|
|
Path::vertexPath(const Vertex *vertex,
|
|
|
|
|
Tag *tag,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
const Search *search = sta->search();
|
|
|
|
|
TagGroup *tag_group = search->tagGroup(vertex);
|
|
|
|
|
if (tag_group) {
|
|
|
|
|
size_t path_index;
|
|
|
|
|
bool exists;
|
|
|
|
|
tag_group->pathIndex(tag, path_index, exists);
|
|
|
|
|
if (exists) {
|
|
|
|
|
Path *paths = vertex->paths();
|
|
|
|
|
Path &src_vpath = paths[path_index];
|
|
|
|
|
if (!src_vpath.isNull())
|
|
|
|
|
return &src_vpath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
int
|
|
|
|
|
Path::cmpPinTrClk(const Path *path1,
|
|
|
|
|
const Path *path2,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
if (path1 && path2) {
|
|
|
|
|
const Pin *pin1 = path1->pin(sta);
|
|
|
|
|
const Pin *pin2 = path2->pin(sta);
|
|
|
|
|
const Network *network = sta->network();
|
|
|
|
|
if (pin1 == pin2) {
|
2019-11-11 23:30:19 +01:00
|
|
|
int tr_index1 = path1->rfIndex(sta);
|
|
|
|
|
int tr_index2 = path2->rfIndex(sta);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (tr_index1 == tr_index2)
|
|
|
|
|
return cmpClk(path1, path2, sta);
|
|
|
|
|
else if (tr_index1 < tr_index2)
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else if (network->pathNameLess(pin1, pin2))
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (path1 == nullptr && path2 == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
return 0;
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (path1 == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Path::cmpClk(const Path *path1,
|
|
|
|
|
const Path *path2,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
2023-01-19 19:23:45 +01:00
|
|
|
const ClockEdge *clk_edge1 = path1->clkEdge(sta);
|
|
|
|
|
const ClockEdge *clk_edge2 = path2->clkEdge(sta);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (clk_edge1 && clk_edge2) {
|
|
|
|
|
int index1 = clk_edge1->index();
|
|
|
|
|
int index2 = clk_edge2->index();
|
|
|
|
|
if (index1 == index2)
|
|
|
|
|
return 0;
|
|
|
|
|
else if (index1 < index2)
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (clk_edge1 == nullptr
|
|
|
|
|
&& clk_edge2 == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
return 0;
|
|
|
|
|
else if (clk_edge2)
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
Path::equal(const Path *path1,
|
|
|
|
|
const Path *path2,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
return (path1 == nullptr && path2 == nullptr)
|
|
|
|
|
|| (path1
|
|
|
|
|
&& path2
|
2020-01-06 22:56:47 +01:00
|
|
|
&& path1->vertexId(sta) == path2->vertexId(sta)
|
|
|
|
|
// Tag equal implies transition and path ap equal.
|
|
|
|
|
&& path1->tagIndex(sta) == path2->tagIndex(sta));
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
PathLess::PathLess(const StaState *sta) :
|
|
|
|
|
sta_(sta)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PathLess::operator()(const Path *path1,
|
|
|
|
|
const Path *path2) const
|
|
|
|
|
{
|
|
|
|
|
return Path::less(path1, path2, sta_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
Path::less(const Path *path1,
|
2020-01-07 01:16:43 +01:00
|
|
|
const Path *path2,
|
|
|
|
|
const StaState *sta)
|
2018-09-28 17:54:21 +02:00
|
|
|
{
|
|
|
|
|
return cmp(path1, path2, sta) < 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Path::cmp(const Path *path1,
|
|
|
|
|
const Path *path2,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
if (path1 && path2) {
|
2019-11-11 17:38:25 +01:00
|
|
|
VertexId vertex_id1 = path1->vertexId(sta);
|
|
|
|
|
VertexId vertex_id2 = path2->vertexId(sta);
|
|
|
|
|
if (vertex_id1 == vertex_id2) {
|
2018-09-28 17:54:21 +02:00
|
|
|
TagIndex tag_index1 = path1->tagIndex(sta);
|
|
|
|
|
TagIndex tag_index2 = path2->tagIndex(sta);
|
|
|
|
|
if (tag_index1 == tag_index2)
|
|
|
|
|
return 0;
|
|
|
|
|
else if (tag_index1 < tag_index2)
|
|
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-11-11 17:38:25 +01:00
|
|
|
else if (vertex_id1 < vertex_id2)
|
2018-09-28 17:54:21 +02:00
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (path1 == nullptr
|
|
|
|
|
&& path2 == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
return 0;
|
2019-03-13 01:25:53 +01:00
|
|
|
else if (path1 == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Path::cmpNoCrpr(const Path *path1,
|
|
|
|
|
const Path *path2,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
2019-11-11 17:38:25 +01:00
|
|
|
VertexId vertex_id1 = path1->vertexId(sta);
|
|
|
|
|
VertexId vertex_id2 = path2->vertexId(sta);
|
|
|
|
|
if (vertex_id1 == vertex_id2)
|
2018-09-28 17:54:21 +02:00
|
|
|
return tagMatchCmp(path1->tag(sta), path2->tag(sta), false, sta);
|
2019-11-11 17:38:25 +01:00
|
|
|
else if (vertex_id1 < vertex_id2)
|
2018-09-28 17:54:21 +02:00
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Path::cmpAll(const Path *path1,
|
|
|
|
|
const Path *path2,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
2025-03-27 02:21:03 +01:00
|
|
|
const Path *p1 = path1;
|
|
|
|
|
const Path *p2 = path2;
|
|
|
|
|
while (p1 && p2) {
|
|
|
|
|
int cmp = Path::cmp(p1, p2, sta);
|
2018-09-28 17:54:21 +02:00
|
|
|
if (cmp != 0)
|
|
|
|
|
return cmp;
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
TimingArc *prev_arc1 = p1->prevArc(sta);
|
|
|
|
|
TimingArc *prev_arc2 = p2->prevArc(sta);
|
|
|
|
|
p1 = p1->prevPath();
|
|
|
|
|
p2 = p2->prevPath();
|
|
|
|
|
if (equal(p1, path1, sta))
|
2018-09-28 17:54:21 +02:00
|
|
|
// Equivalent latch loops.
|
|
|
|
|
return 0;
|
2023-12-07 18:27:45 +01:00
|
|
|
if ((prev_arc1 && prev_arc1->role()->isLatchDtoQ())
|
|
|
|
|
|| (prev_arc2 && prev_arc2->role()->isLatchDtoQ()))
|
|
|
|
|
break;
|
2018-09-28 17:54:21 +02:00
|
|
|
}
|
2025-03-27 02:21:03 +01:00
|
|
|
if (p1 == nullptr && p2 == nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
return 0;
|
2025-03-27 02:21:03 +01:00
|
|
|
else if (p1 == nullptr && p2 != nullptr)
|
2018-09-28 17:54:21 +02:00
|
|
|
return -1;
|
|
|
|
|
else
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
Path::lessAll(const Path *path1,
|
|
|
|
|
const Path *path2,
|
|
|
|
|
const StaState *sta)
|
|
|
|
|
{
|
|
|
|
|
return cmpAll(path1, path2, sta) < 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-27 02:21:03 +01:00
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
VertexPathIterator::VertexPathIterator(Vertex *vertex,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
search_(sta->search()),
|
|
|
|
|
//filtered_(false),
|
|
|
|
|
rf_(nullptr),
|
|
|
|
|
path_ap_(nullptr),
|
|
|
|
|
min_max_(nullptr),
|
|
|
|
|
paths_(vertex->paths()),
|
|
|
|
|
path_count_(0),
|
|
|
|
|
//path_index_(0),
|
|
|
|
|
next_(nullptr)
|
|
|
|
|
{
|
|
|
|
|
TagGroup *tag_group = search_->tagGroup(vertex);
|
|
|
|
|
if (tag_group) {
|
|
|
|
|
path_count_ = tag_group->pathCount();
|
|
|
|
|
path_iter_.init(tag_group->pathIndexMap());
|
|
|
|
|
findNext();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Iterate over vertex paths with the same transition and
|
|
|
|
|
// analysis pt but different but different tags.
|
|
|
|
|
VertexPathIterator::VertexPathIterator(Vertex *vertex,
|
|
|
|
|
const RiseFall *rf,
|
|
|
|
|
const PathAnalysisPt *path_ap,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
search_(sta->search()),
|
|
|
|
|
//filtered_(true),
|
|
|
|
|
rf_(rf),
|
|
|
|
|
path_ap_(path_ap),
|
|
|
|
|
min_max_(nullptr),
|
|
|
|
|
paths_(vertex->paths()),
|
|
|
|
|
//path_count_(0),
|
|
|
|
|
//path_index_(0),
|
|
|
|
|
next_(nullptr)
|
|
|
|
|
{
|
|
|
|
|
TagGroup *tag_group = search_->tagGroup(vertex);
|
|
|
|
|
if (tag_group) {
|
|
|
|
|
path_count_ = tag_group->pathCount();
|
|
|
|
|
path_iter_.init(tag_group->pathIndexMap());
|
|
|
|
|
findNext();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VertexPathIterator::VertexPathIterator(Vertex *vertex,
|
|
|
|
|
const RiseFall *rf,
|
|
|
|
|
const MinMax *min_max,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
search_(sta->search()),
|
|
|
|
|
//filtered_(true),
|
|
|
|
|
rf_(rf),
|
|
|
|
|
path_ap_(nullptr),
|
|
|
|
|
min_max_(min_max),
|
|
|
|
|
paths_(vertex->paths()),
|
|
|
|
|
//path_count_(0),
|
|
|
|
|
//path_index_(0),
|
|
|
|
|
next_(nullptr)
|
|
|
|
|
{
|
|
|
|
|
TagGroup *tag_group = search_->tagGroup(vertex);
|
|
|
|
|
if (tag_group) {
|
|
|
|
|
path_count_ = tag_group->pathCount();
|
|
|
|
|
path_iter_.init(tag_group->pathIndexMap());
|
|
|
|
|
findNext();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VertexPathIterator::VertexPathIterator(Vertex *vertex,
|
|
|
|
|
const RiseFall *rf,
|
|
|
|
|
const PathAnalysisPt *path_ap,
|
|
|
|
|
const MinMax *min_max,
|
|
|
|
|
const StaState *sta) :
|
|
|
|
|
search_(sta->search()),
|
|
|
|
|
//filtered_(true),
|
|
|
|
|
rf_(rf),
|
|
|
|
|
path_ap_(path_ap),
|
|
|
|
|
min_max_(min_max),
|
|
|
|
|
paths_(vertex->paths()),
|
|
|
|
|
//path_count_(0),
|
|
|
|
|
//path_index_(0),
|
|
|
|
|
next_(nullptr)
|
|
|
|
|
{
|
|
|
|
|
TagGroup *tag_group = search_->tagGroup(vertex);
|
|
|
|
|
if (tag_group) {
|
|
|
|
|
path_count_ = tag_group->pathCount();
|
|
|
|
|
path_iter_.init(tag_group->pathIndexMap());
|
|
|
|
|
findNext();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VertexPathIterator::~VertexPathIterator()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
VertexPathIterator::hasNext()
|
|
|
|
|
{
|
|
|
|
|
return next_ != nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
void
|
|
|
|
|
VertexPathIterator::findNext()
|
|
|
|
|
{
|
|
|
|
|
while (path_index_ < path_count_) {
|
|
|
|
|
Path *path = &paths_[path_index_++];
|
|
|
|
|
if (filtered_) {
|
|
|
|
|
const Tag *tag = path->tag(search_);
|
|
|
|
|
if ((rf_ == nullptr
|
|
|
|
|
|| tag->rfIndex() == rf_->index())
|
|
|
|
|
&& (path_ap_ == nullptr
|
|
|
|
|
|| tag->pathAPIndex() == path_ap_->index())
|
|
|
|
|
&& (min_max_ == nullptr
|
|
|
|
|
|| tag->pathAnalysisPt(search_)->pathMinMax() == min_max_)) {
|
|
|
|
|
next_ = path;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
next_ = path;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
next_ = nullptr;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
VertexPathIterator::findNext()
|
|
|
|
|
{
|
|
|
|
|
while (path_iter_.hasNext()) {
|
|
|
|
|
Tag *tag;
|
|
|
|
|
size_t path_index;
|
|
|
|
|
path_iter_.next(tag, path_index);
|
|
|
|
|
if ((rf_ == nullptr
|
|
|
|
|
|| tag->rfIndex() == rf_->index())
|
|
|
|
|
&& (path_ap_ == nullptr
|
|
|
|
|
|| tag->pathAPIndex() == path_ap_->index())
|
|
|
|
|
&& (min_max_ == nullptr
|
|
|
|
|
|| tag->pathAnalysisPt(search_)->pathMinMax() == min_max_)) {
|
|
|
|
|
next_ = &paths_[path_index];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
next_ = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Path *
|
|
|
|
|
VertexPathIterator::next()
|
|
|
|
|
{
|
|
|
|
|
Path *path = next_;
|
|
|
|
|
findNext();
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 17:54:21 +02:00
|
|
|
} // namespace
|