class Path replaces PathVertex etc

commit 08c062d3dd1d0cea846407dda0b5fd75ca64329c
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 25 16:17:42 2025 -0700

    ApiChanges.txt

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit ef72112a00419e466e19b5c1442cac6f2835adaa
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 23 12:37:10 2025 -0700

    crpr29/30

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 2065acfbfbaa84307fde1c46ff51a1c619c45f50
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 23 12:33:55 2025 -0700

    compile error

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit d3133015b90b59f7e8e934c20d1ed8449d543d7b
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Mar 17 15:20:55 2025 -0700

    rebase falout

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 8a4b81755765db823e18ffb497f1fb3f0c64ec7b
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Mar 17 09:22:01 2025 -0700

    rebase fallout

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 7ef00dcaa4ed0b6db3f4205da47013e4f2ef1049
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sat Mar 15 17:00:51 2025 -0700

    deleteEdge clear to path prev_paths

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 912dacbca8f5c286f623f13659c831be6ed4d93e
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sat Mar 15 12:05:06 2025 -0700

    undo 7f8c7adb

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 9944c2ec907e9f07ab46f71af55ec947f3815de0
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Mar 14 21:25:10 2025 -0700

    rm Path::path()

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit a42c28b8447466a445cd8f6fb022eb42e6dcc0f2
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Mar 14 17:12:17 2025 -0700

    const

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 3f72adf1b5ad5581adc81afd3e00be7343ae4183
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Mar 14 17:03:04 2025 -0700

    PathExpanded rm prev_arcs_

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 25879e66eddf9f12db38705807e1270459661810
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Mar 13 12:34:12 2025 -0700

    worst path init path

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 5c7a4fbdf3b8823a1944074a7eb663c6ea8e32df
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Mar 13 10:47:02 2025 -0700

    delete edge -> xelete paths of to vertex

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit aa8d3035489de2cd25f27f7531177193be7a40ac
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Mar 13 09:17:27 2025 -0700

    debug

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 53741b6c624b1313b0464a31e3900472d0b7c8d2
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Mar 13 08:50:01 2025 -0700

    debug

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit cdebd8f3e476e5a2afab1a949449b75dcec9ed97
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Mar 13 08:14:58 2025 -0700

    dbg network_edit

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 60cc960439e65cda8cd244723456b81242ced458
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Mar 13 07:42:22 2025 -0700

    dbg network edit

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit f4e4264ac1c11dafddbe18971ca35127a0ffc171
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 11 19:23:17 2025 -0700

    rm PathVertex.hh

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit aeba9b293f095aecd01d0f5d16de51640f3d2381
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 11 13:33:21 2025 -0700

    PathEnum rm divEdge

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit ad97706562da7ceb41b9fbf4c882083de36d578d
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 11 13:18:38 2025 -0700

    genclks use path vector

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit a9c2563199d0cee3dee3d420c70f8117cfd69221
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 11 12:42:12 2025 -0700

    group_path_count, end_path_count use size_t

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit f16309a8e09e22964b998bf1b7e0922fbb9f02c1
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 11 12:30:08 2025 -0700

    Path rm uused

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 51295613c4ab6a6a4170080252397e2846a61bf1
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 11 12:22:23 2025 -0700

    network_edit3

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 5de6da2190460183cf07d0d4ffc1d1c6ebbe3e10
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 11 10:33:09 2025 -0700

    leak

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit f52dbc18ce08bd2b14d7107b61a57e614b1e3a07
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 11 08:06:56 2025 -0700

    valgrind 3 leaks left

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit de1a3727d908c4494f3039ff714ddb939d3390b5
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Mar 10 18:21:50 2025 -0700

    Path::prevPath

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit c40aadcac8d2cd6d6dd8ba18f2e9db607358a01f
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Mar 10 18:21:31 2025 -0700

    clk_skew init

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 041c97194553e7f7a4746f506be251ee42eb83ee
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Mar 10 07:38:49 2025 -0700

    delete path groups before paths

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit fb4aed589f9f67ddb39f4260cb2901764cf49a98
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 9 17:23:27 2025 -0700

    leak

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 70b3062872cefdcf1358847025bc7bb1a85f4a5b
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 9 17:09:45 2025 -0700

    1 failure

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 92cd7c33c1eb22e4f574a767a645c5db1c9efe4d
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 9 11:19:59 2025 -0700

    7 failures

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 537ec153a5f8ab30d800cd36130e7668047b67af
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 9 09:05:31 2025 -0700

    11 failures

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit df514124c4daaf90175a89138ed954e20573e02f
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 9 08:37:00 2025 -0700

    25 failures

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 0096e8ee5a83194aee84da2cba95f410931f5c0e
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sat Mar 8 16:05:04 2025 -0700

    33 failures

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 02ba7ffdf38b538cd1659df25837d37e8317e741
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Mar 7 21:39:53 2025 -0700

    delete path groups before pahts

    Signed-Off-by: James Cherry <cherry@parallaxsw.com>

commit 270dbad6bc9303f9255256b5b85cac84deb27a94
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Mar 7 18:27:52 2025 -0700

    no seg faults, 42 failures

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 3ceca5981fd6032294523cd23dc1334b9619f6a0
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Mar 6 15:43:28 2025 -0700

    multiclk1,2 seg fault

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 0441c00dc172817cc1a39bbb740d6369cf163869
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Mar 6 15:29:47 2025 -0700

    gated_clocks15

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 7a1f87737e9c8247acd2c78138ee482d46123952
Author: James Cherry <cherry@parallaxsw.com>
Date:   Thu Mar 6 09:05:09 2025 -0700

    nworst, crpr

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 74b52e5ac0ed9dac5b7c31835393c4e2dd30ca95
Author: James Cherry <cherry@parallaxsw.com>
Date:   Wed Mar 5 17:18:47 2025 -0700

    check_timiing6

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 93bddf0d940e9b833d5bc47d5af8b3bdefac67a5
Author: James Cherry <cherry@parallaxsw.com>
Date:   Wed Mar 5 17:13:24 2025 -0700

    nworst10

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit f1edddbffb2e0d23bc3f4a10733203b9756f2e2e
Author: James Cherry <cherry@parallaxsw.com>
Date:   Wed Mar 5 16:22:25 2025 -0700

    path enum

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit c57d241b668d305f0492e55e273b3411320692b4
Author: James Cherry <cherry@parallaxsw.com>
Date:   Wed Mar 5 16:09:11 2025 -0700

    most nwost pass

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit c6fca38e28571e5f2d63236aa67233d572c3a1d6
Author: James Cherry <cherry@parallaxsw.com>
Date:   Wed Mar 5 09:15:47 2025 -0700

    most genclks

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 82f5e6e9252987433f9699919c5716b3a4321a5d
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 4 17:51:29 2025 -0700

    genclks

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 19f4035496e004c543110b063482928e55bddbc9
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 4 17:33:28 2025 -0700

    nworst1

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit edafefa4e4f98291a3edebe5c7b3e2630988723f
Author: James Cherry <cherry@parallaxsw.com>
Date:   Tue Mar 4 15:02:38 2025 -0700

    path enum

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 3e4684fd67eacdb474574eee9e51741e75bba907
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Mar 3 21:07:18 2025 -0700

    rm unused Path* files

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 3f04819c01002f8b5eec0f4b8f0caf6798f3a20f
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Mar 3 19:43:35 2025 -0700

    more regressions pass

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 276d70283cda14dfd6c48d1e2e4f45d326bf286c
Author: James Cherry <cherry@parallaxsw.com>
Date:   Mon Mar 3 10:43:30 2025 -0700

    arrival1

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 383a480450833741144b57383bb40a33310fad44
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 2 19:23:40 2025 -0700

    arrival1 no segfault

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 36e3a6b8d8b19f185a5a71fb4547e17586ea2c44
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 2 18:40:23 2025 -0700

    VertexPathIterator

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 083c76201e1a5482726e5856f124b15a523453d6
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 2 18:18:15 2025 -0700

    report_checks3 passes

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 834c076b7e2cb733655d917881463c76ce6196f6
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 2 14:10:34 2025 -0800

    links

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 371792b1e6dd44ad0c72399b999d86cd2557cbe1
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 2 13:37:33 2025 -0800

    link errors

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 158e9dafa6d11e0a4fd4e7ef253b0b6cb7595bf6
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 2 12:30:29 2025 -0800

    compiles

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 8df515dab15c0744abe04eae7e4a7d7688455f03
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 2 09:41:51 2025 -0800

    PathEnd compiles

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit d94f241d0803376b1526f32e4f5111d081c604af
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sun Mar 2 07:42:51 2025 -0800

    compile progress

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 591997e3bb496c4cc2fd6963c3798a8e17b8f587
Author: James Cherry <cherry@parallaxsw.com>
Date:   Sat Mar 1 10:42:11 2025 -0800

    path unification

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2025-03-26 18:21:03 -07:00
parent 950d5b3383
commit 8992827b5b
69 changed files with 2148 additions and 3883 deletions

View File

@ -184,15 +184,11 @@ set(STA_SOURCE
search/MakeTimingModel.cc
search/Path.cc
search/PathAnalysisPt.cc
search/Path.cc
search/PathEnd.cc
search/PathEnum.cc
search/PathEnumed.cc
search/PathExpanded.cc
search/PathGroup.cc
search/PathPrev.cc
search/PathRef.cc
search/PathVertex.cc
search/PathVertexPtr.cc
search/Property.cc
search/ReportPath.cc
search/Search.cc

View File

@ -24,6 +24,19 @@
This file summarizes STA API changes for each release.
Release 2.4.0 2025/03/??
-------------------------
The following classes have been replaced by the class Path.
PathEnumed
PathPrev
PathRef
PathVertex
PathVertexPtr
PathVertexRep
The PathExpanded::prevArc function has been removed. Use Path::prevArc instead.
Release 2.4.0 2023/01/19
-------------------------

View File

@ -571,75 +571,25 @@ Graph::gateEdgeArc(const Pin *in_pin,
////////////////////////////////////////////////////////////////
Arrival *
Graph::makeArrivals(Vertex *vertex,
uint32_t count)
Path *
Graph::makePaths(Vertex *vertex,
uint32_t count)
{
Arrival *arrivals = new Arrival[count];
vertex->setArrivals(arrivals);
return arrivals;
Path *paths = new Path[count];
vertex->setPaths(paths);
return paths;
}
Arrival *
Graph::arrivals(const Vertex *vertex) const
Path *
Graph::paths(const Vertex *vertex) const
{
return vertex->arrivals();
}
void
Graph::deleteArrivals(Vertex *vertex)
{
vertex->setArrivals(nullptr);
}
Required *
Graph::requireds(const Vertex *vertex) const
{
return vertex->requireds();
}
Required *
Graph::makeRequireds(Vertex *vertex,
uint32_t count)
{
Required *requireds = new Arrival[count];
vertex->setRequireds(requireds);
return requireds;
}
void
Graph::deleteRequireds(Vertex *vertex)
{
vertex->setRequireds(nullptr);
}
PathPrev *
Graph::prevPaths(const Vertex *vertex) const
{
return vertex->prevPaths();
}
PathPrev *
Graph::makePrevPaths(Vertex *vertex,
uint32_t count)
{
PathPrev *prev_paths = new PathPrev[count];
vertex->setPrevPaths(prev_paths);
return prev_paths;
}
void
Graph::deletePrevPaths(Vertex *vertex)
{
vertex->setPrevPaths(nullptr);
return vertex->paths();
}
void
Graph::deletePaths(Vertex *vertex)
{
deleteArrivals(vertex);
deleteRequireds(vertex);
deletePrevPaths(vertex);
vertex->setPaths(nullptr);
vertex->tag_group_index_ = tag_group_index_max;
vertex->crpr_path_pruning_disabled_ = false;
}
@ -1007,9 +957,7 @@ Vertex::init(Pin *pin,
in_edges_ = edge_id_null;
out_edges_ = edge_id_null;
slews_ = nullptr;
arrivals_ = nullptr;
requireds_ = nullptr;
prev_paths_ = nullptr;
paths_ = nullptr;
tag_group_index_ = tag_group_index_max;
slew_annotated_ = false;
sim_value_ = unsigned(LogicValue::unknown);
@ -1035,12 +983,8 @@ Vertex::clear()
{
delete [] slews_;
slews_ = nullptr;
delete [] arrivals_;
arrivals_ = nullptr;
delete [] requireds_;
requireds_ = nullptr;
delete [] prev_paths_;
prev_paths_ = nullptr;
delete [] paths_;
paths_ = nullptr;
}
void
@ -1153,24 +1097,10 @@ Vertex::setTagGroupIndex(TagGroupIndex tag_index)
}
void
Vertex::setArrivals(Arrival *arrivals)
Vertex::setPaths(Path *paths)
{
delete [] arrivals_;
arrivals_ = arrivals;
}
void
Vertex::setRequireds(Required *requireds)
{
delete [] requireds_;
requireds_ = requireds;
}
void
Vertex::setPrevPaths(PathPrev *prev_paths)
{
delete [] prev_paths_;
prev_paths_ = prev_paths;
delete [] paths_;
paths_ = paths;
}
LogicValue

View File

@ -36,7 +36,7 @@
#include "Delay.hh"
#include "GraphClass.hh"
#include "VertexId.hh"
#include "PathPrev.hh"
#include "Path.hh"
#include "StaState.hh"
namespace sta {
@ -96,19 +96,9 @@ public:
void deleteVertex(Vertex *vertex);
bool hasFaninOne(Vertex *vertex) const;
VertexId vertexCount() { return vertices_->size(); }
Arrival *makeArrivals(Vertex *vertex,
uint32_t count);
Arrival *arrivals(const Vertex *vertex) const;
void deleteArrivals(Vertex *vertex);
Required *makeRequireds(Vertex *vertex,
uint32_t count);
Required *requireds(const Vertex *vertex) const;
void deleteRequireds(Vertex *vertex);
PathPrev *makePrevPaths(Vertex *vertex,
uint32_t count);
PathPrev *prevPaths(const Vertex *vertex) const;
void deletePrevPaths(Vertex *vertex);
// Private to Search::deletePaths(Vertex).
Path *makePaths(Vertex *vertex,
uint32_t count);
Path *paths(const Vertex *vertex) const;
void deletePaths(Vertex *vertex);
// Reported slew are the same as those in the liberty tables.
@ -269,10 +259,8 @@ public:
void setColor(LevelColor color);
Slew *slews() { return slews_; }
const Slew *slews() const { return slews_; }
Arrival *arrivals() const { return arrivals_; }
Arrival *requireds() const { return requireds_; }
PathPrev *prevPaths() const { return prev_paths_; }
void setPrevPaths(PathPrev *prev_paths);
Path *paths() const { return paths_; }
void setPaths(Path *paths);
TagGroupIndex tagGroupIndex() const;
void setTagGroupIndex(TagGroupIndex tag_index);
// Slew is annotated by sdc set_annotated_transition cmd.
@ -311,7 +299,6 @@ public:
bool isRegClk() const { return is_reg_clk_; }
bool crprPathPruningDisabled() const { return crpr_path_pruning_disabled_;}
void setCrprPathPruningDisabled(bool disabled);
bool hasRequireds() const { return requireds_ != nullptr; }
// ObjectTable interface.
ObjectIdx objectIdx() const { return object_idx_; }
@ -324,8 +311,6 @@ protected:
bool is_bidirect_drvr,
bool is_reg_clk);
void clear();
void setArrivals(Arrival *arrivals);
void setRequireds(Required *requireds);
void setSlews(Slew *slews);
Pin *pin_;
@ -335,9 +320,7 @@ protected:
// Delay calc
Slew *slews_;
// Search
Arrival *arrivals_;
Arrival *requireds_;
PathPrev *prev_paths_;
Path *paths_;
// These fields are written by multiple threads, so they
// cannot share the same word as the following bit fields.

View File

@ -37,57 +37,96 @@ namespace sta {
class DcalcAnalysisPt;
// Abstract base class for Path API.
class Path
{
public:
Path() {}
virtual ~Path() {}
virtual const char *name(const StaState *sta) const;
virtual bool isNull() const = 0;
virtual Path *path() { return isNull() ? nullptr : this; }
virtual const Path *path() const { return isNull() ? nullptr : this; }
virtual void setRef(PathRef *ref) const = 0;
virtual void setRef(PathRef &ref) const { setRef(&ref); }
virtual Vertex *vertex(const StaState *sta) const = 0;
virtual VertexId vertexId(const StaState *sta) const = 0;
virtual Pin *pin(const StaState *sta) const;
virtual Tag *tag(const StaState *sta) const = 0;
virtual TagIndex tagIndex(const StaState *sta) const;
virtual ClkInfo *clkInfo(const StaState *sta) const;
virtual const ClockEdge *clkEdge(const StaState *sta) const;
virtual const Clock *clock(const StaState *sta) const;
virtual bool isClock(const StaState *sta) const;
virtual const RiseFall *transition(const StaState *sta) const = 0;
virtual int rfIndex(const StaState *sta) const;
virtual const MinMax *minMax(const StaState *sta) const;
virtual PathAnalysisPt *pathAnalysisPt(const StaState *sta) const = 0;
virtual PathAPIndex pathAnalysisPtIndex(const StaState *sta) const;
virtual DcalcAnalysisPt *dcalcAnalysisPt(const StaState *sta) const;
virtual Arrival arrival(const StaState *sta) const = 0;
virtual void setArrival(Arrival arrival,
const StaState *sta) = 0;
virtual void initArrival(const StaState *sta);
virtual bool arrivalIsInitValue(const StaState *sta) const;
virtual const Required &required(const StaState *sta) const = 0;
virtual void setRequired(const Required &required,
const StaState *sta) = 0;
virtual void initRequired(const StaState *sta);
virtual bool requiredIsInitValue(const StaState *sta) const;
virtual Slack slack(const StaState *sta) const;
virtual Slew slew(const StaState *sta) const;
Path();
Path(Path *path);
Path(Vertex *vertex,
Tag *tag,
const StaState *sta);
Path(Vertex *vertex,
Tag *tag,
Arrival arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc,
const StaState *sta);
Path(Vertex *vertex,
Tag *tag,
Arrival arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc,
bool is_enum,
const StaState *sta);
~Path();
const char *name(const StaState *sta) const;
bool isNull() const;
// prev_path null
void init(Vertex *vertex,
Arrival arrival,
const StaState *sta);
void init(Vertex *vertex,
Tag *tag,
Arrival arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc,
const StaState *sta);
void init(Vertex *vertex,
Tag *tag,
const StaState *sta);
void init(Vertex *vertex,
Tag *tag,
Arrival arrival,
const StaState *sta);
Vertex *vertex(const StaState *sta) const;
VertexId vertexId(const StaState *sta) const;
Pin *pin(const StaState *sta) const;
Tag *tag(const StaState *sta) const;
TagIndex tagIndex(const StaState *sta) const;
void setTag(Tag *tag);
size_t pathIndex(const StaState *sta) const;
ClkInfo *clkInfo(const StaState *sta) const;
const ClockEdge *clkEdge(const StaState *sta) const;
const Clock *clock(const StaState *sta) const;
bool isClock(const StaState *sta) const;
const RiseFall *transition(const StaState *sta) const;
int rfIndex(const StaState *sta) const;
const MinMax *minMax(const StaState *sta) const;
PathAnalysisPt *pathAnalysisPt(const StaState *sta) const;
PathAPIndex pathAnalysisPtIndex(const StaState *sta) const;
DcalcAnalysisPt *dcalcAnalysisPt(const StaState *sta) const;
Arrival &arrival() { return arrival_; }
const Arrival &arrival() const { return arrival_; }
void setArrival(Arrival arrival);
Required &required() { return required_; }
const Required &required() const {return required_; }
void setRequired(const Required &required);
Slack slack(const StaState *sta) const;
Slew slew(const StaState *sta) const;
// This takes the same time as prevPath and prevArc combined.
virtual void prevPath(const StaState *sta,
// Return values.
PathRef &prev_path,
TimingArc *&prev_arc) const = 0;
virtual void prevPath(const StaState *sta,
// Return values.
PathRef &prev_path) const;
virtual TimingArc *prevArc(const StaState *sta) const;
// Find the previous edge given the previous arc found above.
Edge *prevEdge(const TimingArc *prev_arc,
const StaState *sta) const;
Path *prevPath() const;
void setPrevPath(Path *prev_path);
void clearPrevPath(const StaState *sta);
TimingArc *prevArc(const StaState *sta) const;
Edge *prevEdge(const StaState *sta) const;
Vertex *prevVertex(const StaState *sta) const;
void setPrevEdgeArc(Edge *prev_edge,
TimingArc *prev_arc,
const StaState *sta);
bool isEnum() const { return is_enum_; }
void setIsEnum(bool is_enum);
void checkPrevPath(const StaState *sta) const;
void checkPrevPaths(const StaState *sta) const;
static Path *vertexPath(const Path &path,
const StaState *sta);
static Path *vertexPath(const Vertex *vertex,
Tag *tag,
const StaState *sta);
static bool less(const Path *path1,
const Path *path2,
@ -118,6 +157,18 @@ public:
static bool lessAll(const Path *path1,
const Path *path2,
const StaState *sta);
protected:
Path *prev_path_;
Arrival arrival_;
Required required_;
union {
VertexId vertex_id_;
EdgeId prev_edge_id_;
};
TagIndex tag_index_:tag_index_bit_count;
bool is_enum_:1;
unsigned prev_arc_idx_:2;
};
// Compare all path attributes (vertex, transition, tag, analysis point).
@ -132,4 +183,47 @@ protected:
const StaState *sta_;
};
// Iterator for paths on a vertex.
class VertexPathIterator : public Iterator<Path*>
{
public:
// Iterate over all vertex paths.
VertexPathIterator(Vertex *vertex,
const StaState *sta);
// Iterate over vertex paths with the same transition and
// analysis pt but different tags.
VertexPathIterator(Vertex *vertex,
const RiseFall *rf,
const PathAnalysisPt *path_ap,
const StaState *sta);
// Iterate over vertex paths with the same transition and
// analysis pt min/max but different tags.
VertexPathIterator(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max,
const StaState *sta);
VertexPathIterator(Vertex *vertex,
const RiseFall *rf,
const PathAnalysisPt *path_ap,
const MinMax *min_max,
const StaState *sta);
virtual ~VertexPathIterator();
virtual bool hasNext();
virtual Path *next();
private:
void findNext();
const Search *search_;
//bool filtered_;
const RiseFall *rf_;
const PathAnalysisPt *path_ap_;
const MinMax *min_max_;
Path *paths_;
size_t path_count_;
//size_t path_index_;
Path *next_;
PathIndexMap::Iterator path_iter_;
};
} // namespace

View File

@ -30,7 +30,7 @@
#include "GraphClass.hh"
#include "SdcClass.hh"
#include "SearchClass.hh"
#include "PathRef.hh"
#include "Path.hh"
#include "StaState.hh"
namespace sta {
@ -73,10 +73,9 @@ public:
virtual PathEnd *copy() = 0;
virtual ~PathEnd();
void deletePath();
Path *path() { return &path_; }
const Path *path() const { return &path_; }
PathRef &pathRef() { return path_; }
virtual void setPath(const Path *path);
Path *path() { return path_; }
const Path *path() const { return path_; }
virtual void setPath(Path *path);
Vertex *vertex(const StaState *sta) const;
const MinMax *minMax(const StaState *sta) const;
// Synonym for minMax().
@ -118,8 +117,8 @@ public:
virtual float sourceClkOffset(const StaState *sta) const = 0;
virtual Delay sourceClkLatency(const StaState *sta) const;
virtual Delay sourceClkInsertionDelay(const StaState *sta) const;
virtual PathVertex *targetClkPath();
virtual const PathVertex *targetClkPath() const;
virtual Path *targetClkPath();
virtual const Path *targetClkPath() const;
virtual const Clock *targetClk(const StaState *sta) const;
virtual const ClockEdge *targetClkEdge(const StaState *sta) const;
const RiseFall *targetClkEndTrans(const StaState *sta) const;
@ -149,7 +148,7 @@ public:
virtual MultiCyclePath *multiCyclePath() const;
virtual TimingArc *checkArc() const { return nullptr; }
// PathEndDataCheck data clock path.
virtual const PathVertex *dataClkPath() const { return nullptr; }
virtual const Path *dataClkPath() const { return nullptr; }
virtual int setupDefaultCycles() const { return 1; }
virtual Delay clkSkew(const StaState *sta);
virtual bool ignoreClkLatency(const StaState * /* sta */) const { return false; }
@ -173,11 +172,11 @@ public:
// Helper common to multiple PathEnd classes and used
// externally.
// Target clock insertion delay + latency.
static Delay checkTgtClkDelay(const PathVertex *tgt_clk_path,
static Delay checkTgtClkDelay(const Path *tgt_clk_path,
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const StaState *sta);
static void checkTgtClkDelay(const PathVertex *tgt_clk_path,
static void checkTgtClkDelay(const Path *tgt_clk_path,
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const StaState *sta,
@ -186,11 +185,11 @@ public:
Delay &latency);
static float checkClkUncertainty(const ClockEdge *src_clk_edge,
const ClockEdge *tgt_clk_edge,
const PathVertex *tgt_clk_path,
const Path *tgt_clk_path,
const TimingRole *check_role,
const StaState *sta);
// Non inter-clock uncertainty.
static float checkTgtClkUncertainty(const PathVertex *tgt_clk_path,
static float checkTgtClkUncertainty(const Path *tgt_clk_path,
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const StaState *sta);
@ -211,14 +210,14 @@ protected:
static float outputDelayMargin(OutputDelay *output_delay,
const Path *path,
const StaState *sta);
static float pathDelaySrcClkOffset(const PathRef &path,
static float pathDelaySrcClkOffset(const Path *path,
PathDelay *path_delay,
Arrival src_clk_arrival,
const StaState *sta);
static bool ignoreClkLatency(const PathRef &path,
static bool ignoreClkLatency(const Path *path,
PathDelay *path_delay,
const StaState *sta);
PathRef path_;
Path *path_;
};
class PathEndUnconstrained : public PathEnd
@ -247,8 +246,8 @@ public:
virtual Delay sourceClkInsertionDelay(const StaState *sta) const;
virtual const Clock *targetClk(const StaState *sta) const;
virtual const ClockEdge *targetClkEdge(const StaState *sta) const;
virtual PathVertex *targetClkPath();
virtual const PathVertex *targetClkPath() const;
virtual Path *targetClkPath();
virtual const Path *targetClkPath() const;
virtual float targetClkTime(const StaState *sta) const;
virtual float targetClkOffset(const StaState *sta) const;
virtual Arrival targetClkArrival(const StaState *sta) const;
@ -263,13 +262,13 @@ public:
virtual Slack slackNoCrpr(const StaState *sta) const;
virtual int exceptPathCmp(const PathEnd *path_end,
const StaState *sta) const;
virtual void setPath(const Path *path);
virtual void setPath(Path *path);
protected:
PathEndClkConstrained(Path *path,
PathVertex *clk_path);
Path *clk_path);
PathEndClkConstrained(Path *path,
PathVertex *clk_path,
Path *clk_path,
Crpr crpr,
bool crpr_valid);
@ -281,7 +280,7 @@ protected:
virtual Arrival targetClkArrivalNoCrpr(const StaState *sta) const;
virtual Required requiredTimeNoCrpr(const StaState *sta) const;
PathVertex clk_path_;
Path *clk_path_;
mutable Crpr crpr_;
mutable bool crpr_valid_;
};
@ -296,10 +295,10 @@ public:
protected:
PathEndClkConstrainedMcp(Path *path,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp);
PathEndClkConstrainedMcp(Path *path,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp,
Crpr crpr,
bool crpr_valid);
@ -321,7 +320,7 @@ public:
PathEndCheck(Path *path,
TimingArc *check_arc,
Edge *check_edge,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp,
const StaState *sta);
virtual PathEnd *copy();
@ -342,7 +341,7 @@ protected:
PathEndCheck(Path *path,
TimingArc *check_arc,
Edge *check_edge,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp,
Crpr crpr,
bool crpr_valid);
@ -360,7 +359,7 @@ public:
PathEndLatchCheck(Path *path,
TimingArc *check_arc,
Edge *check_edge,
PathVertex *disable_path,
Path *disable_path,
MultiCyclePath *mcp,
PathDelay *path_delay,
const StaState *sta);
@ -371,8 +370,8 @@ public:
virtual bool isLatchCheck() const { return true; }
virtual PathDelay *pathDelay() const { return path_delay_; }
virtual PathEnd *copy();
PathVertex *latchDisable();
const PathVertex *latchDisable() const;
Path *latchDisable();
const Path *latchDisable() const;
virtual void reportShort(const ReportPath *report) const;
virtual void reportFull(const ReportPath *report) const;
virtual TimingRole *checkRole(const StaState *sta) const;
@ -403,8 +402,8 @@ protected:
PathEndLatchCheck(Path *path,
TimingArc *check_arc,
Edge *check_edge,
PathVertex *clk_path,
PathVertex *disable,
Path *clk_path,
Path *disable,
MultiCyclePath *mcp,
PathDelay *path_delay,
Delay src_clk_arrival,
@ -412,7 +411,7 @@ protected:
bool crpr_valid);
private:
PathVertex disable_path_;
Path *disable_path_;
PathDelay *path_delay_;
// Source clk arrival for set_max_delay -ignore_clk_latency.
Arrival src_clk_arrival_;
@ -426,7 +425,7 @@ class PathEndOutputDelay : public PathEndClkConstrainedMcp
public:
PathEndOutputDelay(OutputDelay *output_delay,
Path *path,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp,
const StaState *sta);
virtual PathEnd *copy();
@ -448,7 +447,7 @@ public:
protected:
PathEndOutputDelay(OutputDelay *output_delay,
Path *path,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp,
Crpr crpr,
bool crpr_valid);
@ -470,7 +469,7 @@ class PathEndGatedClock : public PathEndClkConstrainedMcp
{
public:
PathEndGatedClock(Path *gating_ref,
PathVertex *clk_path,
Path *clk_path,
TimingRole *check_role,
MultiCyclePath *mcp,
ArcDelay margin,
@ -488,7 +487,7 @@ public:
protected:
PathEndGatedClock(Path *gating_ref,
PathVertex *clk_path,
Path *clk_path,
TimingRole *check_role,
MultiCyclePath *mcp,
ArcDelay margin,
@ -504,7 +503,7 @@ class PathEndDataCheck : public PathEndClkConstrainedMcp
public:
PathEndDataCheck(DataCheck *check,
Path *data_path,
PathVertex *data_clk_path,
Path *data_clk_path,
MultiCyclePath *mcp,
const StaState *sta);
virtual PathEnd *copy();
@ -518,26 +517,24 @@ public:
virtual ArcDelay margin(const StaState *sta) const;
virtual int exceptPathCmp(const PathEnd *path_end,
const StaState *sta) const;
virtual const PathVertex *dataClkPath() const { return &data_clk_path_; }
virtual const Path *dataClkPath() const { return data_clk_path_; }
protected:
PathEndDataCheck(DataCheck *check,
Path *data_path,
PathVertex *data_clk_path,
PathVertex *clk_path,
Path *data_clk_path,
Path *clk_path,
MultiCyclePath *mcp,
Crpr crpr,
bool crpr_valid);
void clkPath(PathVertex *path,
const StaState *sta,
// Return value.
PathVertex &clk_path);
Path *clkPath(Path *path,
const StaState *sta);
Arrival requiredTimeNoCrpr(const StaState *sta) const;
// setup uses zero cycle default
virtual int setupDefaultCycles() const { return 0; }
private:
PathVertex data_clk_path_;
Path *data_clk_path_;
DataCheck *check_;
};
@ -554,7 +551,7 @@ public:
// Path delay to timing check.
PathEndPathDelay(PathDelay *path_delay,
Path *path,
PathVertex *clk_path,
Path *clk_path,
TimingArc *check_arc,
Edge *check_edge,
const StaState *sta);
@ -588,7 +585,7 @@ public:
protected:
PathEndPathDelay(PathDelay *path_delay,
Path *path,
PathVertex *clk_path,
Path *clk_path,
TimingArc *check_arc,
Edge *check_edge,
OutputDelay *output_delay,

View File

@ -27,7 +27,7 @@
#include "TimingArc.hh"
#include "GraphClass.hh"
#include "SearchClass.hh"
#include "PathRef.hh"
#include "Path.hh"
#include "StaState.hh"
namespace sta {
@ -48,33 +48,31 @@ public:
size_t size() const { return paths_.size(); }
// path(0) is the startpoint.
// path(size()-1) is the endpoint.
const PathRef *path(size_t index) const;
TimingArc *prevArc(size_t index) const;
const Path *path(size_t index) const;
// Returns the path start point.
// Register/Latch Q pin
// Input pin
const PathRef *startPath() const;
const PathRef *startPrevPath() const;
const PathRef *endPath() const;
TimingArc *startPrevArc() const;
const Path *startPath() const;
const Path *startPrevPath() const;
const Path *endPath() const;
const TimingArc *startPrevArc() const;
size_t startIndex() const;
void clkPath(PathRef &clk_path) const;
const Path *clkPath() const;
void latchPaths(// Return values.
const PathRef *&d_path,
const PathRef *&q_path,
const Path *&d_path,
const Path *&q_path,
Edge *&d_q_edge) const;
protected:
void expandGenclk(PathRef *clk_path);
void expandGenclk(const Path *clk_path);
// Convert external index that starts at the path root
// and increases to an index for paths_ (reversed).
size_t pathsIndex(size_t index) const;
// The PathRefs in paths_ are in reverse order.
// The Paths in paths_ are in reverse order.
// paths_[0] is the endpoint.
// paths_[size-1] is the beginning of the path.
PathRefSeq paths_;
TimingArcSeq prev_arcs_;
ConstPathSeq paths_;
// Index of the startpoint.
size_t start_index_;
const StaState *sta_;

View File

@ -74,12 +74,12 @@ public:
PathGroupIterator *iterator();
// This does NOT delete the path ends.
void clear();
static int group_path_count_max;
static size_t group_path_count_max;
protected:
PathGroup(const char *name,
int group_path_count,
int endpoint_path_count,
size_t group_path_count,
size_t endpoint_path_count,
bool unique_pins,
float min_slack,
float max_slack,
@ -91,8 +91,8 @@ protected:
void sort();
const char *name_;
int group_path_count_;
int endpoint_path_count_;
size_t group_path_count_;
size_t endpoint_path_count_;
bool unique_pins_;
float slack_min_;
float slack_max_;

View File

@ -1,75 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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/>.
//
// 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.
#pragma once
#include "SdcClass.hh"
#include "SearchClass.hh"
namespace sta {
// "Pointer" to a previous path on a vertex (PathVertex) thru an edge/arc.
class PathPrev
{
public:
PathPrev();
PathPrev(const PathVertex *path,
const Edge *prev_edge,
const TimingArc *prev_arc,
const StaState *sta);
void init();
void init(const PathPrev *path);
void init(const PathPrev &path);
void init(const PathVertex *path,
const Edge *prev_edge,
const TimingArc *prev_arc,
const StaState *sta);
bool isNull() const;
const char *name(const StaState *sta) const;
Vertex *vertex(const StaState *sta) const;
VertexId vertexId(const StaState *sta) const;
Edge *prevEdge(const StaState *sta) const;
TimingArc *prevArc(const StaState *sta) const;
Tag *tag(const StaState *sta) const;
TagIndex tagIndex() const { return prev_tag_index_; }
Arrival arrival(const StaState *sta) const;
void prevPath(const StaState *sta,
// Return values.
PathRef &prev_path,
TimingArc *&prev_arc) const;
static bool equal(const PathPrev *path1,
const PathPrev *path2);
static bool equal(const PathPrev &path1,
const PathPrev &path2);
static int cmp(const PathPrev &path1,
const PathPrev &path2);
protected:
EdgeId prev_edge_id_;
TagIndex prev_tag_index_:tag_index_bit_count;
unsigned prev_arc_idx_:2;
};
} // namespace

View File

@ -1,94 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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/>.
//
// 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.
#pragma once
#include "Vector.hh"
#include "SearchClass.hh"
#include "Path.hh"
#include "PathVertex.hh"
namespace sta {
// Path reference to either a PathVertex or PathEnum.
// This "could" be made smaller by using a union for
// path_vertex_.vertex_ and path_enumed_ and a non-legal
// value for path_vertex_.arrival_index_ (because a nullptr tag
// in PathVertex is valid).
class PathRef : public Path
{
public:
PathRef();
PathRef(const Path *path);
PathRef(const PathRef &path);
PathRef(const PathRef *path);
PathRef(const PathVertex &path);
void init();
void init(const PathRef &path);
void init(const PathRef *path);
void init(const PathVertex &path);
void init(const PathVertex *path);
void init(const PathPrev &path,
const StaState *sta);
void init(Vertex *vertex,
Tag *tag,
int arrival_index);
void init(PathEnumed *path);
virtual void setRef(PathRef *ref) const;
virtual bool isNull() const;
virtual Vertex *vertex(const StaState *sta) const;
virtual VertexId vertexId(const StaState *sta) const;
virtual Tag *tag(const StaState *sta) const;
virtual TagIndex tagIndex(const StaState *sta) const;
virtual const RiseFall *transition(const StaState *sta) const;
virtual int rfIndex(const StaState *sta) const;
virtual PathAnalysisPt *pathAnalysisPt(const StaState *sta) const;
virtual PathAPIndex pathAnalysisPtIndex(const StaState *sta) const;
void arrivalIndex(int &arrival_index,
bool &arrival_exists) const;
virtual Arrival arrival(const StaState *sta) const;
virtual void setArrival(Arrival arrival,
const StaState *sta);
virtual const Required &required(const StaState *sta) const;
virtual void setRequired(const Required &required,
const StaState *sta);
virtual void prevPath(const StaState *sta,
// Return values.
PathRef &prev_path,
TimingArc *&prev_arc) const;
void deleteRep();
using Path::setRef;
using Path::prevPath;
protected:
PathVertex path_vertex_;
PathEnumed *path_enumed_;
private:
friend class PathVertex;
friend class PathEnumed;
};
} // namespace

View File

@ -1,158 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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/>.
//
// 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.
#pragma once
#include "SearchClass.hh"
#include "Path.hh"
namespace sta {
class PathPrev;
class PathVertexPtr;
// Implements Path API for a vertex.
class PathVertex : public Path
{
public:
PathVertex();
PathVertex(const PathVertex &path);
PathVertex(const PathVertex *path);
PathVertex(const PathPrev *path,
const StaState *sta);
PathVertex(const PathPrev &path,
const StaState *sta);
PathVertex(const PathVertexPtr &path,
const StaState *sta);
// If tag is not in the vertex tag group isNull() is true.
PathVertex(Vertex *vertex,
Tag *tag,
const StaState *sta);
PathVertex(Vertex *vertex,
Tag *tag,
int arrival_index);
void init();
void init(const PathPrev *path,
const StaState *sta);
void init(const PathPrev &path,
const StaState *sta);
void init(const PathVertexPtr &path,
const StaState *sta);
void init(Vertex *vertex,
Tag *tag,
const StaState *sta);
void init(Vertex *vertex,
Tag *tag,
int arrival_index);
void operator=(const PathVertex &path);
virtual bool isNull() const;
virtual void setRef(PathRef *ref) const;
virtual Vertex *vertex(const StaState *) const { return vertex_; }
virtual VertexId vertexId(const StaState *sta) const;
virtual Tag *tag(const StaState *) const { return tag_; }
virtual TagIndex tagIndex(const StaState *sta) const;
virtual const RiseFall *transition(const StaState *) const;
virtual int rfIndex(const StaState *sta) const;
virtual PathAnalysisPt *pathAnalysisPt(const StaState *sta) const;
virtual PathAPIndex pathAnalysisPtIndex(const StaState *sta) const;
void arrivalIndex(int &arrival_index,
bool &arrival_exists) const;
void setArrivalIndex(int arrival_index);
virtual Arrival arrival(const StaState *sta) const;
virtual void setArrival(Arrival arrival,
const StaState *sta);
virtual const Required &required(const StaState *sta) const;
virtual void setRequired(const Required &required,
const StaState *sta);
virtual void prevPath(const StaState *sta,
// Return values.
PathRef &prev_path,
TimingArc *&prev_arc) const;
void prevPath(const StaState *sta,
// Return values.
PathVertex &prev_path) const;
void prevPath(const StaState *sta,
// Return values.
PathVertex &prev_path,
TimingArc *&prev_arc) const;
static bool equal(const PathVertex *path1,
const PathVertex *path2);
using Path::setRef;
using Path::prevPath;
protected:
Vertex *vertex_;
Tag *tag_;
int arrival_index_;
private:
friend class PathRef;
friend class VertexPathIterator;
friend bool pathVertexEqual(const PathVertex *path1,
const PathVertex *path2);
};
// Iterator for vertex paths.
class VertexPathIterator : public Iterator<PathVertex*>
{
public:
// Iterate over all vertex paths.
VertexPathIterator(Vertex *vertex,
const StaState *sta);
// Iterate over vertex paths with the same transition and
// analysis pt but different tags.
VertexPathIterator(Vertex *vertex,
const RiseFall *rf,
const PathAnalysisPt *path_ap,
const StaState *sta);
// Iterate over vertex paths with the same transition and
// analysis pt min/max but different tags.
VertexPathIterator(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max,
const StaState *sta);
VertexPathIterator(Vertex *vertex,
const RiseFall *rf,
const PathAnalysisPt *path_ap,
const MinMax *min_max,
const StaState *sta);
virtual ~VertexPathIterator();
virtual bool hasNext();
virtual PathVertex *next();
private:
void findNext();
const Search *search_;
Vertex *vertex_;
const RiseFall *rf_;
const PathAnalysisPt *path_ap_;
const MinMax *min_max_;
ArrivalMap::Iterator arrival_iter_;
PathVertex path_;
PathVertex next_;
};
} // namespace

View File

@ -1,63 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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/>.
//
// 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.
#pragma once
#include "SearchClass.hh"
namespace sta {
// "Pointer" to a vertex path because there is no real path object to point to.
class PathVertexPtr
{
public:
PathVertexPtr();
PathVertexPtr(const PathVertex *path,
const StaState *sta);
void init();
void init(const PathVertexPtr *path);
void init(const PathVertexPtr &path);
void init(const PathVertex *path,
const StaState *sta);
bool isNull() const;
const char *name(const StaState *sta) const;
Vertex *vertex(const StaState *sta) const;
VertexId vertexId() const { return vertex_id_; }
Tag *tag(const StaState *sta) const;
TagIndex tagIndex() const { return tag_index_; }
Arrival arrival(const StaState *sta) const;
static bool equal(const PathVertexPtr *path1,
const PathVertexPtr *path2);
static bool equal(const PathVertexPtr &path1,
const PathVertexPtr &path2);
static int cmp(const PathVertexPtr &path1,
const PathVertexPtr &path2);
protected:
VertexId vertex_id_;
TagIndex tag_index_;
};
} // namespace

View File

@ -55,7 +55,7 @@ public:
type_library, type_cell, type_port,
type_liberty_library, type_liberty_cell, type_liberty_port,
type_instance, type_pin, type_pins, type_net,
type_clk, type_clks, type_path_refs, type_pwr_activity };
type_clk, type_clks, type_paths, type_pwr_activity };
PropertyValue();
PropertyValue(const char *value);
PropertyValue(string &value);
@ -77,7 +77,7 @@ public:
PropertyValue(const Clock *value);
PropertyValue(ClockSeq *value);
PropertyValue(ClockSet *value);
PropertyValue(PathRefSeq *value);
PropertyValue(ConstPathSeq *value);
PropertyValue(PwrActivity *value);
// Copy constructor.
PropertyValue(const PropertyValue &props);
@ -103,7 +103,7 @@ public:
const Net *net() const { return net_; }
const Clock *clock() const { return clk_; }
ClockSeq *clocks() const { return clks_; }
PathRefSeq *pathRefs() const { return path_refs_; }
ConstPathSeq *paths() const { return paths_; }
PwrActivity pwrActivity() const { return pwr_activity_; }
// Copy assignment.
@ -129,7 +129,7 @@ private:
const Net *net_;
const Clock *clk_;
ClockSeq *clks_;
PathRefSeq *path_refs_;
ConstPathSeq *paths_;
PwrActivity pwr_activity_;
};
const Unit *unit_;
@ -196,7 +196,7 @@ getProperty(PathEnd *end,
Sta *sta);
PropertyValue
getProperty(PathRef *end,
getProperty(Path *end,
const char *property,
Sta *sta);

View File

@ -1,4 +1,4 @@
// OpenSTA, Static Timing Analyzer
// opensta, Static Timing Analyzer
// Copyright (c) 2025, Parallax Software, Inc.
//
// This program is free software: you can redistribute it and/or modify
@ -39,6 +39,7 @@
#include "SearchClass.hh"
#include "SearchPred.hh"
#include "VertexVisitor.hh"
#include "Path.hh"
namespace sta {
@ -99,8 +100,8 @@ public:
bool unconstrained,
const Corner *corner,
const MinMaxAll *min_max,
int group_path_count,
int endpoint_path_count,
size_t group_path_count,
size_t endpoint_path_count,
bool unique_pins,
float slack_min,
float slack_max,
@ -126,6 +127,7 @@ public:
void requiredInvalid(const Pin *pin);
// Vertex will be deleted.
void deleteVertexBefore(Vertex *vertex);
void deleteEdgeBefore(Edge *edge);
// Find all arrival times (propatating thru latches).
void findAllArrivals();
// Find all arrivals (without latch propagation).
@ -226,7 +228,7 @@ public:
TagIndex tagCount() const;
TagGroupIndex tagGroupCount() const;
void reportTagGroups() const;
void reportArrivalCountHistogram() const;
void reportPathCountHistogram() const;
virtual int clkInfoCount() const;
virtual bool isEndpoint(Vertex *vertex) const;
virtual bool isEndpoint(Vertex *vertex,
@ -252,7 +254,7 @@ public:
const RiseFall *to_rf,
const MinMax *min_max,
const PathAnalysisPt *path_ap);
Tag *thruClkTag(PathVertex *from_path,
Tag *thruClkTag(Path *from_path,
Vertex *from_vertex,
Tag *from_tag,
bool to_propagates_clk,
@ -261,7 +263,7 @@ public:
bool arc_delay_min_max_eq,
const MinMax *min_max,
const PathAnalysisPt *path_ap);
ClkInfo *thruClkInfo(PathVertex *from_path,
ClkInfo *thruClkInfo(Path *from_path,
Vertex *from_vertex,
ClkInfo *from_clk_info,
bool from_is_clk,
@ -273,7 +275,7 @@ public:
const MinMax *min_max,
const PathAnalysisPt *path_ap);
ClkInfo *clkInfoWithCrprClkPath(ClkInfo *from_clk_info,
PathVertex *from_path,
Path *from_path,
const PathAnalysisPt *path_ap);
void seedClkArrivals(const Pin *pin,
Vertex *vertex,
@ -339,7 +341,7 @@ public:
float latency,
ClockUncertainties *uncertainties,
const PathAnalysisPt *path_ap,
PathVertex *crpr_clk_path);
Path *crpr_clk_path);
ClkInfo *findClkInfo(const ClockEdge *clk_edge,
const Pin *clk_src,
bool is_propagated,
@ -378,7 +380,33 @@ public:
bool unconstrained,
bool thru_latches);
VertexSeq filteredEndpoints();
bool alwaysSavePrevPaths() const { return always_save_prev_paths_; }
Arrival *arrivals(const Vertex *vertex) const;
Arrival *makeArrivals(const Vertex *vertex,
uint32_t count);
void deleteArrivals(const Vertex *vertex);
Required *requireds(const Vertex *vertex) const;
bool hasRequireds(const Vertex *vertex) const;
Required *makeRequireds(const Vertex *vertex,
uint32_t count);
void deleteRequireds(const Vertex *vertex);
size_t arrivalCount() const;
size_t requiredCount() const;
Path *prevPaths(const Vertex *vertex) const;
Path *makePrevPaths(const Vertex *vertex,
uint32_t count);
void deletePrevPaths(Vertex *vertex);
bool crprPathPruningDisabled(const Vertex *vertex) const;
void setCrprPathPruningDisabled(const Vertex *vertex,
bool disabled);
bool bfsInQueue(const Vertex *vertex,
BfsIndex index) const;
void setBfsInQueue(const Vertex *vertex,
BfsIndex index,
bool value);
TagGroupIndex tagGroupIndex(const Vertex *vertex) const;
void setTagGroupIndex(const Vertex *vertex,
TagGroupIndex tag_index);
protected:
void init(StaState *sta);
@ -544,7 +572,8 @@ protected:
void tnsNotifyBefore(Vertex *vertex);
bool matchesFilterTo(Path *path,
const ClockEdge *to_clk_edge) const;
PathRef pathClkPathArrival1(const Path *path) const;
const Path *pathClkPathArrival1(const Path *path) const;
void deletePathsState(const Vertex *vertex) const;
void clocks(const Vertex *vertex,
// Return value.
ClockSet &clks) const;
@ -619,7 +648,6 @@ protected:
std::mutex pending_latch_outputs_lock_;
VertexSet *endpoints_;
VertexSet *invalid_endpoints_;
bool always_save_prev_paths_;
// Filter exception to tag arrivals for
// report_timing -from pin|inst -through.
// -to is always nullptr.
@ -682,7 +710,7 @@ protected:
bool visitArc(const Pin *from_pin,
Vertex *from_vertex,
const RiseFall *from_rf,
PathVertex *from_path,
Path *from_path,
Edge *edge,
TimingArc *arc,
const Pin *to_pin,
@ -694,7 +722,7 @@ protected:
virtual bool visitFromPath(const Pin *from_pin,
Vertex *from_vertex,
const RiseFall *from_rf,
PathVertex *from_path,
Path *from_path,
Edge *edge,
TimingArc *arc,
const Pin *to_pin,
@ -707,7 +735,7 @@ protected:
Vertex *from_vertex,
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
Path *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
@ -740,7 +768,7 @@ public:
Vertex *from_vertex,
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
Path *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
@ -781,14 +809,14 @@ public:
RequiredCmp();
void requiredsInit(Vertex *vertex,
const StaState *sta);
void requiredSet(int arrival_index,
Required required,
void requiredSet(size_t path_index,
Required &required,
const MinMax *min_max,
const StaState *sta);
// Return true if the requireds changed.
bool requiredsSave(Vertex *vertex,
const StaState *sta);
Required required(int arrival_index);
Required required(size_t path_index);
protected:
ArrivalSeq requireds_;
@ -811,7 +839,7 @@ protected:
Vertex *from_vertex,
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
Path *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,

View File

@ -41,12 +41,6 @@ namespace sta {
class Search;
class Corner;
class Path;
class PathRep;
class PathVertex;
class PathPrev;
class PathVertexPtr;
class PathRef;
class PathEnumed;
class PathEnd;
class PathGroup;
class Tag;
@ -120,12 +114,12 @@ typedef Vector<MaxSkewCheck*> MaxSkewCheckSeq;
typedef StringSet PathGroupNameSet;
typedef Vector<PathEnd*> PathEndSeq;
typedef Vector<Arrival> ArrivalSeq;
typedef Map<Vertex*, int> VertexPathCountMap;
typedef UnorderedMap<Tag*, int, TagMatchHash, TagMatchEqual> ArrivalMap;
typedef Vector<PathVertex> PathVertexSeq;
typedef Map<Vertex*, size_t> VertexPathCountMap;
typedef UnorderedMap<Tag*, size_t, TagMatchHash, TagMatchEqual> PathIndexMap;
typedef Vector<Slack> SlackSeq;
typedef Delay Crpr;
typedef Vector<PathRef> PathRefSeq;
typedef Vector<Path*> PathSeq;
typedef vector<const Path*> ConstPathSeq;
enum class ReportPathFormat { full,
full_clock,

View File

@ -1000,21 +1000,21 @@ public:
VertexPathIterator *vertexPathIterator(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max);
PathRef vertexWorstArrivalPath(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max);
PathRef vertexWorstArrivalPath(Vertex *vertex,
const MinMax *min_max);
PathRef vertexWorstRequiredPath(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max);
PathRef vertexWorstRequiredPath(Vertex *vertex,
const MinMax *min_max);
PathRef vertexWorstSlackPath(Vertex *vertex,
const MinMax *min_max);
PathRef vertexWorstSlackPath(Vertex *vertex,
Path *vertexWorstArrivalPath(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max);
Path *vertexWorstArrivalPath(Vertex *vertex,
const MinMax *min_max);
Path *vertexWorstRequiredPath(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max);
Path *vertexWorstRequiredPath(Vertex *vertex,
const MinMax *min_max);
Path *vertexWorstSlackPath(Vertex *vertex,
const MinMax *min_max);
Path *vertexWorstSlackPath(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max);
// Find the min clock period for rise/rise and fall/fall paths of a clock
// using the slack. This does NOT correctly predict min period when there
@ -1112,10 +1112,9 @@ public:
TagIndex tagCount() const;
TagGroupIndex tagGroupCount() const;
int clkInfoCount() const;
int arrivalCount() const;
int requiredCount() const;
int vertexArrivalCount(Vertex *vertex) const;
Vertex *maxArrivalCountVertex() const;
int pathCount() const;
int vertexPathCount(Vertex *vertex) const;
Vertex *maxPathCountVertex() const;
LogicValue simLogicValue(const Pin *pin);
// Propagate liberty constant functions and pins tied high/low through
@ -1314,7 +1313,7 @@ public:
LibertyLibrarySeq *map_libs);
LibertyCellSeq *equivCells(LibertyCell *cell);
void writePathSpice(PathRef *path,
void writePathSpice(Path *path,
const char *spice_filename,
const char *subckt_filename,
const char *lib_subckt_filename,

View File

@ -85,7 +85,7 @@ protected:
Path *path,
const RiseFall *end_rf,
const ClockEdge *tgt_clk_edge,
PathVertex *ref_path,
Path *ref_path,
const MinMax *min_max,
PathEndVisitor *visitor,
bool &is_constrained);

View File

@ -50,7 +50,7 @@
#include "DcalcAnalysisPt.hh"
#include "GraphDelayCalc.hh"
#include "Corner.hh"
#include "PathVertex.hh"
#include "Path.hh"
#include "search/Levelize.hh"
#include "search/Sim.hh"
#include "Search.hh"
@ -1339,7 +1339,7 @@ Power::findClk(const Pin *to_pin)
if (to_vertex) {
VertexPathIterator path_iter(to_vertex, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
const Clock *path_clk = path->clock(this);
if (path_clk
&& (clk == nullptr

View File

@ -30,7 +30,7 @@
#include "Network.hh"
#include "Graph.hh"
#include "Clock.hh"
#include "PathVertex.hh"
#include "Path.hh"
#include "PathAnalysisPt.hh"
#include "Search.hh"
@ -199,13 +199,13 @@ CheckMaxSkews:: visitMaxSkewChecks(Vertex *vertex,
RiseFall *ref_rf = arc->toEdge()->asRiseFall();
VertexPathIterator clk_path_iter(vertex, clk_rf, clk_min_max, search);
while (clk_path_iter.hasNext()) {
PathVertex *clk_path = clk_path_iter.next();
Path *clk_path = clk_path_iter.next();
if (clk_path->isClock(search)) {
const PathAnalysisPt *clk_ap = clk_path->pathAnalysisPt(sta_);
PathAnalysisPt *ref_ap = clk_ap->tgtClkAnalysisPt();
VertexPathIterator ref_path_iter(ref_vertex, ref_rf, ref_ap, sta_);
while (ref_path_iter.hasNext()) {
PathVertex *ref_path = ref_path_iter.next();
Path *ref_path = ref_path_iter.next();
if (ref_path->isClock(search)) {
MaxSkewCheck check(clk_path, ref_path, arc, edge);
visitor->visit(check, sta_);
@ -220,8 +220,8 @@ CheckMaxSkews:: visitMaxSkewChecks(Vertex *vertex,
////////////////////////////////////////////////////////////////
MaxSkewCheck::MaxSkewCheck(PathVertex *clk_path,
PathVertex *ref_path,
MaxSkewCheck::MaxSkewCheck(Path *clk_path,
Path *ref_path,
TimingArc *check_arc,
Edge *check_edge) :
clk_path_(clk_path),
@ -234,34 +234,34 @@ MaxSkewCheck::MaxSkewCheck(PathVertex *clk_path,
Pin *
MaxSkewCheck::clkPin(const StaState *sta) const
{
return clk_path_.pin(sta);
return clk_path_->pin(sta);
}
Pin *
MaxSkewCheck::refPin(const StaState *sta) const
{
return ref_path_.pin(sta);
return ref_path_->pin(sta);
}
ArcDelay
MaxSkewCheck::maxSkew(const StaState *sta) const
{
Search *search = sta->search();
return search->deratedDelay(ref_path_.vertex(sta),
return search->deratedDelay(ref_path_->vertex(sta),
check_arc_, check_edge_, false,
clk_path_.pathAnalysisPt(sta));
clk_path_->pathAnalysisPt(sta));
}
Delay
MaxSkewCheck::skew(const StaState *sta) const
MaxSkewCheck::skew() const
{
return Delay(clk_path_.arrival(sta) - ref_path_.arrival(sta));
return Delay(clk_path_->arrival() - ref_path_->arrival());
}
Slack
MaxSkewCheck::slack(const StaState *sta) const
{
return maxSkew(sta) - skew(sta);
return maxSkew(sta) - skew();
}
////////////////////////////////////////////////////////////////

View File

@ -28,7 +28,7 @@
#include "Delay.hh"
#include "StaState.hh"
#include "SearchClass.hh"
#include "PathRef.hh"
#include "Path.hh"
namespace sta {
@ -57,22 +57,22 @@ protected:
class MaxSkewCheck
{
public:
MaxSkewCheck(PathVertex *clk_path,
PathVertex *ref_path,
MaxSkewCheck(Path *clk_path,
Path *ref_path,
TimingArc *check_arc,
Edge *check_edge);
const PathVertex *clkPath() const { return &clk_path_; }
const Path *clkPath() const { return clk_path_; }
Pin *clkPin(const StaState *sta) const;
const PathVertex *refPath() const { return &ref_path_; }
const Path *refPath() const { return ref_path_; }
Pin *refPin(const StaState *sta) const;
Delay skew(const StaState *sta) const;
Delay skew() const;
ArcDelay maxSkew(const StaState *sta) const;
Slack slack(const StaState *sta) const;
TimingArc *checkArc() const { return check_arc_; }
private:
PathVertex clk_path_;
PathVertex ref_path_;
Path *clk_path_;
Path *ref_path_;
TimingArc *check_arc_;
Edge *check_edge_;
};

View File

@ -35,8 +35,7 @@
#include "GraphDelayCalc.hh"
#include "ClkInfo.hh"
#include "Tag.hh"
#include "PathVertex.hh"
#include "PathRef.hh"
#include "Path.hh"
#include "Corner.hh"
#include "PathAnalysisPt.hh"
#include "SearchPred.hh"
@ -275,10 +274,9 @@ visitMinPulseWidthChecks(Vertex *vertex,
minPulseWidth(path, sta_, min_width, exists);
if (exists) {
MinPulseWidthCheck check(path);
PathVertex close_path;
check.closePath(sta_, close_path);
Path *close_path = check.closePath(sta_);
// Don't bother visiting if nobody is home.
if (!close_path.isNull())
if (close_path)
visitor->visit(check, sta_);
}
}
@ -289,7 +287,7 @@ visitMinPulseWidthChecks(Vertex *vertex,
////////////////////////////////////////////////////////////////
MinPulseWidthCheck::MinPulseWidthCheck() :
open_path_()
open_path_(nullptr)
{
}
@ -301,31 +299,29 @@ MinPulseWidthCheck::MinPulseWidthCheck(Path *open_path) :
MinPulseWidthCheck *
MinPulseWidthCheck::copy()
{
return new MinPulseWidthCheck(&open_path_);
return new MinPulseWidthCheck(open_path_);
}
Pin *
MinPulseWidthCheck::pin(const StaState *sta) const
{
return open_path_.pin(sta);
return open_path_->pin(sta);
}
const RiseFall *
MinPulseWidthCheck::openTransition(const StaState *sta) const
{
return open_path_.transition(sta);
return open_path_->transition(sta);
}
void
MinPulseWidthCheck::closePath(const StaState *sta,
// Return value.
PathVertex &close) const
Path *
MinPulseWidthCheck::closePath(const StaState *sta) const
{
PathAnalysisPt *open_ap = open_path_.pathAnalysisPt(sta);
PathAnalysisPt *open_ap = open_path_->pathAnalysisPt(sta);
PathAnalysisPt *close_ap = open_ap->tgtClkAnalysisPt();
const RiseFall *open_rf = open_path_.transition(sta);
const RiseFall *open_rf = open_path_->transition(sta);
const RiseFall *close_rf = open_rf->opposite();
Tag *open_tag = open_path_.tag(sta);
Tag *open_tag = open_path_->tag(sta);
ClkInfo *open_clk_info = open_tag->clkInfo();
ClkInfo close_clk_info(open_clk_info->clkEdge()->opposite(),
open_clk_info->clkSrc(),
@ -335,7 +331,7 @@ MinPulseWidthCheck::closePath(const StaState *sta,
open_clk_info->pulseClkSense(),
delay_zero, 0.0, nullptr,
open_clk_info->pathAPIndex(),
open_clk_info->crprClkPath(),
open_clk_info->crprClkPath(sta),
sta);
Tag close_tag(0,
close_rf->index(),
@ -350,31 +346,30 @@ MinPulseWidthCheck::closePath(const StaState *sta,
open_tag->asString(sta));
debugPrint(sta->debug(), "mpw", 3, " close %s",
close_tag.asString(sta));
VertexPathIterator close_iter(open_path_.vertex(sta), close_rf,
VertexPathIterator close_iter(open_path_->vertex(sta), close_rf,
close_ap, sta);
while (close_iter.hasNext()) {
PathVertex *close_path = close_iter.next();
Path *close_path = close_iter.next();
if (tagMatchNoPathAp(close_path->tag(sta), &close_tag)) {
debugPrint(sta->debug(), "mpw", 3, " match %s",
close_path->tag(sta)->asString(sta));
close = close_path;
break;
return close_path;
}
}
return nullptr;
}
Arrival
MinPulseWidthCheck::openArrival(const StaState *sta) const
MinPulseWidthCheck::openArrival(const StaState *) const
{
return open_path_.arrival(sta);
return open_path_->arrival();
}
Arrival
MinPulseWidthCheck::closeArrival(const StaState *sta) const
{
PathVertex close;
closePath(sta, close);
return close.arrival(sta);
Path *close = closePath(sta);
return close->arrival();
}
Arrival
@ -392,13 +387,13 @@ MinPulseWidthCheck::closeDelay(const StaState *sta) const
const ClockEdge *
MinPulseWidthCheck::openClkEdge(const StaState *sta) const
{
return open_path_.clkEdge(sta->search());
return open_path_->clkEdge(sta->search());
}
const ClockEdge *
MinPulseWidthCheck::closeClkEdge(const StaState *sta) const
{
Tag *open_tag = open_path_.tag(sta);
Tag *open_tag = open_path_->tag(sta);
ClkInfo *open_clk_info = open_tag->clkInfo();
return open_clk_info->clkEdge()->opposite();
}
@ -418,7 +413,7 @@ Arrival
MinPulseWidthCheck::width(const StaState *sta) const
{
return closeArrival(sta) + closeOffset(sta)
- open_path_.arrival(sta)
- open_path_->arrival()
+ checkCrpr(sta);
}
@ -427,7 +422,7 @@ MinPulseWidthCheck::minWidth(const StaState *sta) const
{
float min_width;
bool exists;
minPulseWidth(&open_path_, sta, min_width, exists);
minPulseWidth(open_path_, sta, min_width, exists);
return min_width;
}
@ -469,10 +464,9 @@ Crpr
MinPulseWidthCheck::checkCrpr(const StaState *sta) const
{
CheckCrpr *check_crpr = sta->search()->checkCrpr();
PathVertex close;
closePath(sta, close);
if (!close.isNull())
return check_crpr->checkCrpr(openPath(), &close);
Path *close = closePath(sta);
if (close)
return check_crpr->checkCrpr(openPath(), close);
else
return 0.0;
}
@ -486,7 +480,7 @@ MinPulseWidthCheck::slack(const StaState *sta) const
Corner *
MinPulseWidthCheck::corner(const StaState *sta) const
{
return open_path_.pathAnalysisPt(sta)->corner();
return open_path_->pathAnalysisPt(sta)->corner();
}
////////////////////////////////////////////////////////////////

View File

@ -27,7 +27,7 @@
#include "SdcClass.hh"
#include "SearchClass.hh"
#include "StaState.hh"
#include "PathRef.hh"
#include "Path.hh"
namespace sta {
@ -75,13 +75,11 @@ public:
Arrival width(const StaState *sta) const;
float minWidth(const StaState *sta) const;
Slack slack(const StaState *sta) const;
Path *openPath() { return &open_path_; }
Path *openPath() { return open_path_; }
Corner *corner(const StaState *sta) const;
const Path *openPath() const { return &open_path_; }
const Path *openPath() const { return open_path_; }
Arrival openArrival(const StaState *sta) const;
void closePath(const StaState *sta,
// Return value.
PathVertex &close) const;
Path *closePath(const StaState *sta) const;
Arrival closeArrival(const StaState *sta) const;
Arrival openDelay(const StaState *sta) const;
Arrival closeDelay(const StaState *sta) const;
@ -92,7 +90,7 @@ public:
protected:
// Open path of the pulse.
PathRef open_path_;
Path *open_path_;
};
class MinPulseWidthSlackLess

View File

@ -34,7 +34,7 @@
#include "GraphDelayCalc.hh"
#include "StaState.hh"
#include "Corner.hh"
#include "PathVertex.hh"
#include "Path.hh"
#include "PortDirection.hh"
#include "Search.hh"
#include "ClkNetwork.hh"

View File

@ -38,7 +38,7 @@
#include "Bfs.hh"
#include "Search.hh"
#include "Genclks.hh"
#include "PathVertex.hh"
#include "Path.hh"
#include "Sim.hh"
namespace sta {
@ -316,7 +316,7 @@ CheckTiming::hasClkedArrival(Vertex *vertex)
{
VertexPathIterator path_iter(vertex, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
if (path->clock(this))
return true;
}

View File

@ -27,7 +27,7 @@
#include "MinMax.hh"
#include "StaState.hh"
#include "Transition.hh"
#include "PathVertex.hh"
#include "Path.hh"
namespace sta {
@ -43,7 +43,7 @@ public:
Delay &delay,
float &internal_latency,
Delay &latency,
PathVertex &path,
Path &path,
bool &exists) const;
void latency(const RiseFall *src_rf,
const RiseFall *end_rf,
@ -51,28 +51,28 @@ public:
// Return values.
Delay &delay,
bool &exists) const;
static Delay latency(PathVertex *clk_path,
static Delay latency(Path *clk_path,
StaState *sta);
void setLatency(const RiseFall *src_rf,
const RiseFall *end_rf,
const MinMax *min_max,
PathVertex *path,
Path *path,
bool include_internal_latency,
StaState *sta);
private:
static float insertionDelay(PathVertex *clk_path,
static float insertionDelay(Path *clk_path,
StaState *sta);
static float delay(PathVertex *clk_path,
static float delay(Path *clk_path,
StaState *sta);
static float clkTreeDelay(PathVertex *clk_path,
static float clkTreeDelay(Path *clk_path,
StaState *sta);
Delay insertion_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
Delay delay_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
float internal_latency_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
Delay latency_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
PathVertex path_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
Path path_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
bool exists_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
};

View File

@ -53,12 +53,12 @@ ClkInfo::ClkInfo(const ClockEdge *clk_edge,
float latency,
ClockUncertainties *uncertainties,
PathAPIndex path_ap_index,
PathVertexPtr &crpr_clk_path,
Path *crpr_clk_path,
const StaState *sta) :
clk_edge_(clk_edge),
clk_src_(clk_src),
gen_clk_src_(gen_clk_src),
crpr_clk_path_(is_propagated ? crpr_clk_path : PathVertexPtr()),
crpr_clk_path_(is_propagated ? crpr_clk_path : nullptr),
uncertainties_(uncertainties),
insertion_(insertion),
latency_(latency),
@ -87,7 +87,7 @@ ClkInfo::findHash(const StaState *sta)
hashIncr(hash_, network->vertexId(clk_src_));
if (gen_clk_src_)
hashIncr(hash_, network->vertexId(gen_clk_src_));
hashIncr(hash_, crprClkVertexId());
hashIncr(hash_, crprClkVertexId(sta));
if (uncertainties_) {
float uncertainty;
bool exists;
@ -108,12 +108,24 @@ ClkInfo::findHash(const StaState *sta)
}
VertexId
ClkInfo::crprClkVertexId() const
ClkInfo::crprClkVertexId(const StaState *sta) const
{
if (crpr_clk_path_.isNull())
return 0;
return vertex_id_null;
else
return crpr_clk_path_.vertexId();
return crpr_clk_path_.vertexId(sta);
}
Path *
ClkInfo::crprClkPath(const StaState *sta)
{
return Path::vertexPath(crpr_clk_path_, sta);
}
const Path *
ClkInfo::crprClkPath(const StaState *sta) const
{
return Path::vertexPath(crpr_clk_path_, sta);
}
const char *
@ -213,8 +225,9 @@ clkInfoEqual(const ClkInfo *clk_info1,
&& clk_info1->clkSrc() == clk_info2->clkSrc()
&& clk_info1->genClkSrc() == clk_info2->genClkSrc()
&& (!crpr_on
|| (PathVertexPtr::equal(clk_info1->crprClkPath(),
clk_info2->crprClkPath())))
|| Path::equal(clk_info1->crprClkPath(sta),
clk_info2->crprClkPath(sta),
sta))
&& ((uncertainties1 == nullptr
&& uncertainties2 == nullptr)
|| (uncertainties1 && uncertainties2
@ -279,9 +292,9 @@ clkInfoCmp(const ClkInfo *clk_info1,
bool crpr_on = sta->sdc()->crprActive();
if (crpr_on) {
const PathVertexPtr &crpr_path1 = clk_info1->crprClkPath();
const PathVertexPtr &crpr_path2 = clk_info2->crprClkPath();
int path_cmp = PathVertexPtr::cmp(crpr_path1, crpr_path2);
const Path *crpr_path1 = clk_info1->crprClkPath(sta);
const Path *crpr_path2 = clk_info2->crprClkPath(sta);
int path_cmp = Path::cmp(crpr_path1, crpr_path2, sta);
if (path_cmp != 0)
return path_cmp;
}

View File

@ -26,12 +26,12 @@
#include "Transition.hh"
#include "SearchClass.hh"
#include "PathVertexPtr.hh"
#include "Sdc.hh"
#include "Path.hh"
namespace sta {
class PathVertex;
class Path;
class ClkInfo
{
@ -46,7 +46,7 @@ public:
float latency,
ClockUncertainties *uncertainties,
PathAPIndex path_ap_index,
PathVertexPtr &crpr_clk_path,
Path *crpr_clk_path,
const StaState *sta);
~ClkInfo();
const char *asString(const StaState *sta) const;
@ -65,9 +65,9 @@ public:
PathAPIndex pathAPIndex() const { return path_ap_index_; }
// Clock path used for crpr resolution.
// Null for clocks because the path cannot point to itself.
PathVertexPtr &crprClkPath() { return crpr_clk_path_; }
const PathVertexPtr &crprClkPath() const { return crpr_clk_path_; }
VertexId crprClkVertexId() const;
Path *crprClkPath(const StaState *sta);
const Path *crprClkPath(const StaState *sta) const;
VertexId crprClkVertexId(const StaState *sta) const;
bool hasCrprClkPin() const { return !crpr_clk_path_.isNull(); }
bool refsFilter(const StaState *sta) const;
// This clk_info/tag is used for a generated clock source path.
@ -81,7 +81,7 @@ private:
const ClockEdge *clk_edge_;
const Pin *clk_src_;
const Pin *gen_clk_src_;
PathVertexPtr crpr_clk_path_;
Path crpr_clk_path_;
ClockUncertainties *uncertainties_;
Arrival insertion_;
float latency_;

View File

@ -33,7 +33,7 @@
#include "Network.hh"
#include "Clock.hh"
#include "Graph.hh"
#include "PathVertex.hh"
#include "Path.hh"
#include "StaState.hh"
#include "Search.hh"
#include "PathAnalysisPt.hh"
@ -88,7 +88,7 @@ ClkLatency::reportClkLatency(const Clock *clk,
report_->reportLine("Clock %s", clk->name());
for (const RiseFall *src_rf : RiseFall::range()) {
for (const RiseFall *end_rf : RiseFall::range()) {
PathVertex path_min;
Path path_min;
Delay insertion_min;
Delay delay_min;
float internal_latency_min;
@ -97,7 +97,7 @@ ClkLatency::reportClkLatency(const Clock *clk,
clk_delays.delay(src_rf, end_rf, MinMax::min(), insertion_min,
delay_min, internal_latency_min, latency_min,
path_min, exists_min);
PathVertex path_max;
Path path_max;
Delay insertion_max;
Delay delay_max;
float internal_latency_max;
@ -153,7 +153,7 @@ ClkLatency::findClkDelays(ConstClockSeq &clks,
for (Vertex *clk_vertex : *graph_->regClkVertices()) {
VertexPathIterator path_iter(clk_vertex, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
const ClockEdge *path_clk_edge = path->clkEdge(this);
const PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
if (path_clk_edge
@ -206,7 +206,7 @@ ClkDelays::delay(const RiseFall *src_rf,
Delay &delay,
float &lib_clk_delay,
Delay &latency,
PathVertex &path,
Path &path,
bool &exists) const
{
int src_rf_index = src_rf->index();
@ -239,7 +239,7 @@ void
ClkDelays::setLatency(const RiseFall *src_rf,
const RiseFall *end_rf,
const MinMax *min_max,
PathVertex *path,
Path *path,
bool include_internal_latency,
StaState *sta)
{
@ -267,7 +267,7 @@ ClkDelays::setLatency(const RiseFall *src_rf,
}
Delay
ClkDelays::latency(PathVertex *clk_path,
ClkDelays::latency(Path *clk_path,
StaState *sta)
{
@ -278,16 +278,16 @@ ClkDelays::latency(PathVertex *clk_path,
}
float
ClkDelays::delay(PathVertex *clk_path,
ClkDelays::delay(Path *clk_path,
StaState *sta)
{
Arrival arrival = clk_path->arrival(sta);
Arrival arrival = clk_path->arrival();
const ClockEdge *path_clk_edge = clk_path->clkEdge(sta);
return delayAsFloat(arrival) - path_clk_edge->time();
}
float
ClkDelays::insertionDelay(PathVertex *clk_path,
ClkDelays::insertionDelay(Path *clk_path,
StaState *sta)
{
const ClockEdge *clk_edge = clk_path->clkEdge(sta);
@ -302,7 +302,7 @@ ClkDelays::insertionDelay(PathVertex *clk_path,
}
float
ClkDelays::clkTreeDelay(PathVertex *clk_path,
ClkDelays::clkTreeDelay(Path *clk_path,
StaState *sta)
{
const Vertex *vertex = clk_path->vertex(sta);

View File

@ -30,7 +30,7 @@
#include "StaState.hh"
#include "Transition.hh"
#include "SearchClass.hh"
#include "PathVertex.hh"
#include "Path.hh"
#include "ClkDelays.hh"
namespace sta {

View File

@ -38,7 +38,7 @@
#include "Graph.hh"
#include "Sdc.hh"
#include "Bfs.hh"
#include "PathVertex.hh"
#include "Path.hh"
#include "StaState.hh"
#include "PathAnalysisPt.hh"
#include "SearchPred.hh"
@ -55,14 +55,14 @@ class ClkSkew
{
public:
ClkSkew();
ClkSkew(PathVertex *src_path,
PathVertex *tgt_path,
ClkSkew(Path *src_path,
Path *tgt_path,
bool include_internal_latency,
StaState *sta);
ClkSkew(const ClkSkew &clk_skew);
void operator=(const ClkSkew &clk_skew);
PathVertex *srcPath() { return &src_path_; }
PathVertex *tgtPath() { return &tgt_path_; }
Path *srcPath() { return src_path_; }
Path *tgtPath() { return tgt_path_; }
float srcLatency(const StaState *sta);
float tgtLatency(const StaState *sta);
float srcInternalClkLatency(const StaState *sta);
@ -75,23 +75,25 @@ public:
const StaState *sta);
private:
float clkTreeDelay(PathVertex &clk_path,
float clkTreeDelay(Path *clk_path,
const StaState *sta);
PathVertex src_path_;
PathVertex tgt_path_;
Path *src_path_;
Path *tgt_path_;
bool include_internal_latency_;
float skew_;
};
ClkSkew::ClkSkew() :
src_path_(nullptr),
tgt_path_(nullptr),
include_internal_latency_(false),
skew_(0.0)
{
}
ClkSkew::ClkSkew(PathVertex *src_path,
PathVertex *tgt_path,
ClkSkew::ClkSkew(Path *src_path,
Path *tgt_path,
bool include_internal_latency,
StaState *sta) :
src_path_(src_path),
@ -124,8 +126,8 @@ ClkSkew::operator=(const ClkSkew &clk_skew)
float
ClkSkew::srcLatency(const StaState *sta)
{
Arrival src_arrival = src_path_.arrival(sta);
return delayAsFloat(src_arrival) - src_path_.clkEdge(sta)->time()
Arrival src_arrival = src_path_->arrival();
return delayAsFloat(src_arrival) - src_path_->clkEdge(sta)->time()
+ clkTreeDelay(src_path_, sta);
}
@ -138,8 +140,8 @@ ClkSkew::srcInternalClkLatency(const StaState *sta)
float
ClkSkew::tgtLatency(const StaState *sta)
{
Arrival tgt_arrival = tgt_path_.arrival(sta);
return delayAsFloat(tgt_arrival) - tgt_path_.clkEdge(sta)->time()
Arrival tgt_arrival = tgt_path_->arrival();
return delayAsFloat(tgt_arrival) - tgt_path_->clkEdge(sta)->time()
+ clkTreeDelay(tgt_path_, sta);
}
@ -150,16 +152,16 @@ ClkSkew::tgtInternalClkLatency(const StaState *sta)
}
float
ClkSkew::clkTreeDelay(PathVertex &clk_path,
ClkSkew::clkTreeDelay(Path *clk_path,
const StaState *sta)
{
if (include_internal_latency_) {
const Vertex *vertex = clk_path.vertex(sta);
const Vertex *vertex = clk_path->vertex(sta);
const Pin *pin = vertex->pin();
const LibertyPort *port = sta->network()->libertyPort(pin);
const MinMax *min_max = clk_path.minMax(sta);
const RiseFall *rf = clk_path.transition(sta);
float slew = delayAsFloat(clk_path.slew(sta));
const MinMax *min_max = clk_path->minMax(sta);
const RiseFall *rf = clk_path->transition(sta);
float slew = delayAsFloat(clk_path->slew(sta));
return port->clkTreeDelay(slew, rf, min_max);
}
else
@ -170,17 +172,17 @@ Crpr
ClkSkew::crpr(const StaState *sta)
{
CheckCrpr *check_crpr = sta->search()->checkCrpr();
return check_crpr->checkCrpr(&src_path_, &tgt_path_);
return check_crpr->checkCrpr(src_path_, tgt_path_);
}
float
ClkSkew::uncertainty(const StaState *sta)
{
TimingRole *check_role = (src_path_.minMax(sta) == SetupHold::max())
TimingRole *check_role = (src_path_->minMax(sta) == SetupHold::max())
? TimingRole::setup()
: TimingRole::hold();
// Uncertainty decreases slack, but increases skew.
return -PathEnd::checkTgtClkUncertainty(&tgt_path_, tgt_path_.clkEdge(sta),
return -PathEnd::checkTgtClkUncertainty(tgt_path_, tgt_path_->clkEdge(sta),
check_role, sta);
}
@ -240,8 +242,8 @@ ClkSkews::reportClkSkew(ClkSkew &clk_skew,
int digits)
{
Unit *time_unit = units_->timeUnit();
PathVertex *src_path = clk_skew.srcPath();
PathVertex *tgt_path = clk_skew.tgtPath();
Path *src_path = clk_skew.srcPath();
Path *tgt_path = clk_skew.tgtPath();
float src_latency = clk_skew.srcLatency(this);
float tgt_latency = clk_skew.tgtLatency(this);
float src_internal_clk_latency = clk_skew.srcInternalClkLatency(this);
@ -352,7 +354,7 @@ ClkSkews::hasClkPaths(Vertex *vertex)
{
VertexPathIterator path_iter(vertex, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
const Clock *path_clk = path->clock(this);
if (clk_set_.find(path_clk) != clk_set_.end())
return true;
@ -417,7 +419,7 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
const SetupHold *tgt_min_max = setup_hold_->opposite();
VertexPathIterator src_iter(src_vertex, this);
while (src_iter.hasNext()) {
PathVertex *src_path = src_iter.next();
Path *src_path = src_iter.next();
const Clock *src_clk = src_path->clock(this);
if (src_rf->matches(src_path->transition(this))
&& src_path->minMax(this) == setup_hold_
@ -427,7 +429,7 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
|| src_corner == corner_) {
VertexPathIterator tgt_iter(tgt_vertex, this);
while (tgt_iter.hasNext()) {
PathVertex *tgt_path = tgt_iter.next();
Path *tgt_path = tgt_iter.next();
const Clock *tgt_clk = tgt_path->clock(this);
if (tgt_clk == src_clk
&& tgt_path->isClock(this)
@ -446,7 +448,7 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
time_unit->asString(probe.tgtLatency(this)),
delayAsString(probe.crpr(this), this),
time_unit->asString(probe.skew()));
if (clk_skew.srcPath()->isNull()
if (clk_skew.srcPath() == nullptr
|| abs(probe.skew()) > abs(clk_skew.skew()))
clk_skew = probe;
}

View File

@ -32,7 +32,7 @@
#include "Transition.hh"
#include "SearchClass.hh"
#include "SearchPred.hh"
#include "PathVertex.hh"
#include "Path.hh"
namespace sta {

View File

@ -32,8 +32,6 @@
#include "Network.hh"
#include "Graph.hh"
#include "Sdc.hh"
#include "PathVertex.hh"
#include "PathPrev.hh"
#include "Path.hh"
#include "PathAnalysisPt.hh"
#include "ClkInfo.hh"
@ -54,60 +52,26 @@ CheckCrpr::CheckCrpr(StaState *sta) :
{
}
void
CheckCrpr::clkPathPrev(const PathVertex *path,
PathVertex &prev)
{
Vertex *vertex = path->vertex(this);
int arrival_index;
bool exists;
path->arrivalIndex(arrival_index, exists);
PathPrev *prevs = graph_->prevPaths(vertex);
if (prevs)
prev.init(prevs[arrival_index], this);
else
criticalError(2200, "missing prev paths");
}
PathVertex
CheckCrpr::clkPathPrev(Vertex *vertex,
int arrival_index)
{
PathPrev *prevs = graph_->prevPaths(vertex);
if (prevs)
return PathVertex(prevs[arrival_index], this);
else {
criticalError(2201, "missing prev paths");
return PathVertex();
}
}
////////////////////////////////////////////////////////////////
// Find the maximum possible crpr (clock min/max delta delay) for a
// path from it's ClkInfo.
Arrival
CheckCrpr::maxCrpr(ClkInfo *clk_info)
{
const PathVertexPtr &crpr_clk_path = clk_info->crprClkPath();
if (!crpr_clk_path.isNull()) {
PathVertex crpr_clk_vpath(crpr_clk_path, this);
if (!crpr_clk_vpath.isNull()) {
Arrival other_arrival = otherMinMaxArrival(&crpr_clk_vpath);
float crpr_diff = abs(delayAsFloat(crpr_clk_vpath.arrival(this),
EarlyLate::late(),
this)
- delayAsFloat(other_arrival, EarlyLate::early(),
this));
return crpr_diff;
}
const Path *crpr_clk_path = clk_info->crprClkPath(this);
if (crpr_clk_path) {
Arrival other_arrival = otherMinMaxArrival(crpr_clk_path);
float crpr_diff = abs(delayAsFloat(crpr_clk_path->arrival(),
EarlyLate::late(),
this)
- delayAsFloat(other_arrival, EarlyLate::early(),
this));
return crpr_diff;
}
return 0.0F;
}
Arrival
CheckCrpr::otherMinMaxArrival(const PathVertex *path)
CheckCrpr::otherMinMaxArrival(const Path *path)
{
PathAnalysisPt *other_ap = path->pathAnalysisPt(this)->tgtClkAnalysisPt();
Tag *tag = path->tag(this);
@ -115,18 +79,18 @@ CheckCrpr::otherMinMaxArrival(const PathVertex *path)
path->transition(this),
other_ap, this);
while (other_iter.hasNext()) {
PathVertex *other = other_iter.next();
Path *other = other_iter.next();
if (tagMatchCrpr(other->tag(this), tag))
return other->arrival(this);
return other->arrival();
}
// No corresponding path found.
// Match the arrival so the difference is zero.
return path->arrival(this);
return path->arrival();
}
Crpr
CheckCrpr::checkCrpr(const Path *src_path,
const PathVertex *tgt_clk_path)
const Path *tgt_clk_path)
{
Crpr crpr;
Pin *crpr_pin;
@ -136,7 +100,7 @@ CheckCrpr::checkCrpr(const Path *src_path,
void
CheckCrpr::checkCrpr(const Path *src_path,
const PathVertex *tgt_clk_path,
const Path *tgt_clk_path,
// Return values.
Crpr &crpr,
Pin *&crpr_pin)
@ -152,7 +116,7 @@ CheckCrpr::checkCrpr(const Path *src_path,
void
CheckCrpr::checkCrpr1(const Path *src_path,
const PathVertex *tgt_clk_path,
const Path *tgt_clk_path,
bool same_pin,
// Return values.
Crpr &crpr,
@ -165,17 +129,11 @@ CheckCrpr::checkCrpr1(const Path *src_path,
ClkInfo *tgt_clk_info = tgt_clk_path->tag(this)->clkInfo();
const Clock *src_clk = src_clk_info->clock();
const Clock *tgt_clk = tgt_clk_info->clock();
PathVertex src_clk_path1;
const PathVertexPtr &src_crpr_clk_path = src_clk_info->crprClkPath();
const PathVertex *src_clk_path = nullptr;
if (src_tag->isClock()) {
src_clk_path1.init(src_path->vertex(this), src_path->tag(this), this);
src_clk_path = &src_clk_path1;
}
else if (!src_crpr_clk_path.isNull()) {
src_clk_path1.init(src_crpr_clk_path, this);
src_clk_path = &src_clk_path1;
}
const Path *src_clk_path = nullptr;
if (src_tag->isClock())
src_clk_path = src_path;
else
src_clk_path = src_clk_info->crprClkPath(this);
const MinMax *src_clk_min_max =
src_clk_path ? src_clk_path->minMax(this) : src_path->minMax(this);
if (src_clk && tgt_clk
@ -189,42 +147,37 @@ CheckCrpr::checkCrpr1(const Path *src_path,
&& (src_clk_path
|| src_clk->isGenerated())) {
// Src path from input port clk path can only be from generated clk path.
PathVertex port_clk_path;
if (src_clk_path == nullptr) {
portClkPath(src_clk_info->clkEdge(),
src_clk_info->clkSrc(),
src_path->pathAnalysisPt(this),
port_clk_path);
src_clk_path = &port_clk_path;
src_clk_path = portClkPath(src_clk_info->clkEdge(),
src_clk_info->clkSrc(),
src_path->pathAnalysisPt(this));
}
findCrpr(src_clk_path, tgt_clk_path, same_pin, crpr, crpr_pin);
}
}
// Find the clk path for an input/output port.
void
Path *
CheckCrpr::portClkPath(const ClockEdge *clk_edge,
const Pin *clk_src_pin,
const PathAnalysisPt *path_ap,
// Return value.
PathVertex &genclk_path)
const PathAnalysisPt *path_ap)
{
Vertex *clk_vertex = graph_->pinDrvrVertex(clk_src_pin);
VertexPathIterator path_iter(clk_vertex, clk_edge->transition(),
path_ap, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
if (path->clkEdge(this) == clk_edge
&& path->isClock(this)) {
genclk_path = path;
break;
return path;
}
}
return nullptr;
}
void
CheckCrpr::findCrpr(const PathVertex *src_clk_path,
const PathVertex *tgt_clk_path,
CheckCrpr::findCrpr(const Path *src_clk_path,
const Path *tgt_clk_path,
bool same_pin,
// Return values.
Crpr &crpr,
@ -232,35 +185,33 @@ CheckCrpr::findCrpr(const PathVertex *src_clk_path,
{
crpr = 0.0;
crpr_pin = nullptr;
const PathVertex *src_clk_path1 = src_clk_path;
const PathVertex *tgt_clk_path1 = tgt_clk_path;
PathVertexSeq src_gclk_paths, tgt_gclk_paths;
const Path *src_clk_path1 = src_clk_path;
const Path *tgt_clk_path1 = tgt_clk_path;
if (src_clk_path1->clkInfo(this)->clkSrc()
!= tgt_clk_path1->clkInfo(this)->clkSrc()) {
// Push src/tgt genclk src paths into a vector,
// The last genclk src path is at index 0.
genClkSrcPaths(src_clk_path1, src_gclk_paths);
genClkSrcPaths(tgt_clk_path1, tgt_gclk_paths);
ConstPathSeq src_gclk_paths = genClkSrcPaths(src_clk_path1);
ConstPathSeq tgt_gclk_paths = genClkSrcPaths(tgt_clk_path1);
// Search from the first gen clk toward the end
// of the path to find a common root pin.
int i = src_gclk_paths.size() - 1;
int j = tgt_gclk_paths.size() - 1;
for (; i >= 0 && j >= 0; i--, j--) {
PathVertex &src_path = src_gclk_paths[i];
PathVertex &tgt_path = tgt_gclk_paths[j];
if (src_path.clkInfo(this)->clkSrc()
== tgt_path.clkInfo(this)->clkSrc()) {
src_clk_path1 = &src_gclk_paths[i];
tgt_clk_path1 = &tgt_gclk_paths[j];
const Path *src_path = src_gclk_paths[i];
const Path *tgt_path = tgt_gclk_paths[j];
if (src_path->clkInfo(this)->clkSrc()
== tgt_path->clkInfo(this)->clkSrc()) {
src_clk_path1 = src_gclk_paths[i];
tgt_clk_path1 = tgt_gclk_paths[j];
}
else
break;
}
}
const PathVertex *src_clk_path2 = src_clk_path1;
const PathVertex *tgt_clk_path2 = tgt_clk_path1;
PathVertex src_prev, tgt_prev;
// src_clk_path and tgt_clk_path are now in the same (gen)clk src path.
const Path *src_clk_path2 = src_clk_path1;
const Path *tgt_clk_path2 = tgt_clk_path1;
// src_clk_path2 and tgt_clk_path2 are now in the same (gen)clk src path.
// Use the vertex levels to back up the deeper path to see if they
// overlap.
int src_level = src_clk_path2->vertex(this)->level();
@ -268,21 +219,19 @@ CheckCrpr::findCrpr(const PathVertex *src_clk_path,
while (src_clk_path2->pin(this) != tgt_clk_path2->pin(this)) {
int level_diff = src_level - tgt_level;
if (level_diff >= 0) {
clkPathPrev(src_clk_path2, src_prev);
if (src_prev.isNull())
src_clk_path2 = src_clk_path2->prevPath();
if (src_clk_path2 == nullptr)
break;
src_clk_path2 = &src_prev;
src_level = src_clk_path2->vertex(this)->level();
}
if (level_diff <= 0) {
clkPathPrev(tgt_clk_path2, tgt_prev);
if (tgt_prev.isNull())
tgt_clk_path2 = tgt_clk_path2->prevPath();
if (tgt_clk_path2 == nullptr)
break;
tgt_clk_path2 = &tgt_prev;
tgt_level = tgt_clk_path2->vertex(this)->level();
}
}
if (!src_clk_path2->isNull() && !tgt_clk_path2->isNull()
if (src_clk_path2 && tgt_clk_path2
&& (src_clk_path2->transition(this) == tgt_clk_path2->transition(this)
|| same_pin)) {
debugPrint(debug_, "crpr", 2, "crpr pin %s",
@ -292,30 +241,31 @@ CheckCrpr::findCrpr(const PathVertex *src_clk_path,
}
}
void
CheckCrpr::genClkSrcPaths(const PathVertex *path,
PathVertexSeq &gclk_paths)
ConstPathSeq
CheckCrpr::genClkSrcPaths(const Path *path)
{
ConstPathSeq gclk_paths;
ClkInfo *clk_info = path->clkInfo(this);
const ClockEdge *clk_edge = clk_info->clkEdge();
const Pin *clk_src = clk_info->clkSrc();
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
gclk_paths.push_back(path);
Genclks *genclks = search_->genclks();
while (clk_edge->clock()->isGenerated()) {
PathVertex genclk_path =
search_->genclks()->srcPath(clk_edge, clk_src, path_ap);
if (genclk_path.isNull())
Path *genclk_path = genclks->srcPath(clk_edge, clk_src, path_ap);
if (genclk_path == nullptr)
break;
clk_info = genclk_path.clkInfo(this);
clk_info = genclk_path->clkInfo(this);
clk_src = clk_info->clkSrc();
clk_edge = clk_info->clkEdge();
gclk_paths.push_back(genclk_path);
}
return gclk_paths;
}
Crpr
CheckCrpr::findCrpr1(const PathVertex *src_clk_path,
const PathVertex *tgt_clk_path)
CheckCrpr::findCrpr1(const Path *src_clk_path,
const Path *tgt_clk_path)
{
if (pocv_enabled_) {
// Remove variation on the common path.
@ -323,8 +273,8 @@ CheckCrpr::findCrpr1(const PathVertex *src_clk_path,
// sigma of the common clock path.
const EarlyLate *src_el = src_clk_path->minMax(this);
const EarlyLate *tgt_el = tgt_clk_path->minMax(this);
Arrival src_arrival = src_clk_path->arrival(this);
Arrival tgt_arrival = tgt_clk_path->arrival(this);
Arrival src_arrival = src_clk_path->arrival();
Arrival tgt_arrival = tgt_clk_path->arrival();
float src_clk_time = src_clk_path->clkEdge(this)->time();
float tgt_clk_time = tgt_clk_path->clkEdge(this)->time();
float crpr_mean = abs(delayAsFloat(src_arrival) - src_clk_time
@ -352,10 +302,10 @@ CheckCrpr::findCrpr1(const PathVertex *src_clk_path,
}
float
CheckCrpr::crprArrivalDiff(const PathVertex *path)
CheckCrpr::crprArrivalDiff(const Path *path)
{
Arrival other_arrival = otherMinMaxArrival(path);
float crpr_diff = abs(delayAsFloat(path->arrival(this))
float crpr_diff = abs(delayAsFloat(path->arrival())
- delayAsFloat(other_arrival));
return crpr_diff;
}
@ -407,13 +357,12 @@ CheckCrpr::outputDelayCrpr1(const Path *src_path,
&& tgt_clk->isGenerated()
&& tgt_clk->isPropagated()
&& crprPossible(src_clk, tgt_clk)) {
PathVertex tgt_genclk_path;
portClkPath(tgt_clk_edge, tgt_clk_edge->clock()->defaultPin(), tgt_path_ap,
tgt_genclk_path);
PathVertex src_clk_path(src_path->clkInfo(this)->crprClkPath(), this);
if (!src_clk_path.isNull()) {
findCrpr(&src_clk_path, &tgt_genclk_path, same_pin, crpr, crpr_pin);
}
Path *tgt_genclk_path = portClkPath(tgt_clk_edge,
tgt_clk_edge->clock()->defaultPin(),
tgt_path_ap);
Path *src_clk_path = src_path->clkInfo(this)->crprClkPath(this);
if (src_clk_path)
findCrpr(src_clk_path, tgt_genclk_path, same_pin, crpr, crpr_pin);
}
}

View File

@ -42,9 +42,9 @@ public:
Arrival maxCrpr(ClkInfo *clk_info);
// Timing check CRPR.
Crpr checkCrpr(const Path *src_clk_path,
const PathVertex *tgt_clk_path);
const Path *tgt_clk_path);
void checkCrpr(const Path *src_path,
const PathVertex *tgt_clk_path,
const Path *tgt_clk_path,
// Return values.
Crpr &crpr,
Pin *&crpr_pin);
@ -57,18 +57,12 @@ public:
Crpr &crpr,
Pin *&crpr_pin);
// Previous clk path when crpr is enabled.
PathVertex clkPathPrev(const PathVertex *path);
// For Search::reportArrivals.
PathVertex clkPathPrev(Vertex *vertex,
int arrival_index);
private:
void clkPathPrev(const PathVertex *path,
PathVertex &prev);
Arrival otherMinMaxArrival(const PathVertex *path);
void clkPathPrev(const Path *path,
Path &prev);
Arrival otherMinMaxArrival(const Path *path);
void checkCrpr1(const Path *src_path,
const PathVertex *tgt_clk_path,
const Path *tgt_clk_path,
bool same_pin,
// Return values.
Crpr &crpr,
@ -82,22 +76,19 @@ private:
Pin *&crpr_pin);
bool crprPossible(const Clock *clk1,
const Clock *clk2);
void genClkSrcPaths(const PathVertex *path,
PathVertexSeq &gclk_paths);
void findCrpr(const PathVertex *src_clk_path,
const PathVertex *tgt_clk_path,
ConstPathSeq genClkSrcPaths(const Path *path);
void findCrpr(const Path *src_clk_path,
const Path *tgt_clk_path,
bool same_pin,
// Return values.
Crpr &crpr,
Pin *&common_pin);
void portClkPath(const ClockEdge *clk_edge,
const Pin *clk_src_pin,
const PathAnalysisPt *path_ap,
// Return value.
PathVertex &port_clk_path);
Crpr findCrpr1(const PathVertex *src_clk_path,
const PathVertex *tgt_clk_path);
float crprArrivalDiff(const PathVertex *path);
Path *portClkPath(const ClockEdge *clk_edge,
const Pin *clk_src_pin,
const PathAnalysisPt *path_ap);
Crpr findCrpr1(const Path *src_clk_path,
const Path *tgt_clk_path);
float crprArrivalDiff(const Path *path);
};
} // namespace

View File

@ -40,7 +40,7 @@
#include "Corner.hh"
#include "PathAnalysisPt.hh"
#include "Levelize.hh"
#include "PathVertexPtr.hh"
#include "Path.hh"
#include "Search.hh"
namespace sta {
@ -137,7 +137,7 @@ Genclks::fanins(const Clock *clk)
}
Vertex *
Genclks::srcPathVertex(const Pin *pin) const
Genclks::srcPath(const Pin *pin) const
{
bool is_bidirect = network_->direction(pin)->isBidirect();
// Insertion delay is to the driver vertex for clks defined on
@ -155,7 +155,7 @@ Genclks::clkPinMaxLevel(const Clock *clk) const
{
Level max_level = 0;
for (const Pin *pin : clk->leafPins()) {
Vertex *vertex = srcPathVertex(pin);
Vertex *vertex = srcPath(pin);
max_level = max(max_level, vertex->level());
}
return max_level;
@ -209,9 +209,7 @@ Genclks::ensureInsertionDelays()
// insertion delay, so sort the clocks by source pin level.
sort(gclks, ClockPinMaxLevelLess(this));
ClockSeq::Iterator gclk_iter(gclks);
while (gclk_iter.hasNext()) {
Clock *gclk = gclk_iter.next();
for (Clock *gclk : gclks) {
if (gclk->masterClk()) {
findInsertionDelays(gclk);
recordSrcPaths(gclk);
@ -546,7 +544,7 @@ Genclks::makeGenclkInfo(Clock *gclk)
VertexSet *fanins = new VertexSet(graph_);
findFanin(gclk, fanins);
GenclkInfo *genclk_info = new GenclkInfo(gclk, gclk_level, fanins,
src_filter);
src_filter);
genclk_info_map_.insert(gclk, genclk_info);
return genclk_info;
}
@ -684,12 +682,12 @@ Genclks::seedSrcPins(Clock *gclk,
for (auto path_ap : corners_->pathAnalysisPts()) {
const MinMax *min_max = path_ap->pathMinMax();
const EarlyLate *early_late = min_max;
for (auto rf : RiseFall::range()) {
Tag *tag = makeTag(gclk, master_clk, master_pin, rf, src_filter,
path_ap);
for (const RiseFall *rf : RiseFall::range()) {
Tag *tag = makeTag(gclk, master_clk, master_pin, rf,
src_filter, path_ap);
Arrival insert = search_->clockInsertion(master_clk, master_pin, rf,
min_max, early_late, path_ap);
tag_bldr.setArrival(tag, insert, nullptr);
tag_bldr.setArrival(tag, insert);
}
}
search_->setVertexArrivals(vertex, &tag_bldr);
@ -854,22 +852,14 @@ void
Genclks::copyGenClkSrcPaths(Vertex *vertex,
TagGroupBldr *tag_bldr)
{
Arrival *arrivals = graph_->arrivals(vertex);
if (arrivals) {
PathPrev *prev_paths = graph_->prevPaths(vertex);
Path *paths = graph_->paths(vertex);
if (paths) {
TagGroup *tag_group = search_->tagGroup(vertex);
if (tag_group) {
ArrivalMap::Iterator arrival_iter(tag_group->arrivalMap());
while (arrival_iter.hasNext()) {
Tag *tag;
int arrival_index;
arrival_iter.next(tag, arrival_index);
for (auto const [tag, path_index] : *tag_group->pathIndexMap()) {
if (tag->isGenClkSrcPath()) {
Arrival arrival = arrivals[arrival_index];
PathPrev *prev_path = prev_paths
? &prev_paths[arrival_index]
: nullptr;
tag_bldr->setArrival(tag, arrival, prev_path);
Path &path = paths[path_index];
tag_bldr->insertPath(path);
}
}
}
@ -881,11 +871,14 @@ Genclks::copyGenClkSrcPaths(Vertex *vertex,
void
Genclks::clearSrcPaths()
{
genclk_src_paths_.deleteArrayContents();
for (auto const & [clk_pin, src_paths] : genclk_src_paths_) {
for (const Path &src_path : src_paths)
delete src_path.prevPath();
}
genclk_src_paths_.clear();
}
int
size_t
Genclks::srcPathIndex(const RiseFall *clk_rf,
const PathAnalysisPt *path_ap) const
{
@ -903,14 +896,13 @@ Genclks::recordSrcPaths(Clock *gclk)
bool has_edges = gclk->edges() != nullptr;
for (const Pin *gclk_pin : gclk->leafPins()) {
PathVertexPtr *src_paths = new PathVertexPtr[path_count];
genclk_src_paths_.insert(ClockPinPair(gclk, gclk_pin), src_paths);
Vertex *gclk_vertex = srcPathVertex(gclk_pin);
vector<Path> &src_paths = genclk_src_paths_[ClockPinPair(gclk, gclk_pin)];
src_paths.resize(path_count);
Vertex *gclk_vertex = srcPath(gclk_pin);
bool found_src_paths = false;
VertexPathIterator path_iter(gclk_vertex, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
const ClockEdge *src_clk_edge = path->clkEdge(this);
if (src_clk_edge
&& matchesSrcFilter(path, gclk)) {
@ -919,24 +911,34 @@ Genclks::recordSrcPaths(Clock *gclk)
const RiseFall *rf = path->transition(this);
bool inverting_path = (rf != src_clk_rf);
const PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
int path_index = srcPathIndex(rf, path_ap);
PathVertexPtr &src_path = src_paths[path_index];
size_t path_index = srcPathIndex(rf, path_ap);
Path &src_path = src_paths[path_index];
if ((!divide_by_1
|| (inverting_path == invert))
&& (!has_edges
|| src_clk_rf == gclk->masterClkEdgeTr(rf))
&& (src_path.isNull()
|| delayGreater(path->arrival(this),
src_path.arrival(this),
|| delayGreater(path->arrival(),
src_path.arrival(),
early_late,
this))) {
debugPrint(debug_, "genclk", 2, " %s insertion %s %s %s",
network_->pathName(gclk_pin),
early_late->asString(),
rf->asString(),
delayAsString(path->arrival(this), this));
src_path.init(path, this);
found_src_paths = true;
delayAsString(path->arrival(), this));
delete src_path.prevPath();
src_path = *path;
Path *prev_copy = &src_path;
Path *p = path->prevPath();
while (p) {
Path *copy = new Path(p);
copy->setIsEnum(true);
prev_copy->setPrevPath(copy);
prev_copy = copy;
p = p->prevPath();
}
found_src_paths = true;
}
}
}
@ -973,8 +975,8 @@ Genclks::matchesSrcFilter(Path *path,
return false;
}
PathVertex
Genclks::srcPath(Path *clk_path) const
Path *
Genclks::srcPath(const Path *clk_path) const
{
const Pin *src_pin = clk_path->pin(this);
const ClockEdge *clk_edge = clk_path->clkEdge(this);
@ -985,7 +987,7 @@ Genclks::srcPath(Path *clk_path) const
insert_ap);
}
PathVertex
Path *
Genclks::srcPath(const ClockEdge *clk_edge,
const Pin *src_pin,
const PathAnalysisPt *path_ap) const
@ -993,20 +995,52 @@ Genclks::srcPath(const ClockEdge *clk_edge,
return srcPath(clk_edge->clock(), src_pin, clk_edge->transition(), path_ap);
}
PathVertex
Path *
Genclks::srcPath(const Clock *gclk,
const Pin *src_pin,
const RiseFall *rf,
const PathAnalysisPt *path_ap) const
{
PathVertexPtr *src_paths =
genclk_src_paths_.findKey(ClockPinPair(gclk, src_pin));
if (src_paths) {
int path_index = srcPathIndex(rf, path_ap);
return PathVertex(src_paths[path_index], this);
auto itr = genclk_src_paths_.find(ClockPinPair(gclk, src_pin));
if (itr != genclk_src_paths_.end()) {
vector<Path> src_paths = itr->second;
if (!src_paths.empty()) {
size_t path_index = srcPathIndex(rf, path_ap);
Path &src_path = src_paths[path_index];
if (!src_path.isNull()) {
Path *src_vpath = Path::vertexPath(src_path, this);
return src_vpath;
}
}
}
return nullptr;
}
void
Genclks::updateSrcPathPrevs()
{
for (auto const & [clk_pin, src_paths] : genclk_src_paths_) {
for (const Path &src_path : src_paths) {
if (!src_path.isNull()) {
const Path *p = &src_path;
while (p) {
Path *src_vpath = Path::vertexPath(p->vertex(this),
p->tag(this), this);
Path *prev_path = p->prevPath();
if (prev_path) {
Path *prev_vpath = Path::vertexPath(prev_path->vertex(this),
prev_path->tag(this), this);
src_vpath->setPrevPath(prev_vpath);
src_vpath->setPrevEdgeArc(p->prevEdge(this),
p->prevArc(this), this);
}
p = p->prevPath();
}
debugPrint(debug_, "genclk", 3, "repaired src path prev %s",
src_path.name(this));
}
}
}
else
return PathVertex();
}
Arrival
@ -1017,9 +1051,9 @@ Genclks::insertionDelay(const Clock *clk,
const PathAnalysisPt *path_ap) const
{
PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late);
PathVertex src_path = srcPath(clk, pin, rf, insert_ap);
if (!src_path.isNull())
return src_path.arrival(this);
Path *src_path = srcPath(clk, pin, rf, insert_ap);
if (src_path)
return src_path->arrival();
else
return 0.0;
}

View File

@ -50,7 +50,7 @@ public:
};
typedef Map<Clock*, GenclkInfo*> GenclkInfoMap;
typedef Map<ClockPinPair, PathVertexPtr*, ClockPinPairLess> GenclkSrcPathMap;
typedef Map<ClockPinPair, vector<Path>, ClockPinPairLess> GenclkSrcPathMap;
class Genclks : public StaState
{
@ -71,19 +71,20 @@ public:
const EarlyLate *early_late,
const PathAnalysisPt *path_ap) const;
// Generated clock source path for a clock path root.
PathVertex srcPath(Path *clk_path) const;
Path *srcPath(const Path *clk_path) const;
// Generated clock source path.
PathVertex srcPath(const ClockEdge *clk_edge,
const Pin *src_pin,
const PathAnalysisPt *path_ap) const;
PathVertex srcPath(const Clock *clk,
const Pin *src_pin,
const RiseFall *rf,
const PathAnalysisPt *path_ap) const;
Vertex *srcPathVertex(const Pin *pin) const;
Path *srcPath(const ClockEdge *clk_edge,
const Pin *src_pin,
const PathAnalysisPt *path_ap) const;
Path *srcPath(const Clock *clk,
const Pin *src_pin,
const RiseFall *rf,
const PathAnalysisPt *path_ap) const;
Vertex *srcPath(const Pin *pin) const;
Level clkPinMaxLevel(const Clock *clk) const;
void copyGenClkSrcPaths(Vertex *vertex,
TagGroupBldr *tag_bldr);
void updateSrcPathPrevs();
private:
void findInsertionDelays();
@ -94,8 +95,8 @@ private:
void seedClkVertices(Clock *clk,
BfsBkwdIterator &iter,
VertexSet *fanins);
int srcPathIndex(const RiseFall *clk_rf,
const PathAnalysisPt *path_ap) const;
size_t srcPathIndex(const RiseFall *clk_rf,
const PathAnalysisPt *path_ap) const;
bool matchesSrcFilter(Path *path,
const Clock *gclk) const;
void seedSrcPins(Clock *gclk,
@ -129,7 +130,6 @@ private:
VertexSet &visited_vertices,
EdgeSet *&fdbk_edges);
bool found_insertion_delays_;
GenclkSrcPathMap genclk_src_paths_;
GenclkInfoMap genclk_info_map_;

View File

@ -49,8 +49,8 @@ Latches::Latches(StaState *sta) :
void
Latches::latchRequired(const Path *data_path,
const PathVertex *enable_path,
const PathVertex *disable_path,
const Path *enable_path,
const Path *disable_path,
const MultiCyclePath *mcp,
const PathDelay *path_delay,
Arrival src_clk_latency,
@ -61,7 +61,7 @@ Latches::latchRequired(const Path *data_path,
Arrival &adjusted_data_arrival,
Delay &time_given_to_startpoint) const
{
const Arrival data_arrival = data_path->arrival(this);
const Arrival data_arrival = data_path->arrival();
float max_delay = 0.0;
bool ignore_clk_latency = false;
if (path_delay) {
@ -149,8 +149,8 @@ Latches::latchRequired(const Path *data_path,
void
Latches::latchBorrowInfo(const Path *data_path,
const PathVertex *enable_path,
const PathVertex *disable_path,
const Path *enable_path,
const Path *disable_path,
const ArcDelay &margin,
bool ignore_clk_latency,
// Return values.
@ -213,8 +213,8 @@ Latches::latchBorrowInfo(const Path *data_path,
void
Latches::latchRequired(const Path *data_path,
const PathVertex *enable_path,
const PathVertex *disable_path,
const Path *enable_path,
const Path *disable_path,
const PathAnalysisPt *path_ap,
// Return values.
Required &required,
@ -243,11 +243,9 @@ Latches::latchRequired(const Path *data_path,
}
// Find the latch enable open/close path from the close/open path.
void
Path *
Latches::latchEnableOtherPath(const Path *path,
const PathAnalysisPt *tgt_clk_path_ap,
// Return value.
PathVertex &other_path) const
const PathAnalysisPt *tgt_clk_path_ap) const
{
Vertex *vertex = path->vertex(this);
const ClockEdge *clk_edge = path->clkEdge(this);
@ -256,20 +254,18 @@ Latches::latchEnableOtherPath(const Path *path,
RiseFall *other_rf = path->transition(this)->opposite();
VertexPathIterator path_iter(vertex, other_rf, tgt_clk_path_ap, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
if (path->isClock(this)
&& path->clkEdge(this) == other_clk_edge) {
other_path = path;
break;
return path;
}
}
return nullptr;
}
void
Path *
Latches::latchEnablePath(const Path *q_path,
const Edge *d_q_edge,
// Return value.
PathVertex &enable_path) const
const Edge *d_q_edge) const
{
const ClockEdge *en_clk_edge = q_path->clkEdge(this);
@ -283,15 +279,15 @@ Latches::latchEnablePath(const Path *q_path,
if (state == LatchEnableState::enabled) {
VertexPathIterator path_iter(en_vertex, en_rf, tgt_clk_path_ap, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
const ClockEdge *clk_edge = path->clkEdge(this);
if (path->isClock(this)
&& clk_edge == en_clk_edge) {
enable_path = path;
break;
return path;
}
}
}
return nullptr;
}
// The arrival time for a latch D->Q edge is clipped to the window of
@ -324,7 +320,7 @@ Latches::latchOutArrival(const Path *data_path,
if (!(excpt && excpt->isFalse())) {
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
false, path_ap);
q_arrival = data_path->arrival(this) + arc_delay;
q_arrival = data_path->arrival() + arc_delay;
q_tag = data_path->tag(this);
}
}
@ -334,7 +330,7 @@ Latches::latchOutArrival(const Path *data_path,
VertexPathIterator enable_iter(enable_vertex, enable_rf,
tgt_clk_path_ap, this);
while (enable_iter.hasNext()) {
PathVertex *enable_path = enable_iter.next();
Path *enable_path = enable_iter.next();
ClkInfo *en_clk_info = enable_path->clkInfo(this);
const ClockEdge *en_clk_edge = en_clk_info->clkEdge();
if (enable_path->isClock(this)) {
@ -342,12 +338,11 @@ Latches::latchOutArrival(const Path *data_path,
// D->Q is disabled when if there is a path delay -to D or EN clk.
if (!(excpt && (excpt->isFalse()
|| excpt->isPathDelay()))) {
PathVertex disable_path;
latchEnableOtherPath(enable_path, tgt_clk_path_ap, disable_path);
Path *disable_path = latchEnableOtherPath(enable_path, tgt_clk_path_ap);
Delay borrow, time_given_to_startpoint;
Arrival adjusted_data_arrival;
Required required;
latchRequired(data_path, enable_path, &disable_path, path_ap,
latchRequired(data_path, enable_path, disable_path, path_ap,
required, borrow, adjusted_data_arrival,
time_given_to_startpoint);
if (delayGreater(borrow, 0.0, this)) {
@ -357,7 +352,7 @@ Latches::latchOutArrival(const Path *data_path,
q_arrival = adjusted_data_arrival + arc_delay;
// Tag switcheroo - data passing thru gets latch enable tag.
// States and path ap come from Q, everything else from enable.
PathVertex *crpr_clk_path =
Path *crpr_clk_path =
sdc_->crprActive() ? enable_path : nullptr;
ClkInfo *q_clk_info =
search_->findClkInfo(en_clk_edge,
@ -448,24 +443,23 @@ Latches::latchTimeGivenToStartpoint(const Path *d_path,
const Edge *d_q_edge,
// Return values.
Arrival &time_given,
PathVertex &enable_path) const
Path *&enable_path) const
{
latchEnablePath(q_path, d_q_edge, enable_path);
if (!enable_path.isNull()
&& enable_path.isClock(this)) {
enable_path = latchEnablePath(q_path, d_q_edge);
if (enable_path
&& enable_path->isClock(this)) {
const PathAnalysisPt *path_ap = q_path->pathAnalysisPt(this);
const PathAnalysisPt *tgt_clk_path_ap = path_ap->tgtClkAnalysisPt();
PathVertex disable_path;
latchEnableOtherPath(enable_path.path(), tgt_clk_path_ap, disable_path);
Path *disable_path = latchEnableOtherPath(enable_path, tgt_clk_path_ap);
Delay borrow;
Required required;
Arrival adjusted_data_arrival;
latchRequired(d_path, &enable_path, &disable_path, path_ap,
latchRequired(d_path, enable_path, disable_path, path_ap,
required, borrow, adjusted_data_arrival, time_given);
}
else {
time_given = 0.0;
enable_path.init();
enable_path = nullptr;
}
}
@ -517,7 +511,7 @@ Latches::latchDtoQEnable(const Edge *d_q_edge,
}
LatchEnableState
Latches::latchDtoQState(Edge *edge) const
Latches::latchDtoQState(const Edge *edge) const
{
const Vertex *from_vertex = edge->from(graph_);
const Pin *from_pin = from_vertex->pin();
@ -532,7 +526,7 @@ Latches::latchDtoQState(Edge *edge) const
// Latch D->Q arc looks combinational when the enable pin is disabled
// or constant.
bool
Latches::isLatchDtoQ(Edge *edge) const
Latches::isLatchDtoQ(const Edge *edge) const
{
return edge->role() == TimingRole::latchDtoQ()
&& latchDtoQState(edge) == LatchEnableState::enabled;

View File

@ -43,10 +43,10 @@ public:
const Edge *d_q_edge,
// Return values.
Arrival &time_given,
PathVertex &enable_path) const;
Path *&enable_path) const;
void latchRequired(const Path *data_path,
const PathVertex *enable_path,
const PathVertex *disable_path,
const Path *enable_path,
const Path *disable_path,
const MultiCyclePath *mcp,
const PathDelay *path_delay,
Arrival src_clk_latency,
@ -57,8 +57,8 @@ public:
Arrival &adjusted_data_arrival,
Delay &time_given_to_startpoint) const;
void latchRequired(const Path *data_path,
const PathVertex *enable_path,
const PathVertex *disable_path,
const Path *enable_path,
const Path *disable_path,
const PathAnalysisPt *path_ap,
// Return values.
Required &required,
@ -66,8 +66,8 @@ public:
Arrival &adjusted_data_arrival,
Delay &time_given_to_startpoint) const;
void latchBorrowInfo(const Path *data_path,
const PathVertex *enable_path,
const PathVertex *disable_path,
const Path *enable_path,
const Path *disable_path,
const ArcDelay &margin,
bool ignore_clk_latency,
// Return values.
@ -79,7 +79,7 @@ public:
Crpr &crpr_diff,
Delay &max_borrow,
bool &borrow_limit_exists) const;
bool isLatchDtoQ(Edge *edge) const;
bool isLatchDtoQ(const Edge *edge) const;
// Find the latch EN->Q edge for a D->Q edge.
void latchDtoQEnable(const Edge *d_q_edge,
const Instance *inst,
@ -87,15 +87,11 @@ public:
Vertex *&enable_vertex,
const RiseFall *&enable_rf,
LatchEnableState &state) const;
LatchEnableState latchDtoQState(Edge *d_q_edge) const;
void latchEnableOtherPath(const Path *path,
const PathAnalysisPt *tgt_clk_path_ap,
// Return value.
PathVertex &other_path) const;
void latchEnablePath(const Path *q_path,
const Edge *d_q_edge,
// Return value.
PathVertex &enable_path) const;
LatchEnableState latchDtoQState(const Edge *d_q_edge) const;
Path *latchEnableOtherPath(const Path *path,
const PathAnalysisPt *tgt_clk_path_ap) const;
Path *latchEnablePath(const Path *q_path,
const Edge *d_q_edge) const;
void latchOutArrival(const Path *data_path,
const TimingArc *d_q_arc,
const Edge *d_q_edge,

View File

@ -280,7 +280,7 @@ MakeEndTimingArcs::visit(PathEnd *path_end)
Network *network = sta_->network();
Debug *debug = sta_->debug();
const MinMax *min_max = path_end->minMax(sta_);
Arrival data_delay = src_path->arrival(sta_);
Arrival data_delay = src_path->arrival();
Delay clk_latency = path_end->targetClkDelay(sta_);
ArcDelay check_margin = path_end->margin(sta_);
Delay margin = min_max == MinMax::max()
@ -377,11 +377,11 @@ MakeTimingModel::findOutputDelays(const RiseFall *input_rf,
Vertex *output_vertex = graph_->pinLoadVertex(output_pin);
VertexPathIterator path_iter(output_vertex, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
if (search_->matchesFilter(path, nullptr)) {
const RiseFall *output_rf = path->transition(sta_);
const MinMax *min_max = path->minMax(sta_);
Arrival delay = path->arrival(sta_);
Arrival delay = path->arrival();
OutputDelays &delays = output_pin_delays[output_pin];
delays.delays.mergeValue(output_rf, min_max,
delayAsFloat(delay, min_max, sta_));
@ -486,12 +486,12 @@ MakeTimingModel::findClkedOutputPaths()
Vertex *output_vertex = graph_->pinLoadVertex(output_pin);
VertexPathIterator path_iter(output_vertex, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
const ClockEdge *clk_edge = path->clkEdge(sta_);
if (clk_edge) {
const RiseFall *output_rf = path->transition(sta_);
const MinMax *min_max = path->minMax(sta_);
Arrival delay = path->arrival(sta_);
Arrival delay = path->arrival();
RiseFallMinMax &delays = clk_delays[clk_edge];
delays.mergeValue(output_rf, min_max,
delayAsFloat(delay, min_max, sta_));
@ -567,7 +567,7 @@ MakeTimingModel::makeClkTreePaths(LibertyPort *lib_port,
const RiseFall *end_rf = (sense == TimingSense::positive_unate)
? clk_rf
: clk_rf->opposite();
PathVertex clk_path;
Path clk_path;
Delay insertion, delay, latency;
float lib_clk_delay;
bool exists;

View File

@ -33,17 +33,180 @@
#include "Corner.hh"
#include "PathAnalysisPt.hh"
#include "Tag.hh"
#include "PathRef.hh"
#include "TagGroup.hh"
#include "Search.hh"
namespace sta {
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;
}
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);
Vertex *vertex = this->vertex(sta);
if (vertex) {
const char *vertex_name = vertex->name(network);
const char *tr_str = transition(sta)->asString();
const PathAnalysisPt *path_ap = pathAnalysisPt(sta);
int ap_index = path_ap->index();
@ -57,16 +220,67 @@ Path::name(const StaState *sta) const
return "NULL";
}
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_;
}
Pin *
Path::pin(const StaState *sta) const
{
return vertex(sta)->pin();
}
TagIndex
Path::tagIndex(const StaState *sta) const
Tag *
Path::tag(const StaState *sta) const
{
return tag(sta)->index();
const Search *search = sta->search();
return search->tag(tag_index_);
}
void
Path::setTag(Tag *tag)
{
tag_index_ = tag->index();
}
TagIndex
Path::tagIndex(const StaState *) const
{
return tag_index_;
}
size_t
Path::pathIndex(const StaState *sta) const
{
Vertex *vertex = this->vertex(sta);
Path *paths = vertex->paths();
return this - paths;
}
ClkInfo *
@ -118,80 +332,187 @@ Path::slew(const StaState *sta) const
dcalcAnalysisPt(sta)->index());
}
const RiseFall *
Path::transition(const StaState *sta) const
{
return tag(sta)->transition();
}
int
Path::rfIndex(const StaState *sta) const
{
return transition(sta)->index();
}
void
Path::initArrival(const StaState *sta)
PathAnalysisPt *
Path::pathAnalysisPt(const StaState *sta) const
{
setArrival(delayInitValue(minMax(sta)), sta);
}
bool
Path::arrivalIsInitValue(const StaState *sta) const
{
return delayIsInitValue(arrival(sta), minMax(sta));
return tag(sta)->pathAnalysisPt(sta);
}
void
Path::initRequired(const StaState *sta)
Path::setArrival(Arrival arrival)
{
setRequired(delayInitValue(minMax(sta)->opposite()), sta);
arrival_ = arrival;
}
bool
Path::requiredIsInitValue(const StaState *sta) const
void
Path::setRequired(const Required &required)
{
return delayIsInitValue(required(sta), minMax(sta)->opposite());
required_ = required;
}
Slack
Path::slack(const StaState *sta) const
{
if (minMax(sta) == MinMax::max())
return required(sta) - arrival(sta);
return required_ - arrival_;
else
return arrival(sta) - required(sta);
return arrival_ - required_;
}
Path *
Path::prevPath() const
{
return prev_path_;
}
void
Path::prevPath(const StaState *sta,
// Return values.
PathRef &prev_path) const
Path::setPrevPath(Path *prev_path)
{
TimingArc *prev_arc;
prevPath(sta, prev_path, prev_arc);
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;
}
TimingArc *
Path::prevArc(const StaState *sta) const
{
PathRef prev_path;
TimingArc *prev_arc;
prevPath(sta, prev_path, prev_arc);
return prev_arc;
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;
}
Edge *
Path::prevEdge(const TimingArc *prev_arc,
const StaState *sta) const
Path::prevEdge(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;
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));
}
}
}
void
Path::setIsEnum(bool is_enum)
{
is_enum_ = is_enum;
}
////////////////////////////////////////////////////////////////
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;
}
int
Path::cmpPinTrClk(const Path *path1,
@ -256,11 +577,9 @@ 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
return (path1 == nullptr && path2 == nullptr)
|| (path1
&& path2
&& path1->vertexId(sta) == path2->vertexId(sta)
// Tag equal implies transition and path ap equal.
&& path1->tagIndex(sta) == path2->tagIndex(sta));
@ -340,27 +659,27 @@ 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);
const Path *p1 = path1;
const Path *p2 = path2;
while (p1 && p2) {
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))
TimingArc *prev_arc1 = p1->prevArc(sta);
TimingArc *prev_arc2 = p2->prevArc(sta);
p1 = p1->prevPath();
p2 = p2->prevPath();
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())
if (p1 == nullptr && p2 == nullptr)
return 0;
else if (p1.isNull() && !p2.isNull())
else if (p1 == nullptr && p2 != nullptr)
return -1;
else
return 1;
@ -374,4 +693,160 @@ Path::lessAll(const Path *path1,
return cmpAll(path1, path2, sta) < 0;
}
////////////////////////////////////////////////////////////////
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;
}
} // namespace

View File

@ -55,31 +55,32 @@ PathEnd::PathEnd(Path *path) :
PathEnd::~PathEnd()
{
path_.deleteRep();
if (path_->isEnum())
delete path_;
}
void
PathEnd::setPath(const Path *path)
PathEnd::setPath(Path *path)
{
path_.init(path);
path_ = path;
}
Vertex *
PathEnd::vertex(const StaState *sta) const
{
return path_.vertex(sta);
return path_->vertex(sta);
}
const MinMax *
PathEnd::minMax(const StaState *sta) const
{
return path_.pathAnalysisPt(sta)->pathMinMax();
return path_->pathAnalysisPt(sta)->pathMinMax();
}
const EarlyLate *
PathEnd::pathEarlyLate(const StaState *sta) const
{
return path_.pathAnalysisPt(sta)->pathMinMax();
return path_->pathAnalysisPt(sta)->pathMinMax();
}
const EarlyLate *
@ -91,31 +92,31 @@ PathEnd::clkEarlyLate(const StaState *sta) const
const RiseFall *
PathEnd::transition(const StaState *sta) const
{
return path_.transition(sta);
return path_->transition(sta);
}
PathAPIndex
PathEnd::pathIndex(const StaState *sta) const
{
return path_.pathAnalysisPtIndex(sta);
return path_->pathAnalysisPtIndex(sta);
}
PathAnalysisPt *
PathEnd::pathAnalysisPt(const StaState *sta) const
{
return path_.pathAnalysisPt(sta);
return path_->pathAnalysisPt(sta);
}
const ClockEdge *
PathEnd::sourceClkEdge(const StaState *sta) const
{
return path_.clkEdge(sta);
return path_->clkEdge(sta);
}
Arrival
PathEnd::dataArrivalTime(const StaState *sta) const
PathEnd::dataArrivalTime(const StaState *) const
{
return path_.arrival(sta);
return path_->arrival();
}
Arrival
@ -133,7 +134,7 @@ PathEnd::requiredTimeOffset(const StaState *sta) const
const RiseFall *
PathEnd::targetClkEndTrans(const StaState *sta) const
{
const PathVertex *clk_path = targetClkPath();
const Path *clk_path = targetClkPath();
if (clk_path)
return clk_path->transition(sta);
else {
@ -235,13 +236,13 @@ PathEnd::checkRole(const StaState *) const
return nullptr;
}
PathVertex *
Path *
PathEnd::targetClkPath()
{
return nullptr;
}
const PathVertex *
const Path *
PathEnd::targetClkPath() const
{
return nullptr;
@ -303,7 +304,7 @@ PathEnd::exceptPathCmp(const PathEnd *path_end,
////////////////////////////////////////////////////////////////
Delay
PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path,
PathEnd::checkTgtClkDelay(const Path *tgt_clk_path,
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const StaState *sta)
@ -315,7 +316,7 @@ PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path,
}
void
PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path,
PathEnd::checkTgtClkDelay(const Path *tgt_clk_path,
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const StaState *sta,
@ -340,7 +341,7 @@ PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path,
|| check_role->isDataCheck()) {
// Propagated clock. Propagated arrival is seeded with
// early_late==path_min_max insertion delay.
Arrival clk_arrival = tgt_clk_path->arrival(sta);
Arrival clk_arrival = tgt_clk_path->arrival();
Delay path_insertion = search->clockInsertion(tgt_clk, tgt_src_pin,
tgt_clk_rf, min_max,
min_max, tgt_path_ap);
@ -359,7 +360,7 @@ PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path,
float
PathEnd::checkClkUncertainty(const ClockEdge *src_clk_edge,
const ClockEdge *tgt_clk_edge,
const PathVertex *tgt_clk_path,
const Path *tgt_clk_path,
const TimingRole *check_role,
const StaState *sta)
{
@ -375,7 +376,7 @@ PathEnd::checkClkUncertainty(const ClockEdge *src_clk_edge,
}
float
PathEnd::checkTgtClkUncertainty(const PathVertex *tgt_clk_path,
PathEnd::checkTgtClkUncertainty(const Path *tgt_clk_path,
const ClockEdge *tgt_clk_edge,
const TimingRole *check_role,
const StaState *sta)
@ -455,7 +456,7 @@ PathEndUnconstrained::PathEndUnconstrained(Path *path) :
PathEnd *
PathEndUnconstrained::copy()
{
return new PathEndUnconstrained(path_.path());
return new PathEndUnconstrained(path_);
}
bool
@ -510,7 +511,7 @@ PathEndUnconstrained::typeName() const
////////////////////////////////////////////////////////////////
PathEndClkConstrained::PathEndClkConstrained(Path *path,
PathVertex *clk_path) :
Path *clk_path) :
PathEnd(path),
clk_path_(clk_path),
crpr_(0.0),
@ -519,7 +520,7 @@ PathEndClkConstrained::PathEndClkConstrained(Path *path,
}
PathEndClkConstrained::PathEndClkConstrained(Path *path,
PathVertex *clk_path,
Path *clk_path,
Crpr crpr,
bool crpr_valid) :
PathEnd(path),
@ -530,9 +531,9 @@ PathEndClkConstrained::PathEndClkConstrained(Path *path,
}
void
PathEndClkConstrained::setPath(const Path *path)
PathEndClkConstrained::setPath(Path *path)
{
path_.init(path);
path_ = path;
crpr_valid_ = false;
}
@ -559,33 +560,27 @@ PathEndClkConstrained::sourceClkOffset(const ClockEdge *src_clk_edge,
Arrival
PathEndClkConstrained::sourceClkLatency(const StaState *sta) const
{
ClkInfo *clk_info = path_.clkInfo(sta);
ClkInfo *clk_info = path_->clkInfo(sta);
return clk_info->latency();
}
Arrival
PathEndClkConstrained::sourceClkInsertionDelay(const StaState *sta) const
{
ClkInfo *clk_info = path_.clkInfo(sta);
ClkInfo *clk_info = path_->clkInfo(sta);
return clk_info->insertion();
}
PathVertex *
Path *
PathEndClkConstrained::targetClkPath()
{
if (clk_path_.isNull())
return nullptr;
else
return &clk_path_;
return clk_path_;
}
const PathVertex *
const Path *
PathEndClkConstrained::targetClkPath() const
{
if (clk_path_.isNull())
return nullptr;
else
return &clk_path_;
return clk_path_;
}
float
@ -602,8 +597,8 @@ PathEndClkConstrained::targetClkOffset(const StaState *sta) const
const ClockEdge *
PathEndClkConstrained::targetClkEdge(const StaState *sta) const
{
if (!clk_path_.isNull())
return clk_path_.clkEdge(sta);
if (clk_path_)
return clk_path_->clkEdge(sta);
else
return nullptr;
}
@ -708,7 +703,7 @@ PathEndClkConstrained::crpr(const StaState *sta) const
{
if (!crpr_valid_) {
CheckCrpr *check_crpr = sta->search()->checkCrpr();
crpr_ = check_crpr->checkCrpr(path_.path(), targetClkPath());
crpr_ = check_crpr->checkCrpr(path_, targetClkPath());
crpr_valid_ = true;
}
return crpr_;
@ -751,7 +746,7 @@ PathEndClkConstrained::exceptPathCmp(const PathEnd *path_end,
if (cmp == 0) {
const PathEndClkConstrained *path_end2 =
dynamic_cast<const PathEndClkConstrained*>(path_end);
const PathVertex *clk_path2 = path_end2->targetClkPath();
const Path *clk_path2 = path_end2->targetClkPath();
return Path::cmp(targetClkPath(), clk_path2, sta);
}
else
@ -761,7 +756,7 @@ PathEndClkConstrained::exceptPathCmp(const PathEnd *path_end,
////////////////////////////////////////////////////////////////
PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp) :
PathEndClkConstrained(path, clk_path),
mcp_(mcp)
@ -769,7 +764,7 @@ PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path,
}
PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp,
Crpr crpr,
bool crpr_valid) :
@ -781,7 +776,7 @@ PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path,
float
PathEndClkConstrainedMcp::targetClkMcpAdjustment(const StaState *sta) const
{
return checkMcpAdjustment(path_.path(), targetClkEdge(sta), sta);
return checkMcpAdjustment(path_, targetClkEdge(sta), sta);
}
float
@ -887,8 +882,8 @@ PathEndClkConstrainedMcp::findHoldMcps(const ClockEdge *tgt_clk_edge,
const StaState *sta) const
{
Pin *pin = path_.pin(sta);
const RiseFall *rf = path_.transition(sta);
Pin *pin = path_->pin(sta);
const RiseFall *rf = path_->transition(sta);
// Mcp may be setup, hold or setup_hold, since all match min paths.
const MinMaxAll *mcp_min_max = mcp_->minMax();
Search *search = sta->search();
@ -896,7 +891,7 @@ PathEndClkConstrainedMcp::findHoldMcps(const ClockEdge *tgt_clk_edge,
hold_mcp = mcp_;
setup_mcp =
dynamic_cast<MultiCyclePath*>(search->exceptionTo(ExceptionPathType::multi_cycle,
path_.path(), pin, rf,
path_, pin, rf,
tgt_clk_edge,
MinMax::max(), true,
false));
@ -905,7 +900,7 @@ PathEndClkConstrainedMcp::findHoldMcps(const ClockEdge *tgt_clk_edge,
setup_mcp = mcp_;
hold_mcp =
dynamic_cast<MultiCyclePath*>(search->exceptionTo(ExceptionPathType::multi_cycle,
path_.path(), pin, rf,
path_, pin, rf,
tgt_clk_edge,
MinMax::min(), true,
false));
@ -937,7 +932,7 @@ PathEndClkConstrainedMcp::exceptPathCmp(const PathEnd *path_end,
PathEndCheck::PathEndCheck(Path *path,
TimingArc *check_arc,
Edge *check_edge,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp,
const StaState *) :
PathEndClkConstrainedMcp(path, clk_path, mcp),
@ -949,7 +944,7 @@ PathEndCheck::PathEndCheck(Path *path,
PathEndCheck::PathEndCheck(Path *path,
TimingArc *check_arc,
Edge *check_edge,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp,
Crpr crpr,
bool crpr_valid) :
@ -962,8 +957,8 @@ PathEndCheck::PathEndCheck(Path *path,
PathEnd *
PathEndCheck::copy()
{
return new PathEndCheck(path_.path(), check_arc_, check_edge_,
&clk_path_, mcp_, crpr_, crpr_valid_);
return new PathEndCheck(path_, check_arc_, check_edge_,
clk_path_, mcp_, crpr_, crpr_valid_);
}
PathEnd::Type
@ -999,7 +994,7 @@ PathEndCheck::checkRole(const StaState *) const
ArcDelay
PathEndCheck::margin(const StaState *sta) const
{
return sta->search()->deratedDelay(clk_path_.vertex(sta),
return sta->search()->deratedDelay(clk_path_->vertex(sta),
check_arc_, check_edge_, false,
pathAnalysisPt(sta));
}
@ -1028,20 +1023,20 @@ PathEndCheck::clkSkew(const StaState *sta)
{
return sourceClkDelay(sta) - targetClkDelay(sta) - crpr(sta)
// Uncertainty decreases slack, but increases skew.
- checkTgtClkUncertainty(&clk_path_, clk_path_.clkEdge(sta), checkRole(sta), sta);
- checkTgtClkUncertainty(clk_path_, clk_path_->clkEdge(sta),
checkRole(sta), sta);
}
Delay
PathEndCheck::sourceClkDelay(const StaState *sta) const
{
PathExpanded expanded(&path_, sta);
PathRef src_clk_path;
expanded.clkPath(src_clk_path);
if (!src_clk_path.isNull()) {
ClkInfo *src_clk_info = path_.tag(sta)->clkInfo();
PathExpanded expanded(path_, sta);
const Path *src_clk_path = expanded.clkPath();
if (src_clk_path) {
ClkInfo *src_clk_info = path_->tag(sta)->clkInfo();
if (src_clk_info->isPropagated()) {
// Propagated clock. Propagated arrival is seeded with insertion delay.
Arrival clk_arrival = src_clk_path.arrival(sta);
Arrival clk_arrival = src_clk_path->arrival();
const ClockEdge *src_clk_edge = src_clk_info->clkEdge();
Delay insertion = sourceClkInsertionDelay(sta);
return delayRemove(clk_arrival - src_clk_edge->time(), insertion);
@ -1072,16 +1067,16 @@ PathEndCheck::macroClkTreeDelay(const StaState *sta) const
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
const Clock *tgt_clk = tgt_clk_edge->clock();
const Network *network = sta->network();
const Pin *clk_pin = clk_path_.pin(sta);
const Pin *clk_pin = clk_path_->pin(sta);
const Instance *inst = network->instance(clk_pin);
const LibertyCell *inst_cell = network->libertyCell(inst);
if (tgt_clk->isIdeal()
&& inst_cell && inst_cell->isMacro()) {
LibertyPort *clk_port = network->libertyPort(clk_pin);
if (clk_port) {
const MinMax *min_max = clk_path_.minMax(sta);
const RiseFall *rf = clk_path_.transition(sta);
float slew = delayAsFloat(clk_path_.slew(sta));
const MinMax *min_max = clk_path_->minMax(sta);
const RiseFall *rf = clk_path_->transition(sta);
float slew = delayAsFloat(clk_path_->slew(sta));
return clk_port->clkTreeDelay(slew, rf, min_max);
}
}
@ -1093,7 +1088,7 @@ PathEndCheck::macroClkTreeDelay(const StaState *sta) const
PathEndLatchCheck::PathEndLatchCheck(Path *path,
TimingArc *check_arc,
Edge *check_edge,
PathVertex *disable_path,
Path *disable_path,
MultiCyclePath *mcp,
PathDelay *path_delay,
const StaState *sta) :
@ -1102,23 +1097,22 @@ PathEndLatchCheck::PathEndLatchCheck(Path *path,
path_delay_(path_delay),
src_clk_arrival_(0.0)
{
PathVertex enable_path;
Latches *latches = sta->latches();
latches->latchEnableOtherPath(disable_path,
disable_path->pathAnalysisPt(sta),
enable_path);
Path *enable_path =
latches->latchEnableOtherPath(disable_path,
disable_path->pathAnalysisPt(sta));
clk_path_ = enable_path;
Search *search = sta->search();
// Same as PathEndPathDelay::findRequired.
if (path_delay_ && ignoreClkLatency(sta))
src_clk_arrival_ = search->pathClkPathArrival(&path_);
src_clk_arrival_ = search->pathClkPathArrival(path_);
}
PathEndLatchCheck::PathEndLatchCheck(Path *path,
TimingArc *check_arc,
Edge *check_edge,
PathVertex *clk_path,
PathVertex *disable_path,
Path *clk_path,
Path *disable_path,
MultiCyclePath *mcp,
PathDelay *path_delay,
Delay src_clk_arrival,
@ -1134,8 +1128,8 @@ PathEndLatchCheck::PathEndLatchCheck(Path *path,
PathEnd *
PathEndLatchCheck::copy()
{
return new PathEndLatchCheck(path_.path(), check_arc_, check_edge_,
&clk_path_, &disable_path_, mcp_, path_delay_,
return new PathEndLatchCheck(path_, check_arc_, check_edge_,
clk_path_, disable_path_, mcp_, path_delay_,
src_clk_arrival_, crpr_, crpr_valid_);
}
@ -1151,22 +1145,16 @@ PathEndLatchCheck::typeName() const
return "latch_check";
}
PathVertex *
Path *
PathEndLatchCheck::latchDisable()
{
if (disable_path_.isNull())
return nullptr;
else
return &disable_path_;
return disable_path_;
}
const PathVertex *
const Path *
PathEndLatchCheck::latchDisable() const
{
if (disable_path_.isNull())
return nullptr;
else
return &disable_path_;
return disable_path_;
}
void
@ -1188,7 +1176,7 @@ PathEndLatchCheck::sourceClkOffset(const StaState *sta) const
return pathDelaySrcClkOffset(path_, path_delay_, src_clk_arrival_, sta);
else
return PathEndClkConstrained::sourceClkOffset(sourceClkEdge(sta),
disable_path_.clkEdge(sta),
disable_path_->clkEdge(sta),
TimingRole::setup(),
sta);
}
@ -1196,7 +1184,7 @@ PathEndLatchCheck::sourceClkOffset(const StaState *sta) const
TimingRole *
PathEndLatchCheck::checkRole(const StaState *sta) const
{
if (clk_path_.clkInfo(sta)->isPulseClk())
if (clk_path_->clkInfo(sta)->isPulseClk())
// Pulse latches use register cycle accounting.
return TimingRole::setup();
else
@ -1211,7 +1199,7 @@ PathEndLatchCheck::requiredTime(const StaState *sta) const
Required required;
Arrival borrow, adjusted_data_arrival, time_given_to_startpoint;
Latches *latches = sta->latches();
latches->latchRequired(path_.path(), targetClkPath(), latchDisable(),
latches->latchRequired(path_, targetClkPath(), latchDisable(),
mcp_, path_delay_, src_clk_arrival_, margin(sta),
required, borrow, adjusted_data_arrival,
time_given_to_startpoint);
@ -1224,7 +1212,7 @@ PathEndLatchCheck::borrow(const StaState *sta) const
Latches *latches = sta->latches();
Required required;
Arrival borrow, adjusted_data_arrival, time_given_to_startpoint;
latches->latchRequired(path_.path(), targetClkPath(), latchDisable(),
latches->latchRequired(path_, targetClkPath(), latchDisable(),
mcp_, path_delay_, src_clk_arrival_, margin(sta),
required, borrow, adjusted_data_arrival,
time_given_to_startpoint);
@ -1240,7 +1228,7 @@ PathEndLatchCheck::latchRequired(const StaState *sta,
Delay &time_given_to_startpoint) const
{
Latches *latches = sta->latches();
latches->latchRequired(path_.path(), targetClkPath(), latchDisable(),
latches->latchRequired(path_, targetClkPath(), latchDisable(),
mcp_, path_delay_, src_clk_arrival_, margin(sta),
required, borrow, adjusted_data_arrival,
time_given_to_startpoint);
@ -1259,7 +1247,7 @@ PathEndLatchCheck::latchBorrowInfo(const StaState *sta,
bool &borrow_limit_exists) const
{
Latches *latches = sta->latches();
latches->latchBorrowInfo(path_.path(), targetClkPath(), latchDisable(),
latches->latchBorrowInfo(path_, targetClkPath(), latchDisable(),
margin(sta),
path_delay_ && ignoreClkLatency(sta),
nom_pulse_width, open_latency,
@ -1272,9 +1260,9 @@ Arrival
PathEndLatchCheck::targetClkWidth(const StaState *sta) const
{
const Search *search = sta->search();
Arrival disable_arrival = search->clkPathArrival(&disable_path_);
Arrival enable_arrival = search->clkPathArrival(&clk_path_);
ClkInfo *enable_clk_info = clk_path_.clkInfo(sta);
Arrival disable_arrival = search->clkPathArrival(disable_path_);
Arrival enable_arrival = search->clkPathArrival(clk_path_);
ClkInfo *enable_clk_info = clk_path_->clkInfo(sta);
if (enable_clk_info->isPulseClk())
return disable_arrival - enable_arrival;
else {
@ -1297,8 +1285,8 @@ PathEndLatchCheck::exceptPathCmp(const PathEnd *path_end,
dynamic_cast<const PathEndLatchCheck*>(path_end);
const TimingArc *check_arc2 = path_end2->check_arc_;
if (check_arc_ == check_arc2) {
const Path *disable_path2 = path_end2->disable_path_.path();
return Path::cmp(disable_path_.path(), disable_path2, sta);
const Path *disable_path2 = path_end2->disable_path_;
return Path::cmp(disable_path_, disable_path2, sta);
}
else if (check_arc_ < check_arc2)
return -1;
@ -1319,7 +1307,7 @@ PathEndLatchCheck::ignoreClkLatency(const StaState *sta) const
PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
Path *path,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp,
const StaState *) :
// No target clk_path_ for output delays.
@ -1330,7 +1318,7 @@ PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
Path *path,
PathVertex *clk_path,
Path *clk_path,
MultiCyclePath *mcp,
Crpr crpr,
bool crpr_valid) :
@ -1342,7 +1330,7 @@ PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
PathEnd *
PathEndOutputDelay::copy()
{
return new PathEndOutputDelay(output_delay_, path_.path(), &clk_path_,
return new PathEndOutputDelay(output_delay_, path_, clk_path_,
mcp_, crpr_, crpr_valid_);
}
@ -1373,7 +1361,7 @@ PathEndOutputDelay::reportShort(const ReportPath *report) const
ArcDelay
PathEndOutputDelay::margin(const StaState *sta) const
{
return outputDelayMargin(output_delay_, path_.path(), sta);
return outputDelayMargin(output_delay_, path_, sta);
}
float
@ -1393,7 +1381,7 @@ PathEnd::outputDelayMargin(OutputDelay *output_delay,
TimingRole *
PathEndOutputDelay::checkRole(const StaState *sta) const
{
if (path_.minMax(sta) == MinMax::max())
if (path_->minMax(sta) == MinMax::max())
return TimingRole::outputSetup();
else
return TimingRole::outputHold();
@ -1402,8 +1390,8 @@ PathEndOutputDelay::checkRole(const StaState *sta) const
const ClockEdge *
PathEndOutputDelay::targetClkEdge(const StaState *sta) const
{
if (!clk_path_.isNull())
return clk_path_.clkEdge(sta);
if (clk_path_)
return clk_path_->clkEdge(sta);
else
return output_delay_->clkEdge();
}
@ -1411,7 +1399,7 @@ PathEndOutputDelay::targetClkEdge(const StaState *sta) const
Arrival
PathEndOutputDelay::targetClkArrivalNoCrpr(const StaState *sta) const
{
if (!clk_path_.isNull())
if (clk_path_)
return PathEndClkConstrained::targetClkArrivalNoCrpr(sta);
else {
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
@ -1419,7 +1407,7 @@ PathEndOutputDelay::targetClkArrivalNoCrpr(const StaState *sta) const
return targetClkTime(sta)
+ tgtClkDelay(tgt_clk_edge, check_role, sta)
+ targetClkUncertainty(sta)
+ checkMcpAdjustment(path_.path(), tgt_clk_edge, sta);
+ checkMcpAdjustment(path_, tgt_clk_edge, sta);
}
}
@ -1428,7 +1416,7 @@ PathEndOutputDelay::crpr(const StaState *sta) const
{
if (!crpr_valid_) {
CheckCrpr *check_crpr = sta->search()->checkCrpr();
crpr_ = check_crpr->outputDelayCrpr(path_.path(), targetClkEdge(sta));
crpr_ = check_crpr->outputDelayCrpr(path_, targetClkEdge(sta));
crpr_valid_ = true;
}
return crpr_;
@ -1437,7 +1425,7 @@ PathEndOutputDelay::crpr(const StaState *sta) const
Delay
PathEndOutputDelay::targetClkDelay(const StaState *sta) const
{
if (!clk_path_.isNull())
if (clk_path_)
return PathEndClkConstrained::targetClkDelay(sta);
else
return tgtClkDelay(targetClkEdge(sta), checkRole(sta), sta);
@ -1465,7 +1453,7 @@ PathEndOutputDelay::tgtClkDelay(const ClockEdge *tgt_clk_edge,
// Early late: setup early, hold late.
const EarlyLate *early_late = check_role->tgtClkEarlyLate();
// Latency min_max depends on bc_wc or ocv.
const PathAnalysisPt *path_ap = path_.pathAnalysisPt(sta);
const PathAnalysisPt *path_ap = path_->pathAnalysisPt(sta);
const MinMax *latency_min_max = path_ap->tgtClkAnalysisPt()->pathMinMax();
Clock *tgt_clk = tgt_clk_edge->clock();
RiseFall *tgt_clk_rf = tgt_clk_edge->transition();
@ -1488,7 +1476,7 @@ PathEndOutputDelay::tgtClkDelay(const ClockEdge *tgt_clk_edge,
Delay
PathEndOutputDelay::targetClkInsertionDelay(const StaState *sta) const
{
if (!clk_path_.isNull())
if (clk_path_)
return PathEndClkConstrained::targetClkInsertionDelay(sta);
else {
Arrival insertion, latency;
@ -1521,7 +1509,7 @@ PathEndOutputDelay::exceptPathCmp(const PathEnd *path_end,
////////////////////////////////////////////////////////////////
PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
PathVertex *clk_path,
Path *clk_path,
TimingRole *check_role,
MultiCyclePath *mcp,
ArcDelay margin,
@ -1533,7 +1521,7 @@ PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
}
PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
PathVertex *clk_path,
Path *clk_path,
TimingRole *check_role,
MultiCyclePath *mcp,
ArcDelay margin,
@ -1548,7 +1536,7 @@ PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
PathEnd *
PathEndGatedClock::copy()
{
return new PathEndGatedClock(path_.path(), &clk_path_, check_role_,
return new PathEndGatedClock(path_, clk_path_, check_role_,
mcp_, margin_, crpr_, crpr_valid_);
}
@ -1606,59 +1594,52 @@ PathEndGatedClock::exceptPathCmp(const PathEnd *path_end,
PathEndDataCheck::PathEndDataCheck(DataCheck *check,
Path *data_path,
PathVertex *data_clk_path,
Path *data_clk_path,
MultiCyclePath *mcp,
const StaState *sta) :
PathEndClkConstrainedMcp(data_path, nullptr, mcp),
data_clk_path_(data_clk_path),
check_(check)
{
clkPath(data_clk_path, sta, clk_path_);
clk_path_ = clkPath(data_clk_path, sta);
}
// PathExpanded::expand() and PathExpanded::clkPath().
void
PathEndDataCheck::clkPath(PathVertex *path,
const StaState *sta,
// Return value.
PathVertex &clk_path)
Path *
PathEndDataCheck::clkPath(Path *path,
const StaState *sta)
{
PathVertex p(path);
while (!p.isNull()) {
PathVertex prev_path;
TimingArc *prev_arc;
p.prevPath(sta, prev_path, prev_arc);
Path *p = path;
while (p) {
Path *prev_path = p->prevPath();
TimingArc *prev_arc = p->prevArc(sta);
if (p.isClock(sta)) {
clk_path = p;
return;
}
if (p->isClock(sta))
return p;
if (prev_arc) {
TimingRole *prev_role = prev_arc->role();
if (prev_role == TimingRole::regClkToQ()
|| prev_role == TimingRole::latchEnToQ()) {
p.prevPath(sta, prev_path, prev_arc);
clk_path = prev_path;
return;
prev_path = p->prevPath();
return prev_path;
}
else if (prev_role == TimingRole::latchDtoQ()) {
const Latches *latches = sta->latches();
Edge *prev_edge = p.prevEdge(prev_arc, sta);
PathVertex enable_path;
latches->latchEnablePath(&p, prev_edge, enable_path);
clk_path = enable_path;
return;
Edge *prev_edge = p->prevEdge(sta);
Path *enable_path = latches->latchEnablePath(p, prev_edge);
return enable_path;
}
}
p = prev_path;
}
return nullptr;
}
PathEndDataCheck::PathEndDataCheck(DataCheck *check,
Path *data_path,
PathVertex *data_clk_path,
PathVertex *clk_path,
Path *data_clk_path,
Path *clk_path,
MultiCyclePath *mcp,
Crpr crpr,
bool crpr_valid) :
@ -1671,8 +1652,8 @@ PathEndDataCheck::PathEndDataCheck(DataCheck *check,
PathEnd *
PathEndDataCheck::copy()
{
return new PathEndDataCheck(check_, path_.path(), &data_clk_path_,
&clk_path_, mcp_, crpr_, crpr_valid_);
return new PathEndDataCheck(check_, path_, data_clk_path_,
clk_path_, mcp_, crpr_, crpr_valid_);
}
PathEnd::Type
@ -1691,14 +1672,14 @@ const ClockEdge *
PathEndDataCheck::targetClkEdge(const StaState *sta) const
{
// clk_path_ can be null if data_clk_path is from an input port.
return data_clk_path_.clkEdge(sta);
return data_clk_path_->clkEdge(sta);
}
Arrival
PathEndDataCheck::requiredTimeNoCrpr(const StaState *sta) const
{
Arrival data_clk_arrival = data_clk_path_.arrival(sta);
float data_clk_time = data_clk_path_.clkEdge(sta)->time();
Arrival data_clk_arrival = data_clk_path_->arrival();
float data_clk_time = data_clk_path_->clkEdge(sta)->time();
Arrival data_clk_delay = data_clk_arrival - data_clk_time;
Arrival tgt_clk_arrival = targetClkTime(sta)
+ data_clk_delay
@ -1717,9 +1698,9 @@ PathEndDataCheck::margin(const StaState *sta) const
{
float margin;
bool margin_exists;
check_->margin(data_clk_path_.transition(sta),
path_.transition(sta),
path_.minMax(sta),
check_->margin(data_clk_path_->transition(sta),
path_->transition(sta),
path_->minMax(sta),
margin, margin_exists);
return margin;
}
@ -1727,7 +1708,7 @@ PathEndDataCheck::margin(const StaState *sta) const
TimingRole *
PathEndDataCheck::checkRole(const StaState *sta) const
{
if (path_.minMax(sta) == MinMax::max())
if (path_->minMax(sta) == MinMax::max())
return TimingRole::dataCheckSetup();
else
return TimingRole::dataCheckHold();
@ -1794,7 +1775,7 @@ PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
Path *path,
PathVertex *clk_path,
Path *clk_path,
TimingArc *check_arc,
Edge *check_edge,
const StaState *sta) :
@ -1809,7 +1790,7 @@ PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
Path *path,
PathVertex *clk_path,
Path *clk_path,
TimingArc *check_arc,
Edge *check_edge,
OutputDelay *output_delay,
@ -1828,7 +1809,7 @@ PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
PathEnd *
PathEndPathDelay::copy()
{
return new PathEndPathDelay(path_delay_, path_.path(), &clk_path_,
return new PathEndPathDelay(path_delay_, path_, clk_path_,
check_arc_, check_edge_, output_delay_,
src_clk_arrival_, crpr_, crpr_valid_);
}
@ -1850,7 +1831,7 @@ PathEndPathDelay::findSrcClkArrival(const StaState *sta)
{
if (ignoreClkLatency(sta)) {
Search *search = sta->search();
src_clk_arrival_ = search->pathClkPathArrival(&path_);
src_clk_arrival_ = search->pathClkPathArrival(path_);
}
else
src_clk_arrival_ = 0.0;
@ -1895,7 +1876,7 @@ PathEndPathDelay::margin(const StaState *sta) const
pathAnalysisPt(sta));
}
else if (output_delay_)
return outputDelayMargin(output_delay_, path_.path(), sta);
return outputDelayMargin(output_delay_, path_, sta);
else
return delay_zero;
}
@ -1914,13 +1895,13 @@ PathEnd::clkSkew(const StaState *)
// Helper shared by PathEndLatchCheck.
float
PathEnd::pathDelaySrcClkOffset(const PathRef &path,
PathEnd::pathDelaySrcClkOffset(const Path *path,
PathDelay *path_delay,
Arrival src_clk_arrival,
const StaState *sta)
{
float offset = 0.0;
const ClockEdge *clk_edge = path.clkEdge(sta);
const ClockEdge *clk_edge = path->clkEdge(sta);
if (clk_edge) {
if (ignoreClkLatency(path, path_delay, sta))
offset = -delayAsFloat(src_clk_arrival);
@ -1933,18 +1914,18 @@ PathEnd::pathDelaySrcClkOffset(const PathRef &path,
}
bool
PathEnd::ignoreClkLatency(const PathRef &path,
PathEnd::ignoreClkLatency(const Path *path,
PathDelay *path_delay,
const StaState *sta)
{
return path_delay->ignoreClkLatency() && !path.isClock(sta);
return path_delay->ignoreClkLatency() && !path->isClock(sta);
}
const ClockEdge *
PathEndPathDelay::targetClkEdge(const StaState *sta) const
{
if (!clk_path_.isNull())
return clk_path_.clkEdge(sta);
if (clk_path_)
return clk_path_->clkEdge(sta);
else if (output_delay_)
return output_delay_->clkEdge();
else
@ -1968,8 +1949,8 @@ PathEndPathDelay::targetClkArrivalNoCrpr(const StaState *sta) const
if (tgt_clk_edge)
return targetClkDelay(sta)
+ targetClkUncertainty(sta);
else if (!clk_path_.isNull())
return clk_path_.arrival(sta);
else if (clk_path_)
return clk_path_->arrival();
else
return 0.0;
}
@ -1985,8 +1966,8 @@ PathEndPathDelay::requiredTime(const StaState *sta) const
{
float delay = path_delay_->delay();
if (path_delay_->ignoreClkLatency()) {
Required src_offset = path_.isClock(sta)
? path_.clkEdge(sta)->time()
Required src_offset = path_->isClock(sta)
? path_->clkEdge(sta)->time()
: src_clk_arrival_;
return src_offset + delay
+ ((minMax(sta) == MinMax::max()) ? -margin(sta) : margin(sta));

View File

@ -36,8 +36,7 @@
#include "Tag.hh"
#include "Search.hh"
#include "PathEnd.hh"
#include "PathRef.hh"
#include "PathEnumed.hh"
#include "Path.hh"
namespace sta {
@ -104,8 +103,8 @@ deleteDiversionPathEnd(Diversion *div)
////////////////////////////////////////////////////////////////
PathEnum::PathEnum(int group_path_count,
int endpoint_path_count,
PathEnum::PathEnum(size_t group_path_count,
size_t endpoint_path_count,
bool unique_pins,
bool cmp_slack,
const StaState *sta) :
@ -214,17 +213,16 @@ PathEnum::reportDiversionPath(Diversion *div)
{
PathEnd *path_end = div->pathEnd();
Path *path = path_end->path();
PathRef p;
path->prevPath(this, p);
Path *p = path->prevPath();
Path *after_div = div->divPath();
while (!p.isNull()) {
while (p) {
report_->reportLine("path_enum: %s %s%s",
p.name(this),
delayAsString(p.arrival(this), this),
Path::equal(&p, after_div, this) ? " <-diversion" : "");
if (network_->isLatchData(p.pin(this)))
p->name(this),
delayAsString(p->arrival(), this),
Path::equal(p, after_div, this) ? " <-diversion" : "");
if (network_->isLatchData(p->pin(this)))
break;
p.prevPath(this, p);
p = p->prevPath();
}
}
@ -234,19 +232,19 @@ class PathEnumFaninVisitor : public PathVisitor
{
public:
PathEnumFaninVisitor(PathEnd *path_end,
PathRef &before_div,
Path *before_div,
bool unique_pins,
PathEnum *path_enum);
virtual VertexVisitor *copy() const;
virtual void visit(Vertex *) {} // Not used.
void visitFaninPathsThru(Vertex *vertex,
void visitFaninPathsThru(Path *before_div,
Vertex *prev_vertex,
TimingArc *prev_arc);
virtual bool visitFromToPath(const Pin *from_pin,
Vertex *from_vertex,
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
Path *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
@ -260,16 +258,18 @@ public:
private:
void makeDivertedPathEnd(Path *after_div,
Edge *div_edge,
TimingArc *div_arc,
// Return values.
PathEnd *&div_end,
PathEnumed *&after_div_copy);
void reportDiversion(TimingArc *div_arc,
Path *&after_div_copy);
void reportDiversion(const Edge *edge,
const TimingArc *div_arc,
Path *after_div);
PathEnd *path_end_;
Slack path_end_slack_;
PathRef &before_div_;
Path *before_div_;
bool unique_pins_;
int before_div_rf_index_;
Tag *before_div_tag_;
@ -282,7 +282,7 @@ private:
};
PathEnumFaninVisitor::PathEnumFaninVisitor(PathEnd *path_end,
PathRef &before_div,
Path *before_div,
bool unique_pins,
PathEnum *path_enum) :
PathVisitor(path_enum),
@ -290,27 +290,28 @@ PathEnumFaninVisitor::PathEnumFaninVisitor(PathEnd *path_end,
path_end_slack_(path_end->slack(this)),
before_div_(before_div),
unique_pins_(unique_pins),
before_div_rf_index_(before_div_.rfIndex(this)),
before_div_tag_(before_div_.tag(this)),
before_div_ap_index_(before_div_.pathAnalysisPtIndex(this)),
before_div_arrival_(before_div_.arrival(this)),
before_div_rf_index_(before_div_->rfIndex(this)),
before_div_tag_(before_div_->tag(this)),
before_div_ap_index_(before_div_->pathAnalysisPtIndex(this)),
before_div_arrival_(before_div_->arrival()),
path_enum_(path_enum),
crpr_active_(sdc_->crprActive())
{
}
void
PathEnumFaninVisitor::visitFaninPathsThru(Vertex *vertex,
PathEnumFaninVisitor::visitFaninPathsThru(Path *before_div,
Vertex *prev_vertex,
TimingArc *prev_arc)
{
before_div_rf_index_ = before_div_.rfIndex(this);
before_div_tag_ = before_div_.tag(this);
before_div_ap_index_ = before_div_.pathAnalysisPtIndex(this);
before_div_arrival_ = before_div_.arrival(this);
before_div_ = before_div;
before_div_rf_index_ = before_div_->rfIndex(this);
before_div_tag_ = before_div_->tag(this);
before_div_ap_index_ = before_div_->pathAnalysisPtIndex(this);
before_div_arrival_ = before_div_->arrival();
prev_arc_ = prev_arc;
prev_vertex_ = prev_vertex;
visitFaninPaths(vertex);
visitFaninPaths(before_div_->vertex(this));
}
VertexVisitor *
@ -325,7 +326,7 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *,
Vertex *from_vertex,
const RiseFall *,
Tag *,
PathVertex *from_path,
Path *from_path,
const Arrival &,
Edge *edge,
TimingArc *arc,
@ -351,13 +352,13 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *,
&& tagMatchNoCrpr(to_tag, before_div_tag_)) {
if (crpr_active_) {
PathEnd *div_end;
PathEnumed *after_div_copy;
Path *after_div_copy;
// Make the diverted path end to check slack with from_path crpr.
makeDivertedPathEnd(from_path, arc, div_end, after_div_copy);
makeDivertedPathEnd(from_path, edge, arc, div_end, after_div_copy);
if (div_end) {
// Only enumerate paths with greater slack.
if (delayGreaterEqual(div_end->slack(this), path_end_slack_, this)) {
reportDiversion(arc, from_path);
reportDiversion(edge, arc, from_path);
path_enum_->makeDiversion(div_end, after_div_copy);
}
else
@ -367,9 +368,9 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *,
// Only enumerate slower/faster paths.
else if (delayLessEqual(to_arrival, before_div_arrival_, min_max, this)) {
PathEnd *div_end;
PathEnumed *after_div_copy;
makeDivertedPathEnd(from_path, arc, div_end, after_div_copy);
reportDiversion(arc, from_path);
Path *after_div_copy;
makeDivertedPathEnd(from_path, edge, arc, div_end, after_div_copy);
reportDiversion(edge, arc, from_path);
path_enum_->makeDiversion(div_end, after_div_copy);
}
}
@ -378,14 +379,15 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *,
void
PathEnumFaninVisitor::makeDivertedPathEnd(Path *after_div,
Edge *div_edge,
TimingArc *div_arc,
// Return values.
PathEnd *&div_end,
PathEnumed *&after_div_copy)
Path *&after_div_copy)
{
PathEnumed *div_path;
path_enum_->makeDivertedPath(path_end_->path(), &before_div_, after_div,
div_arc, div_path, after_div_copy);
Path *div_path;
path_enum_->makeDivertedPath(path_end_->path(), before_div_, after_div,
div_edge, div_arc, div_path, after_div_copy);
if (after_div_copy) {
div_end = path_end_->copy();
div_end->setPath(div_path);
@ -395,7 +397,8 @@ PathEnumFaninVisitor::makeDivertedPathEnd(Path *after_div,
}
void
PathEnumFaninVisitor::reportDiversion(TimingArc *div_arc,
PathEnumFaninVisitor::reportDiversion(const Edge *div_edge,
const TimingArc *div_arc,
Path *after_div)
{
if (debug_->check("path_enum", 3)) {
@ -404,19 +407,18 @@ PathEnumFaninVisitor::reportDiversion(TimingArc *div_arc,
Arrival path_delay = path_enum_->cmp_slack_
? path_end_->slack(this)
: path_end_->dataArrivalTime(this);
Arrival div_delay = path_delay - path_enum_->divSlack(&before_div_,
after_div,
div_arc, path_ap);
PathRef div_prev;
before_div_.prevPath(this, div_prev);
Arrival div_delay = path_delay - path_enum_->divSlack(before_div_,
after_div, div_edge,
div_arc, path_ap);
Path *div_prev = before_div_->prevPath();
report_->reportLine("path_enum: diversion %s %s %s -> %s",
path->name(this),
path_enum_->cmp_slack_ ? "slack" : "delay",
delayAsString(path_delay, this),
delayAsString(div_delay, this));
report_->reportLine("path_enum: from %s -> %s",
div_prev.name(this),
before_div_.name(this));
div_prev->name(this),
before_div_->name(this));
report_->reportLine("path_enum: to %s",
after_div->name(this));
}
@ -431,13 +433,13 @@ PathEnumFaninVisitor::reportDiversion(TimingArc *div_arc,
// <--...--before_div<--...--path<---path_end
void
PathEnum::makeDiversion(PathEnd *div_end,
PathEnumed *after_div_copy)
Path *after_div_copy)
{
Diversion *div = new Diversion(div_end, after_div_copy);
div_queue_.push(div);
div_count_++;
if (static_cast<int>(div_queue_.size()) > group_path_count_ * 2)
if (div_queue_.size() > group_path_count_ * 2)
// We have more potenial paths than we will need.
pruneDiversionQueue();
}
@ -447,7 +449,7 @@ PathEnum::pruneDiversionQueue()
{
debugPrint(debug_, "path_enum", 2, "prune queue");
VertexPathCountMap path_counts;
int end_count = 0;
size_t end_count = 0;
// Collect endpoint_path_count diversions per vertex.
DiversionSeq divs;
while (!div_queue_.empty()) {
@ -476,11 +478,11 @@ PathEnum::pruneDiversionQueue()
Arrival
PathEnum::divSlack(Path *before_div,
Path *after_div,
TimingArc *div_arc,
const Edge *div_edge,
const TimingArc *div_arc,
const PathAnalysisPt *path_ap)
{
Arrival arc_arrival = before_div->arrival(this);
Edge *div_edge = divEdge(before_div, div_arc);
Arrival arc_arrival = before_div->arrival();
if (div_edge) {
ArcDelay div_delay = search_->deratedDelay(div_edge->from(graph_),
div_arc, div_edge,
@ -494,45 +496,30 @@ PathEnum::divSlack(Path *before_div,
}
}
Edge *
PathEnum::divEdge(Path *before_div,
TimingArc *div_arc)
{
TimingArcSet *arc_set = div_arc->set();
VertexInEdgeIterator edge_iter(before_div->vertex(this), graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
if (edge->timingArcSet() == arc_set)
return edge;
}
return nullptr;
}
// Make diversions for all arcs that merge into path for paths
// starting at "before" to the beginning of the path.
void
PathEnum::makeDiversions(PathEnd *path_end,
Path *before)
{
PathRef path(before);
PathRef prev_path;
TimingArc *prev_arc;
path.prevPath(this, prev_path, prev_arc);
Path *path = before;
Path *prev_path = path->prevPath();
TimingArc *prev_arc = path->prevArc(this);
PathEnumFaninVisitor fanin_visitor(path_end, path, unique_pins_, this);
while (prev_arc
while (prev_path
// Do not enumerate paths in the clk network.
&& !path.isClock(this)) {
&& !path->isClock(this)) {
// Fanin visitor does all the work.
// While visiting the fanins the fanin_visitor finds the
// previous path and arc as well as diversions.
fanin_visitor.visitFaninPathsThru(path.vertex(this),
prev_path.vertex(this), prev_arc);
fanin_visitor.visitFaninPathsThru(path, prev_path->vertex(this), prev_arc);
// Do not enumerate beyond latch D to Q edges.
// This breaks latch loop paths.
if (prev_arc->role() == TimingRole::latchDtoQ())
break;
path.init(prev_path);
path.prevPath(this, prev_path, prev_arc);
path = prev_path;
prev_path = path->prevPath();
prev_arc = path->prevArc(this);
}
}
@ -540,47 +527,52 @@ void
PathEnum::makeDivertedPath(Path *path,
Path *before_div,
Path *after_div,
Edge *div_edge,
TimingArc *div_arc,
// Returned values.
PathEnumed *&div_path,
PathEnumed *&after_div_copy)
Path *&div_path,
Path *&after_div_copy)
{
div_path = nullptr;
after_div_copy = nullptr;
// Copy the diversion path.
bool found_div = false;
PathEnumedSeq copies;
PathRef p(path);
PathSeq copies;
Path *p = path;
bool first = true;
PathEnumed *prev_copy = nullptr;
while (!p.isNull()) {
PathRef prev;
TimingArc *prev_arc;
p.prevPath(this, prev, prev_arc);
PathEnumed *copy = new PathEnumed(p.vertexId(this),
p.tagIndex(this),
p.arrival(this),
nullptr, // prev_path made in next pass.
prev_arc);
Path *prev_copy = nullptr;
while (p) {
// prev_path made in next pass.
Path *copy = new Path(p->vertex(this),
p->tag(this),
p->arrival(),
// Replaced on next pass.
p->prevPath(),
p->prevEdge(this),
p->prevArc(this),
true, this);
if (prev_copy)
prev_copy->setPrevPath(copy);
copies.push_back(copy);
if (Path::equal(&p, after_div, this))
if (Path::equal(p, after_div, this))
after_div_copy = copy;
if (first)
div_path = copy;
else if (network_->isLatchData(p.pin(this)))
else if (network_->isLatchData(p->pin(this)))
break;
if (Path::equal(&p, before_div, this)) {
copy->setPrevArc(div_arc);
if (Path::equal(p, before_div, this)) {
// Replaced on next pass.
copy->setPrevPath(after_div);
copy->setPrevEdgeArc(div_edge, div_arc, this);
// Update the delays forward from before_div to the end of the path.
updatePathHeadDelays(copies, after_div);
p.init(after_div);
p = after_div;
found_div = true;
}
else
p.init(prev);
p = p->prevPath();
prev_copy = copy;
first = false;
}
@ -589,16 +581,16 @@ PathEnum::makeDivertedPath(Path *path,
}
void
PathEnum::updatePathHeadDelays(PathEnumedSeq &paths,
PathEnum::updatePathHeadDelays(PathSeq &paths,
Path *after_div)
{
Tag *prev_tag = after_div->tag(this);
ClkInfo *prev_clk_info = prev_tag->clkInfo();
Arrival prev_arrival = search_->clkPathArrival(after_div);
for (int i = paths.size() - 1; i >= 0; i--) {
PathEnumed *path = paths[i];
Path *path = paths[i];
TimingArc *arc = path->prevArc(this);
Edge *edge = path->prevEdge(arc, this);
Edge *edge = path->prevEdge(this);
if (edge) {
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
ArcDelay arc_delay = search_->deratedDelay(edge->from(graph_),
@ -607,9 +599,9 @@ PathEnum::updatePathHeadDelays(PathEnumedSeq &paths,
debugPrint(debug_, "path_enum", 5, "update arrival %s %s %s -> %s",
path->vertex(this)->name(network_),
path->tag(this)->asString(this),
delayAsString(path->arrival(this), this),
delayAsString(path->arrival(), this),
delayAsString(arrival, this));
path->setArrival(arrival, this);
path->setArrival(arrival);
prev_arrival = arrival;
if (sdc_->crprActive()
// D->Q paths use the EN->Q clk info so no need to update.

View File

@ -36,11 +36,9 @@ namespace sta {
class Diversion;
class PathEnumFaninVisitor;
class PathEnumed;
class DiversionGreater;
typedef Vector<Diversion*> DiversionSeq;
typedef Vector<PathEnumed*> PathEnumedSeq;
typedef std::priority_queue<Diversion*,DiversionSeq,
DiversionGreater> DiversionQueue;
@ -60,8 +58,8 @@ private:
class PathEnum : public Iterator<PathEnd*>, StaState
{
public:
PathEnum(int group_path_count,
int endpoint_path_count,
PathEnum(size_t group_path_count,
size_t endpoint_path_count,
bool unique_pins,
bool cmp_slack,
const StaState *sta);
@ -75,29 +73,29 @@ private:
void makeDiversions(PathEnd *path_end,
Path *before);
void makeDiversion(PathEnd *div_end,
PathEnumed *after_div_copy);
Path *after_div_copy);
void makeDivertedPath(Path *path,
Path *before_div,
Path *after_div,
Edge *div_edge,
TimingArc *div_arc,
// Returned values.
PathEnumed *&div_path,
PathEnumed *&after_div_copy);
void updatePathHeadDelays(PathEnumedSeq &path,
Path *&div_path,
Path *&after_div_copy);
void updatePathHeadDelays(PathSeq &path,
Path *after_div);
Arrival divSlack(Path *path,
Path *after_div,
TimingArc *div_arc,
const Edge *div_edge,
const TimingArc *div_arc,
const PathAnalysisPt *path_ap);
void reportDiversionPath(Diversion *div);
void pruneDiversionQueue();
Edge *divEdge(Path *before_div,
TimingArc *div_arc);
void findNext();
bool cmp_slack_;
int group_path_count_;
int endpoint_path_count_;
size_t group_path_count_;
size_t endpoint_path_count_;
bool unique_pins_;
DiversionQueue div_queue_;
int div_count_;

View File

@ -1,192 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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/>.
//
// 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.
#include "PathEnumed.hh"
#include "Set.hh"
#include "Graph.hh"
#include "Corner.hh"
#include "Search.hh"
#include "Tag.hh"
#include "PathRef.hh"
namespace sta {
PathEnumed:: PathEnumed(VertexId vertex_id,
TagIndex tag_index,
Arrival arrival,
PathEnumed *prev_path,
TimingArc *prev_arc) :
Path(),
prev_path_(prev_path),
prev_arc_(prev_arc),
arrival_(arrival),
vertex_id_(vertex_id),
tag_index_(tag_index)
{
}
void
deletePathEnumed(PathEnumed *path)
{
while (path) {
PathEnumed *prev = path->prevPathEnumed();
delete path;
path = prev;
}
}
void
PathEnumed::setRef(PathRef *ref) const
{
ref->init(const_cast<PathEnumed*>(this));
}
Vertex *
PathEnumed::vertex(const StaState *sta) const
{
const Graph *graph = sta->graph();
return graph->vertex(vertex_id_);
}
VertexId
PathEnumed::vertexId(const StaState *) const
{
return vertex_id_;
}
Tag *
PathEnumed::tag(const StaState *sta) const
{
const Search *search = sta->search();
return search->tag(tag_index_);
}
void
PathEnumed::setTag(Tag *tag)
{
tag_index_ = tag->index();
}
const RiseFall *
PathEnumed::transition(const StaState *sta) const
{
return tag(sta)->transition();
}
int
PathEnumed::trIndex(const StaState *sta) const
{
return tag(sta)->rfIndex();
}
PathAnalysisPt *
PathEnumed::pathAnalysisPt(const StaState *sta) const
{
const Corners *corners = sta->corners();
return corners->findPathAnalysisPt(pathAnalysisPtIndex(sta));
}
PathAPIndex
PathEnumed::pathAnalysisPtIndex(const StaState *sta) const
{
return tag(sta)->pathAPIndex();
}
Arrival
PathEnumed::arrival(const StaState *) const
{
return arrival_;
}
void
PathEnumed::setArrival(Arrival arrival,
const StaState *)
{
arrival_ = arrival;
}
const Required &
PathEnumed::required(const StaState *sta) const
{
// Required times are never needed for enumerated paths.
sta->report()->critical(1380, "enumerated path required time");
return delay_zero;
}
void
PathEnumed::setRequired(const Required &,
const StaState *sta)
{
// Required times are never needed for enumerated paths.
sta->report()->critical(1381, "enumerated path required time");
}
Path *
PathEnumed::prevPath(const StaState *) const
{
return prev_path_;
}
void
PathEnumed::prevPath(const StaState *,
// Return values.
PathRef &prev_path,
TimingArc *&prev_arc) const
{
if (prev_path_) {
prev_path_->setRef(prev_path);
prev_arc = prev_arc_;
}
else {
prev_path.init();
prev_arc = nullptr;
}
}
TimingArc *
PathEnumed::prevArc(const StaState *) const
{
return prev_arc_;
}
PathEnumed *
PathEnumed::prevPathEnumed() const
{
return prev_path_;
}
void
PathEnumed::setPrevPath(PathEnumed *prev)
{
prev_path_ = prev;
}
void
PathEnumed::setPrevArc(TimingArc *arc)
{
prev_arc_ = arc;
}
} // namespace

View File

@ -1,80 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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/>.
//
// 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.
#pragma once
#include "Path.hh"
namespace sta {
// Implements Path API for paths returned by PathEnum.
class PathEnumed : public Path
{
public:
PathEnumed(VertexId vertex_id,
TagIndex tag_index,
Arrival arrival,
PathEnumed *prev_path,
TimingArc *prev_arc);
virtual void setRef(PathRef *ref) const;
virtual bool isNull() const { return vertex_id_ == 0; }
virtual Vertex *vertex(const StaState *sta) const;
virtual VertexId vertexId(const StaState *sta) const;
virtual Tag *tag(const StaState *sta) const;
virtual const RiseFall *transition(const StaState *sta) const;
virtual int trIndex(const StaState *) const;
virtual PathAnalysisPt *pathAnalysisPt(const StaState *sta) const;
virtual PathAPIndex pathAnalysisPtIndex(const StaState *sta) const;
virtual Arrival arrival(const StaState *sta) const;
virtual void setArrival(Arrival arrival, const StaState *sta);
virtual const Required &required(const StaState *sta) const;
virtual void setRequired(const Required &required,
const StaState *sta);
virtual Path *prevPath(const StaState *sta) const;
virtual void prevPath(const StaState *sta,
// Return values.
PathRef &prev_path,
TimingArc *&prev_arc) const;
virtual TimingArc *prevArc(const StaState *sta) const;
PathEnumed *prevPathEnumed() const;
void setPrevPath(PathEnumed *prev);
void setPrevArc(TimingArc *arc);
void setTag(Tag *tag);
using Path::setRef;
using Path::prevPath;
protected:
// Pointer to previous path.
// A path is traversed by following prev_path/arcs.
PathEnumed *prev_path_;
TimingArc *prev_arc_;
Arrival arrival_;
VertexId vertex_id_;
TagIndex tag_index_;
};
void deletePathEnumed(PathEnumed *path);
} // namespace

View File

@ -29,7 +29,7 @@
#include "Network.hh"
#include "Clock.hh"
#include "Search.hh"
#include "PathRef.hh"
#include "Path.hh"
#include "Latches.hh"
#include "Genclks.hh"
@ -61,35 +61,32 @@ PathExpanded::expand(const Path *path,
bool expand_genclks)
{
const Latches *latches = sta_->latches();
// Push the paths from the end into an array of PathRefs.
PathRef p(path);
PathRef last_path;
// Push the paths from the end into an array of Paths.
const Path *p = path;
const Path *last_path = nullptr;
size_t i = 0;
bool found_start = false;
while (!p.isNull()) {
PathRef prev_path;
TimingArc *prev_arc;
p.prevPath(sta_, prev_path, prev_arc);
while (p) {
const Path *prev_path = p->prevPath();
const TimingArc *prev_arc = p->prevArc(sta_);
if (!found_start) {
if (prev_arc) {
TimingRole *prev_role = prev_arc->role();
const TimingRole *prev_role = prev_arc->role();
if (prev_role == TimingRole::regClkToQ()
|| prev_role == TimingRole::latchEnToQ()) {
start_index_ = i;
found_start = true;
}
else if (prev_role == TimingRole::latchDtoQ()) {
Edge *prev_edge = p.prevEdge(prev_arc, sta_);
const Edge *prev_edge = p->prevEdge(sta_);
if (prev_edge && latches->isLatchDtoQ(prev_edge)) {
start_index_ = i;
found_start = true;
paths_.push_back(p);
prev_arcs_.push_back(prev_arc);
// Push latch D path.
paths_.push_back(prev_path);
prev_arcs_.push_back(nullptr);
// This breaks latch loop paths.
break;
}
@ -97,43 +94,37 @@ PathExpanded::expand(const Path *path,
}
}
paths_.push_back(p);
prev_arcs_.push_back(prev_arc);
last_path.init(p);
p.init(prev_path);
last_path = p;
p = prev_path;
i++;
}
if (!found_start)
start_index_ = i - 1;
if (expand_genclks)
expandGenclk(&last_path);
expandGenclk(last_path);
}
void
PathExpanded::expandGenclk(PathRef *clk_path)
PathExpanded::expandGenclk(const Path *clk_path)
{
if (!clk_path->isNull()) {
if (clk_path) {
const Clock *src_clk = clk_path->clock(sta_);
if (src_clk && src_clk->isGenerated()) {
PathVertex src_path = sta_->search()->genclks()->srcPath(clk_path);
if (!src_path.isNull()) {
const Path *src_path = sta_->search()->genclks()->srcPath(clk_path);
if (src_path) {
// The head of the genclk src path is already in paths_,
// so skip past it.
PathRef prev_path;
TimingArc *prev_arc;
src_path.prevPath(sta_, prev_path, prev_arc);
PathRef p(prev_path);
PathRef last_path;
while (!p.isNull()) {
p.prevPath(sta_, prev_path, prev_arc);
Path *prev_path = src_path->prevPath();
Path *p = prev_path;
Path *last_path = nullptr;
while (p) {
prev_path = p->prevPath();
paths_.push_back(p);
prev_arcs_.push_back(prev_arc);
last_path.init(p);
p.init(prev_path);
last_path = p;
p = prev_path;
}
expandGenclk(&last_path);
expandGenclk(last_path);
}
}
}
@ -153,91 +144,84 @@ PathExpanded::startIndex() const
return pathsIndex(start_index_);
}
const PathRef *
const Path *
PathExpanded::path(size_t index) const
{
if (index < paths_.size())
return &paths_[pathsIndex(index)];
return paths_[pathsIndex(index)];
else
return nullptr;
}
TimingArc *
PathExpanded::prevArc(size_t index) const
{
return prev_arcs_[pathsIndex(index)];
}
const PathRef *
const Path *
PathExpanded::startPath() const
{
return &paths_[start_index_];
return paths_[start_index_];
}
const PathRef *
const Path *
PathExpanded::endPath() const
{
return &paths_[0];
return paths_[0];
}
TimingArc *
const TimingArc *
PathExpanded::startPrevArc() const
{
return prev_arcs_[start_index_];
return paths_[start_index_]->prevArc(sta_);
}
const PathRef *
const Path *
PathExpanded::startPrevPath() const
{
size_t start1 = start_index_ + 1;
if (start1 < paths_.size())
return &paths_[start1];
return paths_[start1];
else
return nullptr;
}
void
PathExpanded::clkPath(PathRef &clk_path) const
const Path *
PathExpanded::clkPath() const
{
const Latches *latches = sta_->latches();
const PathRef *start = startPath();
const Path *start = startPath();
const TimingArc *prev_arc = startPrevArc();
if (start && prev_arc) {
TimingRole *role = prev_arc->role();
if (role == TimingRole::latchDtoQ()) {
Edge *prev_edge = start->prevEdge(prev_arc, sta_);
Edge *prev_edge = start->prevEdge(sta_);
if (prev_edge && latches->isLatchDtoQ(prev_edge)) {
PathVertex enable_path;
latches->latchEnablePath(start, prev_edge, enable_path);
clk_path.init(enable_path);
return latches->latchEnablePath(start, prev_edge);
}
}
else if (role == TimingRole::regClkToQ()
|| role == TimingRole::latchEnToQ()) {
const PathRef *start_prev = startPrevPath();
const Path *start_prev = startPrevPath();
if (start_prev)
clk_path.init(start_prev);
return start_prev;
}
}
else if (start && start->isClock(sta_))
clk_path.init(start);
return start;
return nullptr;
}
void
PathExpanded::latchPaths(// Return values.
const PathRef *&d_path,
const PathRef *&q_path,
const Path *&d_path,
const Path *&q_path,
Edge *&d_q_edge) const
{
d_path = nullptr;
q_path = nullptr;
d_q_edge = nullptr;
const PathRef *start = startPath();
const Path *start = startPath();
const TimingArc *prev_arc = startPrevArc();
if (start
&& prev_arc
&& prev_arc->role() == TimingRole::latchDtoQ()) {
Edge *prev_edge = start->prevEdge(prev_arc, sta_);
Edge *prev_edge = start->prevEdge(sta_);
// This breaks latch loop paths.
if (prev_edge
&& sta_->latches()->isLatchDtoQ(prev_edge)) {

View File

@ -46,7 +46,7 @@
namespace sta {
int PathGroup::group_path_count_max = std::numeric_limits<int>::max();
size_t PathGroup::group_path_count_max = std::numeric_limits<size_t>::max();
PathGroup *
PathGroup::makePathGroupSlack(const char *name,
@ -74,8 +74,8 @@ PathGroup::makePathGroupArrival(const char *name,
}
PathGroup::PathGroup(const char *name,
int group_path_count,
int endpoint_path_count,
size_t group_path_count,
size_t endpoint_path_count,
bool unique_pins,
float slack_min,
float slack_max,
@ -148,7 +148,7 @@ PathGroup::enumMinSlackUnderMin(PathEnd *path_end)
path->transition(sta_),
other_ap, sta_);
while (other_iter.hasNext()) {
PathVertex *other = other_iter.next();
Path *other = other_iter.next();
if (tagMatchCrpr(other->tag(sta_), tag)) {
PathEnd *end_min = path_end->copy();
end_min->setPath(other);
@ -168,7 +168,7 @@ PathGroup::insert(PathEnd *path_end)
LockGuard lock(lock_);
path_ends_.push_back(path_end);
if (group_path_count_ != group_path_count_max
&& static_cast<int>(path_ends_.size()) > group_path_count_ * 2)
&& path_ends_.size() > group_path_count_ * 2)
prune();
}
@ -177,7 +177,7 @@ PathGroup::prune()
{
sort();
VertexPathCountMap path_counts;
int end_count = 0;
size_t end_count = 0;
for (unsigned i = 0; i < path_ends_.size(); i++) {
PathEnd *path_end = path_ends_[i];
Vertex *vertex = path_end->vertex(sta_);
@ -220,7 +220,7 @@ PathGroup::iterator()
void
PathGroup::ensureSortedMaxPaths()
{
if (static_cast<int>(path_ends_.size()) > group_path_count_)
if (path_ends_.size() > group_path_count_)
prune();
else
sort();

View File

@ -1,246 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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/>.
//
// 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.
#include "PathPrev.hh"
#include "Graph.hh"
#include "TimingArc.hh"
#include "SearchClass.hh"
#include "Tag.hh"
#include "TagGroup.hh"
#include "Search.hh"
#include "PathAnalysisPt.hh"
#include "PathVertex.hh"
namespace sta {
PathPrev::PathPrev()
{
init();
}
void
PathPrev::init()
{
prev_edge_id_ = edge_id_null;
prev_arc_idx_ = 0;
prev_tag_index_ = tag_index_null;
}
void
PathPrev::init(const PathPrev *path)
{
if (path) {
prev_edge_id_ = path->prev_edge_id_;
prev_arc_idx_ = path->prev_arc_idx_;
prev_tag_index_ = path->prev_tag_index_;
}
else
init();
}
void
PathPrev::init(const PathPrev &path)
{
prev_edge_id_ = path.prev_edge_id_;
prev_arc_idx_ = path.prev_arc_idx_;
prev_tag_index_ = path.prev_tag_index_;
}
void
PathPrev::init(const PathVertex *path,
const Edge *prev_edge,
const TimingArc *prev_arc,
const StaState *sta)
{
if (path == nullptr || path->isNull())
init();
else {
const Graph *graph = sta->graph();
prev_edge_id_ = graph->id(prev_edge);
prev_arc_idx_ = prev_arc->index();
prev_tag_index_ = path->tag(sta)->index();
}
}
const char *
PathPrev::name(const StaState *sta) const
{
const Network *network = sta->network();
const Search *search = sta->search();
Vertex *vertex = this->vertex(sta);
if (vertex) {
const char *vertex_name = vertex->name(network);
const Tag *tag = this->tag(search);
const RiseFall *rf = tag->transition();
const char *rf_str = rf->asString();
const PathAnalysisPt *path_ap = tag->pathAnalysisPt(sta);
int ap_index = path_ap->index();
const char *min_max = path_ap->pathMinMax()->asString();
TagIndex tag_index = tag->index();
return stringPrintTmp("%s %s %s/%d %d",
vertex_name, rf_str, min_max,
ap_index, tag_index);
}
else
return "NULL";
}
bool
PathPrev::isNull() const
{
return prev_edge_id_ == edge_id_null;
}
VertexId
PathPrev::vertexId(const StaState *sta) const
{
if (prev_edge_id_ == edge_id_null)
return vertex_id_null;
else {
const Graph *graph = sta->graph();
const Edge *edge = graph->edge(prev_edge_id_);
return edge->from();
}
}
Vertex *
PathPrev::vertex(const StaState *sta) const
{
if (prev_edge_id_ == edge_id_null)
return nullptr;
else {
const Graph *graph = sta->graph();
const Edge *edge = graph->edge(prev_edge_id_);
return edge->from(graph);
}
}
Edge *
PathPrev::prevEdge(const StaState *sta) const
{
if (prev_edge_id_ == edge_id_null)
return nullptr;
else {
const Graph *graph = sta->graph();
return graph->edge(prev_edge_id_);
}
}
TimingArc *
PathPrev::prevArc(const StaState *sta) const
{
if (prev_edge_id_ == edge_id_null)
return nullptr;
else {
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_);
}
}
Tag *
PathPrev::tag(const StaState *sta) const
{
const Search *search = sta->search();
return search->tag(prev_tag_index_);
}
Arrival
PathPrev::arrival(const StaState *sta) const
{
Graph *graph = sta->graph();
const Search *search = sta->search();
Tag *tag = search->tag(prev_tag_index_);
Vertex *vertex = this->vertex(sta);
TagGroup *tag_group = search->tagGroup(vertex);
if (tag_group) {
int arrival_index;
bool arrival_exists;
tag_group->arrivalIndex(tag, arrival_index, arrival_exists);
if (!arrival_exists)
sta->report()->critical(1420, "tag group missing tag");
Arrival *arrivals = graph->arrivals(vertex);
if (arrivals)
return arrivals[arrival_index];
else
sta->report()->critical(1421, "missing arrivals");
}
else
sta->report()->error(1422, "missing arrivals.");
return 0.0;
}
void
PathPrev::prevPath(const StaState *sta,
// Return values.
PathRef &prev_path,
TimingArc *&prev_arc) const
{
PathVertex path_vertex(this, sta);
path_vertex.prevPath(sta, prev_path, prev_arc);
}
////////////////////////////////////////////////////////////////
bool
PathPrev::equal(const PathPrev *path1,
const PathPrev *path2)
{
return path1->prev_edge_id_ == path2->prev_edge_id_
&& path1->prev_tag_index_ == path2->prev_tag_index_;
}
bool
PathPrev::equal(const PathPrev &path1,
const PathPrev &path2)
{
return path1.prev_edge_id_ == path2.prev_edge_id_
&& path1.prev_tag_index_ == path2.prev_tag_index_;
}
int
PathPrev::cmp(const PathPrev &path1,
const PathPrev &path2)
{
EdgeId edge_id1 = path1.prev_edge_id_;
EdgeId edge_id2 = path2.prev_edge_id_;
if (edge_id1 == edge_id2) {
TagIndex tag_index1 = path1.prev_tag_index_;
TagIndex tag_index2 = path2.prev_tag_index_;
if (tag_index1 == tag_index2)
return 0;
else if (tag_index1 < tag_index2)
return -1;
else
return 1;
}
else if (edge_id1 < edge_id2)
return -1;
else
return 1;
}
} // namespace

View File

@ -1,284 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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/>.
//
// 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.
#include "PathRef.hh"
#include "Graph.hh"
#include "TagGroup.hh"
#include "PathEnumed.hh"
#include "PathVertex.hh"
#include "Search.hh"
namespace sta {
PathRef::PathRef() :
path_enumed_(nullptr)
{
}
PathRef::PathRef(const Path *path) :
path_enumed_(nullptr)
{
if (path)
path->setRef(this);
}
PathRef::PathRef(const PathRef &path) :
path_vertex_(path.path_vertex_),
path_enumed_(path.path_enumed_)
{
}
PathRef::PathRef(const PathRef *path) :
path_vertex_(path->path_vertex_),
path_enumed_(path->path_enumed_)
{
}
PathRef::PathRef(const PathVertex &path) :
path_vertex_(&path),
path_enumed_(nullptr)
{
}
void
PathRef::init()
{
path_vertex_.init();
path_enumed_ = nullptr;
}
void
PathRef::init(const PathRef &path)
{
path_vertex_ = path.path_vertex_;
path_enumed_ = path.path_enumed_;
}
void
PathRef::init(const PathRef *path)
{
path_vertex_ = path->path_vertex_;
path_enumed_ = path->path_enumed_;
}
void
PathRef::init(const PathVertex *path)
{
path_vertex_ = path;
}
void
PathRef::init(const PathVertex &path)
{
path_vertex_ = path;
}
void
PathRef::init(const PathPrev &path,
const StaState *sta)
{
int arrival_index = 0;
TagIndex tag_index = path.tagIndex();
Tag *tag = nullptr;
if (tag_index != tag_index_null) {
const Search *search = sta->search();
tag = search->tag(tag_index);
Vertex *vertex = path.vertex(sta);
TagGroup *tag_group = search->tagGroup(vertex);
if (tag_group) {
bool arrival_exists;
tag_group->arrivalIndex(tag, arrival_index, arrival_exists);
}
}
path_vertex_.init(path.vertex(sta), tag, arrival_index);
}
void
PathRef::init(Vertex *vertex,
Tag *tag,
int arrival_index)
{
path_vertex_.init(vertex, tag, arrival_index);
path_enumed_ = nullptr;
}
void
PathRef::init(PathEnumed *path)
{
path_enumed_ = path;
}
void
PathRef::setRef(PathRef *ref) const
{
ref->path_vertex_ = path_vertex_;
ref->path_enumed_ = path_enumed_;
}
void
PathRef::deleteRep()
{
if (path_enumed_)
deletePathEnumed(path_enumed_);
}
bool
PathRef::isNull() const
{
return path_enumed_ == nullptr
&& path_vertex_.isNull();
}
Vertex *
PathRef::vertex(const StaState *sta) const
{
if (path_enumed_)
return path_enumed_->vertex(sta);
else
return path_vertex_.vertex(sta);
}
VertexId
PathRef::vertexId(const StaState *sta) const
{
if (path_enumed_)
return path_enumed_->vertexId(sta);
else
return path_vertex_.vertexId(sta);
}
Tag *
PathRef::tag(const StaState *sta) const
{
if (path_enumed_)
return path_enumed_->tag(sta);
else
return path_vertex_.tag(sta);
}
TagIndex
PathRef::tagIndex(const StaState *sta) const
{
if (path_enumed_)
return path_enumed_->tagIndex(sta);
else
return path_vertex_.tagIndex(sta);
}
const RiseFall *
PathRef::transition(const StaState *sta) const
{
if (path_enumed_)
return path_enumed_->transition(sta);
else
return path_vertex_.transition(sta);
}
int
PathRef::rfIndex(const StaState *sta) const
{
if (path_enumed_)
return path_enumed_->rfIndex(sta);
else
return path_vertex_.rfIndex(sta);
}
PathAnalysisPt *
PathRef::pathAnalysisPt(const StaState *sta) const
{
if (path_enumed_)
return path_enumed_->pathAnalysisPt(sta);
else
return path_vertex_.pathAnalysisPt(sta);
}
PathAPIndex
PathRef::pathAnalysisPtIndex(const StaState *sta) const
{
if (path_enumed_)
return path_enumed_->pathAnalysisPtIndex(sta);
else
return path_vertex_.pathAnalysisPtIndex(sta);
}
Arrival
PathRef::arrival(const StaState *sta) const
{
if (path_enumed_)
return path_enumed_->arrival(sta);
else
return path_vertex_.arrival(sta);
}
void
PathRef::setArrival(Arrival arrival,
const StaState *sta)
{
if (path_enumed_)
return path_enumed_->setArrival(arrival, sta);
else
return path_vertex_.setArrival(arrival, sta);
}
const Required &
PathRef::required(const StaState *sta) const
{
if (path_enumed_)
return path_enumed_->required(sta);
else
return path_vertex_.required(sta);
}
void
PathRef::setRequired(const Required &required,
const StaState *sta)
{
if (path_enumed_)
return path_enumed_->setRequired(required, sta);
else
return path_vertex_.setRequired(required, sta);
}
void
PathRef::prevPath(const StaState *sta,
// Return values.
PathRef &prev_path,
TimingArc *&prev_arc) const
{
if (path_enumed_)
path_enumed_->prevPath(sta, prev_path, prev_arc);
else
path_vertex_.prevPath(sta, prev_path, prev_arc);
}
void
PathRef::arrivalIndex(int &arrival_index,
bool &arrival_exists) const
{
return path_vertex_.arrivalIndex(arrival_index, arrival_exists);
}
} // namespace

View File

@ -1,628 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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/>.
//
// 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.
#include "PathVertex.hh"
#include <cmath>
#include "Fuzzy.hh"
#include "Graph.hh"
#include "ExceptionPath.hh"
#include "Sdc.hh"
#include "GraphDelayCalc.hh"
#include "Corner.hh"
#include "Tag.hh"
#include "TagGroup.hh"
#include "PathAnalysisPt.hh"
#include "PathRef.hh"
#include "PathPrev.hh"
#include "PathVertexPtr.hh"
#include "Search.hh"
namespace sta {
PathVertex::PathVertex() :
vertex_(nullptr),
tag_(nullptr),
arrival_index_(0)
{
}
PathVertex::PathVertex(const PathVertex &path) :
vertex_(path.vertex_),
tag_(path.tag_),
arrival_index_(path.arrival_index_)
{
}
PathVertex::PathVertex(const PathVertex *path) :
vertex_(nullptr),
tag_(nullptr),
arrival_index_(0)
{
if (path) {
vertex_ = path->vertex_;
tag_ = path->tag_;
arrival_index_ = path->arrival_index_;
}
}
PathVertex::PathVertex(Vertex *vertex,
Tag *tag,
const StaState *sta)
{
init(vertex, tag, sta);
}
PathVertex::PathVertex(Vertex *vertex,
Tag *tag,
int arrival_index) :
vertex_(vertex),
tag_(tag),
arrival_index_(arrival_index)
{
}
PathVertex::PathVertex(const PathPrev *path,
const StaState *sta)
{
if (path)
init(path->vertex(sta), path->tag(sta), sta);
else
init();
}
PathVertex::PathVertex(const PathPrev &path,
const StaState *sta)
{
if (path.isNull())
init();
else
init(path.vertex(sta), path.tag(sta), sta);
}
PathVertex::PathVertex(const PathVertexPtr &path,
const StaState *sta)
{
if (path.isNull())
init();
else
init(path.vertex(sta), path.tag(sta), sta);
}
void
PathVertex::init()
{
vertex_ = nullptr;
tag_ = nullptr;
arrival_index_ = 0;
}
void
PathVertex::init(Vertex *vertex,
Tag *tag,
const StaState *sta)
{
vertex_ = nullptr;
tag_ = nullptr;
arrival_index_ = 0;
const Search *search = sta->search();
TagGroup *tag_group = search->tagGroup(vertex);
if (tag_group) {
bool arrival_exists;
tag_group->arrivalIndex(tag, arrival_index_, arrival_exists);
if (arrival_exists) {
vertex_ = vertex;
tag_ = tag;
}
}
}
void
PathVertex::init(Vertex *vertex,
Tag *tag,
int arrival_index)
{
vertex_ = vertex;
tag_ = tag;
arrival_index_ = arrival_index;
}
void
PathVertex::init(const PathPrev *path,
const StaState *sta)
{
if (path)
init(path->vertex(sta), path->tag(sta), sta);
else
init();
}
void
PathVertex::init(const PathPrev &path,
const StaState *sta)
{
if (!path.isNull())
init(path.vertex(sta), path.tag(sta), sta);
else
init();
}
void
PathVertex::init(const PathVertexPtr &path,
const StaState *sta)
{
if (!path.isNull())
init(path.vertex(sta), path.tag(sta), sta);
else
init();
}
void
PathVertex::operator=(const PathVertex &path)
{
vertex_ = path.vertex_;
tag_ = path.tag_;
arrival_index_ = path.arrival_index_;
}
bool
PathVertex::isNull() const
{
return tag_ == nullptr;
}
void
PathVertex::setRef(PathRef *ref) const
{
ref->init(vertex_, tag_, arrival_index_);
}
VertexId
PathVertex::vertexId(const StaState *sta) const
{
const Graph *graph = sta->graph();
return graph->id(vertex_);
}
TagIndex
PathVertex::tagIndex(const StaState *) const
{
return tag_->index();
}
const RiseFall *
PathVertex::transition(const StaState *) const
{
return tag_->transition();
}
int
PathVertex::rfIndex(const StaState *) const
{
return tag_->rfIndex();
}
PathAnalysisPt *
PathVertex::pathAnalysisPt(const StaState *sta) const
{
return tag_->pathAnalysisPt(sta);
}
PathAPIndex
PathVertex::pathAnalysisPtIndex(const StaState *) const
{
return tag_->pathAPIndex();
}
void
PathVertex::arrivalIndex(int &arrival_index,
bool &arrival_exists) const
{
if (tag_) {
arrival_index = arrival_index_;
arrival_exists = true;
}
else
arrival_exists = false;
}
void
PathVertex::setArrivalIndex(int arrival_index)
{
arrival_index_ = arrival_index;
}
Arrival
PathVertex::arrival(const StaState *sta) const
{
Arrival *arrivals = sta->graph()->arrivals(vertex_);
if (arrivals)
return arrivals[arrival_index_];
else {
sta->report()->error(1400, "missing arrivals.");
return 0.0;
}
}
void
PathVertex::setArrival(Arrival arrival,
const StaState *sta)
{
if (tag_) {
Arrival *arrivals = sta->graph()->arrivals(vertex_);
if (arrivals)
arrivals[arrival_index_] = arrival;
else
sta->report()->error(1401, "missing arrivals.");
}
}
const Required &
PathVertex::required(const StaState *sta) const
{
if (tag_) {
Required *requireds = sta->graph()->requireds(vertex_);
if (requireds)
return requireds[arrival_index_];
}
return delayInitValue(minMax(sta)->opposite());
}
void
PathVertex::setRequired(const Required &required,
const StaState *sta)
{
Graph *graph = sta->graph();
Required *requireds = graph->requireds(vertex_);
if (requireds == nullptr) {
const Search *search = sta->search();
TagGroup *tag_group = search->tagGroup(vertex_);
if (tag_group) {
int arrival_count = tag_group->arrivalCount();
requireds = graph->makeRequireds(vertex_, arrival_count);
}
else
sta->report()->error(1402, "missing requireds.");
}
requireds[arrival_index_] = required;
}
bool
PathVertex::equal(const PathVertex *path1,
const PathVertex *path2)
{
return path1->vertex_ == path2->vertex_
&& path1->tag_ == path2->tag_;
}
////////////////////////////////////////////////////////////////
// EvalPred but search to clk source pin.
class PrevPred2 : public SearchPred0
{
public:
explicit PrevPred2(const StaState *sta);
virtual bool searchThru(Edge *edge);
};
PrevPred2::PrevPred2(const StaState *sta) :
SearchPred0(const_cast<StaState*>(sta))
{
}
bool
PrevPred2::searchThru(Edge *edge)
{
const Sdc *sdc = sta_->sdc();
TimingRole *role = edge->role();
return SearchPred0::searchThru(edge)
&& (sdc->dynamicLoopBreaking()
|| !edge->isDisabledLoop())
&& !role->isTimingCheck();
}
class PrevPathVisitor : public PathVisitor
{
public:
PrevPathVisitor(const Path *path,
SearchPred *pred,
const StaState *sta);
virtual VertexVisitor *copy() const;
virtual void visit(Vertex *) {}
virtual bool visitFromToPath(const Pin *from_pin,
Vertex *from_vertex,
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
ArcDelay arc_delay,
Vertex *to_vertex,
const RiseFall *to_rf,
Tag *to_tag,
Arrival &to_arrival,
const MinMax *min_max,
const PathAnalysisPt *path_ap);
PathVertex &prevPath() { return prev_path_; }
TimingArc *prevArc() const { return prev_arc_; }
protected:
Tag *unfilteredTag(const Tag *tag) const;
const Path *path_;
Arrival path_arrival_;
Tag *path_tag_;
int path_rf_index_;
PathAPIndex path_ap_index_;
PathVertex prev_path_;
TimingArc *prev_arc_;
float dcalc_tol_;
};
PrevPathVisitor::PrevPathVisitor(const Path *path,
SearchPred *pred,
const StaState *sta) :
PathVisitor(pred, sta),
path_(path),
path_arrival_(path->arrival(sta)),
path_tag_(path->tag(sta)),
path_rf_index_(path->rfIndex(sta)),
path_ap_index_(path->pathAnalysisPtIndex(sta)),
prev_path_(),
prev_arc_(nullptr),
dcalc_tol_(sta->graphDelayCalc()->incrementalDelayTolerance())
{
}
VertexVisitor *
PrevPathVisitor::copy() const
{
return new PrevPathVisitor(path_, pred_, this);
}
bool
PrevPathVisitor::visitFromToPath(const Pin *,
Vertex *,
const RiseFall *,
Tag *from_tag,
PathVertex *from_path,
const Arrival &,
Edge *,
TimingArc *arc,
ArcDelay,
Vertex *,
const RiseFall *to_rf,
Tag *to_tag,
Arrival &to_arrival,
const MinMax *,
const PathAnalysisPt *path_ap)
{
PathAPIndex path_ap_index = path_ap->index();
if (to_rf->index() == path_rf_index_
&& path_ap_index == path_ap_index_
&& delayEqual(to_arrival, path_arrival_)
&& (tagMatch(to_tag, path_tag_, this)
// If the filter exception became active searching from
// from_path to to_path the tag includes the filter, but
// to_vertex still has paths from previous searches that do
// not have the filter.
|| (!from_tag->isFilter()
&& to_tag->isFilter()
&& tagMatch(unfilteredTag(to_tag), path_tag_, this)))) {
int arrival_index;
bool arrival_exists;
from_path->arrivalIndex(arrival_index, arrival_exists);
if (arrival_exists) {
prev_path_ = from_path;
prev_arc_ = arc;
// Stop looking for the previous path/arc.
return false;
}
}
return true;
}
Tag *
PrevPathVisitor::unfilteredTag(const Tag *tag) const
{
ExceptionStateSet *unfiltered_states = nullptr;
const ExceptionStateSet *states = tag->states();
ExceptionStateSet::ConstIterator state_iter(states);
while (state_iter.hasNext()) {
ExceptionState *state = state_iter.next();
ExceptionPath *except = state->exception();
if (!except->isFilter()) {
if (unfiltered_states == nullptr)
unfiltered_states = new ExceptionStateSet();
unfiltered_states->insert(state);
}
}
return search_->findTag(tag->transition(),
corners_->findPathAnalysisPt(tag->pathAPIndex()),
tag->clkInfo(),
tag->isClock(),
tag->inputDelay(),
tag->isSegmentStart(),
unfiltered_states, true);
}
////////////////////////////////////////////////////////////////
void
PathVertex::prevPath(const StaState *sta,
// Return values.
PathVertex &prev_path,
TimingArc *&prev_arc) const
{
PrevPred2 pred(sta);
PrevPathVisitor visitor(this, &pred, sta);
visitor.visitFaninPaths(vertex(sta));
prev_path = visitor.prevPath();
prev_arc = visitor.prevArc();
}
void
PathVertex::prevPath(const StaState *sta,
// Return values.
PathVertex &prev_path) const
{
PrevPred2 pred(sta);
PrevPathVisitor visitor(this, &pred, sta);
visitor.visitFaninPaths(vertex(sta));
prev_path = visitor.prevPath();
}
void
PathVertex::prevPath(const StaState *sta,
// Return values.
PathRef &prev_path,
TimingArc *&prev_arc) const
{
const Graph *graph = sta->graph();
Vertex *vertex = this->vertex(graph);
PathPrev *prev_paths = vertex->prevPaths();
if (prev_paths) {
PathPrev &prev = prev_paths[arrival_index_];
prev_path.init(prev, sta);
prev_arc = prev.isNull() ? nullptr : prev.prevArc(sta);
}
else {
PathVertex prev;
prevPath(sta, prev, prev_arc);
prev.setRef(prev_path);
}
}
////////////////////////////////////////////////////////////////
VertexPathIterator::VertexPathIterator(Vertex *vertex,
const StaState *sta) :
search_(sta->search()),
vertex_(vertex),
rf_(nullptr),
path_ap_(nullptr),
min_max_(nullptr)
{
TagGroup *tag_group = search_->tagGroup(vertex);
if (tag_group) {
arrival_iter_.init(tag_group->arrivalMap());
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()),
vertex_(vertex),
rf_(rf),
path_ap_(path_ap),
min_max_(nullptr)
{
TagGroup *tag_group = search_->tagGroup(vertex);
if (tag_group) {
arrival_iter_.init(tag_group->arrivalMap());
findNext();
}
}
VertexPathIterator::VertexPathIterator(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max,
const StaState *sta) :
search_(sta->search()),
vertex_(vertex),
rf_(rf),
path_ap_(nullptr),
min_max_(min_max)
{
TagGroup *tag_group = search_->tagGroup(vertex);
if (tag_group) {
arrival_iter_.init(tag_group->arrivalMap());
findNext();
}
}
VertexPathIterator::VertexPathIterator(Vertex *vertex,
const RiseFall *rf,
const PathAnalysisPt *path_ap,
const MinMax *min_max,
const StaState *sta) :
search_(sta->search()),
vertex_(vertex),
rf_(rf),
path_ap_(path_ap),
min_max_(min_max)
{
TagGroup *tag_group = search_->tagGroup(vertex);
if (tag_group) {
arrival_iter_.init(tag_group->arrivalMap());
findNext();
}
}
VertexPathIterator::~VertexPathIterator()
{
}
bool
VertexPathIterator::hasNext()
{
return !next_.isNull();
}
void
VertexPathIterator::findNext()
{
while (arrival_iter_.hasNext()) {
Tag *tag;
int arrival_index;
arrival_iter_.next(tag, arrival_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_.init(vertex_, tag, arrival_index);
return;
}
}
next_.init();
}
PathVertex *
VertexPathIterator::next()
{
path_ = next_;
findNext();
return &path_;
}
} // namespace

View File

@ -1,201 +0,0 @@
// OpenSTA, Static Timing Analyzer
// Copyright (c) 2025, 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/>.
//
// 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.
#include "PathVertexPtr.hh"
#include "Graph.hh"
#include "TimingArc.hh"
#include "SearchClass.hh"
#include "Tag.hh"
#include "TagGroup.hh"
#include "Search.hh"
#include "PathAnalysisPt.hh"
#include "PathVertex.hh"
namespace sta {
PathVertexPtr::PathVertexPtr() :
vertex_id_(vertex_id_null),
tag_index_(tag_index_null)
{
}
PathVertexPtr::PathVertexPtr(const PathVertex *path,
const StaState *sta)
{
init(path, sta);
}
void
PathVertexPtr::init()
{
vertex_id_ = vertex_id_null;
tag_index_ = tag_index_null;
}
void
PathVertexPtr::init(const PathVertexPtr *path)
{
if (path) {
vertex_id_ = path->vertex_id_;
tag_index_ = path->tag_index_;
}
else {
vertex_id_ = vertex_id_null;
tag_index_ = tag_index_null;
}
}
void
PathVertexPtr::init(const PathVertexPtr &path)
{
vertex_id_ = path.vertex_id_;
tag_index_ = path.tag_index_;
}
void
PathVertexPtr::init(const PathVertex *path,
const StaState *sta)
{
if (path == nullptr || path->isNull())
init();
else {
vertex_id_ = path->vertexId(sta);
tag_index_ = path->tagIndex(sta);
}
}
const char *
PathVertexPtr::name(const StaState *sta) const
{
const Network *network = sta->network();
const Search *search = sta->search();
Vertex *vertex = this->vertex(sta);
if (vertex) {
const char *vertex_name = vertex->name(network);
const Tag *tag = this->tag(search);
const RiseFall *rf = tag->transition();
const char *rf_str = rf->asString();
const PathAnalysisPt *path_ap = tag->pathAnalysisPt(sta);
int ap_index = path_ap->index();
const char *min_max = path_ap->pathMinMax()->asString();
TagIndex tag_index = tag->index();
return stringPrintTmp("%s %s %s/%d %d",
vertex_name, rf_str, min_max,
ap_index, tag_index);
}
else
return "NULL";
}
bool
PathVertexPtr::isNull() const
{
return vertex_id_ == vertex_id_null;
}
Vertex *
PathVertexPtr::vertex(const StaState *sta) const
{
if (vertex_id_ == vertex_id_null)
return nullptr;
else {
const Graph *graph = sta->graph();
return graph->vertex(vertex_id_);
}
}
Tag *
PathVertexPtr::tag(const StaState *sta) const
{
const Search *search = sta->search();
return search->tag(tag_index_);
}
Arrival
PathVertexPtr::arrival(const StaState *sta) const
{
const Vertex *vertex = this->vertex(sta);
Arrival *arrivals = sta->graph()->arrivals(vertex);
if (arrivals) {
const Search *search = sta->search();
TagGroup *tag_group = search->tagGroup(vertex);
Tag *tag = this->tag(sta);
int arrival_index;
bool arrival_exists;
tag_group->arrivalIndex(tag, arrival_index, arrival_exists);
if (arrival_exists)
return arrivals[arrival_index];
else {
sta->report()->error(1403, "missing arrival.");
return 0.0;
}
}
else {
sta->report()->error(1404, "missing arrivals.");
return 0.0;
}
}
////////////////////////////////////////////////////////////////
bool
PathVertexPtr::equal(const PathVertexPtr *path1,
const PathVertexPtr *path2)
{
return path1->vertex_id_ == path2->vertex_id_
&& path1->tag_index_ == path2->tag_index_;
}
bool
PathVertexPtr::equal(const PathVertexPtr &path1,
const PathVertexPtr &path2)
{
return path1.vertex_id_ == path2.vertex_id_
&& path1.tag_index_ == path2.tag_index_;
}
int
PathVertexPtr::cmp(const PathVertexPtr &path1,
const PathVertexPtr &path2)
{
VertexId vertex_id1 = path1.vertex_id_;
VertexId vertex_id2 = path2.vertex_id_;
if (vertex_id1 == vertex_id2) {
TagIndex tag_index1 = path1.tagIndex();
TagIndex tag_index2 = path2.tagIndex();
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;
}
} // namespace

View File

@ -37,7 +37,7 @@
#include "Corner.hh"
#include "PathEnd.hh"
#include "PathExpanded.hh"
#include "PathRef.hh"
#include "Path.hh"
#include "power/Power.hh"
#include "Sta.hh"
@ -318,9 +318,9 @@ PropertyValue::PropertyValue(ClockSet *value) :
}
}
PropertyValue::PropertyValue(PathRefSeq *value) :
type_(type_path_refs),
path_refs_(new PathRefSeq(*value)),
PropertyValue::PropertyValue(ConstPathSeq *value) :
type_(type_paths),
paths_(new ConstPathSeq(*value)),
unit_(nullptr)
{
}
@ -384,8 +384,8 @@ PropertyValue::PropertyValue(const PropertyValue &value) :
case Type::type_clks:
clks_ = value.clks_ ? new ClockSeq(*value.clks_) : nullptr;
break;
case Type::type_path_refs:
path_refs_ = value.path_refs_ ? new PathRefSeq(*value.path_refs_) : nullptr;
case Type::type_paths:
paths_ = value.paths_ ? new ConstPathSeq(*value.paths_) : nullptr;
break;
case Type::type_pwr_activity:
pwr_activity_ = value.pwr_activity_;
@ -450,8 +450,8 @@ PropertyValue::PropertyValue(PropertyValue &&value) :
// Steal the value.
value.clks_ = nullptr;
break;
case Type::type_path_refs:
path_refs_ = value.path_refs_;
case Type::type_paths:
paths_ = value.paths_;
// Steal the value.
value.clks_ = nullptr;
break;
@ -473,8 +473,8 @@ PropertyValue::~PropertyValue()
case Type::type_pins:
delete pins_;
break;
case Type::type_path_refs:
delete path_refs_;
case Type::type_paths:
delete paths_;
break;
default:
break;
@ -535,8 +535,8 @@ PropertyValue::operator=(const PropertyValue &value)
case Type::type_clks:
clks_ = value.clks_ ? new ClockSeq(*value.clks_) : nullptr;
break;
case Type::type_path_refs:
path_refs_ = value.path_refs_ ? new PathRefSeq(*value.path_refs_) : nullptr;
case Type::type_paths:
paths_ = value.paths_ ? new ConstPathSeq(*value.paths_) : nullptr;
break;
case Type::type_pwr_activity:
pwr_activity_ = value.pwr_activity_;
@ -602,8 +602,8 @@ PropertyValue::operator=(PropertyValue &&value)
clks_ = value.clks_;
value.clks_ = nullptr;
break;
case Type::type_path_refs:
path_refs_ = value.path_refs_;
case Type::type_paths:
paths_ = value.paths_;
value.clks_ = nullptr;
break;
case Type::type_pwr_activity:
@ -650,7 +650,7 @@ PropertyValue::asString(const Network *network) const
case Type::type_none:
case Type::type_pins:
case Type::type_clks:
case Type::type_path_refs:
case Type::type_paths:
case Type::type_pwr_activity:
return nullptr;
}
@ -1271,10 +1271,10 @@ getProperty(PathEnd *end,
return PropertyValue(delayPropertyValue(end->slack(sta), sta));
else if (stringEqual(property, "points")) {
PathExpanded expanded(end->path(), sta);
PathRefSeq paths;
ConstPathSeq paths;
for (size_t i = expanded.startIndex(); i < expanded.size(); i++) {
const PathRef *path = expanded.path(i);
paths.push_back(*path);
const Path *path = expanded.path(i);
paths.push_back(path);
}
return PropertyValue(&paths);
}
@ -1283,16 +1283,16 @@ getProperty(PathEnd *end,
}
PropertyValue
getProperty(PathRef *path,
getProperty(Path *path,
const char *property,
Sta *sta)
{
if (stringEqual(property, "pin"))
return PropertyValue(path->pin(sta));
else if (stringEqual(property, "arrival"))
return PropertyValue(delayPropertyValue(path->arrival(sta), sta));
return PropertyValue(delayPropertyValue(path->arrival(), sta));
else if (stringEqual(property, "required"))
return PropertyValue(delayPropertyValue(path->required(sta), sta));
return PropertyValue(delayPropertyValue(path->required(), sta));
else if (stringEqual(property, "slack"))
return PropertyValue(delayPropertyValue(path->slack(sta), sta));
else

View File

@ -48,13 +48,12 @@
#include "GraphDelayCalc.hh"
#include "ClkInfo.hh"
#include "Tag.hh"
#include "PathVertex.hh"
#include "PathAnalysisPt.hh"
#include "PathGroup.hh"
#include "CheckMinPulseWidths.hh"
#include "CheckMinPeriods.hh"
#include "CheckMaxSkews.hh"
#include "PathRef.hh"
#include "Path.hh"
#include "Search.hh"
#include "PathExpanded.hh"
#include "Latches.hh"
@ -925,7 +924,7 @@ ReportPath::reportFull(const PathEndDataCheck *end) const
// It is like a target because crpr and uncertainty are reported.
// It is always propagated, even if the clock is ideal.
reportTgtClk(end, 0.0, true);
const PathVertex *data_clk_path = end->dataClkPath();
const Path *data_clk_path = end->dataClkPath();
if (!data_clk_path->isClock(this)) {
// Report the path from the clk network to the data check.
PathExpanded clk_expanded(data_clk_path, this);
@ -1037,7 +1036,7 @@ string
ReportPath::pathStartpoint(const PathEnd *end,
const PathExpanded &expanded) const
{
const PathRef *start = expanded.startPath();
const Path *start = expanded.startPath();
Pin *pin = start->pin(graph_);
const char *pin_name = cmd_network_->pathName(pin);
if (network_->isTopLevelPort(pin)) {
@ -1103,7 +1102,7 @@ ReportPath::reportJson(const PathEnd *end,
sdc_network_->pathName(endpoint));
const ClockEdge *src_clk_edge = end->sourceClkEdge(this);
const PathVertex *tgt_clk_path = end->targetClkPath();
const Path *tgt_clk_path = end->targetClkPath();
if (src_clk_edge) {
stringAppend(result, " \"source_clock\": \"%s\",\n",
src_clk_edge->clock()->name());
@ -1181,7 +1180,7 @@ ReportPath::reportJson(const PathExpanded &expanded,
{
stringAppend(result, "%*s\"%s\": [\n", indent, "", path_name);
for (size_t i = 0; i < expanded.size(); i++) {
const PathRef *path = expanded.path(i);
const Path *path = expanded.path(i);
const Pin *pin = path->vertex(this)->pin();
const Net *net = network_->net(pin);
const Instance *inst = network_->instance(pin);
@ -1238,7 +1237,7 @@ ReportPath::reportJson(const PathExpanded &expanded,
stringAppend(result, "%*s \"arrival\": %.3e,\n",
indent, "",
delayAsFloat(path->arrival(this)));
delayAsFloat(path->arrival()));
if (is_driver)
stringAppend(result, "%*s \"capacitance\": %.3e,\n",
indent, "",
@ -1592,7 +1591,7 @@ ReportPath::reportShort(const MaxSkewCheck *check) const
reportDescription(what.c_str(), line);
const EarlyLate *early_late = EarlyLate::early();
reportSpaceFieldDelay(check->maxSkew(this), early_late, line);
reportSpaceFieldDelay(check->skew(this), early_late, line);
reportSpaceFieldDelay(check->skew(), early_late, line);
reportSpaceSlack(check->slack(this), line);
report_->reportLineString(line);
}
@ -1621,7 +1620,7 @@ ReportPath::reportVerbose(const MaxSkewCheck *check) const
reportDashLine();
reportLine("allowable skew", check->maxSkew(this), EarlyLate::early());
reportLine("actual skew", check->skew(this), EarlyLate::late());
reportLine("actual skew", check->skew(), EarlyLate::late());
reportDashLine();
reportSlack(check->slack(this));
}
@ -1629,7 +1628,7 @@ ReportPath::reportVerbose(const MaxSkewCheck *check) const
// Based on reportTgtClk.
void
ReportPath::reportSkewClkPath(const char *arrival_msg,
const PathVertex *clk_path) const
const Path *clk_path) const
{
const ClockEdge *clk_edge = clk_path->clkEdge(this);
const Clock *clk = clk_edge->clock();
@ -1767,9 +1766,9 @@ ReportPath::reportStartpoint(const PathEnd *end,
const PathExpanded &expanded) const
{
const Path *path = end->path();
const PathRef *start = expanded.startPath();
const Path *start = expanded.startPath();
const TimingArc *prev_arc = expanded.startPrevArc();
const Edge *prev_edge = start->prevEdge(prev_arc, this);
const Edge *prev_edge = start->prevEdge(this);
const Pin *pin = start->pin(graph_);
const ClockEdge *clk_edge = path->clkEdge(this);
const Clock *clk = path->clock(search_);
@ -1795,10 +1794,9 @@ ReportPath::reportStartpoint(const PathEnd *end,
const char *inst_name = cmd_network_->pathName(inst);
if (clk_edge) {
const RiseFall *clk_rf = clk_edge->transition();
PathRef clk_path;
expanded.clkPath(clk_path);
bool clk_inverted = !clk_path.isNull()
&& clk_rf != clk_path.transition(this);
const Path *clk_path = expanded.clkPath();
bool clk_inverted = clk_path
&& clk_rf != clk_path->transition(this);
string clk_name = clkName(clk, clk_inverted);
const char *reg_desc = edgeRegLatchDesc(prev_edge, prev_arc);
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
@ -1830,8 +1828,8 @@ ReportPath::reportStartpoint(const PathEnd *end,
bool
ReportPath::pathFromClkPin(const PathExpanded &expanded) const
{
const PathRef *start = expanded.startPath();
const PathRef *end = expanded.endPath();
const Path *start = expanded.startPath();
const Path *end = expanded.endPath();
const Pin *start_pin = start->pin(graph_);
return pathFromClkPin(end, start_pin);
}
@ -2069,13 +2067,12 @@ ReportPath::reportSrcClkAndPath(const Path *path,
bool path_from_input = false;
bool input_has_ref_path = false;
Arrival clk_delay, clk_end_time;
PathRef clk_path;
expanded.clkPath(clk_path);
const Path *clk_path = expanded.clkPath();
const RiseFall *clk_end_rf;
if (!clk_path.isNull()) {
clk_end_time = search_->clkPathArrival(&clk_path) + time_offset;
if (clk_path) {
clk_end_time = search_->clkPathArrival(clk_path) + time_offset;
clk_delay = clk_end_time - clk_time;
clk_end_rf = clk_path.transition(this);
clk_end_rf = clk_path->transition(this);
}
else {
// Path from input port or clk used as data.
@ -2083,16 +2080,16 @@ ReportPath::reportSrcClkAndPath(const Path *path,
clk_delay = clk_insertion + clk_latency;
clk_end_time = clk_time + clk_delay;
const PathRef *first_path = expanded.startPath();
const Path *first_path = expanded.startPath();
const InputDelay *input_delay = pathInputDelay(first_path);
if (input_delay) {
path_from_input = true;
const Pin *ref_pin = input_delay->refPin();
if (ref_pin && clk->isPropagated()) {
PathRef ref_path;
Path ref_path;
pathInputDelayRefPath(first_path, input_delay, ref_path);
if (!ref_path.isNull()) {
const Arrival &ref_end_time = ref_path.arrival(this);
const Arrival &ref_end_time = ref_path.arrival();
clk_delay = ref_end_time - clk_time;
clk_end_time = ref_end_time + time_offset;
input_has_ref_path = true;
@ -2105,8 +2102,7 @@ ReportPath::reportSrcClkAndPath(const Path *path,
bool clk_used_as_data = pathFromClkPin(expanded);
bool is_prop = isPropagated(path);
const EarlyLate *early_late = min_max;
if (reportGenClkSrcPath(clk_path.isNull() ? nullptr : &clk_path,
clk, clk_rf, min_max, early_late)
if (reportGenClkSrcPath(clk_path, clk, clk_rf, min_max, early_late)
&& !(path_from_input && !input_has_ref_path)) {
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time,
min_max);
@ -2137,7 +2133,7 @@ ReportPath::reportSrcClkAndPath(const Path *path,
reportPath1(path, expanded, true, time_offset);
else {
Arrival clk_arrival = clk_end_time;
Arrival end_arrival = path->arrival(this) + time_offset;
Arrival end_arrival = path->arrival() + time_offset;
Delay clk_delay = end_arrival - clk_arrival;
reportLine("clock network delay", clk_delay,
end_arrival, early_late);
@ -2395,10 +2391,10 @@ ReportPath::reportGenClkSrcPath1(const Clock *clk,
{
PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late);
const MinMax *min_max = path_ap->pathMinMax();
PathVertex src_path =
search_->genclks()->srcPath(clk, clk_pin, clk_rf, insert_ap);
if (!src_path.isNull()) {
ClkInfo *src_clk_info = src_path.clkInfo(search_);
Path *src_path = search_->genclks()->srcPath(clk, clk_pin,
clk_rf, insert_ap);
if (src_path) {
ClkInfo *src_clk_info = src_path->clkInfo(this);
const ClockEdge *src_clk_edge = src_clk_info->clkEdge();
const Clock *src_clk = src_clk_info->clock();
if (src_clk) {
@ -2419,12 +2415,12 @@ ReportPath::reportGenClkSrcPath1(const Clock *clk,
early_late, path_ap);
reportClkSrcLatency(insertion, gclk_time, early_late);
}
PathExpanded src_expanded(&src_path, this);
reportPath4(&src_path, src_expanded, skip_first_path, false,
PathExpanded src_expanded(src_path, this);
reportPath4(src_path, src_expanded, skip_first_path, false,
clk_used_as_data, gclk_time);
if (!clk->isPropagated())
reportLine("clock network delay (ideal)", 0.0,
src_path.arrival(this), min_max);
src_path->arrival(), min_max);
}
}
else {
@ -2433,7 +2429,7 @@ ReportPath::reportGenClkSrcPath1(const Clock *clk,
else if (!clk_used_as_data)
reportLine("clock network delay (ideal)", 0.0, gclk_time, min_max);
}
return !src_path.isNull();
return src_path != nullptr;
}
void
@ -2610,22 +2606,21 @@ ReportPath::reportPath1(const Path *path,
bool clk_used_as_data,
float time_offset) const
{
const PathRef *d_path, *q_path;
const Path *d_path, *q_path;
Edge *d_q_edge;
expanded.latchPaths(d_path, q_path, d_q_edge);
if (d_path) {
Arrival latch_time_given, latch_enable_time;
PathVertex latch_enable_path;
Path *latch_enable_path;
latches_->latchTimeGivenToStartpoint(d_path, q_path, d_q_edge,
latch_time_given,
latch_enable_path);
if (!latch_enable_path.isNull()) {
const EarlyLate *early_late = latch_enable_path.minMax(this);
latch_enable_time = search_->clkPathArrival(&latch_enable_path);
latch_time_given, latch_enable_path);
if (latch_enable_path) {
const EarlyLate *early_late = latch_enable_path->minMax(this);
latch_enable_time = search_->clkPathArrival(latch_enable_path);
if (reportClkPath()) {
PathExpanded enable_expanded(&latch_enable_path, this);
PathExpanded enable_expanded(latch_enable_path, this);
// Report the path to the latch enable.
reportPath2(&latch_enable_path, enable_expanded, false,
reportPath2(latch_enable_path, enable_expanded, false,
time_offset);
}
Arrival time = latch_enable_time + latch_time_given;
@ -2689,8 +2684,8 @@ ReportPath::reportPath4(const Path *path,
Arrival prev_time(0.0);
if (skip_first_path) {
path_first_index = 1;
const PathRef *start = expanded.path(0);
prev_time = start->arrival(this) + time_offset;
const Path *start = expanded.path(0);
prev_time = start->arrival() + time_offset;
}
size_t path_last_index = expanded.size() - 1;
if (skip_last_path
@ -2719,15 +2714,14 @@ ReportPath::reportPath5(const Path *path,
const MinMax *min_max = path->minMax(this);
DcalcAnalysisPt *dcalc_ap = path->pathAnalysisPt(this)->dcalcAnalysisPt();
DcalcAPIndex ap_index = dcalc_ap->index();
PathRef clk_path;
expanded.clkPath(clk_path);
Vertex *clk_start = clk_path.vertex(this);
const Path *clk_path = expanded.clkPath();
Vertex *clk_start = clk_path ? clk_path->vertex(this) : nullptr;
for (size_t i = path_first_index; i <= path_last_index; i++) {
const PathRef *path1 = expanded.path(i);
TimingArc *prev_arc = expanded.prevArc(i);
const Path *path1 = expanded.path(i);
const TimingArc *prev_arc = path1->prevArc(this);
Vertex *vertex = path1->vertex(this);
Pin *pin = vertex->pin();
Arrival time = path1->arrival(this) + time_offset;
Arrival time = path1->arrival() + time_offset;
Delay incr = 0.0;
const char *line_case = nullptr;
bool is_clk_start = path1->vertex(this) == clk_start;
@ -2747,7 +2741,7 @@ ReportPath::reportPath5(const Path *path,
// First path.
reportInputExternalDelay(path1, time_offset);
size_t next_index = i + 1;
const PathRef *next_path = expanded.path(next_index);
const Path *next_path = expanded.path(next_index);
if (network_->isTopLevelPort(pin)
&& next_path
&& !nextArcAnnotated(next_path, next_index, expanded, ap_index)
@ -2756,7 +2750,7 @@ ReportPath::reportPath5(const Path *path,
// The delay calculator annotates wire delays on the edges
// from the input to the loads. Report the wire delay on the
// input pin instead.
Arrival next_time = next_path->arrival(this) + time_offset;
Arrival next_time = next_path->arrival() + time_offset;
incr = delayIncr(next_time, time, min_max);
time = next_time;
line_case = "input_drive";
@ -2833,7 +2827,7 @@ ReportPath::reportPath5(const Path *path,
prev_time = time;
}
else {
reportHierPinsThru(path1, prev_arc);
reportHierPinsThru(path1);
if (report_input_pin_
|| (i == 0)
|| (i == path_last_index)
@ -2852,11 +2846,10 @@ ReportPath::reportPath5(const Path *path,
}
void
ReportPath::reportHierPinsThru(const Path *path,
const TimingArc *prev_arc) const
ReportPath::reportHierPinsThru(const Path *path) const
{
if (report_hier_pins_) {
const Edge *prev_edge = path->prevEdge(prev_arc, this);
const Edge *prev_edge = path->prevEdge(this);
if (prev_edge && prev_edge->isWire()) {
for (const Pin *hpin : hierPinsThruEdge(prev_edge, network_, graph_)) {
const string what = descriptionField(hpin);
@ -2880,13 +2873,13 @@ ReportPath::delayIncr(Delay time,
}
bool
ReportPath::nextArcAnnotated(const PathRef *next_path,
ReportPath::nextArcAnnotated(const Path *next_path,
size_t next_index,
const PathExpanded &expanded,
DcalcAPIndex ap_index) const
{
TimingArc *arc = expanded.prevArc(next_index);
Edge *edge = next_path->prevEdge(arc, this);
const TimingArc *arc = expanded.path(next_index)->prevArc(this);
Edge *edge = next_path->prevEdge(this);
return graph_->arcDelayAnnotated(edge, arc, ap_index);
}
@ -2983,13 +2976,13 @@ ReportPath::reportInputExternalDelay(const Path *first_path,
const Pin *first_pin = first_path->pin(graph_);
if (!pathFromClkPin(first_path, first_pin)) {
const RiseFall *rf = first_path->transition(this);
Arrival time = first_path->arrival(this) + time_offset;
Arrival time = first_path->arrival() + time_offset;
const EarlyLate *early_late = first_path->minMax(this);
InputDelay *input_delay = pathInputDelay(first_path);
if (input_delay) {
const Pin *ref_pin = input_delay->refPin();
if (ref_pin) {
PathRef ref_path;
Path ref_path;
pathInputDelayRefPath(first_path, input_delay, ref_path);
if (!ref_path.isNull() && reportClkPath()) {
PathExpanded ref_expanded(&ref_path, this);
@ -3018,7 +3011,7 @@ void
ReportPath::pathInputDelayRefPath(const Path *path,
const InputDelay *input_delay,
// Return value.
PathRef &ref_path) const
Path &ref_path) const
{
const Pin *ref_pin = input_delay->refPin();
const RiseFall *ref_rf = input_delay->refTransition();
@ -3028,10 +3021,10 @@ ReportPath::pathInputDelayRefPath(const Path *path,
const ClockEdge *clk_edge = path->clkEdge(this);
VertexPathIterator path_iter(ref_vertex, ref_rf, path_ap, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
if (path->isClock(this)
&& path->clkEdge(this) == clk_edge) {
ref_path.init(path);
ref_path = path;
break;
}
}

View File

@ -326,8 +326,7 @@ protected:
bool report_clk_path,
Arrival prev_time,
float time_offset) const;
void reportHierPinsThru(const Path *path,
const TimingArc *prev_arc) const;
void reportHierPinsThru(const Path *path) const;
void reportInputExternalDelay(const Path *path,
float time_offset) const;
void reportLine(const char *what,
@ -426,7 +425,7 @@ protected:
const MinMax *min_max) const;
const char *mpwCheckHiLow(const MinPulseWidthCheck *check) const;
void reportSkewClkPath(const char *arrival_msg,
const PathVertex *clk_path) const;
const Path *clk_path) const;
const char *edgeRegLatchDesc(const Edge *edge,
const TimingArc *arc) const;
const char *checkRegLatchDesc(const TimingRole *role,
@ -434,7 +433,7 @@ protected:
const char *regDesc(const RiseFall *clk_rf) const;
const char *latchDesc(const RiseFall *clk_rf) const;
void pathClkPath(const Path *path,
const PathRef &clk_path) const;
const Path &clk_path) const;
bool isPropagated(const Path *clk_path) const;
bool isPropagated(const Path *clk_path,
const Clock *clk) const;
@ -443,10 +442,10 @@ protected:
const Pin *start_pin) const;
void latchPaths(const Path *path,
// Return values.
PathRef &d_path,
PathRef &q_path,
Path &d_path,
Path &q_path,
Edge *&d_q_edge) const;
bool nextArcAnnotated(const PathRef *next_path,
bool nextArcAnnotated(const Path *next_path,
size_t next_index,
const PathExpanded &expanded,
DcalcAPIndex ap_index) const;
@ -458,7 +457,7 @@ protected:
void pathInputDelayRefPath(const Path *path,
const InputDelay *input_delay,
// Return value.
PathRef &ref_path) const;
Path &ref_path) const;
const char *asRisingFalling(const RiseFall *rf) const;
const char *asRiseFall(const RiseFall *rf) const;
Delay delayIncr(Delay time,

View File

@ -54,9 +54,7 @@
#include "Bfs.hh"
#include "Corner.hh"
#include "Sim.hh"
#include "PathVertex.hh"
#include "PathPrev.hh"
#include "PathRef.hh"
#include "Path.hh"
#include "ClkInfo.hh"
#include "Tag.hh"
#include "TagGroup.hh"
@ -142,11 +140,7 @@ DynLoopSrchPred::hasPendingLoopPaths(Edge *edge,
Corners *corners = search->corners();
Vertex *from_vertex = edge->from(graph);
TagGroup *prev_tag_group = search->tagGroup(from_vertex);
ArrivalMap::Iterator arrival_iter(tag_bldr_->arrivalMap());
while (arrival_iter.hasNext()) {
Tag *from_tag;
int arrival_index;
arrival_iter.next(from_tag, arrival_index);
for (auto const [from_tag, path_index] : tag_bldr_->pathIndexMap()) {
if (from_tag->isLoop()) {
// Loop false path exceptions apply to rise/fall edges so to_rf
// does not matter.
@ -255,7 +249,6 @@ Search::init(StaState *sta)
path_groups_ = nullptr;
endpoints_ = nullptr;
invalid_endpoints_ = nullptr;
always_save_prev_paths_ = true;
filter_ = nullptr;
filter_from_ = nullptr;
filter_to_ = nullptr;
@ -274,6 +267,7 @@ Search::initVars()
Search::~Search()
{
deletePathGroups();
deletePaths();
deleteTags();
delete tag_set_;
@ -299,7 +293,6 @@ Search::~Search()
delete genclks_;
delete filtered_arrivals_;
deleteFilter();
deletePathGroups();
}
void
@ -433,6 +426,8 @@ Search::deletePathsIncr(Vertex *vertex)
void
Search::deletePaths(Vertex *vertex)
{
debugPrint(debug_, "search", 4, "delete paths %s",
vertex->name(network_));
TagGroup *tag_group = tagGroup(vertex);
if (tag_group)
graph_->deletePaths(vertex);
@ -450,8 +445,8 @@ Search::findPathEnds(ExceptionFrom *from,
bool unconstrained,
const Corner *corner,
const MinMaxAll *min_max,
int group_path_count,
int endpoint_path_count,
size_t group_path_count,
size_t endpoint_path_count,
bool unique_pins,
float slack_min,
float slack_max,
@ -490,9 +485,6 @@ Search::findFilteredArrivals(ExceptionFrom *from,
bool thru_latches)
{
unconstrained_paths_ = unconstrained;
// Delete results from last findPathEnds.
// Filtered arrivals are deleted by Sta::searchPreamble.
deletePathGroups();
checkFromThrusTo(from, thrus, to);
filter_from_ = from;
filter_to_ = to;
@ -618,6 +610,7 @@ Search::findFilteredArrivals(bool thru_latches)
int arrival_count = arrival_iter_->visitParallel(max_level,
arrival_visitor_);
deleteTagsPrev();
genclks_->updateSrcPathPrevs();
debugPrint(debug_, "search", 1, "found %d arrivals", arrival_count);
}
arrivals_exist_ = true;
@ -725,6 +718,20 @@ Search::deleteVertexBefore(Vertex *vertex)
invalid_endpoints_->erase(vertex);
}
void
Search::deleteEdgeBefore(Edge *edge)
{
Vertex *from = edge->from(graph_);
Vertex *to = edge->to(graph_);
arrivalInvalid(to);
requiredInvalid(from);
VertexPathIterator path_iter(to, graph_);
while (path_iter.hasNext()) {
Path *path = path_iter.next();
path->clearPrevPath(this);
}
}
bool
Search::arrivalsValid()
{
@ -740,6 +747,7 @@ Search::arrivalsInvalid()
// Delete paths to make sure no state is left over.
// For example, set_disable_timing strands a vertex, which means
// the search won't revisit it to clear the previous arrival.
deletePathGroups();
deletePaths();
deleteTags();
genclks_->clear();
@ -865,6 +873,7 @@ Search::findClkArrivals()
arrival_visitor_->init(false, &search_clk);
arrival_iter_->visitParallel(levelize_->maxLevel(), arrival_visitor_);
deleteTagsPrev();
genclks_->updateSrcPathPrevs();
arrivals_exist_ = true;
stats.report("Find clk arrivals");
}
@ -1036,6 +1045,7 @@ Search::findArrivals1(Level level)
Stats stats(debug_, report_);
int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_);
deleteTagsPrev();
genclks_->updateSrcPathPrevs();
stats.report("Find arrivals");
if (arrival_iter_->empty()
&& invalid_arrivals_->empty()) {
@ -1043,7 +1053,7 @@ Search::findArrivals1(Level level)
arrivals_at_endpoints_exist_ = true;
}
arrivals_exist_ = true;
debugPrint(debug_, "search", 1, "found %u arrivals", arrival_count);
debugPrint(debug_, "search", 1, "found %d arrivals", arrival_count);
}
void
@ -1066,8 +1076,7 @@ Search::findArrivalsSeed()
////////////////////////////////////////////////////////////////
ArrivalVisitor::ArrivalVisitor(const StaState *sta) :
PathVisitor(nullptr, sta),
always_save_prev_paths_(true)
PathVisitor(nullptr, sta)
{
init0();
init(true);
@ -1104,8 +1113,6 @@ ArrivalVisitor::init(bool always_to_endpoints,
always_to_endpoints_ = always_to_endpoints;
pred_ = pred;
crpr_active_ = sdc_->crprActive();
if (search_)
always_save_prev_paths_ = search_->alwaysSavePrevPaths();
}
@ -1187,9 +1194,7 @@ ArrivalVisitor::visit(Vertex *vertex)
|| arrivals_changed)
search_->arrivalIterator()->enqueueAdjacentVertices(vertex, adj_pred_);
if (arrivals_changed) {
debugPrint(debug_, "search", 4, "arrival changed");
// Only update arrivals when delays change by more than
// fuzzyEqual can distinguish.
debugPrint(debug_, "search", 4, "arrivals changed");
search_->setVertexArrivals(vertex, tag_bldr_);
search_->tnsInvalid(vertex);
constrainedRequiredsInvalid(vertex, is_clk);
@ -1239,28 +1244,21 @@ bool
Search::arrivalsChanged(Vertex *vertex,
TagGroupBldr *tag_bldr)
{
Arrival *arrivals1 = graph_->arrivals(vertex);
PathPrev *prev_paths1 = graph_->prevPaths(vertex);
if (arrivals1) {
Path *paths1 = graph_->paths(vertex);
if (paths1) {
TagGroup *tag_group = tagGroup(vertex);
if (tag_group == nullptr
|| tag_group->arrivalMap()->size() != tag_bldr->arrivalMap()->size())
|| tag_group->pathCount() != tag_bldr->pathCount())
return true;
ArrivalMap::Iterator arrival_iter1(tag_group->arrivalMap());
while (arrival_iter1.hasNext()) {
Tag *tag1;
int arrival_index1;
arrival_iter1.next(tag1, arrival_index1);
Arrival &arrival1 = arrivals1[arrival_index1];
Tag *tag2;
Arrival arrival2;
int arrival_index2;
tag_bldr->tagMatchArrival(tag1, tag2, arrival2, arrival_index2);
if (tag2 != tag1
|| !delayEqual(arrival1, arrival2)
|| (prev_paths1
&& !PathPrev::equal(prev_paths1[arrival_index1],
tag_bldr->prevPath(arrival_index2))))
for (auto const [tag1, path_index1] : *tag_group->pathIndexMap()) {
Path *path1 = &paths1[path_index1];
Path *path2 = tag_bldr->tagMatchPath(tag1);
if (path2 == nullptr
|| path1->tag(this) != path2->tag(this)
|| !delayEqual(path1->arrival(), path2->arrival())
|| path1->prevEdge(this) != path2->prevEdge(this)
|| path1->prevArc(this) != path2->prevArc(this)
|| path1->prevPath() != path2->prevPath())
return true;
}
return false;
@ -1270,11 +1268,11 @@ Search::arrivalsChanged(Vertex *vertex,
}
bool
ArrivalVisitor::visitFromToPath(const Pin *,
ArrivalVisitor::visitFromToPath(const Pin * /* from_pin */,
Vertex *from_vertex,
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
Path *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
@ -1298,39 +1296,27 @@ ArrivalVisitor::visitFromToPath(const Pin *,
to_tag->asString(this));
ClkInfo *to_clk_info = to_tag->clkInfo();
bool to_is_clk = to_tag->isClock();
Arrival arrival;
int arrival_index;
Tag *tag_match;
tag_bldr_->tagMatchArrival(to_tag, tag_match, arrival, arrival_index);
if (tag_match == nullptr
|| delayGreater(to_arrival, arrival, min_max, this)) {
Path *match;
size_t path_index;
tag_bldr_->tagMatchPath(to_tag, match, path_index);
if (match == nullptr
|| delayGreater(to_arrival, match->arrival(), min_max, this)) {
debugPrint(debug_, "search", 3, " %s + %s = %s %s %s",
delayAsString(from_arrival, this),
delayAsString(arc_delay, this),
delayAsString(to_arrival, this),
min_max == MinMax::max() ? ">" : "<",
tag_match ? delayAsString(arrival, this) : "MIA");
PathPrev prev_path;
bool always_save_prev_paths = true;
bool save_prev = always_save_prev_paths
|| to_tag->isClock()
|| to_tag->isGenClkSrcPath();
if (save_prev)
prev_path.init(from_path, edge, arc, this);
tag_bldr_->setMatchArrival(to_tag, tag_match,
to_arrival, arrival_index,
&prev_path);
match ? delayAsString(match->arrival(), this) : "MIA");
tag_bldr_->setMatchPath(match, path_index, to_tag, to_arrival, from_path, edge, arc);
if (crpr_active_
&& !has_fanin_one_
&& to_clk_info->hasCrprClkPin()
&& !to_is_clk) {
tag_bldr_no_crpr_->tagMatchArrival(to_tag, tag_match,
arrival, arrival_index);
if (tag_match == nullptr
|| delayGreater(to_arrival, arrival, min_max, this)) {
tag_bldr_no_crpr_->setMatchArrival(to_tag, tag_match,
to_arrival, arrival_index,
&prev_path);
tag_bldr_no_crpr_->tagMatchPath(to_tag, match, path_index);
if (match == nullptr
|| delayGreater(to_arrival, match->arrival(), min_max, this)) {
tag_bldr_no_crpr_->setMatchPath(match, path_index, to_tag, to_arrival,
from_path, edge, arc);
}
}
}
@ -1341,23 +1327,20 @@ void
ArrivalVisitor::pruneCrprArrivals()
{
CheckCrpr *crpr = search_->checkCrpr();
ArrivalMap *arrival_map = tag_bldr_->arrivalMap();
for (auto arrival_itr = arrival_map->cbegin(); arrival_itr != arrival_map->cend(); ) {
Tag *tag = arrival_itr->first;
int arrival_index = arrival_itr->second;
PathIndexMap &path_index_map = tag_bldr_->pathIndexMap();
for (auto path_itr = path_index_map.cbegin(); path_itr != path_index_map.cend(); ) {
Tag *tag = path_itr->first;
size_t path_index = path_itr->second;
ClkInfo *clk_info = tag->clkInfo();
bool deleted_tag = false;
if (!tag->isClock()
&& clk_info->hasCrprClkPin()) {
PathAnalysisPt *path_ap = tag->pathAnalysisPt(this);
const MinMax *min_max = path_ap->pathMinMax();
Tag *tag_no_crpr;
Arrival max_arrival;
int max_arrival_index;
tag_bldr_no_crpr_->tagMatchArrival(tag, tag_no_crpr,
max_arrival, max_arrival_index);
if (tag_no_crpr) {
ClkInfo *clk_info_no_crpr = tag_no_crpr->clkInfo();
Path *path_no_crpr = tag_bldr_no_crpr_->tagMatchPath(tag);
if (path_no_crpr) {
Arrival max_arrival = path_no_crpr->arrival();
ClkInfo *clk_info_no_crpr = path_no_crpr->clkInfo(this);
Arrival max_crpr = crpr->maxCrpr(clk_info_no_crpr);
Arrival max_arrival_max_crpr = (min_max == MinMax::max())
? max_arrival - max_crpr
@ -1367,17 +1350,17 @@ ArrivalVisitor::pruneCrprArrivals()
delayAsString(max_arrival, this),
delayAsString(max_crpr, this),
delayAsString(max_arrival_max_crpr, this));
Arrival arrival = tag_bldr_->arrival(arrival_index);
Arrival arrival = tag_bldr_->arrival(path_index);
if (delayGreater(max_arrival_max_crpr, arrival, min_max, this)) {
debugPrint(debug_, "search", 3, " pruned %s",
tag->asString(this));
arrival_itr = arrival_map->erase(arrival_itr);
path_itr = path_index_map.erase(path_itr);
deleted_tag = true;
}
}
}
if (!deleted_tag)
arrival_itr++;
path_itr++;
}
}
@ -1506,8 +1489,9 @@ Search::seedArrival(Vertex *vertex)
}
}
else {
debugPrint(debug_, "search", 2, "arrival enqueue %s",
network_->pathName(pin));
debugPrint(debug_, "search", 4, "arrival enqueue %s %u",
network_->pathName(pin),
vertex->level());
arrival_iter_->enqueue(vertex);
}
}
@ -1599,7 +1583,7 @@ Search::seedClkArrival(const Pin *pin,
sdc_->exceptionFromClkStates(pin,rf,clk,rf,min_max,states);
Tag *tag = findTag(rf, path_ap, clk_info, true, nullptr, false, states, true);
Arrival arrival(clk_edge->time() + insertion);
tag_bldr->setArrival(tag, arrival, nullptr);
tag_bldr->setArrival(tag, arrival);
}
void
@ -1616,7 +1600,7 @@ Search::seedClkDataArrival(const Pin *pin,
if (tag) {
// Data arrivals include insertion delay.
Arrival arrival(clk_edge->time() + insertion);
tag_bldr->setArrival(tag, arrival, nullptr);
tag_bldr->setArrival(tag, arrival);
}
}
@ -1658,7 +1642,7 @@ Search::makeUnclkedPaths(Vertex *vertex,
is_segment_start,
require_exception);
if (tag) {
tag_bldr->setArrival(tag, delay_zero, nullptr);
tag_bldr->setArrival(tag, delay_zero);
search_from = true;
}
}
@ -1869,7 +1853,7 @@ Search::inputDelayRefPinArrival(Path *ref_path,
Clock *clk = clk_edge->clock();
if (clk->isPropagated()) {
ClkInfo *clk_info = ref_path->clkInfo(this);
ref_arrival = delayAsFloat(ref_path->arrival(this));
ref_arrival = delayAsFloat(ref_path->arrival());
ref_insertion = delayAsFloat(clk_info->insertion());
ref_latency = clk_info->latency();
}
@ -1930,7 +1914,7 @@ Search::seedInputDelayArrival(const Pin *pin,
Tag *tag = inputDelayTag(pin, rf, clk_edge, clk_insertion, clk_latency,
input_delay, is_segment_start, min_max, path_ap);
if (tag)
tag_bldr->setArrival(tag, arrival, nullptr);
tag_bldr->setArrival(tag, arrival);
}
void
@ -2075,7 +2059,7 @@ PathVisitor::visitEdge(const Pin *from_pin,
TimingArcSet *arc_set = edge->timingArcSet();
VertexPathIterator from_iter(from_vertex, search_);
while (from_iter.hasNext()) {
PathVertex *from_path = from_iter.next();
Path *from_path = from_iter.next();
PathAnalysisPt *path_ap = from_path->pathAnalysisPt(this);
const MinMax *min_max = path_ap->pathMinMax();
const RiseFall *from_rf = from_path->transition(this);
@ -2098,7 +2082,7 @@ bool
PathVisitor::visitArc(const Pin *from_pin,
Vertex *from_vertex,
const RiseFall *from_rf,
PathVertex *from_path,
Path *from_path,
Edge *edge,
TimingArc *arc,
const Pin *to_pin,
@ -2120,7 +2104,7 @@ bool
PathVisitor::visitFromPath(const Pin *from_pin,
Vertex *from_vertex,
const RiseFall *from_rf,
PathVertex *from_path,
Path *from_path,
Edge *edge,
TimingArc *arc,
const Pin *to_pin,
@ -2135,7 +2119,7 @@ PathVisitor::visitFromPath(const Pin *from_pin,
Tag *to_tag = nullptr;
const ClockEdge *clk_edge = from_clk_info->clkEdge();
const Clock *clk = from_clk_info->clock();
Arrival from_arrival = from_path->arrival(this);
Arrival from_arrival = from_path->arrival();
ArcDelay arc_delay = 0.0;
Arrival to_arrival;
if (from_clk_info->isGenClkSrcPath()) {
@ -2202,7 +2186,7 @@ PathVisitor::visitFromPath(const Pin *from_pin,
&& from_tag->isClock())) {
const RiseFall *clk_rf = clk_edge ? clk_edge->transition() : nullptr;
ClkInfo *to_clk_info = from_clk_info;
if (from_clk_info->crprClkPath().isNull()
if (from_clk_info->crprClkPath(this) == nullptr
|| network_->direction(to_pin)->isInternal())
to_clk_info = search_->clkInfoWithCrprClkPath(from_clk_info,
from_path, path_ap);
@ -2308,7 +2292,7 @@ Search::clkPathArrival(const Path *clk_path,
+ clk_info->latency();
}
else
return clk_path->arrival(this);
return clk_path->arrival();
}
Arrival
@ -2316,9 +2300,9 @@ Search::pathClkPathArrival(const Path *path) const
{
ClkInfo *clk_info = path->clkInfo(this);
if (clk_info->isPropagated()) {
PathRef src_clk_path = pathClkPathArrival1(path);
if (!src_clk_path.isNull())
return clkPathArrival(&src_clk_path);
const Path *src_clk_path = pathClkPathArrival1(path);
if (src_clk_path)
return clkPathArrival(src_clk_path);
}
// Check for input arrival clock.
const ClockEdge *clk_edge = path->clkEdge(this);
@ -2328,34 +2312,30 @@ Search::pathClkPathArrival(const Path *path) const
}
// PathExpanded::expand() and PathExpanded::clkPath().
PathRef
const Path *
Search::pathClkPathArrival1(const Path *path) const
{
PathRef p(path);
while (!p.isNull()) {
PathRef prev_path;
TimingArc *prev_arc;
p.prevPath(this, prev_path, prev_arc);
const Path *p = path;
while (p) {
Path *prev_path = p->prevPath();
Edge *prev_edge = p->prevEdge(this);
if (p.isClock(this))
if (p->isClock(this))
return p;
if (prev_arc) {
TimingRole *prev_role = prev_arc->role();
if (prev_edge) {
TimingRole *prev_role = prev_edge->role();
if (prev_role == TimingRole::regClkToQ()
|| prev_role == TimingRole::latchEnToQ()) {
p.prevPath(this, prev_path, prev_arc);
return prev_path;
return p->prevPath();
}
else if (prev_role == TimingRole::latchDtoQ()) {
Edge *prev_edge = p.prevEdge(prev_arc, this);
PathVertex enable_path;
latches_->latchEnablePath(&p, prev_edge, enable_path);
Path *enable_path = latches_->latchEnablePath(p, prev_edge);
return enable_path;
}
}
p.init(prev_path);
p = prev_path;
}
return PathRef();
return nullptr;
}
////////////////////////////////////////////////////////////////
@ -2405,7 +2385,7 @@ Search::fromRegClkTag(const Pin *from_pin,
// Insert from_path as ClkInfo crpr_clk_path.
ClkInfo *
Search::clkInfoWithCrprClkPath(ClkInfo *from_clk_info,
PathVertex *from_path,
Path *from_path,
const PathAnalysisPt *path_ap)
{
if (sdc_->crprActive())
@ -2447,7 +2427,7 @@ Search::thruTag(Tag *from_tag,
// thruTag for clocks.
Tag *
Search::thruClkTag(PathVertex *from_path,
Search::thruClkTag(Path *from_path,
Vertex *from_vertex,
Tag *from_tag,
bool to_propagates_clk,
@ -2479,7 +2459,7 @@ Search::thruClkTag(PathVertex *from_path,
}
ClkInfo *
Search::thruClkInfo(PathVertex *from_path,
Search::thruClkInfo(Path *from_path,
Vertex *from_vertex,
ClkInfo *from_clk_info,
bool from_is_clk,
@ -2516,7 +2496,7 @@ Search::thruClkInfo(PathVertex *from_path,
changed = true;
}
PathVertex *to_crpr_clk_path = nullptr;
Path *to_crpr_clk_path = nullptr;
if (sdc_->crprActive()
// Update crpr clk path for combinational paths leaving the clock
// network (ie, tristate en->out) and buffer driving reg clk.
@ -2747,54 +2727,27 @@ Search::setVertexArrivals(Vertex *vertex,
deletePathsIncr(vertex);
else {
TagGroup *prev_tag_group = tagGroup(vertex);
Arrival *prev_arrivals = graph_->arrivals(vertex);
PathPrev *prev_paths = graph_->prevPaths(vertex);
bool save_prev = always_save_prev_paths_
|| tag_bldr->hasClkTag()
|| tag_bldr->hasGenClkSrcTag();
Path *prev_paths = graph_->paths(vertex);
TagGroup *tag_group = findTagGroup(tag_bldr);
int arrival_count = tag_group->arrivalCount();
bool has_requireds = vertex->hasRequireds();
// Reuse arrival array if it is the same size.
size_t path_count = tag_group->pathCount();
// Reuse path array if it is the same size.
if (prev_tag_group
&& arrival_count == prev_tag_group->arrivalCount()) {
if (save_prev) {
if (prev_paths == nullptr)
prev_paths = graph_->makePrevPaths(vertex, arrival_count);
}
else {
// Prev paths not required.
prev_paths = nullptr;
graph_->deletePrevPaths(vertex);
}
tag_bldr->copyArrivals(tag_group, prev_arrivals, prev_paths);
&& path_count == prev_tag_group->pathCount()) {
tag_bldr->copyPaths(tag_group, prev_paths);
vertex->setTagGroupIndex(tag_group->index());
if (tag_group->hasFilterTag()) {
LockGuard lock(filtered_arrivals_lock_);
filtered_arrivals_->insert(vertex);
}
if (has_requireds) {
requiredInvalid(vertex);
if (tag_group != prev_tag_group)
// Requireds can only be reused if the tag group is unchanged.
graph_->deleteRequireds(vertex);
}
requiredInvalid(vertex);
}
else {
if (prev_tag_group) {
graph_->deleteArrivals(vertex);
if (has_requireds) {
requiredInvalid(vertex);
graph_->deleteRequireds(vertex);
}
graph_->deletePaths(vertex);
requiredInvalid(vertex);
}
Arrival *arrivals = graph_->makeArrivals(vertex, arrival_count);
prev_paths = nullptr;
if (save_prev)
prev_paths = graph_->makePrevPaths(vertex, arrival_count);
tag_bldr->copyArrivals(tag_group, arrivals, prev_paths);
Path *paths = graph_->makePaths(vertex, path_count);
tag_bldr->copyPaths(tag_group, paths);
vertex->setTagGroupIndex(tag_group->index());
if (tag_group->hasFilterTag()) {
@ -2810,56 +2763,38 @@ Search::reportArrivals(Vertex *vertex) const
{
report_->reportLine("Vertex %s", vertex->name(sdc_network_));
TagGroup *tag_group = tagGroup(vertex);
Arrival *arrivals = graph_->arrivals(vertex);
Required *requireds = graph_->requireds(vertex);
PathPrev *prev_paths = graph_->prevPaths(vertex);
if (tag_group) {
report_->reportLine("Group %u", tag_group->index());
ArrivalMap::Iterator arrival_iter(tag_group->arrivalMap());
while (arrival_iter.hasNext()) {
Tag *tag;
int arrival_index;
arrival_iter.next(tag, arrival_index);
PathAnalysisPt *path_ap = tag->pathAnalysisPt(this);
VertexPathIterator path_iter(vertex, this);
while (path_iter.hasNext()) {
const Path *path = path_iter.next();
const Tag *tag = path->tag(this);
const PathAnalysisPt *path_ap = tag->pathAnalysisPt(this);
const RiseFall *rf = tag->transition();
const char *req = "?";
if (requireds)
req = delayAsString(requireds[arrival_index], this);
bool report_clk_prev = false;
const char *clk_prev = "";
if (report_clk_prev
&& tag_group->hasClkTag()) {
PathVertex prev = check_crpr_->clkPathPrev(vertex, arrival_index);
if (!prev.isNull())
clk_prev = prev.name(this);
}
const char *req = delayAsString(path->required(), this);
string prev_str;
if (prev_paths) {
PathPrev &prev = prev_paths[arrival_index];
if (!prev.isNull()) {
prev_str += prev.name(this);
prev_str += " ";
const Edge *prev_edge = prev.prevEdge(this);
TimingArc *arc = prev.prevArc(this);
prev_str += prev_edge->from(graph_)->name(network_);
prev_str += " ";
prev_str += arc->fromEdge()->asString();
prev_str += " -> ";
prev_str += prev_edge->to(graph_)->name(network_);
prev_str += " ";
prev_str += arc->toEdge()->asString();
}
else
prev_str = "NULL";
Path *prev_path = path->prevPath();
if (prev_path) {
prev_str += prev_path->name(this);
prev_str += " ";
const Edge *prev_edge = path->prevEdge(this);
TimingArc *arc = path->prevArc(this);
prev_str += prev_edge->from(graph_)->name(network_);
prev_str += " ";
prev_str += arc->fromEdge()->asString();
prev_str += " -> ";
prev_str += prev_edge->to(graph_)->name(network_);
prev_str += " ";
prev_str += arc->toEdge()->asString();
}
report_->reportLine(" %d %s %s %s / %s %s %s prev %s",
arrival_index,
else
prev_str = "NULL";
report_->reportLine(" %s %s %s / %s %s prev %s",
rf->asString(),
path_ap->pathMinMax()->asString(),
delayAsString(arrivals[arrival_index], this),
delayAsString(path->arrival(), this),
req,
tag->asString(true, false, this),
clk_prev,
prev_str.c_str());
}
}
@ -2913,7 +2848,7 @@ Search::reportTagGroups() const
}
void
Search::reportArrivalCountHistogram() const
Search::reportPathCountHistogram() const
{
Vector<int> vertex_counts(10);
VertexIterator vertex_iter(graph_);
@ -2921,17 +2856,17 @@ Search::reportArrivalCountHistogram() const
Vertex *vertex = vertex_iter.next();
TagGroup *tag_group = tagGroup(vertex);
if (tag_group) {
size_t arrival_count = tag_group->arrivalCount();
if (arrival_count >= vertex_counts.size())
vertex_counts.resize(arrival_count * 2);
vertex_counts[arrival_count]++;
size_t path_count = tag_group->pathCount();
if (path_count >= vertex_counts.size())
vertex_counts.resize(path_count * 2);
vertex_counts[path_count]++;
}
}
for (size_t arrival_count = 0; arrival_count < vertex_counts.size(); arrival_count++) {
int vertex_count = vertex_counts[arrival_count];
for (size_t path_count = 0; path_count < vertex_counts.size(); path_count++) {
int vertex_count = vertex_counts[path_count];
if (vertex_count > 0)
report_->reportLine("%6lu %6d", arrival_count, vertex_count);
report_->reportLine("%6lu %6d",path_count, vertex_count);
}
}
@ -3043,19 +2978,18 @@ Search::findClkInfo(const ClockEdge *clk_edge,
float latency,
ClockUncertainties *uncertainties,
const PathAnalysisPt *path_ap,
PathVertex *crpr_clk_path)
Path *crpr_clk_path)
{
PathVertexPtr crpr_clk_path_ptr(crpr_clk_path, this);
ClkInfo probe(clk_edge, clk_src, is_propagated, gen_clk_src, gen_clk_src_path,
pulse_clk_sense, insertion, latency, uncertainties,
path_ap->index(), crpr_clk_path_ptr, this);
path_ap->index(), crpr_clk_path, this);
LockGuard lock(clk_info_lock_);
ClkInfo *clk_info = clk_info_set_->findKey(&probe);
if (clk_info == nullptr) {
clk_info = new ClkInfo(clk_edge, clk_src,
is_propagated, gen_clk_src, gen_clk_src_path,
pulse_clk_sense, insertion, latency, uncertainties,
path_ap->index(), crpr_clk_path_ptr, this);
path_ap->index(), crpr_clk_path, this);
clk_info_set_->insert(clk_info);
}
return clk_info;
@ -3234,6 +3168,7 @@ Search::findRequireds(Level level)
seedInvalidRequireds();
int required_count = required_iter_->visitParallel(level, &req_visitor);
deleteTagsPrev();
genclks_->updateSrcPathPrevs();
requireds_exist_ = true;
debugPrint(debug_, "search", 1, "found %d requireds", required_count);
stats.report("Find requireds");
@ -3398,13 +3333,11 @@ void
FindEndRequiredVisitor::visit(PathEnd *path_end)
{
if (!path_end->isUnconstrained()) {
PathRef &path = path_end->pathRef();
const MinMax *req_min = path.minMax(sta_)->opposite();
int arrival_index;
bool arrival_exists;
path.arrivalIndex(arrival_index, arrival_exists);
Path *path = path_end->path();
const MinMax *min_max = path->minMax(sta_)->opposite();
size_t path_index = path->pathIndex(sta_);
Required required = path_end->requiredTime(sta_);
required_cmp_->requiredSet(arrival_index, required, req_min, sta_);
required_cmp_->requiredSet(path_index, required, min_max, sta_);
}
}
@ -3449,31 +3382,27 @@ RequiredCmp::requiredsInit(Vertex *vertex,
Search *search = sta->search();
TagGroup *tag_group = search->tagGroup(vertex);
if (tag_group) {
requireds_.resize(tag_group->arrivalCount());
ArrivalMap *arrival_entries = tag_group->arrivalMap();
ArrivalMap::Iterator arrival_iter(arrival_entries);
while (arrival_iter.hasNext()) {
Tag *tag;
int arrival_index;
arrival_iter.next(tag, arrival_index);
size_t path_count = tag_group->pathCount();
requireds_.resize(path_count);
for (auto const [tag, path_index] : *tag_group->pathIndexMap()) {
PathAnalysisPt *path_ap = tag->pathAnalysisPt(sta);
const MinMax *min_max = path_ap->pathMinMax();
requireds_[arrival_index] = delayInitValue(min_max->opposite());
requireds_[path_index] = delayInitValue(min_max->opposite());
}
}
else
requireds_.resize(0);
requireds_.clear();
have_requireds_ = false;
}
void
RequiredCmp::requiredSet(int arrival_index,
Required required,
RequiredCmp::requiredSet(size_t path_index,
Required &required,
const MinMax *min_max,
const StaState *sta)
{
if (delayGreater(required, requireds_[arrival_index], min_max, sta)) {
requireds_[arrival_index] = required;
if (delayGreater(required, requireds_[path_index], min_max, sta)) {
requireds_[path_index] = required;
have_requireds_ = true;
}
}
@ -3483,53 +3412,26 @@ RequiredCmp::requiredsSave(Vertex *vertex,
const StaState *sta)
{
bool requireds_changed = false;
bool prev_reqs = vertex->hasRequireds();
if (have_requireds_) {
if (!prev_reqs)
requireds_changed = true;
Debug *debug = sta->debug();
VertexPathIterator path_iter(vertex, sta);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
int arrival_index;
bool arrival_exists;
path->arrivalIndex(arrival_index, arrival_exists);
Required req = requireds_[arrival_index];
if (prev_reqs) {
Required prev_req = path->required(sta);
if (!delayEqual(prev_req, req)) {
debugPrint(debug, "search", 3, "required save %s -> %s",
delayAsString(prev_req, sta),
delayAsString(req, sta));
path->setRequired(req, sta);
requireds_changed = true;
}
}
else {
debugPrint(debug, "search", 3, "required save MIA -> %s",
delayAsString(req, sta));
path->setRequired(req, sta);
}
}
}
else if (prev_reqs) {
Graph *graph = sta->graph();
const Search *search = sta->search();
TagGroup *tag_group = search->tagGroup(vertex);
if (tag_group == nullptr)
requireds_changed = true;
else {
graph->deleteRequireds(vertex);
requireds_changed = true;
}
Debug *debug = sta->debug();
VertexPathIterator path_iter(vertex, sta);
while (path_iter.hasNext()) {
Path *path = path_iter.next();
size_t path_index = path->pathIndex(sta);
Required req = requireds_[path_index];
Required &prev_req = path->required();
debugPrint(debug, "search", 3, "required save %s -> %s",
delayAsString(prev_req, sta),
delayAsString(req, sta));
requireds_changed |= !delayEqual(prev_req, req);
path->setRequired(req);
}
return requireds_changed;
}
Required
RequiredCmp::required(int arrival_index)
RequiredCmp::required(size_t path_index)
{
return requireds_[arrival_index];
return requireds_[path_index];
}
////////////////////////////////////////////////////////////////
@ -3575,10 +3477,10 @@ RequiredVisitor::visit(Vertex *vertex)
bool
RequiredVisitor::visitFromToPath(const Pin *,
Vertex *,
Vertex * /* from_vertex */,
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
Path *from_path,
const Arrival &,
Edge *edge,
TimingArc *,
@ -3599,15 +3501,14 @@ RequiredVisitor::visitFromToPath(const Pin *,
debugPrint(debug_, "search", 3, " from tag %2u: %s",
from_tag->index(),
from_tag->asString(this));
int arrival_index;
bool arrival_exists;
from_path->arrivalIndex(arrival_index, arrival_exists);
size_t path_index = from_path->pathIndex(this);
const MinMax *req_min = min_max->opposite();
TagGroup *to_tag_group = search_->tagGroup(to_vertex);
// Check to see if to_tag was pruned.
if (to_tag_group && to_tag_group->hasTag(to_tag)) {
PathVertex to_path(to_vertex, to_tag, this);
Required to_required = to_path.required(this);
size_t to_path_index = to_tag_group->pathIndex(to_tag);
Path &to_path = to_vertex->paths()[to_path_index];
Required &to_required = to_path.required();
Required from_required = to_required - arc_delay;
debugPrint(debug_, "search", 3, " to tag %2u: %s",
to_tag->index(),
@ -3617,8 +3518,8 @@ RequiredVisitor::visitFromToPath(const Pin *,
delayAsString(arc_delay, this),
delayAsString(from_required, this),
min_max == MinMax::max() ? "<" : ">",
delayAsString(required_cmp_->required(arrival_index), this));
required_cmp_->requiredSet(arrival_index, from_required, req_min, this);
delayAsString(required_cmp_->required(path_index), this));
required_cmp_->requiredSet(path_index, from_required, req_min, this);
}
else {
if (search_->crprApproxMissingRequireds()) {
@ -3627,10 +3528,10 @@ RequiredVisitor::visitFromToPath(const Pin *,
// as an appromate required.
VertexPathIterator to_iter(to_vertex, to_rf, path_ap, this);
while (to_iter.hasNext()) {
PathVertex *to_path = to_iter.next();
Path *to_path = to_iter.next();
Tag *to_path_tag = to_path->tag(this);
if (tagMatchNoCrpr(to_path_tag, to_tag)) {
Required to_required = to_path->required(this);
Required to_required = to_path->required();
Required from_required = to_required - arc_delay;
debugPrint(debug_, "search", 3, " to tag %2u: %s",
to_path_tag->index(),
@ -3640,9 +3541,9 @@ RequiredVisitor::visitFromToPath(const Pin *,
delayAsString(arc_delay, this),
delayAsString(from_required, this),
min_max == MinMax::max() ? "<" : ">",
delayAsString(required_cmp_->required(arrival_index),
delayAsString(required_cmp_->required(path_index),
this));
required_cmp_->requiredSet(arrival_index, from_required, req_min, this);
required_cmp_->requiredSet(path_index, from_required, req_min, this);
break;
}
}
@ -4024,8 +3925,8 @@ void
FindEndSlackVisitor::visit(PathEnd *path_end)
{
if (!path_end->isUnconstrained()) {
PathRef &path = path_end->pathRef();
PathAPIndex path_ap_index = path.pathAnalysisPtIndex(sta_);
Path *path = path_end->path();
PathAPIndex path_ap_index = path->pathAnalysisPtIndex(sta_);
Slack slack = path_end->slack(sta_);
if (delayLess(slack, slacks_[path_ap_index], sta_))
slacks_[path_ap_index] = slack;

View File

@ -51,11 +51,11 @@ private:
~VertexPathIterator();
};
class PathRef
class Path
{
private:
PathRef();
~PathRef();
Path();
~Path();
};
class PathEnd
@ -221,44 +221,32 @@ worst_slack_corner(const Corner *corner,
return worst_slack;
}
PathRef *
Path *
vertex_worst_arrival_path(Vertex *vertex,
const MinMax *min_max)
{
Sta *sta = Sta::sta();
sta->ensureLibLinked();
PathRef path = sta->vertexWorstArrivalPath(vertex, min_max);
if (!path.isNull())
return new PathRef(path);
else
return nullptr;
return sta->vertexWorstArrivalPath(vertex, min_max);
}
PathRef *
Path *
vertex_worst_arrival_path_rf(Vertex *vertex,
const RiseFall *rf,
MinMax *min_max)
{
Sta *sta = Sta::sta();
sta->ensureLibLinked();
PathRef path = sta->vertexWorstArrivalPath(vertex, rf, min_max);
if (!path.isNull())
return new PathRef(path);
else
return nullptr;
return sta->vertexWorstArrivalPath(vertex, rf, min_max);
}
PathRef *
Path *
vertex_worst_slack_path(Vertex *vertex,
const MinMax *min_max)
{
Sta *sta = Sta::sta();
sta->ensureLibLinked();
PathRef path = sta->vertexWorstSlackPath(vertex, min_max);
if (!path.isNull())
return new PathRef(path);
else
return nullptr;
return sta->vertexWorstSlackPath(vertex, min_max);
}
int
@ -280,9 +268,9 @@ report_tag_arrivals_cmd(Vertex *vertex)
}
void
report_arrival_count_histogram()
report_path_count_histogram()
{
Sta::sta()->search()->reportArrivalCountHistogram();
Sta::sta()->search()->reportPathCountHistogram();
}
int
@ -310,15 +298,9 @@ clk_info_count()
}
int
arrival_count()
path_count()
{
return Sta::sta()->arrivalCount();
}
int
required_count()
{
return Sta::sta()->requiredCount();
return Sta::sta()->pathCount();
}
int
@ -494,13 +476,7 @@ set_report_path_sigmas(bool report_sigmas)
}
void
delete_path_ref(PathRef *path)
{
delete path;
}
void
report_path_cmd(PathRef *path)
report_path_cmd(Path *path)
{
Sta::sta()->reportPath(path);
}
@ -1245,7 +1221,7 @@ path_end_property(PathEnd *end,
}
PropertyValue
path_ref_property(PathRef *path,
path_ref_property(Path *path,
const char *property)
{
return getProperty(path, property, Sta::sta());
@ -1275,7 +1251,7 @@ bool is_output_delay() { return self->isOutputDelay(); }
bool is_path_delay() { return self->isPathDelay(); }
bool is_gated_clock() { return self->isGatedClock(); }
Vertex *vertex() { return self->vertex(Sta::sta()); }
PathRef *path() { return &self->pathRef(); }
Path *path() { return self->path(); }
RiseFall *end_transition()
{ return const_cast<RiseFall*>(self->path()->transition(Sta::sta())); }
Slack slack() { return self->slack(Sta::sta()); }
@ -1312,19 +1288,17 @@ Delay clk_skew() { return self->clkSkew(Sta::sta()); }
}
%extend PathRef {
%extend Path {
float
arrival()
{
Sta *sta = Sta::sta();
return delayAsFloat(self->arrival(sta));
return delayAsFloat(self->arrival());
}
float
required()
{
Sta *sta = Sta::sta();
return delayAsFloat(self->required(sta));
return delayAsFloat(self->required());
}
float
@ -1354,12 +1328,10 @@ pins()
{
Sta *sta = Sta::sta();
PinSeq pins;
PathRef path1(self);
while (!path1.isNull()) {
pins.push_back(path1.vertex(sta)->pin());
PathRef prev_path;
path1.prevPath(sta, prev_path);
path1.init(prev_path);
Path *path1 = self;
while (path1) {
pins.push_back(path1->vertex(sta)->pin());
path1 = path1->prevPath();
}
return pins;
}
@ -1368,11 +1340,10 @@ pins()
%extend VertexPathIterator {
bool has_next() { return self->hasNext(); }
PathRef *
Path *
next()
{
Path *path = self->next();
return new PathRef(path);
return self->next();
}
void finish() { delete self; }

View File

@ -854,7 +854,6 @@ proc_redirect report_path {
report_line "Tag: [$path tag]"
}
report_path_cmd $path
delete_path_ref $path
set first 0
}
$path_iter finish
@ -865,7 +864,6 @@ proc_redirect report_path {
report_line "Tag: [$worst_path tag]"
}
report_path_cmd $worst_path
delete_path_ref $worst_path
}
}
}

View File

@ -2488,6 +2488,8 @@ Sta::searchPreamble()
findDelays();
updateGeneratedClks();
sdc_->searchPreamble();
// Delete results from last findPathEnds because they point to filtered arrivals.
search_->deletePathGroups();
search_->deleteFilteredArrivals();
}
@ -2759,82 +2761,82 @@ Sta::vertexPathIterator(Vertex *vertex,
return new VertexPathIterator(vertex, rf, min_max, this);
}
PathRef
Path *
Sta::vertexWorstArrivalPath(Vertex *vertex,
const MinMax *min_max)
{
return vertexWorstArrivalPath(vertex, nullptr, min_max);
}
PathRef
Path *
Sta::vertexWorstArrivalPath(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max)
{
PathRef worst_path;
Path *worst_path = nullptr;
Arrival worst_arrival = min_max->initValue();
VertexPathIterator path_iter(vertex, rf, min_max, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Arrival arrival = path->arrival(this);
Path *path = path_iter.next();
Arrival arrival = path->arrival();
if (!path->tag(this)->isGenClkSrcPath()
&& delayGreater(arrival, worst_arrival, min_max, this)) {
worst_arrival = arrival;
worst_path.init(path);
worst_path = path;
}
}
return worst_path;
}
PathRef
Path *
Sta::vertexWorstRequiredPath(Vertex *vertex,
const MinMax *min_max)
{
return vertexWorstRequiredPath(vertex, nullptr, min_max);
}
PathRef
Path *
Sta::vertexWorstRequiredPath(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max)
{
PathRef worst_path;
Path *worst_path = nullptr;
const MinMax *req_min_max = min_max->opposite();
Arrival worst_req = req_min_max->initValue();
VertexPathIterator path_iter(vertex, rf, min_max, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
const Required path_req = path->required(this);
Path *path = path_iter.next();
const Required path_req = path->required();
if (!path->tag(this)->isGenClkSrcPath()
&& delayGreater(path_req, worst_req, req_min_max, this)) {
worst_req = path_req;
worst_path.init(path);
worst_path = path;
}
}
return worst_path;
}
PathRef
Path *
Sta::vertexWorstSlackPath(Vertex *vertex,
const RiseFall *rf,
const MinMax *min_max)
{
PathRef worst_path;
Path *worst_path = nullptr;
Slack min_slack = MinMax::min()->initValue();
VertexPathIterator path_iter(vertex, rf, min_max, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
Slack slack = path->slack(this);
if (!path->tag(this)->isGenClkSrcPath()
&& delayLess(slack, min_slack, this)) {
min_slack = slack;
worst_path.init(path);
worst_path = path;
}
}
return worst_path;
}
PathRef
Path *
Sta::vertexWorstSlackPath(Vertex *vertex,
const MinMax *min_max)
@ -2891,12 +2893,12 @@ Sta::vertexArrival(Vertex *vertex,
VertexPathIterator path_iter(vertex, rf, path_ap, this);
while (path_iter.hasNext()) {
Path *path = path_iter.next();
const Arrival &path_arrival = path->arrival(this);
const Arrival &path_arrival = path->arrival();
ClkInfo *clk_info = path->clkInfo(search_);
if ((clk_edge == clk_edge_wildcard
|| clk_info->clkEdge() == clk_edge)
&& !clk_info->isGenClkSrcPath()
&& delayGreater(path->arrival(this), arrival, min_max, this))
&& delayGreater(path->arrival(), arrival, min_max, this))
arrival = path_arrival;
}
return arrival;
@ -2949,7 +2951,7 @@ Sta::vertexRequired(Vertex *vertex,
VertexPathIterator path_iter(vertex, rf, path_ap, min_max, this);
while (path_iter.hasNext()) {
const Path *path = path_iter.next();
const Required path_required = path->required(this);
const Required path_required = path->required();
if ((clk_edge == clk_edge_wildcard
|| path->clkEdge(search_) == clk_edge)
&& delayGreater(path_required, required, req_min_max, this))
@ -3177,7 +3179,7 @@ bool
MinPeriodEndVisitor::pathIsFromInputPort(PathEnd *path_end)
{
PathExpanded expanded(path_end->path(), sta_);
const PathRef *start = expanded.startPath();
const Path *start = expanded.startPath();
Graph *graph = sta_->graph();
const Pin *first_pin = start->pin(graph);
Network *network = sta_->network();
@ -3539,14 +3541,14 @@ Sta::pathDcalcAnalysisPt(Path *path)
}
Vertex *
Sta::maxArrivalCountVertex() const
Sta::maxPathCountVertex() const
{
Vertex *max_vertex = nullptr;
int max_count = 0;
VertexIterator vertex_iter(graph_);
while (vertex_iter.hasNext()) {
Vertex *vertex = vertex_iter.next();
int count = vertexArrivalCount(vertex);
int count = vertexPathCount(vertex);
if (count > max_count) {
max_count = count;
max_vertex = vertex;
@ -3556,36 +3558,23 @@ Sta::maxArrivalCountVertex() const
}
int
Sta::vertexArrivalCount(Vertex *vertex) const
Sta::vertexPathCount(Vertex *vertex) const
{
TagGroup *tag_group = search_->tagGroup(vertex);
if (tag_group)
return tag_group->arrivalCount();
return tag_group->pathCount();
else
return 0;
}
int
Sta::arrivalCount() const
Sta::pathCount() const
{
int count = 0;
VertexIterator vertex_iter(graph_);
while (vertex_iter.hasNext()) {
Vertex *vertex = vertex_iter.next();
count += vertexArrivalCount(vertex);
}
return count;
}
int
Sta::requiredCount() const
{
int count = 0;
VertexIterator vertex_iter(graph_);
while (vertex_iter.hasNext()) {
Vertex *vertex = vertex_iter.next();
if (vertex->hasRequireds())
count += vertexArrivalCount(vertex);
count += vertexPathCount(vertex);
}
return count;
}
@ -4195,6 +4184,8 @@ Sta::makePortPin(const char *port_name,
void
Sta::makeInstanceAfter(const Instance *inst)
{
debugPrint(debug_, "network_edit", 1, "make instance %s",
sdc_network_->pathName(inst));
if (graph_) {
LibertyCell *lib_cell = network_->libertyCell(inst);
if (lib_cell) {
@ -4367,6 +4358,9 @@ Sta::replaceCellAfter(const Instance *inst)
void
Sta::connectPinAfter(const Pin *pin)
{
debugPrint(debug_, "network_edit", 1, "connect %s to %s",
sdc_network_->pathName(pin),
sdc_network_->pathName(network_->net(pin)));
if (graph_) {
if (network_->isHierarchical(pin)) {
graph_->makeWireEdgesThruPin(pin);
@ -4453,6 +4447,9 @@ Sta::connectLoadPinAfter(Vertex *vertex)
void
Sta::disconnectPinBefore(const Pin *pin)
{
debugPrint(debug_, "network_edit", 1, "disconnect %s from %s",
sdc_network_->pathName(pin),
sdc_network_->pathName(network_->net(pin)));
parasitics_->disconnectPinBefore(pin, network_);
sdc_->disconnectPinBefore(pin);
sim_->disconnectPinBefore(pin);
@ -4500,10 +4497,11 @@ Sta::disconnectPinBefore(const Pin *pin)
void
Sta::deleteEdge(Edge *edge)
{
Vertex *from = edge->from(graph_);
debugPrint(debug_, "network_edit", 1, "delete edge %s -> %s",
edge->from(graph_)->name(sdc_network_),
edge->to(graph_)->name(sdc_network_));
Vertex *to = edge->to(graph_);
search_->arrivalInvalid(to);
search_->requiredInvalid(from);
search_->deleteEdgeBefore(edge);
graph_delay_calc_->delayInvalid(to);
levelize_->relevelizeFrom(to);
levelize_->deleteEdgeBefore(edge);
@ -4514,6 +4512,8 @@ Sta::deleteEdge(Edge *edge)
void
Sta::deleteNetBefore(const Net *net)
{
debugPrint(debug_, "network_edit", 1, "delete net %s",
sdc_network_->pathName(net));
if (graph_) {
NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net);
while (pin_iter->hasNext()) {
@ -4540,6 +4540,8 @@ Sta::deleteNetBefore(const Net *net)
void
Sta::deleteInstanceBefore(const Instance *inst)
{
debugPrint(debug_, "network_edit", 1, "delete instance %s",
sdc_network_->pathName(inst));
if (network_->isLeaf(inst)) {
deleteInstancePinsBefore(inst);
deleteLeafInstanceBefore(inst);
@ -5715,7 +5717,7 @@ Sta::activity(const Pin *pin)
////////////////////////////////////////////////////////////////
void
Sta::writePathSpice(PathRef *path,
Sta::writePathSpice(Path *path,
const char *spice_filename,
const char *subckt_filename,
const char *lib_subckt_filename,

View File

@ -148,10 +148,10 @@ Tag::asString(bool report_index,
result += network->pathName(clk_src);
}
const PathVertex crpr_clk_path(clk_info_->crprClkPath(), sta);
if (!crpr_clk_path.isNull()) {
const Path *crpr_clk_path = clk_info_->crprClkPath(sta);
if (crpr_clk_path != nullptr) {
result += " crpr_pin ";
result += network->pathName(crpr_clk_path.pin(sta));
result += network->pathName(crpr_clk_path->pin(sta));
}
if (input_delay_) {
@ -280,11 +280,12 @@ Tag::findHash()
}
size_t
Tag::matchHash(bool match_crpr_clk_pin) const
Tag::matchHash(bool match_crpr_clk_pin,
const StaState *sta) const
{
if (match_crpr_clk_pin)
// match_hash_ with crpr clk pin thrown in.
return hashSum(match_hash_, clk_info_->crprClkVertexId());
return hashSum(match_hash_, clk_info_->crprClkVertexId(sta));
else
return match_hash_;
}
@ -421,7 +422,7 @@ tagMatch(const Tag *tag1,
&& clk_info1->isGenClkSrcPath() == clk_info2->isGenClkSrcPath()
&& (!match_crpr_clk_pin
|| !sta->sdc()->crprActive()
|| clk_info1->crprClkVertexId() == clk_info2->crprClkVertexId())
|| clk_info1->crprClkVertexId(sta) == clk_info2->crprClkVertexId(sta))
&& tagStateEqual(tag1, tag2));
}
@ -482,8 +483,8 @@ tagMatchCmp(const Tag *tag1,
if (match_crpr_clk_pin
&& sta->sdc()->crprActive()) {
VertexId crpr_vertex1 = clk_info1->crprClkVertexId();
VertexId crpr_vertex2 = clk_info2->crprClkVertexId();
VertexId crpr_vertex1 = clk_info1->crprClkVertexId(sta);
VertexId crpr_vertex2 = clk_info2->crprClkVertexId(sta);
if (crpr_vertex1 < crpr_vertex2)
return -1;
if (crpr_vertex1 > crpr_vertex2)
@ -676,7 +677,7 @@ TagMatchHash::TagMatchHash(bool match_crpr_clk_pin,
size_t
TagMatchHash::operator()(const Tag *tag) const
{
return tag->matchHash(match_crpr_clk_pin_);
return tag->matchHash(match_crpr_clk_pin_, sta_);
}
TagMatchEqual::TagMatchEqual(bool match_crpr_clk_pin,

View File

@ -29,7 +29,7 @@
#include "Transition.hh"
#include "SdcClass.hh"
#include "SearchClass.hh"
#include "PathRef.hh"
#include "Path.hh"
namespace sta {
@ -86,7 +86,8 @@ public:
bool isFilter() const { return is_filter_; }
bool isSegmentStart() const { return is_segment_start_; }
size_t hash() const { return hash_; }
size_t matchHash(bool match_crpr_clk_pin) const;
size_t matchHash(bool match_crpr_clk_pin,
const StaState *sta) const;
protected:
void findHash();

View File

@ -32,66 +32,70 @@
#include "Tag.hh"
#include "Corner.hh"
#include "Search.hh"
#include "PathPrev.hh"
#include "Path.hh"
namespace sta {
TagGroup::TagGroup(TagGroupIndex index,
ArrivalMap *arrival_map,
PathIndexMap *path_index_map,
bool has_clk_tag,
bool has_genclk_src_tag,
bool has_filter_tag,
bool has_loop_tag) :
arrival_map_(arrival_map),
hash_(arrivalMapHash(arrival_map_)),
path_index_map_(path_index_map),
hash_(pathIndexMapHash(path_index_map)),
index_(index),
has_clk_tag_(has_clk_tag),
has_genclk_src_tag_(has_genclk_src_tag),
has_filter_tag_(has_filter_tag),
has_loop_tag_(has_loop_tag),
own_arrival_map_(true)
own_path_map_(true)
{
}
TagGroup::TagGroup(TagGroupBldr *tag_bldr) :
arrival_map_(tag_bldr->arrivalMap()),
hash_(arrivalMapHash(arrival_map_)),
own_arrival_map_(false)
path_index_map_(&tag_bldr->pathIndexMap()),
hash_(pathIndexMapHash(path_index_map_)),
own_path_map_(false)
{
}
TagGroup::~TagGroup()
{
if (own_arrival_map_)
delete arrival_map_;
if (own_path_map_)
delete path_index_map_;
}
size_t
TagGroup::arrivalMapHash(ArrivalMap *arrival_map)
TagGroup::pathIndexMapHash(PathIndexMap *path_index_map)
{
size_t hash = 0;
ArrivalMap::Iterator arrival_iter(arrival_map);
while (arrival_iter.hasNext()) {
Tag *tag;
int arrival_index;
arrival_iter.next(tag, arrival_index);
for (auto const [tag, path_index] : *path_index_map)
hash += tag->hash();
}
return hash;
}
bool
TagGroup::hasTag(Tag *tag) const
{
return arrival_map_->hasKey(tag);
return path_index_map_->hasKey(tag);
}
size_t
TagGroup::pathIndex(Tag *tag) const
{
size_t path_index;
bool exists;
pathIndex(tag, path_index, exists);
return path_index;
}
void
TagGroup::arrivalIndex(Tag *tag,
int &arrival_index,
bool &exists) const
TagGroup::pathIndex(Tag *tag,
size_t &path_index,
bool &exists) const
{
arrival_map_->findKey(tag, arrival_index, exists);
path_index_map_->findKey(tag, path_index, exists);
}
void
@ -99,29 +103,24 @@ TagGroup::report(const StaState *sta) const
{
Report *report = sta->report();
report->reportLine("Group %u hash = %zu", index_, hash_);
arrivalMapReport(arrival_map_, sta);
pathIndexMapReport(path_index_map_, sta);
}
void
TagGroup::reportArrivalMap(const StaState *sta) const
{
arrivalMapReport(arrival_map_, sta);
pathIndexMapReport(path_index_map_, sta);
}
void
arrivalMapReport(const ArrivalMap *arrival_map,
const StaState *sta)
pathIndexMapReport(const PathIndexMap *path_index_map,
const StaState *sta)
{
Report *report = sta->report();
ArrivalMap::ConstIterator arrival_iter(arrival_map);
while (arrival_iter.hasNext()) {
Tag *tag;
int arrival_index;
arrival_iter.next(tag, arrival_index);
report->reportLine(" %2u %s",
arrival_index,
for (auto const [tag, path_index] : *path_index_map)
report->reportLine(" %2zu %s",
path_index,
tag->asString(sta));
}
report->reportBlankLine();
}
@ -129,14 +128,13 @@ arrivalMapReport(const ArrivalMap *arrival_map,
TagGroupBldr::TagGroupBldr(bool match_crpr_clk_pin,
const StaState *sta) :
default_arrival_count_(sta->corners()->count()
* RiseFall::index_count
* MinMax::index_count),
arrival_map_(default_arrival_count_,
TagMatchHash(match_crpr_clk_pin, sta),
TagMatchEqual(match_crpr_clk_pin, sta)),
arrivals_(default_arrival_count_),
prev_paths_(default_arrival_count_),
default_path_count_(sta->corners()->count()
* RiseFall::index_count
* MinMax::index_count),
path_index_map_(default_path_count_,
TagMatchHash(match_crpr_clk_pin, sta),
TagMatchEqual(match_crpr_clk_pin, sta)),
paths_(default_path_count_),
has_clk_tag_(false),
has_genclk_src_tag_(false),
has_filter_tag_(false),
@ -149,16 +147,15 @@ TagGroupBldr::TagGroupBldr(bool match_crpr_clk_pin,
bool
TagGroupBldr::empty()
{
return arrival_map_.empty();
return path_index_map_.empty();
}
void
TagGroupBldr::init(Vertex *vertex)
{
vertex_ = vertex;
arrival_map_.clear();
arrivals_.clear();
prev_paths_.clear();
path_index_map_.clear();
paths_.clear();
has_clk_tag_ = false;
has_genclk_src_tag_ = false;
has_filter_tag_ = false;
@ -168,147 +165,152 @@ TagGroupBldr::init(Vertex *vertex)
void
TagGroupBldr::reportArrivalEntries() const
{
arrivalMapReport(&arrival_map_, sta_);
pathIndexMapReport(&path_index_map_, sta_);
}
Path *
TagGroupBldr::tagMatchPath(Tag *tag)
{
Path *match;
size_t path_index;
tagMatchPath(tag, match, path_index);
return match;
}
void
TagGroupBldr::tagMatchArrival(Tag *tag,
// Return values.
Tag *&tag_match,
Arrival &arrival,
int &arrival_index) const
TagGroupBldr::tagMatchPath(Tag *tag,
// Return values.
Path *&match,
size_t &path_index)
{
// Find matching group tag.
// Match is not necessarily equal to original tag because it
// must only satisfy tagMatch.
bool exists;
arrival_map_.findKey(tag, tag_match, arrival_index, exists);
Tag *tag_match;
path_index_map_.findKey(tag, tag_match, path_index, exists);
if (exists)
arrival = arrivals_[arrival_index];
match = &paths_[path_index];
else {
tag_match = nullptr;
arrival = -1.0;
arrival_index = -1;
match = nullptr;
path_index = 0;
}
}
Arrival
TagGroupBldr::arrival(int arrival_index) const
TagGroupBldr::arrival(size_t path_index) const
{
return arrivals_[arrival_index];
return paths_[path_index].arrival();
}
void
TagGroupBldr::setArrival(Tag *tag,
const Arrival &arrival,
PathPrev *prev_path)
const Arrival &arrival)
{
Tag *tag_match;
Arrival ignore;
int arrival_index;
// Find matching group tag (not necessarily equal to original tag).
tagMatchArrival(tag, tag_match, ignore, arrival_index);
setMatchArrival(tag, tag_match, arrival, arrival_index, prev_path);
Path *match;
size_t path_index;
tagMatchPath(tag, match, path_index);
setMatchPath(match, path_index, tag, arrival, nullptr, nullptr, nullptr);
}
void
TagGroupBldr::setMatchArrival(Tag *tag,
Tag *tag_match,
const Arrival &arrival,
int arrival_index,
PathPrev *prev_path)
TagGroupBldr::setMatchPath(Path *match,
size_t path_index,
Tag *tag,
Arrival arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc)
{
if (tag_match) {
// If the group_tag exists there has to be an arrival map entry for it.
if (match) {
Tag *tag_match = match->tag(sta_);
// If the tag match exists there has to be a path map entry for it.
if (tag_match != tag) {
// Replace tag in arrival map.
arrival_map_.erase(tag_match);
arrival_map_.insert(tag, arrival_index);
path_index_map_.erase(tag_match);
path_index_map_.insert(tag, path_index);
}
arrivals_[arrival_index] = arrival;
prev_paths_[arrival_index].init(prev_path);
paths_[path_index].init(vertex_, tag, arrival, prev_path,
prev_edge, prev_arc, sta_);
}
else {
arrival_index = arrivals_.size();
arrival_map_.insert(tag, arrival_index);
arrivals_.push_back(arrival);
if (prev_path)
prev_paths_.push_back(*prev_path);
else
prev_paths_.push_back(PathPrev());
else
insertPath(tag, arrival, prev_path, prev_edge, prev_arc);
}
if (tag->isClock())
has_clk_tag_ = true;
if (tag->isGenClkSrcPath())
has_genclk_src_tag_ = true;
if (tag->isFilter()
|| tag->clkInfo()->refsFilter(sta_))
has_filter_tag_ = true;
if (tag->isLoop())
has_loop_tag_ = true;
if (tag->clkInfo()->isPropagated())
has_propagated_clk_ = true;
}
void
TagGroupBldr::insertPath(Tag *tag,
Arrival arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc)
{
size_t path_index = paths_.size();
path_index_map_.insert(tag, path_index);
paths_.emplace_back(vertex_, tag, arrival, prev_path,
prev_edge, prev_arc, sta_);
if (tag->isClock())
has_clk_tag_ = true;
if (tag->isGenClkSrcPath())
has_genclk_src_tag_ = true;
if (tag->isFilter()
|| tag->clkInfo()->refsFilter(sta_))
has_filter_tag_ = true;
if (tag->isLoop())
has_loop_tag_ = true;
if (tag->clkInfo()->isPropagated())
has_propagated_clk_ = true;
}
void
TagGroupBldr::insertPath(const Path &path)
{
insertPath(path.tag(sta_), path.arrival(), path.prevPath(),
path.prevEdge(sta_), path.prevArc(sta_));
}
TagGroup *
TagGroupBldr::makeTagGroup(TagGroupIndex index,
const StaState *sta)
{
return new TagGroup(index, makeArrivalMap(sta),
return new TagGroup(index, makePathIndexMap(sta),
has_clk_tag_, has_genclk_src_tag_, has_filter_tag_,
has_loop_tag_);
}
ArrivalMap *
TagGroupBldr::makeArrivalMap(const StaState *sta)
PathIndexMap *
TagGroupBldr::makePathIndexMap(const StaState *sta)
{
ArrivalMap *arrival_map = new ArrivalMap(arrival_map_.size(),
TagMatchHash(true, sta),
TagMatchEqual(true, sta));
int arrival_index = 0;
ArrivalMap::Iterator arrival_iter(arrival_map_);
while (arrival_iter.hasNext()) {
Tag *tag;
int arrival_index1;
arrival_iter.next(tag, arrival_index1);
arrival_map->insert(tag, arrival_index);
arrival_index++;
PathIndexMap *path_index_map = new PathIndexMap(path_index_map_.size(),
TagMatchHash(true, sta),
TagMatchEqual(true, sta));
size_t path_index = 0;
for (auto const [tag, path_index1] : path_index_map_) {
path_index_map->insert(tag, path_index);
path_index++;
}
return arrival_map;
return path_index_map;
}
void
TagGroupBldr::copyArrivals(TagGroup *tag_group,
Arrival *arrivals,
PathPrev *prev_paths)
TagGroupBldr::copyPaths(TagGroup *tag_group,
Path *paths)
{
ArrivalMap::Iterator arrival_iter1(arrival_map_);
while (arrival_iter1.hasNext()) {
Tag *tag1;
int arrival_index1, arrival_index2;
arrival_iter1.next(tag1, arrival_index1);
for (auto const [tag1, path_index1] : path_index_map_) {
size_t path_index2;
bool exists2;
tag_group->arrivalIndex(tag1, arrival_index2, exists2);
if (exists2) {
arrivals[arrival_index2] = arrivals_[arrival_index1];
if (prev_paths) {
PathPrev *prev_path = &prev_paths_[arrival_index1];
prev_paths[arrival_index2].init(prev_path);
}
}
tag_group->pathIndex(tag1, path_index2, exists2);
if (exists2)
paths[path_index2] = paths_[path_index1];
else
sta_->report()->critical(1351, "tag group missing tag");
}
}
PathPrev &
TagGroupBldr::prevPath(int arrival_index)
{
return prev_paths_[arrival_index];
}
////////////////////////////////////////////////////////////////
size_t
@ -318,19 +320,15 @@ TagGroupHash::operator()(const TagGroup *group) const
}
static bool
arrivalMapEqual(const ArrivalMap *arrival_map1,
const ArrivalMap *arrival_map2)
pathIndexMapEqual(const PathIndexMap *path_index_map1,
const PathIndexMap *path_index_map2)
{
int arrival_count1 = arrival_map1->size();
int arrival_count2 = arrival_map2->size();
if (arrival_count1 == arrival_count2) {
ArrivalMap::ConstIterator arrival_iter1(arrival_map1);
while (arrival_iter1.hasNext()) {
Tag *tag1, *tag2;
int arrival_index1, arrival_index2;
arrival_iter1.next(tag1, arrival_index1);
if (path_index_map1->size() == path_index_map2->size()) {
for (auto const [tag1, path_index1] : *path_index_map1) {
Tag *tag2;
size_t path_index2;
bool exists2;
arrival_map2->findKey(tag1, tag2, arrival_index2, exists2);
path_index_map2->findKey(tag1, tag2, path_index2, exists2);
if (!exists2
// ArrivalMap equal function is TagMatchEqual, so make sure
// the tag is an exact match.
@ -349,8 +347,8 @@ TagGroupEqual::operator()(const TagGroup *tag_group1,
{
return tag_group1 == tag_group2
|| (tag_group1->hash() == tag_group2->hash()
&& arrivalMapEqual(tag_group1->arrivalMap(),
tag_group2->arrivalMap()));
&& pathIndexMapEqual(tag_group1->pathIndexMap(),
tag_group2->pathIndexMap()));
}
} // namespace

View File

@ -37,13 +37,11 @@ namespace sta {
class TagGroupBldr;
typedef Vector<PathPrev> PathPrevSeq;
class TagGroup
{
public:
TagGroup(TagGroupIndex index,
ArrivalMap *arrival_map,
PathIndexMap *path_index_map,
bool has_clk_tag,
bool has_genclk_src_tag,
bool has_filter_tag,
@ -59,26 +57,27 @@ public:
bool hasGenClkSrcTag() const { return has_genclk_src_tag_; }
bool hasFilterTag() const { return has_filter_tag_; }
bool hasLoopTag() const { return has_loop_tag_; }
bool ownArrivalMap() const { return own_arrival_map_; }
int arrivalCount() const { return arrival_map_->size(); }
void arrivalIndex(Tag *tag,
int &arrival_index,
bool &exists) const;
ArrivalMap *arrivalMap() const { return arrival_map_; }
bool ownPathMap() const { return own_path_map_; }
size_t pathCount() const { return path_index_map_->size(); }
void pathIndex(Tag *tag,
size_t &path_index,
bool &exists) const;
size_t pathIndex(Tag *tag) const;
PathIndexMap *pathIndexMap() const { return path_index_map_; }
bool hasTag(Tag *tag) const;
protected:
size_t arrivalMapHash(ArrivalMap *arrival_map);
static size_t pathIndexMapHash(PathIndexMap *path_index_map);
// tag -> arrival index
ArrivalMap *arrival_map_;
// tag -> path index
PathIndexMap *path_index_map_;
size_t hash_;
unsigned int index_:tag_group_index_bits;
bool has_clk_tag_:1;
bool has_genclk_src_tag_:1;
bool has_filter_tag_:1;
bool has_loop_tag_:1;
bool own_arrival_map_:1;
bool own_path_map_:1;
};
class TagGroupHash
@ -106,40 +105,46 @@ public:
void reportArrivalEntries() const;
TagGroup *makeTagGroup(TagGroupIndex index,
const StaState *sta);
size_t pathCount() const { return path_index_map_.size();; }
bool hasClkTag() const { return has_clk_tag_; }
bool hasGenClkSrcTag() const { return has_genclk_src_tag_; }
bool hasFilterTag() const { return has_filter_tag_; }
bool hasLoopTag() const { return has_loop_tag_; }
bool hasPropagatedClk() const { return has_propagated_clk_; }
void tagMatchArrival(Tag *tag,
// Return values.
Tag *&tag_match,
Arrival &arrival,
int &arrival_index) const;
Arrival arrival(int arrival_index) const;
Path *tagMatchPath(Tag *tag);
void tagMatchPath(Tag *tag,
// Return values.
Path *&match,
size_t &path_index);
Arrival arrival(size_t path_index) const;
// prev_path == hull
void setArrival(Tag *tag,
const Arrival &arrival,
PathPrev *prev_path);
void setMatchArrival(Tag *tag,
Tag *tag_match,
const Arrival &arrival,
int arrival_index,
PathPrev *prev_path);
ArrivalMap *arrivalMap() { return &arrival_map_; }
PathPrev &prevPath(int arrival_index);
void copyArrivals(TagGroup *tag_group,
Arrival *arrivals,
PathPrev *prev_paths);
const Arrival &arrival);
void setMatchPath(Path *match,
size_t path_index,
Tag *tag,
Arrival arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc);
void insertPath(Tag *tag,
Arrival arrival,
Path *prev_path,
Edge *prev_edge,
TimingArc *prev_arc);
void insertPath(const Path &path);
PathIndexMap &pathIndexMap() { return path_index_map_; }
void copyPaths(TagGroup *tag_group,
Path *paths);
protected:
int tagMatchIndex();
ArrivalMap *makeArrivalMap(const StaState *sta);
PathIndexMap *makePathIndexMap(const StaState *sta);
Vertex *vertex_;
int default_arrival_count_;
ArrivalMap arrival_map_;
ArrivalSeq arrivals_;
PathPrevSeq prev_paths_;
int default_path_count_;
PathIndexMap path_index_map_;
vector<Path> paths_;
bool has_clk_tag_;
bool has_genclk_src_tag_;
bool has_filter_tag_;
@ -149,7 +154,7 @@ protected:
};
void
arrivalMapReport(const ArrivalMap *arrival_map,
const StaState *sta);
pathIndexMapReport(const PathIndexMap *path_index_map,
const StaState *sta);
} // namespace

View File

@ -34,7 +34,7 @@
#include "Graph.hh"
#include "ClkInfo.hh"
#include "Tag.hh"
#include "PathVertex.hh"
#include "Path.hh"
#include "PathAnalysisPt.hh"
#include "PathEnd.hh"
#include "Search.hh"
@ -91,7 +91,7 @@ VisitPathEnds::visitClkedPathEnds(const Pin *pin,
bool is_segment_start = search_->isSegmentStart(pin);
VertexPathIterator path_iter(vertex, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
const MinMax *path_min_max = path_ap->pathMinMax();
const RiseFall *end_rf = path->transition(this);
@ -161,7 +161,7 @@ VisitPathEnds::visitCheckEnd(const Pin *pin,
VertexPathIterator tgt_clk_path_iter(tgt_clk_vertex, clk_rf,
tgt_clk_path_ap, this);
while (tgt_clk_path_iter.hasNext()) {
PathVertex *tgt_clk_path = tgt_clk_path_iter.next();
Path *tgt_clk_path = tgt_clk_path_iter.next();
ClkInfo *tgt_clk_info = tgt_clk_path->clkInfo(this);
const ClockEdge *tgt_clk_edge = tgt_clk_path->clkEdge(this);
const Clock *tgt_clk = tgt_clk_path->clock(this);
@ -318,7 +318,7 @@ VisitPathEnds::visitOutputDelayEnd(const Pin *pin,
RiseFall *ref_rf = output_delay->refTransition();
VertexPathIterator ref_path_iter(ref_vertex,ref_rf,path_ap,this);
while (ref_path_iter.hasNext()) {
PathVertex *ref_path = ref_path_iter.next();
Path *ref_path = ref_path_iter.next();
if (ref_path->isClock(this)
&& (tgt_clk == nullptr
|| ref_path->clock(this) == tgt_clk))
@ -343,7 +343,7 @@ VisitPathEnds::visitOutputDelayEnd1(OutputDelay *output_delay,
Path *path,
const RiseFall *end_rf,
const ClockEdge *tgt_clk_edge,
PathVertex *ref_path,
Path *ref_path,
const MinMax *min_max,
PathEndVisitor *visitor,
bool &is_constrained)
@ -414,7 +414,7 @@ VisitPathEnds::visitGatedClkEnd(const Pin *pin,
min_max);
VertexPathIterator clk_path_iter(clk_vertex, clk_rf, clk_path_ap, this);
while (clk_path_iter.hasNext()) {
PathVertex *clk_path = clk_path_iter.next();
Path *clk_path = clk_path_iter.next();
const ClockEdge *clk_edge = clk_path->clkEdge(this);
const Clock *clk = clk_edge ? clk_edge->clock() : nullptr;
if (clk_path->isClock(this)
@ -544,7 +544,7 @@ VisitPathEnds::visitDataCheckEnd1(DataCheck *check,
bool found_from_path = false;
VertexPathIterator tgt_clk_path_iter(from_vertex,from_rf,clk_ap,this);
while (tgt_clk_path_iter.hasNext()) {
PathVertex *tgt_clk_path = tgt_clk_path_iter.next();
Path *tgt_clk_path = tgt_clk_path_iter.next();
const ClockEdge *tgt_clk_edge = tgt_clk_path->clkEdge(this);
// Ignore generated clock source paths.
if (tgt_clk_edge
@ -584,7 +584,7 @@ VisitPathEnds::visitUnconstrainedPathEnds(const Pin *pin,
{
VertexPathIterator path_iter(vertex, this);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
const MinMax *path_min_max = path_ap->pathMinMax();
if ((corner == nullptr

View File

@ -28,21 +28,20 @@
#include "Graph.hh"
#include "Bfs.hh"
#include "Search.hh"
#include "PathVertex.hh"
#include "Path.hh"
#include "PathEnd.hh"
#include "Tag.hh"
#include "VisitPathEnds.hh"
namespace sta {
typedef Set<PathVertex*, PathLess> PathVertexSet;
typedef Map<Vertex*, PathVertexSet*> VertexPathSetMap;
typedef Set<Path*, PathLess> PathSet;
typedef Map<Vertex*, PathSet*> VertexPathSetMap;
static void
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
Vertex *vertex,
Tag *tag,
int arrival_index,
const StaState *sta);
// Visit each path end for a vertex and add the worst one in each
@ -87,7 +86,7 @@ protected:
Vertex *from_vertex,
const RiseFall *from_rf,
Tag *from_tag,
PathVertex *from_path,
Path *from_path,
const Arrival &from_arrival,
Edge *edge,
TimingArc *arc,
@ -99,8 +98,7 @@ protected:
const MinMax *min_max,
const PathAnalysisPt *path_ap);
void fromMatches(Vertex *from_vertex,
Tag *from_tag,
int from_arrival_index);
Tag *from_tag);
private:
VertexVisitor *visitor_;
@ -139,10 +137,10 @@ visitPathGroupVertices(PathGroup *path_group,
// Cleanup.
VertexPathSetMap::Iterator matching_iter(matching_path_map);
while (matching_iter.hasNext()) {
PathVertexSet *paths = matching_iter.next();
PathVertexSet::Iterator path_iter(paths);
PathSet *paths = matching_iter.next();
PathSet::Iterator path_iter(paths);
while (path_iter.hasNext()) {
PathVertex *path = path_iter.next();
Path *path = path_iter.next();
delete path;
}
delete paths;
@ -181,14 +179,9 @@ VisitPathGroupEnds::visit(PathEnd *path_end)
{
PathGroup *group = sta_->search()->pathGroup(path_end);
if (group == path_group_) {
PathRef path(path_end->pathRef());
Vertex *vertex = path.vertex(sta_);
int arrival_index;
bool arrival_exists;
path.arrivalIndex(arrival_index, arrival_exists);
vertexPathSetMapInsertPath(matching_path_map_, vertex, path.tag(sta_),
arrival_index, sta_);
Path *path = path_end->path();
Vertex *vertex = path->vertex(sta_);
vertexPathSetMapInsertPath(matching_path_map_, vertex, path->tag(sta_), sta_);
vertex_matches_ = true;
}
}
@ -197,16 +190,15 @@ static void
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
Vertex *vertex,
Tag *tag,
int arrival_index,
const StaState *sta)
{
PathVertexSet *matching_paths = matching_path_map->findKey(vertex);
PathSet *matching_paths = matching_path_map->findKey(vertex);
if (matching_paths == nullptr) {
PathLess path_less(sta);
matching_paths = new PathVertexSet(path_less);
matching_paths = new PathSet(path_less);
(*matching_path_map)[vertex] = matching_paths;
}
PathVertex *vpath = new PathVertex(vertex, tag, arrival_index);
Path *vpath = new Path(vertex, tag, sta);
matching_paths->insert(vpath);
}
@ -262,7 +254,7 @@ PathGroupPathVisitor::visitFromToPath(const Pin *,
Vertex *from_vertex,
const RiseFall *,
Tag *from_tag,
PathVertex *from_path,
Path *,
const Arrival &,
Edge *,
TimingArc *,
@ -274,12 +266,9 @@ PathGroupPathVisitor::visitFromToPath(const Pin *,
const MinMax *,
const PathAnalysisPt *path_ap)
{
PathVertexSet *matching_paths = matching_path_map_->findKey(to_vertex);
PathSet *matching_paths = matching_path_map_->findKey(to_vertex);
if (matching_paths) {
int arrival_index;
bool arrival_exists;
from_path->arrivalIndex(arrival_index, arrival_exists);
PathVertex to_path(to_vertex, to_tag, this);
Path to_path(to_vertex, to_tag, this);
if (!to_path.isNull()) {
if (matching_paths->hasKey(&to_path)) {
debugPrint(debug_, "visit_path_group", 2, "match %s %s -> %s %s",
@ -287,13 +276,13 @@ PathGroupPathVisitor::visitFromToPath(const Pin *,
from_tag->asString(this),
to_vertex->name(network_),
to_tag->asString(this));
fromMatches(from_vertex, from_tag, arrival_index);
fromMatches(from_vertex, from_tag);
}
}
else {
VertexPathIterator to_iter(to_vertex, to_rf, path_ap, this);
while (to_iter.hasNext()) {
PathVertex *to_path = to_iter.next();
Path *to_path = to_iter.next();
if (tagMatchNoCrpr(to_path->tag(this), to_tag)
&& matching_paths->hasKey(to_path)) {
debugPrint(debug_, "visit_path_group", 2,
@ -302,7 +291,7 @@ PathGroupPathVisitor::visitFromToPath(const Pin *,
from_tag->asString(this),
to_vertex->name(network_),
to_tag->asString(this));
fromMatches(from_vertex, from_tag, arrival_index);
fromMatches(from_vertex, from_tag);
}
}
}
@ -312,12 +301,11 @@ PathGroupPathVisitor::visitFromToPath(const Pin *,
void
PathGroupPathVisitor::fromMatches(Vertex *from_vertex,
Tag *from_tag,
int from_arrival_index)
Tag *from_tag)
{
vertex_matches_ = true;
vertexPathSetMapInsertPath(matching_path_map_, from_vertex,
from_tag, from_arrival_index, this);
from_tag, this);
}
} // namespace

View File

@ -45,7 +45,6 @@
#include "Parasitics.hh"
#include "PathAnalysisPt.hh"
#include "Path.hh"
#include "PathRef.hh"
#include "PathExpanded.hh"
#include "StaState.hh"
#include "search/Sim.hh"
@ -118,11 +117,11 @@ private:
int stageGateInputPathIndex(Stage stage);
int stageDrvrPathIndex(Stage stage);
int stageLoadPathIndex(Stage stage);
const PathRef *stageGateInputPath(Stage stage);
const PathRef *stageDrvrPath(Stage stage);
const PathRef *stageLoadPath(Stage stage);
TimingArc *stageGateArc(Stage stage);
TimingArc *stageWireArc(Stage stage);
const Path *stageGateInputPath(Stage stage);
const Path *stageDrvrPath(Stage stage);
const Path *stageLoadPath(Stage stage);
const TimingArc *stageGateArc(Stage stage);
const TimingArc *stageWireArc(Stage stage);
Edge *stageGateEdge(Stage stage);
Edge *stageWireEdge(Stage stage);
Pin *stageGateInputPin(Stage stage);
@ -139,7 +138,7 @@ private:
float findSlew(const Path *path);
float findSlew(const Path *path,
const RiseFall *rf,
TimingArc *next_arc);
const TimingArc *next_arc);
Path *path_;
PathExpanded path_expanded_;
// Input clock waveform cycles.
@ -246,7 +245,7 @@ float
WritePathSpice::maxTime()
{
Stage input_stage = stageFirst();
const PathRef *input_path = stageDrvrPath(input_stage);
const Path *input_path = stageDrvrPath(input_stage);
if (input_path->isClock(this)) {
const Clock *clk = input_path->clock(this);
float period = clk->period();
@ -264,7 +263,7 @@ WritePathSpice::pathMaxTime()
{
float max_time = 0.0;
for (size_t i = 0; i < path_expanded_.size(); i++) {
const PathRef *path = path_expanded_.path(i);
const Path *path = path_expanded_.path(i);
const RiseFall *rf = path->transition(this);
Vertex *vertex = path->vertex(this);
float path_max_slew = railToRailSlew(findSlew(vertex,rf,nullptr), rf);
@ -278,7 +277,7 @@ WritePathSpice::pathMaxTime()
path_max_slew = load_slew;
}
}
float path_max_time = delayAsFloat(path->arrival(this)) + path_max_slew * 2.0;
float path_max_time = delayAsFloat(path->arrival()) + path_max_slew * 2.0;
if (path_max_time > max_time)
max_time = path_max_time;
}
@ -321,7 +320,7 @@ WritePathSpice::writeInputSource()
streamPrint(spice_stream_, "**************\n\n");
Stage input_stage = stageFirst();
const PathRef *input_path = stageDrvrPath(input_stage);
const Path *input_path = stageDrvrPath(input_stage);
if (input_path->isClock(this))
writeClkWaveform();
else
@ -333,9 +332,9 @@ void
WritePathSpice::writeInputWaveform()
{
Stage input_stage = stageFirst();
const PathRef *input_path = stageDrvrPath(input_stage);
const Path *input_path = stageDrvrPath(input_stage);
const RiseFall *rf = input_path->transition(this);
TimingArc *next_arc = stageGateArc(input_stage + 1);
const TimingArc *next_arc = stageGateArc(input_stage + 1);
float slew0 = findSlew(input_path, rf, next_arc);
float threshold = default_library_->inputThreshold(rf);
@ -358,8 +357,8 @@ void
WritePathSpice::writeClkWaveform()
{
Stage input_stage = stageFirst();
const PathRef *input_path = stageDrvrPath(input_stage);
TimingArc *next_arc = stageGateArc(input_stage + 1);
const Path *input_path = stageDrvrPath(input_stage);
const TimingArc *next_arc = stageGateArc(input_stage + 1);
const ClockEdge *clk_edge = input_path->clkEdge(this);
const Clock *clk = clk_edge->clock();
@ -403,7 +402,7 @@ WritePathSpice::findSlew(const Path *path)
float
WritePathSpice::findSlew(const Path *path,
const RiseFall *rf,
TimingArc *next_arc)
const TimingArc *next_arc)
{
Vertex *vertex = path->vertex(this);
return findSlew(vertex, rf, next_arc);
@ -419,9 +418,9 @@ WritePathSpice::writeMeasureStmts()
streamPrint(spice_stream_, "********************\n\n");
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
const PathRef *gate_input_path = stageGateInputPath(stage);
const PathRef *drvr_path = stageDrvrPath(stage);
const PathRef *load_path = stageLoadPath(stage);
const Path *gate_input_path = stageGateInputPath(stage);
const Path *drvr_path = stageDrvrPath(stage);
const Path *load_path = stageLoadPath(stage);
if (gate_input_path) {
// gate input -> gate output
writeMeasureSlewStmt(stage, gate_input_path);
@ -520,7 +519,7 @@ WritePathSpice::writeGateStage(Stage stage)
drvr_port->name());
writeSubcktInst(inst);
const PathRef *drvr_path = stageDrvrPath(stage);
const Path *drvr_path = stageDrvrPath(stage);
const RiseFall *drvr_rf = drvr_path->transition(this);
Edge *gate_edge = stageGateEdge(stage);
@ -550,7 +549,7 @@ WritePathSpice::writeGateStage(Stage stage)
void
WritePathSpice::writeStageParasitics(Stage stage)
{
const PathRef *drvr_path = stageDrvrPath(stage);
const Path *drvr_path = stageDrvrPath(stage);
DcalcAnalysisPt *dcalc_ap = drvr_path->dcalcAnalysisPt(this);
ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
const Pin *drvr_pin = stageDrvrPin(stage);
@ -579,7 +578,7 @@ WritePathSpice::findPathCellNames()
{
StdStringSet path_cell_names;
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
TimingArc *arc = stageGateArc(stage);
const TimingArc *arc = stageGateArc(stage);
if (arc) {
LibertyCell *cell = arc->set()->libertyCell();
if (cell) {
@ -643,64 +642,62 @@ WritePathSpice::stageLoadPathIndex(Stage stage)
return stage * 2 - 1;
}
const PathRef *
const Path *
WritePathSpice::stageGateInputPath(Stage stage)
{
int path_index = stageGateInputPathIndex(stage);
return path_expanded_.path(path_index);
}
const PathRef *
const Path *
WritePathSpice::stageDrvrPath(Stage stage)
{
int path_index = stageDrvrPathIndex(stage);
return path_expanded_.path(path_index);
}
const PathRef *
const Path *
WritePathSpice::stageLoadPath(Stage stage)
{
int path_index = stageLoadPathIndex(stage);
return path_expanded_.path(path_index);
}
TimingArc *
const TimingArc *
WritePathSpice::stageGateArc(Stage stage)
{
int path_index = stageDrvrPathIndex(stage);
if (path_index >= 0)
return path_expanded_.prevArc(path_index);
return path_expanded_.path(path_index)->prevArc(this);
else
return nullptr;
}
TimingArc *
const TimingArc *
WritePathSpice::stageWireArc(Stage stage)
{
int path_index = stageLoadPathIndex(stage);
return path_expanded_.prevArc(path_index);
return path_expanded_.path(path_index)->prevArc(this);
}
Edge *
WritePathSpice::stageGateEdge(Stage stage)
{
const PathRef *path = stageDrvrPath(stage);
TimingArc *arc = stageGateArc(stage);
return path->prevEdge(arc, this);
const Path *path = stageDrvrPath(stage);
return path->prevEdge(this);
}
Edge *
WritePathSpice::stageWireEdge(Stage stage)
{
const PathRef *path = stageLoadPath(stage);
TimingArc *arc = stageWireArc(stage);
return path->prevEdge(arc, this);
const Path *path = stageLoadPath(stage);
return path->prevEdge(this);
}
Pin *
WritePathSpice::stageGateInputPin(Stage stage)
{
const PathRef *path = stageGateInputPath(stage);
const Path *path = stageGateInputPath(stage);
return path->pin(this);
}
@ -714,7 +711,7 @@ WritePathSpice::stageGateInputPort(Stage stage)
Pin *
WritePathSpice::stageDrvrPin(Stage stage)
{
const PathRef *path = stageDrvrPath(stage);
const Path *path = stageDrvrPath(stage);
return path->pin(this);
}
@ -728,7 +725,7 @@ WritePathSpice::stageDrvrPort(Stage stage)
Pin *
WritePathSpice::stageLoadPin(Stage stage)
{
const PathRef *path = stageLoadPath(stage);
const Path *path = stageLoadPath(stage);
return path->pin(this);
}

View File

@ -39,7 +39,7 @@
#include "Graph.hh"
#include "search/Sim.hh"
#include "Clock.hh"
#include "PathVertex.hh"
#include "Path.hh"
#include "DcalcAnalysisPt.hh"
#include "Bdd.hh"
@ -474,7 +474,7 @@ WriteSpice::pgPortVoltage(LibertyPgPort *pg_port)
float
WriteSpice::findSlew(Vertex *vertex,
const RiseFall *rf,
TimingArc *next_arc)
const TimingArc *next_arc)
{
float slew = delayAsFloat(graph_->slew(vertex, rf, dcalc_ap_->index()));
if (slew == 0.0 && next_arc)
@ -486,7 +486,7 @@ WriteSpice::findSlew(Vertex *vertex,
// Look up the smallest slew axis value in the timing arc delay table.
float
WriteSpice::slewAxisMinValue(TimingArc *arc)
WriteSpice::slewAxisMinValue(const TimingArc *arc)
{
GateTableModel *gate_model = arc->gateTableModel(dcalc_ap_);
if (gate_model) {

View File

@ -135,8 +135,8 @@ protected:
const char *spiceTrans(const RiseFall *rf);
float findSlew(Vertex *vertex,
const RiseFall *rf,
TimingArc *next_arc);
float slewAxisMinValue(TimingArc *arc);
const TimingArc *next_arc);
float slewAxisMinValue(const TimingArc *arc);
float clkWaveformTimeOffset(const Clock *clk);
void gatePortValues(const Pin *input_pin,

View File

@ -33,7 +33,7 @@
%inline %{
void
write_path_spice_cmd(PathRef *path,
write_path_spice_cmd(Path *path,
const char *spice_filename,
const char *subckt_filename,
const char *lib_subckt_filename,

View File

@ -77,7 +77,7 @@ proc get_object_property { object prop } {
return [edge_property $object $prop]
} elseif { $object_type == "PathEnd" } {
return [path_end_property $object $prop]
} elseif { $object_type == "PathRef" } {
} elseif { $object_type == "Path" } {
return [path_ref_property $object $prop]
} elseif { $object_type == "TimingArcSet" } {
return [timing_arc_set_property $object $prop]

View File

@ -42,7 +42,7 @@
#include "Clock.hh"
#include "Corner.hh"
#include "Search.hh"
#include "PathRef.hh"
#include "Path.hh"
#include "search/Tag.hh"
#include "PathEnd.hh"
#include "SearchClass.hh"
@ -1138,17 +1138,17 @@ using namespace sta;
Tcl_SetObjResult(interp, obj);
}
%typemap(out) PathRefSeq* {
%typemap(out) PathSeq* {
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
Tcl_SetObjResult(interp, obj);
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
PathRefSeq *paths = $1;
PathRefSeq::Iterator path_iter(paths);
PathSeq *paths = $1;
PathSeq::Iterator path_iter(paths);
while (path_iter.hasNext()) {
PathRef *path = &path_iter.next();
PathRef *copy = new PathRef(path);
Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false);
Path *path = &path_iter.next();
Path *copy = new Path(path);
Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_Path, false);
Tcl_ListObjAppendElement(interp, list, obj);
}
Tcl_SetObjResult(interp, list);
@ -1354,11 +1354,10 @@ using namespace sta;
Tcl_SetObjResult(interp, list);
}
break;
case PropertyValue::Type::type_path_refs: {
case PropertyValue::Type::type_paths: {
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
for (PathRef &path : *value.pathRefs()) {
PathRef *copy = new PathRef(path);
Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false);
for (const Path *path : *value.paths()) {
Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast<Path*>(path), SWIGTYPE_p_Path, false);
Tcl_ListObjAppendElement(interp, list, obj);
}
Tcl_SetObjResult(interp, list);