OpenSTA/search/Path.cc

370 lines
7.8 KiB
C++

// OpenSTA, Static Timing Analyzer
// Copyright (c) 2024, Parallax Software, Inc.
//
// 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/>.
#include "Path.hh"
#include "TimingRole.hh"
#include "TimingArc.hh"
#include "Network.hh"
#include "Graph.hh"
#include "Clock.hh"
#include "DcalcAnalysisPt.hh"
#include "Corner.hh"
#include "PathAnalysisPt.hh"
#include "Tag.hh"
#include "PathRef.hh"
namespace sta {
const char *
Path::name(const StaState *sta) const
{
const Network *network = sta->network();
Vertex *vertex1 = vertex(sta);
if (vertex1) {
const char *vertex_name = vertex1->name(network);
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);
return stringPrintTmp("%s %s %s/%d %d",
vertex_name, tr_str, min_max,
ap_index, tag_index);
}
else
return "NULL";
}
Pin *
Path::pin(const StaState *sta) const
{
return vertex(sta)->pin();
}
TagIndex
Path::tagIndex(const StaState *sta) const
{
return tag(sta)->index();
}
ClkInfo *
Path::clkInfo(const StaState *sta) const
{
return tag(sta)->clkInfo();
}
const ClockEdge *
Path::clkEdge(const StaState *sta) const
{
return tag(sta)->clkEdge();
}
const Clock *
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();
}
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());
}
int
Path::rfIndex(const StaState *sta) const
{
return transition(sta)->index();
}
void
Path::initArrival(const StaState *sta)
{
setArrival(delayInitValue(minMax(sta)), sta);
}
bool
Path::arrivalIsInitValue(const StaState *sta) const
{
return delayIsInitValue(arrival(sta), minMax(sta));
}
void
Path::initRequired(const StaState *sta)
{
setRequired(delayInitValue(minMax(sta)->opposite()), sta);
}
bool
Path::requiredIsInitValue(const StaState *sta) const
{
return delayIsInitValue(required(sta), minMax(sta)->opposite());
}
Slack
Path::slack(const StaState *sta) const
{
if (minMax(sta) == MinMax::max())
return required(sta) - arrival(sta);
else
return arrival(sta) - required(sta);
}
void
Path::prevPath(const StaState *sta,
// Return values.
PathRef &prev_path) const
{
TimingArc *prev_arc;
prevPath(sta, prev_path, prev_arc);
}
TimingArc *
Path::prevArc(const StaState *sta) const
{
PathRef prev_path;
TimingArc *prev_arc;
prevPath(sta, prev_path, prev_arc);
return prev_arc;
}
Edge *
Path::prevEdge(const TimingArc *prev_arc,
const StaState *sta) const
{
if (prev_arc) {
TimingArcSet *arc_set = prev_arc->set();
VertexInEdgeIterator edge_iter(vertex(sta), sta->graph());
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->timingArcSet() == arc_set)
return edge;
}
}
return nullptr;
}
////////////////////////////////////////////////////////////////
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) {
int tr_index1 = path1->rfIndex(sta);
int tr_index2 = path2->rfIndex(sta);
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;
}
else if (path1 == nullptr && path2 == nullptr)
return 0;
else if (path1 == nullptr)
return -1;
else
return 1;
}
int
Path::cmpClk(const Path *path1,
const Path *path2,
const StaState *sta)
{
const ClockEdge *clk_edge1 = path1->clkEdge(sta);
const ClockEdge *clk_edge2 = path2->clkEdge(sta);
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;
}
else if (clk_edge1 == nullptr
&& clk_edge2 == nullptr)
return 0;
else if (clk_edge2)
return -1;
else
return 1;
}
bool
Path::equal(const Path *path1,
const Path *path2,
const StaState *sta)
{
bool path1_null = (path1 == nullptr || path1->isNull());
bool path2_null = (path2 == nullptr || path2->isNull());
return (path1_null && path2_null)
|| (!path1_null
&& !path2_null
&& path1->vertexId(sta) == path2->vertexId(sta)
// Tag equal implies transition and path ap equal.
&& path1->tagIndex(sta) == path2->tagIndex(sta));
}
////////////////////////////////////////////////////////////////
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,
const Path *path2,
const StaState *sta)
{
return cmp(path1, path2, sta) < 0;
}
int
Path::cmp(const Path *path1,
const Path *path2,
const StaState *sta)
{
if (path1 && path2) {
VertexId vertex_id1 = path1->vertexId(sta);
VertexId vertex_id2 = path2->vertexId(sta);
if (vertex_id1 == vertex_id2) {
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;
}
else if (vertex_id1 < vertex_id2)
return -1;
else
return 1;
}
else if (path1 == nullptr
&& path2 == nullptr)
return 0;
else if (path1 == nullptr)
return -1;
else
return 1;
}
int
Path::cmpNoCrpr(const Path *path1,
const Path *path2,
const StaState *sta)
{
VertexId vertex_id1 = path1->vertexId(sta);
VertexId vertex_id2 = path2->vertexId(sta);
if (vertex_id1 == vertex_id2)
return tagMatchCmp(path1->tag(sta), path2->tag(sta), false, sta);
else if (vertex_id1 < vertex_id2)
return -1;
else
return 1;
}
int
Path::cmpAll(const Path *path1,
const Path *path2,
const StaState *sta)
{
PathRef p1(path1);
PathRef p2(path2);
while (!p1.isNull()
&& !p2.isNull()) {
int cmp = Path::cmp(&p1, &p2, sta);
if (cmp != 0)
return cmp;
TimingArc *prev_arc1, *prev_arc2;
p1.prevPath(sta, p1, prev_arc1);
p2.prevPath(sta, p2, prev_arc2);
if (equal(&p1, path1, sta))
// Equivalent latch loops.
return 0;
if ((prev_arc1 && prev_arc1->role()->isLatchDtoQ())
|| (prev_arc2 && prev_arc2->role()->isLatchDtoQ()))
break;
}
if (p1.isNull() && p2.isNull())
return 0;
else if (p1.isNull() && !p2.isNull())
return -1;
else
return 1;
}
bool
Path::lessAll(const Path *path1,
const Path *path2,
const StaState *sta)
{
return cmpAll(path1, path2, sta) < 0;
}
} // namespace