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:
parent
950d5b3383
commit
8992827b5b
|
|
@ -184,15 +184,11 @@ set(STA_SOURCE
|
||||||
search/MakeTimingModel.cc
|
search/MakeTimingModel.cc
|
||||||
search/Path.cc
|
search/Path.cc
|
||||||
search/PathAnalysisPt.cc
|
search/PathAnalysisPt.cc
|
||||||
|
search/Path.cc
|
||||||
search/PathEnd.cc
|
search/PathEnd.cc
|
||||||
search/PathEnum.cc
|
search/PathEnum.cc
|
||||||
search/PathEnumed.cc
|
|
||||||
search/PathExpanded.cc
|
search/PathExpanded.cc
|
||||||
search/PathGroup.cc
|
search/PathGroup.cc
|
||||||
search/PathPrev.cc
|
|
||||||
search/PathRef.cc
|
|
||||||
search/PathVertex.cc
|
|
||||||
search/PathVertexPtr.cc
|
|
||||||
search/Property.cc
|
search/Property.cc
|
||||||
search/ReportPath.cc
|
search/ReportPath.cc
|
||||||
search/Search.cc
|
search/Search.cc
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,19 @@
|
||||||
|
|
||||||
This file summarizes STA API changes for each release.
|
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
|
Release 2.4.0 2023/01/19
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
|
|
||||||
102
graph/Graph.cc
102
graph/Graph.cc
|
|
@ -571,75 +571,25 @@ Graph::gateEdgeArc(const Pin *in_pin,
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Arrival *
|
Path *
|
||||||
Graph::makeArrivals(Vertex *vertex,
|
Graph::makePaths(Vertex *vertex,
|
||||||
uint32_t count)
|
uint32_t count)
|
||||||
{
|
{
|
||||||
Arrival *arrivals = new Arrival[count];
|
Path *paths = new Path[count];
|
||||||
vertex->setArrivals(arrivals);
|
vertex->setPaths(paths);
|
||||||
return arrivals;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival *
|
Path *
|
||||||
Graph::arrivals(const Vertex *vertex) const
|
Graph::paths(const Vertex *vertex) const
|
||||||
{
|
{
|
||||||
return vertex->arrivals();
|
return vertex->paths();
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Graph::deletePaths(Vertex *vertex)
|
Graph::deletePaths(Vertex *vertex)
|
||||||
{
|
{
|
||||||
deleteArrivals(vertex);
|
vertex->setPaths(nullptr);
|
||||||
deleteRequireds(vertex);
|
|
||||||
deletePrevPaths(vertex);
|
|
||||||
vertex->tag_group_index_ = tag_group_index_max;
|
vertex->tag_group_index_ = tag_group_index_max;
|
||||||
vertex->crpr_path_pruning_disabled_ = false;
|
vertex->crpr_path_pruning_disabled_ = false;
|
||||||
}
|
}
|
||||||
|
|
@ -1007,9 +957,7 @@ Vertex::init(Pin *pin,
|
||||||
in_edges_ = edge_id_null;
|
in_edges_ = edge_id_null;
|
||||||
out_edges_ = edge_id_null;
|
out_edges_ = edge_id_null;
|
||||||
slews_ = nullptr;
|
slews_ = nullptr;
|
||||||
arrivals_ = nullptr;
|
paths_ = nullptr;
|
||||||
requireds_ = nullptr;
|
|
||||||
prev_paths_ = nullptr;
|
|
||||||
tag_group_index_ = tag_group_index_max;
|
tag_group_index_ = tag_group_index_max;
|
||||||
slew_annotated_ = false;
|
slew_annotated_ = false;
|
||||||
sim_value_ = unsigned(LogicValue::unknown);
|
sim_value_ = unsigned(LogicValue::unknown);
|
||||||
|
|
@ -1035,12 +983,8 @@ Vertex::clear()
|
||||||
{
|
{
|
||||||
delete [] slews_;
|
delete [] slews_;
|
||||||
slews_ = nullptr;
|
slews_ = nullptr;
|
||||||
delete [] arrivals_;
|
delete [] paths_;
|
||||||
arrivals_ = nullptr;
|
paths_ = nullptr;
|
||||||
delete [] requireds_;
|
|
||||||
requireds_ = nullptr;
|
|
||||||
delete [] prev_paths_;
|
|
||||||
prev_paths_ = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1153,24 +1097,10 @@ Vertex::setTagGroupIndex(TagGroupIndex tag_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Vertex::setArrivals(Arrival *arrivals)
|
Vertex::setPaths(Path *paths)
|
||||||
{
|
{
|
||||||
delete [] arrivals_;
|
delete [] paths_;
|
||||||
arrivals_ = arrivals;
|
paths_ = paths;
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Vertex::setRequireds(Required *requireds)
|
|
||||||
{
|
|
||||||
delete [] requireds_;
|
|
||||||
requireds_ = requireds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Vertex::setPrevPaths(PathPrev *prev_paths)
|
|
||||||
{
|
|
||||||
delete [] prev_paths_;
|
|
||||||
prev_paths_ = prev_paths;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LogicValue
|
LogicValue
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
#include "Delay.hh"
|
#include "Delay.hh"
|
||||||
#include "GraphClass.hh"
|
#include "GraphClass.hh"
|
||||||
#include "VertexId.hh"
|
#include "VertexId.hh"
|
||||||
#include "PathPrev.hh"
|
#include "Path.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
@ -96,19 +96,9 @@ public:
|
||||||
void deleteVertex(Vertex *vertex);
|
void deleteVertex(Vertex *vertex);
|
||||||
bool hasFaninOne(Vertex *vertex) const;
|
bool hasFaninOne(Vertex *vertex) const;
|
||||||
VertexId vertexCount() { return vertices_->size(); }
|
VertexId vertexCount() { return vertices_->size(); }
|
||||||
Arrival *makeArrivals(Vertex *vertex,
|
Path *makePaths(Vertex *vertex,
|
||||||
uint32_t count);
|
uint32_t count);
|
||||||
Arrival *arrivals(const Vertex *vertex) const;
|
Path *paths(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).
|
|
||||||
void deletePaths(Vertex *vertex);
|
void deletePaths(Vertex *vertex);
|
||||||
|
|
||||||
// Reported slew are the same as those in the liberty tables.
|
// Reported slew are the same as those in the liberty tables.
|
||||||
|
|
@ -269,10 +259,8 @@ public:
|
||||||
void setColor(LevelColor color);
|
void setColor(LevelColor color);
|
||||||
Slew *slews() { return slews_; }
|
Slew *slews() { return slews_; }
|
||||||
const Slew *slews() const { return slews_; }
|
const Slew *slews() const { return slews_; }
|
||||||
Arrival *arrivals() const { return arrivals_; }
|
Path *paths() const { return paths_; }
|
||||||
Arrival *requireds() const { return requireds_; }
|
void setPaths(Path *paths);
|
||||||
PathPrev *prevPaths() const { return prev_paths_; }
|
|
||||||
void setPrevPaths(PathPrev *prev_paths);
|
|
||||||
TagGroupIndex tagGroupIndex() const;
|
TagGroupIndex tagGroupIndex() const;
|
||||||
void setTagGroupIndex(TagGroupIndex tag_index);
|
void setTagGroupIndex(TagGroupIndex tag_index);
|
||||||
// Slew is annotated by sdc set_annotated_transition cmd.
|
// Slew is annotated by sdc set_annotated_transition cmd.
|
||||||
|
|
@ -311,7 +299,6 @@ public:
|
||||||
bool isRegClk() const { return is_reg_clk_; }
|
bool isRegClk() const { return is_reg_clk_; }
|
||||||
bool crprPathPruningDisabled() const { return crpr_path_pruning_disabled_;}
|
bool crprPathPruningDisabled() const { return crpr_path_pruning_disabled_;}
|
||||||
void setCrprPathPruningDisabled(bool disabled);
|
void setCrprPathPruningDisabled(bool disabled);
|
||||||
bool hasRequireds() const { return requireds_ != nullptr; }
|
|
||||||
|
|
||||||
// ObjectTable interface.
|
// ObjectTable interface.
|
||||||
ObjectIdx objectIdx() const { return object_idx_; }
|
ObjectIdx objectIdx() const { return object_idx_; }
|
||||||
|
|
@ -324,8 +311,6 @@ protected:
|
||||||
bool is_bidirect_drvr,
|
bool is_bidirect_drvr,
|
||||||
bool is_reg_clk);
|
bool is_reg_clk);
|
||||||
void clear();
|
void clear();
|
||||||
void setArrivals(Arrival *arrivals);
|
|
||||||
void setRequireds(Required *requireds);
|
|
||||||
void setSlews(Slew *slews);
|
void setSlews(Slew *slews);
|
||||||
|
|
||||||
Pin *pin_;
|
Pin *pin_;
|
||||||
|
|
@ -335,9 +320,7 @@ protected:
|
||||||
// Delay calc
|
// Delay calc
|
||||||
Slew *slews_;
|
Slew *slews_;
|
||||||
// Search
|
// Search
|
||||||
Arrival *arrivals_;
|
Path *paths_;
|
||||||
Arrival *requireds_;
|
|
||||||
PathPrev *prev_paths_;
|
|
||||||
|
|
||||||
// These fields are written by multiple threads, so they
|
// These fields are written by multiple threads, so they
|
||||||
// cannot share the same word as the following bit fields.
|
// cannot share the same word as the following bit fields.
|
||||||
|
|
|
||||||
|
|
@ -37,57 +37,96 @@ namespace sta {
|
||||||
|
|
||||||
class DcalcAnalysisPt;
|
class DcalcAnalysisPt;
|
||||||
|
|
||||||
// Abstract base class for Path API.
|
|
||||||
class Path
|
class Path
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Path() {}
|
Path();
|
||||||
virtual ~Path() {}
|
Path(Path *path);
|
||||||
virtual const char *name(const StaState *sta) const;
|
Path(Vertex *vertex,
|
||||||
virtual bool isNull() const = 0;
|
Tag *tag,
|
||||||
virtual Path *path() { return isNull() ? nullptr : this; }
|
const StaState *sta);
|
||||||
virtual const Path *path() const { return isNull() ? nullptr : this; }
|
Path(Vertex *vertex,
|
||||||
virtual void setRef(PathRef *ref) const = 0;
|
Tag *tag,
|
||||||
virtual void setRef(PathRef &ref) const { setRef(&ref); }
|
Arrival arrival,
|
||||||
virtual Vertex *vertex(const StaState *sta) const = 0;
|
Path *prev_path,
|
||||||
virtual VertexId vertexId(const StaState *sta) const = 0;
|
Edge *prev_edge,
|
||||||
virtual Pin *pin(const StaState *sta) const;
|
TimingArc *prev_arc,
|
||||||
virtual Tag *tag(const StaState *sta) const = 0;
|
const StaState *sta);
|
||||||
virtual TagIndex tagIndex(const StaState *sta) const;
|
Path(Vertex *vertex,
|
||||||
virtual ClkInfo *clkInfo(const StaState *sta) const;
|
Tag *tag,
|
||||||
virtual const ClockEdge *clkEdge(const StaState *sta) const;
|
Arrival arrival,
|
||||||
virtual const Clock *clock(const StaState *sta) const;
|
Path *prev_path,
|
||||||
virtual bool isClock(const StaState *sta) const;
|
Edge *prev_edge,
|
||||||
virtual const RiseFall *transition(const StaState *sta) const = 0;
|
TimingArc *prev_arc,
|
||||||
virtual int rfIndex(const StaState *sta) const;
|
bool is_enum,
|
||||||
virtual const MinMax *minMax(const StaState *sta) const;
|
const StaState *sta);
|
||||||
virtual PathAnalysisPt *pathAnalysisPt(const StaState *sta) const = 0;
|
~Path();
|
||||||
virtual PathAPIndex pathAnalysisPtIndex(const StaState *sta) const;
|
const char *name(const StaState *sta) const;
|
||||||
virtual DcalcAnalysisPt *dcalcAnalysisPt(const StaState *sta) const;
|
bool isNull() const;
|
||||||
virtual Arrival arrival(const StaState *sta) const = 0;
|
// prev_path null
|
||||||
virtual void setArrival(Arrival arrival,
|
void init(Vertex *vertex,
|
||||||
const StaState *sta) = 0;
|
Arrival arrival,
|
||||||
virtual void initArrival(const StaState *sta);
|
const StaState *sta);
|
||||||
virtual bool arrivalIsInitValue(const StaState *sta) const;
|
void init(Vertex *vertex,
|
||||||
virtual const Required &required(const StaState *sta) const = 0;
|
Tag *tag,
|
||||||
virtual void setRequired(const Required &required,
|
Arrival arrival,
|
||||||
const StaState *sta) = 0;
|
Path *prev_path,
|
||||||
virtual void initRequired(const StaState *sta);
|
Edge *prev_edge,
|
||||||
virtual bool requiredIsInitValue(const StaState *sta) const;
|
TimingArc *prev_arc,
|
||||||
virtual Slack slack(const StaState *sta) const;
|
const StaState *sta);
|
||||||
virtual Slew slew(const StaState *sta) const;
|
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.
|
// This takes the same time as prevPath and prevArc combined.
|
||||||
virtual void prevPath(const StaState *sta,
|
Path *prevPath() const;
|
||||||
// Return values.
|
void setPrevPath(Path *prev_path);
|
||||||
PathRef &prev_path,
|
void clearPrevPath(const StaState *sta);
|
||||||
TimingArc *&prev_arc) const = 0;
|
TimingArc *prevArc(const StaState *sta) const;
|
||||||
virtual void prevPath(const StaState *sta,
|
Edge *prevEdge(const StaState *sta) const;
|
||||||
// Return values.
|
Vertex *prevVertex(const StaState *sta) const;
|
||||||
PathRef &prev_path) const;
|
void setPrevEdgeArc(Edge *prev_edge,
|
||||||
virtual TimingArc *prevArc(const StaState *sta) const;
|
TimingArc *prev_arc,
|
||||||
// Find the previous edge given the previous arc found above.
|
const StaState *sta);
|
||||||
Edge *prevEdge(const TimingArc *prev_arc,
|
bool isEnum() const { return is_enum_; }
|
||||||
const StaState *sta) const;
|
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,
|
static bool less(const Path *path1,
|
||||||
const Path *path2,
|
const Path *path2,
|
||||||
|
|
@ -118,6 +157,18 @@ public:
|
||||||
static bool lessAll(const Path *path1,
|
static bool lessAll(const Path *path1,
|
||||||
const Path *path2,
|
const Path *path2,
|
||||||
const StaState *sta);
|
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).
|
// Compare all path attributes (vertex, transition, tag, analysis point).
|
||||||
|
|
@ -132,4 +183,47 @@ protected:
|
||||||
const StaState *sta_;
|
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
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
#include "GraphClass.hh"
|
#include "GraphClass.hh"
|
||||||
#include "SdcClass.hh"
|
#include "SdcClass.hh"
|
||||||
#include "SearchClass.hh"
|
#include "SearchClass.hh"
|
||||||
#include "PathRef.hh"
|
#include "Path.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
@ -73,10 +73,9 @@ public:
|
||||||
virtual PathEnd *copy() = 0;
|
virtual PathEnd *copy() = 0;
|
||||||
virtual ~PathEnd();
|
virtual ~PathEnd();
|
||||||
void deletePath();
|
void deletePath();
|
||||||
Path *path() { return &path_; }
|
Path *path() { return path_; }
|
||||||
const Path *path() const { return &path_; }
|
const Path *path() const { return path_; }
|
||||||
PathRef &pathRef() { return path_; }
|
virtual void setPath(Path *path);
|
||||||
virtual void setPath(const Path *path);
|
|
||||||
Vertex *vertex(const StaState *sta) const;
|
Vertex *vertex(const StaState *sta) const;
|
||||||
const MinMax *minMax(const StaState *sta) const;
|
const MinMax *minMax(const StaState *sta) const;
|
||||||
// Synonym for minMax().
|
// Synonym for minMax().
|
||||||
|
|
@ -118,8 +117,8 @@ public:
|
||||||
virtual float sourceClkOffset(const StaState *sta) const = 0;
|
virtual float sourceClkOffset(const StaState *sta) const = 0;
|
||||||
virtual Delay sourceClkLatency(const StaState *sta) const;
|
virtual Delay sourceClkLatency(const StaState *sta) const;
|
||||||
virtual Delay sourceClkInsertionDelay(const StaState *sta) const;
|
virtual Delay sourceClkInsertionDelay(const StaState *sta) const;
|
||||||
virtual PathVertex *targetClkPath();
|
virtual Path *targetClkPath();
|
||||||
virtual const PathVertex *targetClkPath() const;
|
virtual const Path *targetClkPath() const;
|
||||||
virtual const Clock *targetClk(const StaState *sta) const;
|
virtual const Clock *targetClk(const StaState *sta) const;
|
||||||
virtual const ClockEdge *targetClkEdge(const StaState *sta) const;
|
virtual const ClockEdge *targetClkEdge(const StaState *sta) const;
|
||||||
const RiseFall *targetClkEndTrans(const StaState *sta) const;
|
const RiseFall *targetClkEndTrans(const StaState *sta) const;
|
||||||
|
|
@ -149,7 +148,7 @@ public:
|
||||||
virtual MultiCyclePath *multiCyclePath() const;
|
virtual MultiCyclePath *multiCyclePath() const;
|
||||||
virtual TimingArc *checkArc() const { return nullptr; }
|
virtual TimingArc *checkArc() const { return nullptr; }
|
||||||
// PathEndDataCheck data clock path.
|
// 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 int setupDefaultCycles() const { return 1; }
|
||||||
virtual Delay clkSkew(const StaState *sta);
|
virtual Delay clkSkew(const StaState *sta);
|
||||||
virtual bool ignoreClkLatency(const StaState * /* sta */) const { return false; }
|
virtual bool ignoreClkLatency(const StaState * /* sta */) const { return false; }
|
||||||
|
|
@ -173,11 +172,11 @@ public:
|
||||||
// Helper common to multiple PathEnd classes and used
|
// Helper common to multiple PathEnd classes and used
|
||||||
// externally.
|
// externally.
|
||||||
// Target clock insertion delay + latency.
|
// 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 ClockEdge *tgt_clk_edge,
|
||||||
const TimingRole *check_role,
|
const TimingRole *check_role,
|
||||||
const StaState *sta);
|
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 ClockEdge *tgt_clk_edge,
|
||||||
const TimingRole *check_role,
|
const TimingRole *check_role,
|
||||||
const StaState *sta,
|
const StaState *sta,
|
||||||
|
|
@ -186,11 +185,11 @@ public:
|
||||||
Delay &latency);
|
Delay &latency);
|
||||||
static float checkClkUncertainty(const ClockEdge *src_clk_edge,
|
static float checkClkUncertainty(const ClockEdge *src_clk_edge,
|
||||||
const ClockEdge *tgt_clk_edge,
|
const ClockEdge *tgt_clk_edge,
|
||||||
const PathVertex *tgt_clk_path,
|
const Path *tgt_clk_path,
|
||||||
const TimingRole *check_role,
|
const TimingRole *check_role,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
// Non inter-clock uncertainty.
|
// 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 ClockEdge *tgt_clk_edge,
|
||||||
const TimingRole *check_role,
|
const TimingRole *check_role,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
|
@ -211,14 +210,14 @@ protected:
|
||||||
static float outputDelayMargin(OutputDelay *output_delay,
|
static float outputDelayMargin(OutputDelay *output_delay,
|
||||||
const Path *path,
|
const Path *path,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
static float pathDelaySrcClkOffset(const PathRef &path,
|
static float pathDelaySrcClkOffset(const Path *path,
|
||||||
PathDelay *path_delay,
|
PathDelay *path_delay,
|
||||||
Arrival src_clk_arrival,
|
Arrival src_clk_arrival,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
static bool ignoreClkLatency(const PathRef &path,
|
static bool ignoreClkLatency(const Path *path,
|
||||||
PathDelay *path_delay,
|
PathDelay *path_delay,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
PathRef path_;
|
Path *path_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PathEndUnconstrained : public PathEnd
|
class PathEndUnconstrained : public PathEnd
|
||||||
|
|
@ -247,8 +246,8 @@ public:
|
||||||
virtual Delay sourceClkInsertionDelay(const StaState *sta) const;
|
virtual Delay sourceClkInsertionDelay(const StaState *sta) const;
|
||||||
virtual const Clock *targetClk(const StaState *sta) const;
|
virtual const Clock *targetClk(const StaState *sta) const;
|
||||||
virtual const ClockEdge *targetClkEdge(const StaState *sta) const;
|
virtual const ClockEdge *targetClkEdge(const StaState *sta) const;
|
||||||
virtual PathVertex *targetClkPath();
|
virtual Path *targetClkPath();
|
||||||
virtual const PathVertex *targetClkPath() const;
|
virtual const Path *targetClkPath() const;
|
||||||
virtual float targetClkTime(const StaState *sta) const;
|
virtual float targetClkTime(const StaState *sta) const;
|
||||||
virtual float targetClkOffset(const StaState *sta) const;
|
virtual float targetClkOffset(const StaState *sta) const;
|
||||||
virtual Arrival targetClkArrival(const StaState *sta) const;
|
virtual Arrival targetClkArrival(const StaState *sta) const;
|
||||||
|
|
@ -263,13 +262,13 @@ public:
|
||||||
virtual Slack slackNoCrpr(const StaState *sta) const;
|
virtual Slack slackNoCrpr(const StaState *sta) const;
|
||||||
virtual int exceptPathCmp(const PathEnd *path_end,
|
virtual int exceptPathCmp(const PathEnd *path_end,
|
||||||
const StaState *sta) const;
|
const StaState *sta) const;
|
||||||
virtual void setPath(const Path *path);
|
virtual void setPath(Path *path);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PathEndClkConstrained(Path *path,
|
PathEndClkConstrained(Path *path,
|
||||||
PathVertex *clk_path);
|
Path *clk_path);
|
||||||
PathEndClkConstrained(Path *path,
|
PathEndClkConstrained(Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
Crpr crpr,
|
Crpr crpr,
|
||||||
bool crpr_valid);
|
bool crpr_valid);
|
||||||
|
|
||||||
|
|
@ -281,7 +280,7 @@ protected:
|
||||||
virtual Arrival targetClkArrivalNoCrpr(const StaState *sta) const;
|
virtual Arrival targetClkArrivalNoCrpr(const StaState *sta) const;
|
||||||
virtual Required requiredTimeNoCrpr(const StaState *sta) const;
|
virtual Required requiredTimeNoCrpr(const StaState *sta) const;
|
||||||
|
|
||||||
PathVertex clk_path_;
|
Path *clk_path_;
|
||||||
mutable Crpr crpr_;
|
mutable Crpr crpr_;
|
||||||
mutable bool crpr_valid_;
|
mutable bool crpr_valid_;
|
||||||
};
|
};
|
||||||
|
|
@ -296,10 +295,10 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PathEndClkConstrainedMcp(Path *path,
|
PathEndClkConstrainedMcp(Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp);
|
MultiCyclePath *mcp);
|
||||||
PathEndClkConstrainedMcp(Path *path,
|
PathEndClkConstrainedMcp(Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
Crpr crpr,
|
Crpr crpr,
|
||||||
bool crpr_valid);
|
bool crpr_valid);
|
||||||
|
|
@ -321,7 +320,7 @@ public:
|
||||||
PathEndCheck(Path *path,
|
PathEndCheck(Path *path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
virtual PathEnd *copy();
|
virtual PathEnd *copy();
|
||||||
|
|
@ -342,7 +341,7 @@ protected:
|
||||||
PathEndCheck(Path *path,
|
PathEndCheck(Path *path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
Crpr crpr,
|
Crpr crpr,
|
||||||
bool crpr_valid);
|
bool crpr_valid);
|
||||||
|
|
@ -360,7 +359,7 @@ public:
|
||||||
PathEndLatchCheck(Path *path,
|
PathEndLatchCheck(Path *path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
PathVertex *disable_path,
|
Path *disable_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
PathDelay *path_delay,
|
PathDelay *path_delay,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
|
@ -371,8 +370,8 @@ public:
|
||||||
virtual bool isLatchCheck() const { return true; }
|
virtual bool isLatchCheck() const { return true; }
|
||||||
virtual PathDelay *pathDelay() const { return path_delay_; }
|
virtual PathDelay *pathDelay() const { return path_delay_; }
|
||||||
virtual PathEnd *copy();
|
virtual PathEnd *copy();
|
||||||
PathVertex *latchDisable();
|
Path *latchDisable();
|
||||||
const PathVertex *latchDisable() const;
|
const Path *latchDisable() const;
|
||||||
virtual void reportShort(const ReportPath *report) const;
|
virtual void reportShort(const ReportPath *report) const;
|
||||||
virtual void reportFull(const ReportPath *report) const;
|
virtual void reportFull(const ReportPath *report) const;
|
||||||
virtual TimingRole *checkRole(const StaState *sta) const;
|
virtual TimingRole *checkRole(const StaState *sta) const;
|
||||||
|
|
@ -403,8 +402,8 @@ protected:
|
||||||
PathEndLatchCheck(Path *path,
|
PathEndLatchCheck(Path *path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
PathVertex *disable,
|
Path *disable,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
PathDelay *path_delay,
|
PathDelay *path_delay,
|
||||||
Delay src_clk_arrival,
|
Delay src_clk_arrival,
|
||||||
|
|
@ -412,7 +411,7 @@ protected:
|
||||||
bool crpr_valid);
|
bool crpr_valid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PathVertex disable_path_;
|
Path *disable_path_;
|
||||||
PathDelay *path_delay_;
|
PathDelay *path_delay_;
|
||||||
// Source clk arrival for set_max_delay -ignore_clk_latency.
|
// Source clk arrival for set_max_delay -ignore_clk_latency.
|
||||||
Arrival src_clk_arrival_;
|
Arrival src_clk_arrival_;
|
||||||
|
|
@ -426,7 +425,7 @@ class PathEndOutputDelay : public PathEndClkConstrainedMcp
|
||||||
public:
|
public:
|
||||||
PathEndOutputDelay(OutputDelay *output_delay,
|
PathEndOutputDelay(OutputDelay *output_delay,
|
||||||
Path *path,
|
Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
virtual PathEnd *copy();
|
virtual PathEnd *copy();
|
||||||
|
|
@ -448,7 +447,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
PathEndOutputDelay(OutputDelay *output_delay,
|
PathEndOutputDelay(OutputDelay *output_delay,
|
||||||
Path *path,
|
Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
Crpr crpr,
|
Crpr crpr,
|
||||||
bool crpr_valid);
|
bool crpr_valid);
|
||||||
|
|
@ -470,7 +469,7 @@ class PathEndGatedClock : public PathEndClkConstrainedMcp
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PathEndGatedClock(Path *gating_ref,
|
PathEndGatedClock(Path *gating_ref,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
TimingRole *check_role,
|
TimingRole *check_role,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
ArcDelay margin,
|
ArcDelay margin,
|
||||||
|
|
@ -488,7 +487,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PathEndGatedClock(Path *gating_ref,
|
PathEndGatedClock(Path *gating_ref,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
TimingRole *check_role,
|
TimingRole *check_role,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
ArcDelay margin,
|
ArcDelay margin,
|
||||||
|
|
@ -504,7 +503,7 @@ class PathEndDataCheck : public PathEndClkConstrainedMcp
|
||||||
public:
|
public:
|
||||||
PathEndDataCheck(DataCheck *check,
|
PathEndDataCheck(DataCheck *check,
|
||||||
Path *data_path,
|
Path *data_path,
|
||||||
PathVertex *data_clk_path,
|
Path *data_clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
virtual PathEnd *copy();
|
virtual PathEnd *copy();
|
||||||
|
|
@ -518,26 +517,24 @@ public:
|
||||||
virtual ArcDelay margin(const StaState *sta) const;
|
virtual ArcDelay margin(const StaState *sta) const;
|
||||||
virtual int exceptPathCmp(const PathEnd *path_end,
|
virtual int exceptPathCmp(const PathEnd *path_end,
|
||||||
const StaState *sta) const;
|
const StaState *sta) const;
|
||||||
virtual const PathVertex *dataClkPath() const { return &data_clk_path_; }
|
virtual const Path *dataClkPath() const { return data_clk_path_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PathEndDataCheck(DataCheck *check,
|
PathEndDataCheck(DataCheck *check,
|
||||||
Path *data_path,
|
Path *data_path,
|
||||||
PathVertex *data_clk_path,
|
Path *data_clk_path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
Crpr crpr,
|
Crpr crpr,
|
||||||
bool crpr_valid);
|
bool crpr_valid);
|
||||||
void clkPath(PathVertex *path,
|
Path *clkPath(Path *path,
|
||||||
const StaState *sta,
|
const StaState *sta);
|
||||||
// Return value.
|
|
||||||
PathVertex &clk_path);
|
|
||||||
Arrival requiredTimeNoCrpr(const StaState *sta) const;
|
Arrival requiredTimeNoCrpr(const StaState *sta) const;
|
||||||
// setup uses zero cycle default
|
// setup uses zero cycle default
|
||||||
virtual int setupDefaultCycles() const { return 0; }
|
virtual int setupDefaultCycles() const { return 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PathVertex data_clk_path_;
|
Path *data_clk_path_;
|
||||||
DataCheck *check_;
|
DataCheck *check_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -554,7 +551,7 @@ public:
|
||||||
// Path delay to timing check.
|
// Path delay to timing check.
|
||||||
PathEndPathDelay(PathDelay *path_delay,
|
PathEndPathDelay(PathDelay *path_delay,
|
||||||
Path *path,
|
Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
|
@ -588,7 +585,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
PathEndPathDelay(PathDelay *path_delay,
|
PathEndPathDelay(PathDelay *path_delay,
|
||||||
Path *path,
|
Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
OutputDelay *output_delay,
|
OutputDelay *output_delay,
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
#include "TimingArc.hh"
|
#include "TimingArc.hh"
|
||||||
#include "GraphClass.hh"
|
#include "GraphClass.hh"
|
||||||
#include "SearchClass.hh"
|
#include "SearchClass.hh"
|
||||||
#include "PathRef.hh"
|
#include "Path.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
@ -48,33 +48,31 @@ public:
|
||||||
size_t size() const { return paths_.size(); }
|
size_t size() const { return paths_.size(); }
|
||||||
// path(0) is the startpoint.
|
// path(0) is the startpoint.
|
||||||
// path(size()-1) is the endpoint.
|
// path(size()-1) is the endpoint.
|
||||||
const PathRef *path(size_t index) const;
|
const Path *path(size_t index) const;
|
||||||
TimingArc *prevArc(size_t index) const;
|
|
||||||
// Returns the path start point.
|
// Returns the path start point.
|
||||||
// Register/Latch Q pin
|
// Register/Latch Q pin
|
||||||
// Input pin
|
// Input pin
|
||||||
const PathRef *startPath() const;
|
const Path *startPath() const;
|
||||||
const PathRef *startPrevPath() const;
|
const Path *startPrevPath() const;
|
||||||
const PathRef *endPath() const;
|
const Path *endPath() const;
|
||||||
TimingArc *startPrevArc() const;
|
const TimingArc *startPrevArc() const;
|
||||||
size_t startIndex() const;
|
size_t startIndex() const;
|
||||||
void clkPath(PathRef &clk_path) const;
|
const Path *clkPath() const;
|
||||||
void latchPaths(// Return values.
|
void latchPaths(// Return values.
|
||||||
const PathRef *&d_path,
|
const Path *&d_path,
|
||||||
const PathRef *&q_path,
|
const Path *&q_path,
|
||||||
Edge *&d_q_edge) const;
|
Edge *&d_q_edge) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void expandGenclk(PathRef *clk_path);
|
void expandGenclk(const Path *clk_path);
|
||||||
// Convert external index that starts at the path root
|
// Convert external index that starts at the path root
|
||||||
// and increases to an index for paths_ (reversed).
|
// and increases to an index for paths_ (reversed).
|
||||||
size_t pathsIndex(size_t index) const;
|
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_[0] is the endpoint.
|
||||||
// paths_[size-1] is the beginning of the path.
|
// paths_[size-1] is the beginning of the path.
|
||||||
PathRefSeq paths_;
|
ConstPathSeq paths_;
|
||||||
TimingArcSeq prev_arcs_;
|
|
||||||
// Index of the startpoint.
|
// Index of the startpoint.
|
||||||
size_t start_index_;
|
size_t start_index_;
|
||||||
const StaState *sta_;
|
const StaState *sta_;
|
||||||
|
|
|
||||||
|
|
@ -74,12 +74,12 @@ public:
|
||||||
PathGroupIterator *iterator();
|
PathGroupIterator *iterator();
|
||||||
// This does NOT delete the path ends.
|
// This does NOT delete the path ends.
|
||||||
void clear();
|
void clear();
|
||||||
static int group_path_count_max;
|
static size_t group_path_count_max;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PathGroup(const char *name,
|
PathGroup(const char *name,
|
||||||
int group_path_count,
|
size_t group_path_count,
|
||||||
int endpoint_path_count,
|
size_t endpoint_path_count,
|
||||||
bool unique_pins,
|
bool unique_pins,
|
||||||
float min_slack,
|
float min_slack,
|
||||||
float max_slack,
|
float max_slack,
|
||||||
|
|
@ -91,8 +91,8 @@ protected:
|
||||||
void sort();
|
void sort();
|
||||||
|
|
||||||
const char *name_;
|
const char *name_;
|
||||||
int group_path_count_;
|
size_t group_path_count_;
|
||||||
int endpoint_path_count_;
|
size_t endpoint_path_count_;
|
||||||
bool unique_pins_;
|
bool unique_pins_;
|
||||||
float slack_min_;
|
float slack_min_;
|
||||||
float slack_max_;
|
float slack_max_;
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -55,7 +55,7 @@ public:
|
||||||
type_library, type_cell, type_port,
|
type_library, type_cell, type_port,
|
||||||
type_liberty_library, type_liberty_cell, type_liberty_port,
|
type_liberty_library, type_liberty_cell, type_liberty_port,
|
||||||
type_instance, type_pin, type_pins, type_net,
|
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();
|
||||||
PropertyValue(const char *value);
|
PropertyValue(const char *value);
|
||||||
PropertyValue(string &value);
|
PropertyValue(string &value);
|
||||||
|
|
@ -77,7 +77,7 @@ public:
|
||||||
PropertyValue(const Clock *value);
|
PropertyValue(const Clock *value);
|
||||||
PropertyValue(ClockSeq *value);
|
PropertyValue(ClockSeq *value);
|
||||||
PropertyValue(ClockSet *value);
|
PropertyValue(ClockSet *value);
|
||||||
PropertyValue(PathRefSeq *value);
|
PropertyValue(ConstPathSeq *value);
|
||||||
PropertyValue(PwrActivity *value);
|
PropertyValue(PwrActivity *value);
|
||||||
// Copy constructor.
|
// Copy constructor.
|
||||||
PropertyValue(const PropertyValue &props);
|
PropertyValue(const PropertyValue &props);
|
||||||
|
|
@ -103,7 +103,7 @@ public:
|
||||||
const Net *net() const { return net_; }
|
const Net *net() const { return net_; }
|
||||||
const Clock *clock() const { return clk_; }
|
const Clock *clock() const { return clk_; }
|
||||||
ClockSeq *clocks() const { return clks_; }
|
ClockSeq *clocks() const { return clks_; }
|
||||||
PathRefSeq *pathRefs() const { return path_refs_; }
|
ConstPathSeq *paths() const { return paths_; }
|
||||||
PwrActivity pwrActivity() const { return pwr_activity_; }
|
PwrActivity pwrActivity() const { return pwr_activity_; }
|
||||||
|
|
||||||
// Copy assignment.
|
// Copy assignment.
|
||||||
|
|
@ -129,7 +129,7 @@ private:
|
||||||
const Net *net_;
|
const Net *net_;
|
||||||
const Clock *clk_;
|
const Clock *clk_;
|
||||||
ClockSeq *clks_;
|
ClockSeq *clks_;
|
||||||
PathRefSeq *path_refs_;
|
ConstPathSeq *paths_;
|
||||||
PwrActivity pwr_activity_;
|
PwrActivity pwr_activity_;
|
||||||
};
|
};
|
||||||
const Unit *unit_;
|
const Unit *unit_;
|
||||||
|
|
@ -196,7 +196,7 @@ getProperty(PathEnd *end,
|
||||||
Sta *sta);
|
Sta *sta);
|
||||||
|
|
||||||
PropertyValue
|
PropertyValue
|
||||||
getProperty(PathRef *end,
|
getProperty(Path *end,
|
||||||
const char *property,
|
const char *property,
|
||||||
Sta *sta);
|
Sta *sta);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// OpenSTA, Static Timing Analyzer
|
// opensta, Static Timing Analyzer
|
||||||
// Copyright (c) 2025, Parallax Software, Inc.
|
// Copyright (c) 2025, Parallax Software, Inc.
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
#include "SearchClass.hh"
|
#include "SearchClass.hh"
|
||||||
#include "SearchPred.hh"
|
#include "SearchPred.hh"
|
||||||
#include "VertexVisitor.hh"
|
#include "VertexVisitor.hh"
|
||||||
|
#include "Path.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -99,8 +100,8 @@ public:
|
||||||
bool unconstrained,
|
bool unconstrained,
|
||||||
const Corner *corner,
|
const Corner *corner,
|
||||||
const MinMaxAll *min_max,
|
const MinMaxAll *min_max,
|
||||||
int group_path_count,
|
size_t group_path_count,
|
||||||
int endpoint_path_count,
|
size_t endpoint_path_count,
|
||||||
bool unique_pins,
|
bool unique_pins,
|
||||||
float slack_min,
|
float slack_min,
|
||||||
float slack_max,
|
float slack_max,
|
||||||
|
|
@ -126,6 +127,7 @@ public:
|
||||||
void requiredInvalid(const Pin *pin);
|
void requiredInvalid(const Pin *pin);
|
||||||
// Vertex will be deleted.
|
// Vertex will be deleted.
|
||||||
void deleteVertexBefore(Vertex *vertex);
|
void deleteVertexBefore(Vertex *vertex);
|
||||||
|
void deleteEdgeBefore(Edge *edge);
|
||||||
// Find all arrival times (propatating thru latches).
|
// Find all arrival times (propatating thru latches).
|
||||||
void findAllArrivals();
|
void findAllArrivals();
|
||||||
// Find all arrivals (without latch propagation).
|
// Find all arrivals (without latch propagation).
|
||||||
|
|
@ -226,7 +228,7 @@ public:
|
||||||
TagIndex tagCount() const;
|
TagIndex tagCount() const;
|
||||||
TagGroupIndex tagGroupCount() const;
|
TagGroupIndex tagGroupCount() const;
|
||||||
void reportTagGroups() const;
|
void reportTagGroups() const;
|
||||||
void reportArrivalCountHistogram() const;
|
void reportPathCountHistogram() const;
|
||||||
virtual int clkInfoCount() const;
|
virtual int clkInfoCount() const;
|
||||||
virtual bool isEndpoint(Vertex *vertex) const;
|
virtual bool isEndpoint(Vertex *vertex) const;
|
||||||
virtual bool isEndpoint(Vertex *vertex,
|
virtual bool isEndpoint(Vertex *vertex,
|
||||||
|
|
@ -252,7 +254,7 @@ public:
|
||||||
const RiseFall *to_rf,
|
const RiseFall *to_rf,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
const PathAnalysisPt *path_ap);
|
const PathAnalysisPt *path_ap);
|
||||||
Tag *thruClkTag(PathVertex *from_path,
|
Tag *thruClkTag(Path *from_path,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
bool to_propagates_clk,
|
bool to_propagates_clk,
|
||||||
|
|
@ -261,7 +263,7 @@ public:
|
||||||
bool arc_delay_min_max_eq,
|
bool arc_delay_min_max_eq,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
const PathAnalysisPt *path_ap);
|
const PathAnalysisPt *path_ap);
|
||||||
ClkInfo *thruClkInfo(PathVertex *from_path,
|
ClkInfo *thruClkInfo(Path *from_path,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
ClkInfo *from_clk_info,
|
ClkInfo *from_clk_info,
|
||||||
bool from_is_clk,
|
bool from_is_clk,
|
||||||
|
|
@ -273,7 +275,7 @@ public:
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
const PathAnalysisPt *path_ap);
|
const PathAnalysisPt *path_ap);
|
||||||
ClkInfo *clkInfoWithCrprClkPath(ClkInfo *from_clk_info,
|
ClkInfo *clkInfoWithCrprClkPath(ClkInfo *from_clk_info,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
const PathAnalysisPt *path_ap);
|
const PathAnalysisPt *path_ap);
|
||||||
void seedClkArrivals(const Pin *pin,
|
void seedClkArrivals(const Pin *pin,
|
||||||
Vertex *vertex,
|
Vertex *vertex,
|
||||||
|
|
@ -339,7 +341,7 @@ public:
|
||||||
float latency,
|
float latency,
|
||||||
ClockUncertainties *uncertainties,
|
ClockUncertainties *uncertainties,
|
||||||
const PathAnalysisPt *path_ap,
|
const PathAnalysisPt *path_ap,
|
||||||
PathVertex *crpr_clk_path);
|
Path *crpr_clk_path);
|
||||||
ClkInfo *findClkInfo(const ClockEdge *clk_edge,
|
ClkInfo *findClkInfo(const ClockEdge *clk_edge,
|
||||||
const Pin *clk_src,
|
const Pin *clk_src,
|
||||||
bool is_propagated,
|
bool is_propagated,
|
||||||
|
|
@ -378,7 +380,33 @@ public:
|
||||||
bool unconstrained,
|
bool unconstrained,
|
||||||
bool thru_latches);
|
bool thru_latches);
|
||||||
VertexSeq filteredEndpoints();
|
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:
|
protected:
|
||||||
void init(StaState *sta);
|
void init(StaState *sta);
|
||||||
|
|
@ -544,7 +572,8 @@ protected:
|
||||||
void tnsNotifyBefore(Vertex *vertex);
|
void tnsNotifyBefore(Vertex *vertex);
|
||||||
bool matchesFilterTo(Path *path,
|
bool matchesFilterTo(Path *path,
|
||||||
const ClockEdge *to_clk_edge) const;
|
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,
|
void clocks(const Vertex *vertex,
|
||||||
// Return value.
|
// Return value.
|
||||||
ClockSet &clks) const;
|
ClockSet &clks) const;
|
||||||
|
|
@ -619,7 +648,6 @@ protected:
|
||||||
std::mutex pending_latch_outputs_lock_;
|
std::mutex pending_latch_outputs_lock_;
|
||||||
VertexSet *endpoints_;
|
VertexSet *endpoints_;
|
||||||
VertexSet *invalid_endpoints_;
|
VertexSet *invalid_endpoints_;
|
||||||
bool always_save_prev_paths_;
|
|
||||||
// Filter exception to tag arrivals for
|
// Filter exception to tag arrivals for
|
||||||
// report_timing -from pin|inst -through.
|
// report_timing -from pin|inst -through.
|
||||||
// -to is always nullptr.
|
// -to is always nullptr.
|
||||||
|
|
@ -682,7 +710,7 @@ protected:
|
||||||
bool visitArc(const Pin *from_pin,
|
bool visitArc(const Pin *from_pin,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
const Pin *to_pin,
|
const Pin *to_pin,
|
||||||
|
|
@ -694,7 +722,7 @@ protected:
|
||||||
virtual bool visitFromPath(const Pin *from_pin,
|
virtual bool visitFromPath(const Pin *from_pin,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
const Pin *to_pin,
|
const Pin *to_pin,
|
||||||
|
|
@ -707,7 +735,7 @@ protected:
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
const Arrival &from_arrival,
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
|
|
@ -740,7 +768,7 @@ public:
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
const Arrival &from_arrival,
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
|
|
@ -781,14 +809,14 @@ public:
|
||||||
RequiredCmp();
|
RequiredCmp();
|
||||||
void requiredsInit(Vertex *vertex,
|
void requiredsInit(Vertex *vertex,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
void requiredSet(int arrival_index,
|
void requiredSet(size_t path_index,
|
||||||
Required required,
|
Required &required,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
// Return true if the requireds changed.
|
// Return true if the requireds changed.
|
||||||
bool requiredsSave(Vertex *vertex,
|
bool requiredsSave(Vertex *vertex,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
Required required(int arrival_index);
|
Required required(size_t path_index);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ArrivalSeq requireds_;
|
ArrivalSeq requireds_;
|
||||||
|
|
@ -811,7 +839,7 @@ protected:
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
const Arrival &from_arrival,
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,6 @@ namespace sta {
|
||||||
class Search;
|
class Search;
|
||||||
class Corner;
|
class Corner;
|
||||||
class Path;
|
class Path;
|
||||||
class PathRep;
|
|
||||||
class PathVertex;
|
|
||||||
class PathPrev;
|
|
||||||
class PathVertexPtr;
|
|
||||||
class PathRef;
|
|
||||||
class PathEnumed;
|
|
||||||
class PathEnd;
|
class PathEnd;
|
||||||
class PathGroup;
|
class PathGroup;
|
||||||
class Tag;
|
class Tag;
|
||||||
|
|
@ -120,12 +114,12 @@ typedef Vector<MaxSkewCheck*> MaxSkewCheckSeq;
|
||||||
typedef StringSet PathGroupNameSet;
|
typedef StringSet PathGroupNameSet;
|
||||||
typedef Vector<PathEnd*> PathEndSeq;
|
typedef Vector<PathEnd*> PathEndSeq;
|
||||||
typedef Vector<Arrival> ArrivalSeq;
|
typedef Vector<Arrival> ArrivalSeq;
|
||||||
typedef Map<Vertex*, int> VertexPathCountMap;
|
typedef Map<Vertex*, size_t> VertexPathCountMap;
|
||||||
typedef UnorderedMap<Tag*, int, TagMatchHash, TagMatchEqual> ArrivalMap;
|
typedef UnorderedMap<Tag*, size_t, TagMatchHash, TagMatchEqual> PathIndexMap;
|
||||||
typedef Vector<PathVertex> PathVertexSeq;
|
|
||||||
typedef Vector<Slack> SlackSeq;
|
typedef Vector<Slack> SlackSeq;
|
||||||
typedef Delay Crpr;
|
typedef Delay Crpr;
|
||||||
typedef Vector<PathRef> PathRefSeq;
|
typedef Vector<Path*> PathSeq;
|
||||||
|
typedef vector<const Path*> ConstPathSeq;
|
||||||
|
|
||||||
enum class ReportPathFormat { full,
|
enum class ReportPathFormat { full,
|
||||||
full_clock,
|
full_clock,
|
||||||
|
|
|
||||||
|
|
@ -1000,21 +1000,21 @@ public:
|
||||||
VertexPathIterator *vertexPathIterator(Vertex *vertex,
|
VertexPathIterator *vertexPathIterator(Vertex *vertex,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const MinMax *min_max);
|
const MinMax *min_max);
|
||||||
PathRef vertexWorstArrivalPath(Vertex *vertex,
|
Path *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,
|
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const MinMax *min_max);
|
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
|
// 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
|
// using the slack. This does NOT correctly predict min period when there
|
||||||
|
|
@ -1112,10 +1112,9 @@ public:
|
||||||
TagIndex tagCount() const;
|
TagIndex tagCount() const;
|
||||||
TagGroupIndex tagGroupCount() const;
|
TagGroupIndex tagGroupCount() const;
|
||||||
int clkInfoCount() const;
|
int clkInfoCount() const;
|
||||||
int arrivalCount() const;
|
int pathCount() const;
|
||||||
int requiredCount() const;
|
int vertexPathCount(Vertex *vertex) const;
|
||||||
int vertexArrivalCount(Vertex *vertex) const;
|
Vertex *maxPathCountVertex() const;
|
||||||
Vertex *maxArrivalCountVertex() const;
|
|
||||||
|
|
||||||
LogicValue simLogicValue(const Pin *pin);
|
LogicValue simLogicValue(const Pin *pin);
|
||||||
// Propagate liberty constant functions and pins tied high/low through
|
// Propagate liberty constant functions and pins tied high/low through
|
||||||
|
|
@ -1314,7 +1313,7 @@ public:
|
||||||
LibertyLibrarySeq *map_libs);
|
LibertyLibrarySeq *map_libs);
|
||||||
LibertyCellSeq *equivCells(LibertyCell *cell);
|
LibertyCellSeq *equivCells(LibertyCell *cell);
|
||||||
|
|
||||||
void writePathSpice(PathRef *path,
|
void writePathSpice(Path *path,
|
||||||
const char *spice_filename,
|
const char *spice_filename,
|
||||||
const char *subckt_filename,
|
const char *subckt_filename,
|
||||||
const char *lib_subckt_filename,
|
const char *lib_subckt_filename,
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ protected:
|
||||||
Path *path,
|
Path *path,
|
||||||
const RiseFall *end_rf,
|
const RiseFall *end_rf,
|
||||||
const ClockEdge *tgt_clk_edge,
|
const ClockEdge *tgt_clk_edge,
|
||||||
PathVertex *ref_path,
|
Path *ref_path,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
PathEndVisitor *visitor,
|
PathEndVisitor *visitor,
|
||||||
bool &is_constrained);
|
bool &is_constrained);
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@
|
||||||
#include "DcalcAnalysisPt.hh"
|
#include "DcalcAnalysisPt.hh"
|
||||||
#include "GraphDelayCalc.hh"
|
#include "GraphDelayCalc.hh"
|
||||||
#include "Corner.hh"
|
#include "Corner.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "search/Levelize.hh"
|
#include "search/Levelize.hh"
|
||||||
#include "search/Sim.hh"
|
#include "search/Sim.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
|
|
@ -1339,7 +1339,7 @@ Power::findClk(const Pin *to_pin)
|
||||||
if (to_vertex) {
|
if (to_vertex) {
|
||||||
VertexPathIterator path_iter(to_vertex, this);
|
VertexPathIterator path_iter(to_vertex, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
const Clock *path_clk = path->clock(this);
|
const Clock *path_clk = path->clock(this);
|
||||||
if (path_clk
|
if (path_clk
|
||||||
&& (clk == nullptr
|
&& (clk == nullptr
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
#include "Network.hh"
|
#include "Network.hh"
|
||||||
#include "Graph.hh"
|
#include "Graph.hh"
|
||||||
#include "Clock.hh"
|
#include "Clock.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "PathAnalysisPt.hh"
|
#include "PathAnalysisPt.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
|
|
||||||
|
|
@ -199,13 +199,13 @@ CheckMaxSkews:: visitMaxSkewChecks(Vertex *vertex,
|
||||||
RiseFall *ref_rf = arc->toEdge()->asRiseFall();
|
RiseFall *ref_rf = arc->toEdge()->asRiseFall();
|
||||||
VertexPathIterator clk_path_iter(vertex, clk_rf, clk_min_max, search);
|
VertexPathIterator clk_path_iter(vertex, clk_rf, clk_min_max, search);
|
||||||
while (clk_path_iter.hasNext()) {
|
while (clk_path_iter.hasNext()) {
|
||||||
PathVertex *clk_path = clk_path_iter.next();
|
Path *clk_path = clk_path_iter.next();
|
||||||
if (clk_path->isClock(search)) {
|
if (clk_path->isClock(search)) {
|
||||||
const PathAnalysisPt *clk_ap = clk_path->pathAnalysisPt(sta_);
|
const PathAnalysisPt *clk_ap = clk_path->pathAnalysisPt(sta_);
|
||||||
PathAnalysisPt *ref_ap = clk_ap->tgtClkAnalysisPt();
|
PathAnalysisPt *ref_ap = clk_ap->tgtClkAnalysisPt();
|
||||||
VertexPathIterator ref_path_iter(ref_vertex, ref_rf, ref_ap, sta_);
|
VertexPathIterator ref_path_iter(ref_vertex, ref_rf, ref_ap, sta_);
|
||||||
while (ref_path_iter.hasNext()) {
|
while (ref_path_iter.hasNext()) {
|
||||||
PathVertex *ref_path = ref_path_iter.next();
|
Path *ref_path = ref_path_iter.next();
|
||||||
if (ref_path->isClock(search)) {
|
if (ref_path->isClock(search)) {
|
||||||
MaxSkewCheck check(clk_path, ref_path, arc, edge);
|
MaxSkewCheck check(clk_path, ref_path, arc, edge);
|
||||||
visitor->visit(check, sta_);
|
visitor->visit(check, sta_);
|
||||||
|
|
@ -220,8 +220,8 @@ CheckMaxSkews:: visitMaxSkewChecks(Vertex *vertex,
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
MaxSkewCheck::MaxSkewCheck(PathVertex *clk_path,
|
MaxSkewCheck::MaxSkewCheck(Path *clk_path,
|
||||||
PathVertex *ref_path,
|
Path *ref_path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge) :
|
Edge *check_edge) :
|
||||||
clk_path_(clk_path),
|
clk_path_(clk_path),
|
||||||
|
|
@ -234,34 +234,34 @@ MaxSkewCheck::MaxSkewCheck(PathVertex *clk_path,
|
||||||
Pin *
|
Pin *
|
||||||
MaxSkewCheck::clkPin(const StaState *sta) const
|
MaxSkewCheck::clkPin(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return clk_path_.pin(sta);
|
return clk_path_->pin(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pin *
|
Pin *
|
||||||
MaxSkewCheck::refPin(const StaState *sta) const
|
MaxSkewCheck::refPin(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return ref_path_.pin(sta);
|
return ref_path_->pin(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArcDelay
|
ArcDelay
|
||||||
MaxSkewCheck::maxSkew(const StaState *sta) const
|
MaxSkewCheck::maxSkew(const StaState *sta) const
|
||||||
{
|
{
|
||||||
Search *search = sta->search();
|
Search *search = sta->search();
|
||||||
return search->deratedDelay(ref_path_.vertex(sta),
|
return search->deratedDelay(ref_path_->vertex(sta),
|
||||||
check_arc_, check_edge_, false,
|
check_arc_, check_edge_, false,
|
||||||
clk_path_.pathAnalysisPt(sta));
|
clk_path_->pathAnalysisPt(sta));
|
||||||
}
|
}
|
||||||
|
|
||||||
Delay
|
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
|
Slack
|
||||||
MaxSkewCheck::slack(const StaState *sta) const
|
MaxSkewCheck::slack(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return maxSkew(sta) - skew(sta);
|
return maxSkew(sta) - skew();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
#include "Delay.hh"
|
#include "Delay.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
#include "SearchClass.hh"
|
#include "SearchClass.hh"
|
||||||
#include "PathRef.hh"
|
#include "Path.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -57,22 +57,22 @@ protected:
|
||||||
class MaxSkewCheck
|
class MaxSkewCheck
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MaxSkewCheck(PathVertex *clk_path,
|
MaxSkewCheck(Path *clk_path,
|
||||||
PathVertex *ref_path,
|
Path *ref_path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge);
|
Edge *check_edge);
|
||||||
const PathVertex *clkPath() const { return &clk_path_; }
|
const Path *clkPath() const { return clk_path_; }
|
||||||
Pin *clkPin(const StaState *sta) const;
|
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;
|
Pin *refPin(const StaState *sta) const;
|
||||||
Delay skew(const StaState *sta) const;
|
Delay skew() const;
|
||||||
ArcDelay maxSkew(const StaState *sta) const;
|
ArcDelay maxSkew(const StaState *sta) const;
|
||||||
Slack slack(const StaState *sta) const;
|
Slack slack(const StaState *sta) const;
|
||||||
TimingArc *checkArc() const { return check_arc_; }
|
TimingArc *checkArc() const { return check_arc_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PathVertex clk_path_;
|
Path *clk_path_;
|
||||||
PathVertex ref_path_;
|
Path *ref_path_;
|
||||||
TimingArc *check_arc_;
|
TimingArc *check_arc_;
|
||||||
Edge *check_edge_;
|
Edge *check_edge_;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,7 @@
|
||||||
#include "GraphDelayCalc.hh"
|
#include "GraphDelayCalc.hh"
|
||||||
#include "ClkInfo.hh"
|
#include "ClkInfo.hh"
|
||||||
#include "Tag.hh"
|
#include "Tag.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "PathRef.hh"
|
|
||||||
#include "Corner.hh"
|
#include "Corner.hh"
|
||||||
#include "PathAnalysisPt.hh"
|
#include "PathAnalysisPt.hh"
|
||||||
#include "SearchPred.hh"
|
#include "SearchPred.hh"
|
||||||
|
|
@ -275,10 +274,9 @@ visitMinPulseWidthChecks(Vertex *vertex,
|
||||||
minPulseWidth(path, sta_, min_width, exists);
|
minPulseWidth(path, sta_, min_width, exists);
|
||||||
if (exists) {
|
if (exists) {
|
||||||
MinPulseWidthCheck check(path);
|
MinPulseWidthCheck check(path);
|
||||||
PathVertex close_path;
|
Path *close_path = check.closePath(sta_);
|
||||||
check.closePath(sta_, close_path);
|
|
||||||
// Don't bother visiting if nobody is home.
|
// Don't bother visiting if nobody is home.
|
||||||
if (!close_path.isNull())
|
if (close_path)
|
||||||
visitor->visit(check, sta_);
|
visitor->visit(check, sta_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -289,7 +287,7 @@ visitMinPulseWidthChecks(Vertex *vertex,
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
MinPulseWidthCheck::MinPulseWidthCheck() :
|
MinPulseWidthCheck::MinPulseWidthCheck() :
|
||||||
open_path_()
|
open_path_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,31 +299,29 @@ MinPulseWidthCheck::MinPulseWidthCheck(Path *open_path) :
|
||||||
MinPulseWidthCheck *
|
MinPulseWidthCheck *
|
||||||
MinPulseWidthCheck::copy()
|
MinPulseWidthCheck::copy()
|
||||||
{
|
{
|
||||||
return new MinPulseWidthCheck(&open_path_);
|
return new MinPulseWidthCheck(open_path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pin *
|
Pin *
|
||||||
MinPulseWidthCheck::pin(const StaState *sta) const
|
MinPulseWidthCheck::pin(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return open_path_.pin(sta);
|
return open_path_->pin(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
const RiseFall *
|
const RiseFall *
|
||||||
MinPulseWidthCheck::openTransition(const StaState *sta) const
|
MinPulseWidthCheck::openTransition(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return open_path_.transition(sta);
|
return open_path_->transition(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
Path *
|
||||||
MinPulseWidthCheck::closePath(const StaState *sta,
|
MinPulseWidthCheck::closePath(const StaState *sta) const
|
||||||
// Return value.
|
|
||||||
PathVertex &close) const
|
|
||||||
{
|
{
|
||||||
PathAnalysisPt *open_ap = open_path_.pathAnalysisPt(sta);
|
PathAnalysisPt *open_ap = open_path_->pathAnalysisPt(sta);
|
||||||
PathAnalysisPt *close_ap = open_ap->tgtClkAnalysisPt();
|
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();
|
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 *open_clk_info = open_tag->clkInfo();
|
||||||
ClkInfo close_clk_info(open_clk_info->clkEdge()->opposite(),
|
ClkInfo close_clk_info(open_clk_info->clkEdge()->opposite(),
|
||||||
open_clk_info->clkSrc(),
|
open_clk_info->clkSrc(),
|
||||||
|
|
@ -335,7 +331,7 @@ MinPulseWidthCheck::closePath(const StaState *sta,
|
||||||
open_clk_info->pulseClkSense(),
|
open_clk_info->pulseClkSense(),
|
||||||
delay_zero, 0.0, nullptr,
|
delay_zero, 0.0, nullptr,
|
||||||
open_clk_info->pathAPIndex(),
|
open_clk_info->pathAPIndex(),
|
||||||
open_clk_info->crprClkPath(),
|
open_clk_info->crprClkPath(sta),
|
||||||
sta);
|
sta);
|
||||||
Tag close_tag(0,
|
Tag close_tag(0,
|
||||||
close_rf->index(),
|
close_rf->index(),
|
||||||
|
|
@ -350,31 +346,30 @@ MinPulseWidthCheck::closePath(const StaState *sta,
|
||||||
open_tag->asString(sta));
|
open_tag->asString(sta));
|
||||||
debugPrint(sta->debug(), "mpw", 3, " close %s",
|
debugPrint(sta->debug(), "mpw", 3, " close %s",
|
||||||
close_tag.asString(sta));
|
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);
|
close_ap, sta);
|
||||||
while (close_iter.hasNext()) {
|
while (close_iter.hasNext()) {
|
||||||
PathVertex *close_path = close_iter.next();
|
Path *close_path = close_iter.next();
|
||||||
if (tagMatchNoPathAp(close_path->tag(sta), &close_tag)) {
|
if (tagMatchNoPathAp(close_path->tag(sta), &close_tag)) {
|
||||||
debugPrint(sta->debug(), "mpw", 3, " match %s",
|
debugPrint(sta->debug(), "mpw", 3, " match %s",
|
||||||
close_path->tag(sta)->asString(sta));
|
close_path->tag(sta)->asString(sta));
|
||||||
close = close_path;
|
return close_path;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
MinPulseWidthCheck::openArrival(const StaState *sta) const
|
MinPulseWidthCheck::openArrival(const StaState *) const
|
||||||
{
|
{
|
||||||
return open_path_.arrival(sta);
|
return open_path_->arrival();
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
MinPulseWidthCheck::closeArrival(const StaState *sta) const
|
MinPulseWidthCheck::closeArrival(const StaState *sta) const
|
||||||
{
|
{
|
||||||
PathVertex close;
|
Path *close = closePath(sta);
|
||||||
closePath(sta, close);
|
return close->arrival();
|
||||||
return close.arrival(sta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
|
|
@ -392,13 +387,13 @@ MinPulseWidthCheck::closeDelay(const StaState *sta) const
|
||||||
const ClockEdge *
|
const ClockEdge *
|
||||||
MinPulseWidthCheck::openClkEdge(const StaState *sta) const
|
MinPulseWidthCheck::openClkEdge(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return open_path_.clkEdge(sta->search());
|
return open_path_->clkEdge(sta->search());
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClockEdge *
|
const ClockEdge *
|
||||||
MinPulseWidthCheck::closeClkEdge(const StaState *sta) const
|
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();
|
ClkInfo *open_clk_info = open_tag->clkInfo();
|
||||||
return open_clk_info->clkEdge()->opposite();
|
return open_clk_info->clkEdge()->opposite();
|
||||||
}
|
}
|
||||||
|
|
@ -418,7 +413,7 @@ Arrival
|
||||||
MinPulseWidthCheck::width(const StaState *sta) const
|
MinPulseWidthCheck::width(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return closeArrival(sta) + closeOffset(sta)
|
return closeArrival(sta) + closeOffset(sta)
|
||||||
- open_path_.arrival(sta)
|
- open_path_->arrival()
|
||||||
+ checkCrpr(sta);
|
+ checkCrpr(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -427,7 +422,7 @@ MinPulseWidthCheck::minWidth(const StaState *sta) const
|
||||||
{
|
{
|
||||||
float min_width;
|
float min_width;
|
||||||
bool exists;
|
bool exists;
|
||||||
minPulseWidth(&open_path_, sta, min_width, exists);
|
minPulseWidth(open_path_, sta, min_width, exists);
|
||||||
return min_width;
|
return min_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -469,10 +464,9 @@ Crpr
|
||||||
MinPulseWidthCheck::checkCrpr(const StaState *sta) const
|
MinPulseWidthCheck::checkCrpr(const StaState *sta) const
|
||||||
{
|
{
|
||||||
CheckCrpr *check_crpr = sta->search()->checkCrpr();
|
CheckCrpr *check_crpr = sta->search()->checkCrpr();
|
||||||
PathVertex close;
|
Path *close = closePath(sta);
|
||||||
closePath(sta, close);
|
if (close)
|
||||||
if (!close.isNull())
|
return check_crpr->checkCrpr(openPath(), close);
|
||||||
return check_crpr->checkCrpr(openPath(), &close);
|
|
||||||
else
|
else
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
@ -486,7 +480,7 @@ MinPulseWidthCheck::slack(const StaState *sta) const
|
||||||
Corner *
|
Corner *
|
||||||
MinPulseWidthCheck::corner(const StaState *sta) const
|
MinPulseWidthCheck::corner(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return open_path_.pathAnalysisPt(sta)->corner();
|
return open_path_->pathAnalysisPt(sta)->corner();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
#include "SdcClass.hh"
|
#include "SdcClass.hh"
|
||||||
#include "SearchClass.hh"
|
#include "SearchClass.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
#include "PathRef.hh"
|
#include "Path.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -75,13 +75,11 @@ public:
|
||||||
Arrival width(const StaState *sta) const;
|
Arrival width(const StaState *sta) const;
|
||||||
float minWidth(const StaState *sta) const;
|
float minWidth(const StaState *sta) const;
|
||||||
Slack slack(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;
|
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;
|
Arrival openArrival(const StaState *sta) const;
|
||||||
void closePath(const StaState *sta,
|
Path *closePath(const StaState *sta) const;
|
||||||
// Return value.
|
|
||||||
PathVertex &close) const;
|
|
||||||
Arrival closeArrival(const StaState *sta) const;
|
Arrival closeArrival(const StaState *sta) const;
|
||||||
Arrival openDelay(const StaState *sta) const;
|
Arrival openDelay(const StaState *sta) const;
|
||||||
Arrival closeDelay(const StaState *sta) const;
|
Arrival closeDelay(const StaState *sta) const;
|
||||||
|
|
@ -92,7 +90,7 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Open path of the pulse.
|
// Open path of the pulse.
|
||||||
PathRef open_path_;
|
Path *open_path_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MinPulseWidthSlackLess
|
class MinPulseWidthSlackLess
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
#include "GraphDelayCalc.hh"
|
#include "GraphDelayCalc.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
#include "Corner.hh"
|
#include "Corner.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "PortDirection.hh"
|
#include "PortDirection.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
#include "ClkNetwork.hh"
|
#include "ClkNetwork.hh"
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
#include "Bfs.hh"
|
#include "Bfs.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
#include "Genclks.hh"
|
#include "Genclks.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "Sim.hh"
|
#include "Sim.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
@ -316,7 +316,7 @@ CheckTiming::hasClkedArrival(Vertex *vertex)
|
||||||
{
|
{
|
||||||
VertexPathIterator path_iter(vertex, this);
|
VertexPathIterator path_iter(vertex, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
if (path->clock(this))
|
if (path->clock(this))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
#include "MinMax.hh"
|
#include "MinMax.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
#include "Transition.hh"
|
#include "Transition.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ public:
|
||||||
Delay &delay,
|
Delay &delay,
|
||||||
float &internal_latency,
|
float &internal_latency,
|
||||||
Delay &latency,
|
Delay &latency,
|
||||||
PathVertex &path,
|
Path &path,
|
||||||
bool &exists) const;
|
bool &exists) const;
|
||||||
void latency(const RiseFall *src_rf,
|
void latency(const RiseFall *src_rf,
|
||||||
const RiseFall *end_rf,
|
const RiseFall *end_rf,
|
||||||
|
|
@ -51,28 +51,28 @@ public:
|
||||||
// Return values.
|
// Return values.
|
||||||
Delay &delay,
|
Delay &delay,
|
||||||
bool &exists) const;
|
bool &exists) const;
|
||||||
static Delay latency(PathVertex *clk_path,
|
static Delay latency(Path *clk_path,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
void setLatency(const RiseFall *src_rf,
|
void setLatency(const RiseFall *src_rf,
|
||||||
const RiseFall *end_rf,
|
const RiseFall *end_rf,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
PathVertex *path,
|
Path *path,
|
||||||
bool include_internal_latency,
|
bool include_internal_latency,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static float insertionDelay(PathVertex *clk_path,
|
static float insertionDelay(Path *clk_path,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
static float delay(PathVertex *clk_path,
|
static float delay(Path *clk_path,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
static float clkTreeDelay(PathVertex *clk_path,
|
static float clkTreeDelay(Path *clk_path,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
|
|
||||||
Delay insertion_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
|
Delay insertion_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
|
||||||
Delay delay_[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];
|
float internal_latency_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
|
||||||
Delay 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];
|
bool exists_[RiseFall::index_count][RiseFall::index_count][MinMax::index_count];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,12 +53,12 @@ ClkInfo::ClkInfo(const ClockEdge *clk_edge,
|
||||||
float latency,
|
float latency,
|
||||||
ClockUncertainties *uncertainties,
|
ClockUncertainties *uncertainties,
|
||||||
PathAPIndex path_ap_index,
|
PathAPIndex path_ap_index,
|
||||||
PathVertexPtr &crpr_clk_path,
|
Path *crpr_clk_path,
|
||||||
const StaState *sta) :
|
const StaState *sta) :
|
||||||
clk_edge_(clk_edge),
|
clk_edge_(clk_edge),
|
||||||
clk_src_(clk_src),
|
clk_src_(clk_src),
|
||||||
gen_clk_src_(gen_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),
|
uncertainties_(uncertainties),
|
||||||
insertion_(insertion),
|
insertion_(insertion),
|
||||||
latency_(latency),
|
latency_(latency),
|
||||||
|
|
@ -87,7 +87,7 @@ ClkInfo::findHash(const StaState *sta)
|
||||||
hashIncr(hash_, network->vertexId(clk_src_));
|
hashIncr(hash_, network->vertexId(clk_src_));
|
||||||
if (gen_clk_src_)
|
if (gen_clk_src_)
|
||||||
hashIncr(hash_, network->vertexId(gen_clk_src_));
|
hashIncr(hash_, network->vertexId(gen_clk_src_));
|
||||||
hashIncr(hash_, crprClkVertexId());
|
hashIncr(hash_, crprClkVertexId(sta));
|
||||||
if (uncertainties_) {
|
if (uncertainties_) {
|
||||||
float uncertainty;
|
float uncertainty;
|
||||||
bool exists;
|
bool exists;
|
||||||
|
|
@ -108,12 +108,24 @@ ClkInfo::findHash(const StaState *sta)
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexId
|
VertexId
|
||||||
ClkInfo::crprClkVertexId() const
|
ClkInfo::crprClkVertexId(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (crpr_clk_path_.isNull())
|
if (crpr_clk_path_.isNull())
|
||||||
return 0;
|
return vertex_id_null;
|
||||||
else
|
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 *
|
const char *
|
||||||
|
|
@ -213,8 +225,9 @@ clkInfoEqual(const ClkInfo *clk_info1,
|
||||||
&& clk_info1->clkSrc() == clk_info2->clkSrc()
|
&& clk_info1->clkSrc() == clk_info2->clkSrc()
|
||||||
&& clk_info1->genClkSrc() == clk_info2->genClkSrc()
|
&& clk_info1->genClkSrc() == clk_info2->genClkSrc()
|
||||||
&& (!crpr_on
|
&& (!crpr_on
|
||||||
|| (PathVertexPtr::equal(clk_info1->crprClkPath(),
|
|| Path::equal(clk_info1->crprClkPath(sta),
|
||||||
clk_info2->crprClkPath())))
|
clk_info2->crprClkPath(sta),
|
||||||
|
sta))
|
||||||
&& ((uncertainties1 == nullptr
|
&& ((uncertainties1 == nullptr
|
||||||
&& uncertainties2 == nullptr)
|
&& uncertainties2 == nullptr)
|
||||||
|| (uncertainties1 && uncertainties2
|
|| (uncertainties1 && uncertainties2
|
||||||
|
|
@ -279,9 +292,9 @@ clkInfoCmp(const ClkInfo *clk_info1,
|
||||||
|
|
||||||
bool crpr_on = sta->sdc()->crprActive();
|
bool crpr_on = sta->sdc()->crprActive();
|
||||||
if (crpr_on) {
|
if (crpr_on) {
|
||||||
const PathVertexPtr &crpr_path1 = clk_info1->crprClkPath();
|
const Path *crpr_path1 = clk_info1->crprClkPath(sta);
|
||||||
const PathVertexPtr &crpr_path2 = clk_info2->crprClkPath();
|
const Path *crpr_path2 = clk_info2->crprClkPath(sta);
|
||||||
int path_cmp = PathVertexPtr::cmp(crpr_path1, crpr_path2);
|
int path_cmp = Path::cmp(crpr_path1, crpr_path2, sta);
|
||||||
if (path_cmp != 0)
|
if (path_cmp != 0)
|
||||||
return path_cmp;
|
return path_cmp;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,12 @@
|
||||||
|
|
||||||
#include "Transition.hh"
|
#include "Transition.hh"
|
||||||
#include "SearchClass.hh"
|
#include "SearchClass.hh"
|
||||||
#include "PathVertexPtr.hh"
|
|
||||||
#include "Sdc.hh"
|
#include "Sdc.hh"
|
||||||
|
#include "Path.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
class PathVertex;
|
class Path;
|
||||||
|
|
||||||
class ClkInfo
|
class ClkInfo
|
||||||
{
|
{
|
||||||
|
|
@ -46,7 +46,7 @@ public:
|
||||||
float latency,
|
float latency,
|
||||||
ClockUncertainties *uncertainties,
|
ClockUncertainties *uncertainties,
|
||||||
PathAPIndex path_ap_index,
|
PathAPIndex path_ap_index,
|
||||||
PathVertexPtr &crpr_clk_path,
|
Path *crpr_clk_path,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
~ClkInfo();
|
~ClkInfo();
|
||||||
const char *asString(const StaState *sta) const;
|
const char *asString(const StaState *sta) const;
|
||||||
|
|
@ -65,9 +65,9 @@ public:
|
||||||
PathAPIndex pathAPIndex() const { return path_ap_index_; }
|
PathAPIndex pathAPIndex() const { return path_ap_index_; }
|
||||||
// Clock path used for crpr resolution.
|
// Clock path used for crpr resolution.
|
||||||
// Null for clocks because the path cannot point to itself.
|
// Null for clocks because the path cannot point to itself.
|
||||||
PathVertexPtr &crprClkPath() { return crpr_clk_path_; }
|
Path *crprClkPath(const StaState *sta);
|
||||||
const PathVertexPtr &crprClkPath() const { return crpr_clk_path_; }
|
const Path *crprClkPath(const StaState *sta) const;
|
||||||
VertexId crprClkVertexId() const;
|
VertexId crprClkVertexId(const StaState *sta) const;
|
||||||
bool hasCrprClkPin() const { return !crpr_clk_path_.isNull(); }
|
bool hasCrprClkPin() const { return !crpr_clk_path_.isNull(); }
|
||||||
bool refsFilter(const StaState *sta) const;
|
bool refsFilter(const StaState *sta) const;
|
||||||
// This clk_info/tag is used for a generated clock source path.
|
// This clk_info/tag is used for a generated clock source path.
|
||||||
|
|
@ -81,7 +81,7 @@ private:
|
||||||
const ClockEdge *clk_edge_;
|
const ClockEdge *clk_edge_;
|
||||||
const Pin *clk_src_;
|
const Pin *clk_src_;
|
||||||
const Pin *gen_clk_src_;
|
const Pin *gen_clk_src_;
|
||||||
PathVertexPtr crpr_clk_path_;
|
Path crpr_clk_path_;
|
||||||
ClockUncertainties *uncertainties_;
|
ClockUncertainties *uncertainties_;
|
||||||
Arrival insertion_;
|
Arrival insertion_;
|
||||||
float latency_;
|
float latency_;
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
#include "Network.hh"
|
#include "Network.hh"
|
||||||
#include "Clock.hh"
|
#include "Clock.hh"
|
||||||
#include "Graph.hh"
|
#include "Graph.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
#include "PathAnalysisPt.hh"
|
#include "PathAnalysisPt.hh"
|
||||||
|
|
@ -88,7 +88,7 @@ ClkLatency::reportClkLatency(const Clock *clk,
|
||||||
report_->reportLine("Clock %s", clk->name());
|
report_->reportLine("Clock %s", clk->name());
|
||||||
for (const RiseFall *src_rf : RiseFall::range()) {
|
for (const RiseFall *src_rf : RiseFall::range()) {
|
||||||
for (const RiseFall *end_rf : RiseFall::range()) {
|
for (const RiseFall *end_rf : RiseFall::range()) {
|
||||||
PathVertex path_min;
|
Path path_min;
|
||||||
Delay insertion_min;
|
Delay insertion_min;
|
||||||
Delay delay_min;
|
Delay delay_min;
|
||||||
float internal_latency_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,
|
clk_delays.delay(src_rf, end_rf, MinMax::min(), insertion_min,
|
||||||
delay_min, internal_latency_min, latency_min,
|
delay_min, internal_latency_min, latency_min,
|
||||||
path_min, exists_min);
|
path_min, exists_min);
|
||||||
PathVertex path_max;
|
Path path_max;
|
||||||
Delay insertion_max;
|
Delay insertion_max;
|
||||||
Delay delay_max;
|
Delay delay_max;
|
||||||
float internal_latency_max;
|
float internal_latency_max;
|
||||||
|
|
@ -153,7 +153,7 @@ ClkLatency::findClkDelays(ConstClockSeq &clks,
|
||||||
for (Vertex *clk_vertex : *graph_->regClkVertices()) {
|
for (Vertex *clk_vertex : *graph_->regClkVertices()) {
|
||||||
VertexPathIterator path_iter(clk_vertex, this);
|
VertexPathIterator path_iter(clk_vertex, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
const ClockEdge *path_clk_edge = path->clkEdge(this);
|
const ClockEdge *path_clk_edge = path->clkEdge(this);
|
||||||
const PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
const PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
||||||
if (path_clk_edge
|
if (path_clk_edge
|
||||||
|
|
@ -206,7 +206,7 @@ ClkDelays::delay(const RiseFall *src_rf,
|
||||||
Delay &delay,
|
Delay &delay,
|
||||||
float &lib_clk_delay,
|
float &lib_clk_delay,
|
||||||
Delay &latency,
|
Delay &latency,
|
||||||
PathVertex &path,
|
Path &path,
|
||||||
bool &exists) const
|
bool &exists) const
|
||||||
{
|
{
|
||||||
int src_rf_index = src_rf->index();
|
int src_rf_index = src_rf->index();
|
||||||
|
|
@ -239,7 +239,7 @@ void
|
||||||
ClkDelays::setLatency(const RiseFall *src_rf,
|
ClkDelays::setLatency(const RiseFall *src_rf,
|
||||||
const RiseFall *end_rf,
|
const RiseFall *end_rf,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
PathVertex *path,
|
Path *path,
|
||||||
bool include_internal_latency,
|
bool include_internal_latency,
|
||||||
StaState *sta)
|
StaState *sta)
|
||||||
{
|
{
|
||||||
|
|
@ -267,7 +267,7 @@ ClkDelays::setLatency(const RiseFall *src_rf,
|
||||||
}
|
}
|
||||||
|
|
||||||
Delay
|
Delay
|
||||||
ClkDelays::latency(PathVertex *clk_path,
|
ClkDelays::latency(Path *clk_path,
|
||||||
StaState *sta)
|
StaState *sta)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -278,16 +278,16 @@ ClkDelays::latency(PathVertex *clk_path,
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
ClkDelays::delay(PathVertex *clk_path,
|
ClkDelays::delay(Path *clk_path,
|
||||||
StaState *sta)
|
StaState *sta)
|
||||||
{
|
{
|
||||||
Arrival arrival = clk_path->arrival(sta);
|
Arrival arrival = clk_path->arrival();
|
||||||
const ClockEdge *path_clk_edge = clk_path->clkEdge(sta);
|
const ClockEdge *path_clk_edge = clk_path->clkEdge(sta);
|
||||||
return delayAsFloat(arrival) - path_clk_edge->time();
|
return delayAsFloat(arrival) - path_clk_edge->time();
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
ClkDelays::insertionDelay(PathVertex *clk_path,
|
ClkDelays::insertionDelay(Path *clk_path,
|
||||||
StaState *sta)
|
StaState *sta)
|
||||||
{
|
{
|
||||||
const ClockEdge *clk_edge = clk_path->clkEdge(sta);
|
const ClockEdge *clk_edge = clk_path->clkEdge(sta);
|
||||||
|
|
@ -302,7 +302,7 @@ ClkDelays::insertionDelay(PathVertex *clk_path,
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
ClkDelays::clkTreeDelay(PathVertex *clk_path,
|
ClkDelays::clkTreeDelay(Path *clk_path,
|
||||||
StaState *sta)
|
StaState *sta)
|
||||||
{
|
{
|
||||||
const Vertex *vertex = clk_path->vertex(sta);
|
const Vertex *vertex = clk_path->vertex(sta);
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
#include "Transition.hh"
|
#include "Transition.hh"
|
||||||
#include "SearchClass.hh"
|
#include "SearchClass.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "ClkDelays.hh"
|
#include "ClkDelays.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
#include "Graph.hh"
|
#include "Graph.hh"
|
||||||
#include "Sdc.hh"
|
#include "Sdc.hh"
|
||||||
#include "Bfs.hh"
|
#include "Bfs.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
#include "PathAnalysisPt.hh"
|
#include "PathAnalysisPt.hh"
|
||||||
#include "SearchPred.hh"
|
#include "SearchPred.hh"
|
||||||
|
|
@ -55,14 +55,14 @@ class ClkSkew
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClkSkew();
|
ClkSkew();
|
||||||
ClkSkew(PathVertex *src_path,
|
ClkSkew(Path *src_path,
|
||||||
PathVertex *tgt_path,
|
Path *tgt_path,
|
||||||
bool include_internal_latency,
|
bool include_internal_latency,
|
||||||
StaState *sta);
|
StaState *sta);
|
||||||
ClkSkew(const ClkSkew &clk_skew);
|
ClkSkew(const ClkSkew &clk_skew);
|
||||||
void operator=(const ClkSkew &clk_skew);
|
void operator=(const ClkSkew &clk_skew);
|
||||||
PathVertex *srcPath() { return &src_path_; }
|
Path *srcPath() { return src_path_; }
|
||||||
PathVertex *tgtPath() { return &tgt_path_; }
|
Path *tgtPath() { return tgt_path_; }
|
||||||
float srcLatency(const StaState *sta);
|
float srcLatency(const StaState *sta);
|
||||||
float tgtLatency(const StaState *sta);
|
float tgtLatency(const StaState *sta);
|
||||||
float srcInternalClkLatency(const StaState *sta);
|
float srcInternalClkLatency(const StaState *sta);
|
||||||
|
|
@ -75,23 +75,25 @@ public:
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float clkTreeDelay(PathVertex &clk_path,
|
float clkTreeDelay(Path *clk_path,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
|
||||||
PathVertex src_path_;
|
Path *src_path_;
|
||||||
PathVertex tgt_path_;
|
Path *tgt_path_;
|
||||||
bool include_internal_latency_;
|
bool include_internal_latency_;
|
||||||
float skew_;
|
float skew_;
|
||||||
};
|
};
|
||||||
|
|
||||||
ClkSkew::ClkSkew() :
|
ClkSkew::ClkSkew() :
|
||||||
|
src_path_(nullptr),
|
||||||
|
tgt_path_(nullptr),
|
||||||
include_internal_latency_(false),
|
include_internal_latency_(false),
|
||||||
skew_(0.0)
|
skew_(0.0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ClkSkew::ClkSkew(PathVertex *src_path,
|
ClkSkew::ClkSkew(Path *src_path,
|
||||||
PathVertex *tgt_path,
|
Path *tgt_path,
|
||||||
bool include_internal_latency,
|
bool include_internal_latency,
|
||||||
StaState *sta) :
|
StaState *sta) :
|
||||||
src_path_(src_path),
|
src_path_(src_path),
|
||||||
|
|
@ -124,8 +126,8 @@ ClkSkew::operator=(const ClkSkew &clk_skew)
|
||||||
float
|
float
|
||||||
ClkSkew::srcLatency(const StaState *sta)
|
ClkSkew::srcLatency(const StaState *sta)
|
||||||
{
|
{
|
||||||
Arrival src_arrival = src_path_.arrival(sta);
|
Arrival src_arrival = src_path_->arrival();
|
||||||
return delayAsFloat(src_arrival) - src_path_.clkEdge(sta)->time()
|
return delayAsFloat(src_arrival) - src_path_->clkEdge(sta)->time()
|
||||||
+ clkTreeDelay(src_path_, sta);
|
+ clkTreeDelay(src_path_, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,8 +140,8 @@ ClkSkew::srcInternalClkLatency(const StaState *sta)
|
||||||
float
|
float
|
||||||
ClkSkew::tgtLatency(const StaState *sta)
|
ClkSkew::tgtLatency(const StaState *sta)
|
||||||
{
|
{
|
||||||
Arrival tgt_arrival = tgt_path_.arrival(sta);
|
Arrival tgt_arrival = tgt_path_->arrival();
|
||||||
return delayAsFloat(tgt_arrival) - tgt_path_.clkEdge(sta)->time()
|
return delayAsFloat(tgt_arrival) - tgt_path_->clkEdge(sta)->time()
|
||||||
+ clkTreeDelay(tgt_path_, sta);
|
+ clkTreeDelay(tgt_path_, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,16 +152,16 @@ ClkSkew::tgtInternalClkLatency(const StaState *sta)
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
ClkSkew::clkTreeDelay(PathVertex &clk_path,
|
ClkSkew::clkTreeDelay(Path *clk_path,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
if (include_internal_latency_) {
|
if (include_internal_latency_) {
|
||||||
const Vertex *vertex = clk_path.vertex(sta);
|
const Vertex *vertex = clk_path->vertex(sta);
|
||||||
const Pin *pin = vertex->pin();
|
const Pin *pin = vertex->pin();
|
||||||
const LibertyPort *port = sta->network()->libertyPort(pin);
|
const LibertyPort *port = sta->network()->libertyPort(pin);
|
||||||
const MinMax *min_max = clk_path.minMax(sta);
|
const MinMax *min_max = clk_path->minMax(sta);
|
||||||
const RiseFall *rf = clk_path.transition(sta);
|
const RiseFall *rf = clk_path->transition(sta);
|
||||||
float slew = delayAsFloat(clk_path.slew(sta));
|
float slew = delayAsFloat(clk_path->slew(sta));
|
||||||
return port->clkTreeDelay(slew, rf, min_max);
|
return port->clkTreeDelay(slew, rf, min_max);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -170,17 +172,17 @@ Crpr
|
||||||
ClkSkew::crpr(const StaState *sta)
|
ClkSkew::crpr(const StaState *sta)
|
||||||
{
|
{
|
||||||
CheckCrpr *check_crpr = sta->search()->checkCrpr();
|
CheckCrpr *check_crpr = sta->search()->checkCrpr();
|
||||||
return check_crpr->checkCrpr(&src_path_, &tgt_path_);
|
return check_crpr->checkCrpr(src_path_, tgt_path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
ClkSkew::uncertainty(const StaState *sta)
|
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::setup()
|
||||||
: TimingRole::hold();
|
: TimingRole::hold();
|
||||||
// Uncertainty decreases slack, but increases skew.
|
// 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);
|
check_role, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -240,8 +242,8 @@ ClkSkews::reportClkSkew(ClkSkew &clk_skew,
|
||||||
int digits)
|
int digits)
|
||||||
{
|
{
|
||||||
Unit *time_unit = units_->timeUnit();
|
Unit *time_unit = units_->timeUnit();
|
||||||
PathVertex *src_path = clk_skew.srcPath();
|
Path *src_path = clk_skew.srcPath();
|
||||||
PathVertex *tgt_path = clk_skew.tgtPath();
|
Path *tgt_path = clk_skew.tgtPath();
|
||||||
float src_latency = clk_skew.srcLatency(this);
|
float src_latency = clk_skew.srcLatency(this);
|
||||||
float tgt_latency = clk_skew.tgtLatency(this);
|
float tgt_latency = clk_skew.tgtLatency(this);
|
||||||
float src_internal_clk_latency = clk_skew.srcInternalClkLatency(this);
|
float src_internal_clk_latency = clk_skew.srcInternalClkLatency(this);
|
||||||
|
|
@ -352,7 +354,7 @@ ClkSkews::hasClkPaths(Vertex *vertex)
|
||||||
{
|
{
|
||||||
VertexPathIterator path_iter(vertex, this);
|
VertexPathIterator path_iter(vertex, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
const Clock *path_clk = path->clock(this);
|
const Clock *path_clk = path->clock(this);
|
||||||
if (clk_set_.find(path_clk) != clk_set_.end())
|
if (clk_set_.find(path_clk) != clk_set_.end())
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -417,7 +419,7 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
|
||||||
const SetupHold *tgt_min_max = setup_hold_->opposite();
|
const SetupHold *tgt_min_max = setup_hold_->opposite();
|
||||||
VertexPathIterator src_iter(src_vertex, this);
|
VertexPathIterator src_iter(src_vertex, this);
|
||||||
while (src_iter.hasNext()) {
|
while (src_iter.hasNext()) {
|
||||||
PathVertex *src_path = src_iter.next();
|
Path *src_path = src_iter.next();
|
||||||
const Clock *src_clk = src_path->clock(this);
|
const Clock *src_clk = src_path->clock(this);
|
||||||
if (src_rf->matches(src_path->transition(this))
|
if (src_rf->matches(src_path->transition(this))
|
||||||
&& src_path->minMax(this) == setup_hold_
|
&& src_path->minMax(this) == setup_hold_
|
||||||
|
|
@ -427,7 +429,7 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
|
||||||
|| src_corner == corner_) {
|
|| src_corner == corner_) {
|
||||||
VertexPathIterator tgt_iter(tgt_vertex, this);
|
VertexPathIterator tgt_iter(tgt_vertex, this);
|
||||||
while (tgt_iter.hasNext()) {
|
while (tgt_iter.hasNext()) {
|
||||||
PathVertex *tgt_path = tgt_iter.next();
|
Path *tgt_path = tgt_iter.next();
|
||||||
const Clock *tgt_clk = tgt_path->clock(this);
|
const Clock *tgt_clk = tgt_path->clock(this);
|
||||||
if (tgt_clk == src_clk
|
if (tgt_clk == src_clk
|
||||||
&& tgt_path->isClock(this)
|
&& tgt_path->isClock(this)
|
||||||
|
|
@ -446,7 +448,7 @@ ClkSkews::findClkSkew(Vertex *src_vertex,
|
||||||
time_unit->asString(probe.tgtLatency(this)),
|
time_unit->asString(probe.tgtLatency(this)),
|
||||||
delayAsString(probe.crpr(this), this),
|
delayAsString(probe.crpr(this), this),
|
||||||
time_unit->asString(probe.skew()));
|
time_unit->asString(probe.skew()));
|
||||||
if (clk_skew.srcPath()->isNull()
|
if (clk_skew.srcPath() == nullptr
|
||||||
|| abs(probe.skew()) > abs(clk_skew.skew()))
|
|| abs(probe.skew()) > abs(clk_skew.skew()))
|
||||||
clk_skew = probe;
|
clk_skew = probe;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
#include "Transition.hh"
|
#include "Transition.hh"
|
||||||
#include "SearchClass.hh"
|
#include "SearchClass.hh"
|
||||||
#include "SearchPred.hh"
|
#include "SearchPred.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
|
||||||
189
search/Crpr.cc
189
search/Crpr.cc
|
|
@ -32,8 +32,6 @@
|
||||||
#include "Network.hh"
|
#include "Network.hh"
|
||||||
#include "Graph.hh"
|
#include "Graph.hh"
|
||||||
#include "Sdc.hh"
|
#include "Sdc.hh"
|
||||||
#include "PathVertex.hh"
|
|
||||||
#include "PathPrev.hh"
|
|
||||||
#include "Path.hh"
|
#include "Path.hh"
|
||||||
#include "PathAnalysisPt.hh"
|
#include "PathAnalysisPt.hh"
|
||||||
#include "ClkInfo.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
|
// Find the maximum possible crpr (clock min/max delta delay) for a
|
||||||
// path from it's ClkInfo.
|
// path from it's ClkInfo.
|
||||||
Arrival
|
Arrival
|
||||||
CheckCrpr::maxCrpr(ClkInfo *clk_info)
|
CheckCrpr::maxCrpr(ClkInfo *clk_info)
|
||||||
{
|
{
|
||||||
const PathVertexPtr &crpr_clk_path = clk_info->crprClkPath();
|
const Path *crpr_clk_path = clk_info->crprClkPath(this);
|
||||||
if (!crpr_clk_path.isNull()) {
|
if (crpr_clk_path) {
|
||||||
PathVertex crpr_clk_vpath(crpr_clk_path, this);
|
Arrival other_arrival = otherMinMaxArrival(crpr_clk_path);
|
||||||
if (!crpr_clk_vpath.isNull()) {
|
float crpr_diff = abs(delayAsFloat(crpr_clk_path->arrival(),
|
||||||
Arrival other_arrival = otherMinMaxArrival(&crpr_clk_vpath);
|
EarlyLate::late(),
|
||||||
float crpr_diff = abs(delayAsFloat(crpr_clk_vpath.arrival(this),
|
this)
|
||||||
EarlyLate::late(),
|
- delayAsFloat(other_arrival, EarlyLate::early(),
|
||||||
this)
|
this));
|
||||||
- delayAsFloat(other_arrival, EarlyLate::early(),
|
return crpr_diff;
|
||||||
this));
|
|
||||||
return crpr_diff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0.0F;
|
return 0.0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
CheckCrpr::otherMinMaxArrival(const PathVertex *path)
|
CheckCrpr::otherMinMaxArrival(const Path *path)
|
||||||
{
|
{
|
||||||
PathAnalysisPt *other_ap = path->pathAnalysisPt(this)->tgtClkAnalysisPt();
|
PathAnalysisPt *other_ap = path->pathAnalysisPt(this)->tgtClkAnalysisPt();
|
||||||
Tag *tag = path->tag(this);
|
Tag *tag = path->tag(this);
|
||||||
|
|
@ -115,18 +79,18 @@ CheckCrpr::otherMinMaxArrival(const PathVertex *path)
|
||||||
path->transition(this),
|
path->transition(this),
|
||||||
other_ap, this);
|
other_ap, this);
|
||||||
while (other_iter.hasNext()) {
|
while (other_iter.hasNext()) {
|
||||||
PathVertex *other = other_iter.next();
|
Path *other = other_iter.next();
|
||||||
if (tagMatchCrpr(other->tag(this), tag))
|
if (tagMatchCrpr(other->tag(this), tag))
|
||||||
return other->arrival(this);
|
return other->arrival();
|
||||||
}
|
}
|
||||||
// No corresponding path found.
|
// No corresponding path found.
|
||||||
// Match the arrival so the difference is zero.
|
// Match the arrival so the difference is zero.
|
||||||
return path->arrival(this);
|
return path->arrival();
|
||||||
}
|
}
|
||||||
|
|
||||||
Crpr
|
Crpr
|
||||||
CheckCrpr::checkCrpr(const Path *src_path,
|
CheckCrpr::checkCrpr(const Path *src_path,
|
||||||
const PathVertex *tgt_clk_path)
|
const Path *tgt_clk_path)
|
||||||
{
|
{
|
||||||
Crpr crpr;
|
Crpr crpr;
|
||||||
Pin *crpr_pin;
|
Pin *crpr_pin;
|
||||||
|
|
@ -136,7 +100,7 @@ CheckCrpr::checkCrpr(const Path *src_path,
|
||||||
|
|
||||||
void
|
void
|
||||||
CheckCrpr::checkCrpr(const Path *src_path,
|
CheckCrpr::checkCrpr(const Path *src_path,
|
||||||
const PathVertex *tgt_clk_path,
|
const Path *tgt_clk_path,
|
||||||
// Return values.
|
// Return values.
|
||||||
Crpr &crpr,
|
Crpr &crpr,
|
||||||
Pin *&crpr_pin)
|
Pin *&crpr_pin)
|
||||||
|
|
@ -152,7 +116,7 @@ CheckCrpr::checkCrpr(const Path *src_path,
|
||||||
|
|
||||||
void
|
void
|
||||||
CheckCrpr::checkCrpr1(const Path *src_path,
|
CheckCrpr::checkCrpr1(const Path *src_path,
|
||||||
const PathVertex *tgt_clk_path,
|
const Path *tgt_clk_path,
|
||||||
bool same_pin,
|
bool same_pin,
|
||||||
// Return values.
|
// Return values.
|
||||||
Crpr &crpr,
|
Crpr &crpr,
|
||||||
|
|
@ -165,17 +129,11 @@ CheckCrpr::checkCrpr1(const Path *src_path,
|
||||||
ClkInfo *tgt_clk_info = tgt_clk_path->tag(this)->clkInfo();
|
ClkInfo *tgt_clk_info = tgt_clk_path->tag(this)->clkInfo();
|
||||||
const Clock *src_clk = src_clk_info->clock();
|
const Clock *src_clk = src_clk_info->clock();
|
||||||
const Clock *tgt_clk = tgt_clk_info->clock();
|
const Clock *tgt_clk = tgt_clk_info->clock();
|
||||||
PathVertex src_clk_path1;
|
const Path *src_clk_path = nullptr;
|
||||||
const PathVertexPtr &src_crpr_clk_path = src_clk_info->crprClkPath();
|
if (src_tag->isClock())
|
||||||
const PathVertex *src_clk_path = nullptr;
|
src_clk_path = src_path;
|
||||||
if (src_tag->isClock()) {
|
else
|
||||||
src_clk_path1.init(src_path->vertex(this), src_path->tag(this), this);
|
src_clk_path = src_clk_info->crprClkPath(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 MinMax *src_clk_min_max =
|
const MinMax *src_clk_min_max =
|
||||||
src_clk_path ? src_clk_path->minMax(this) : src_path->minMax(this);
|
src_clk_path ? src_clk_path->minMax(this) : src_path->minMax(this);
|
||||||
if (src_clk && tgt_clk
|
if (src_clk && tgt_clk
|
||||||
|
|
@ -189,42 +147,37 @@ CheckCrpr::checkCrpr1(const Path *src_path,
|
||||||
&& (src_clk_path
|
&& (src_clk_path
|
||||||
|| src_clk->isGenerated())) {
|
|| src_clk->isGenerated())) {
|
||||||
// Src path from input port clk path can only be from generated clk path.
|
// Src path from input port clk path can only be from generated clk path.
|
||||||
PathVertex port_clk_path;
|
|
||||||
if (src_clk_path == nullptr) {
|
if (src_clk_path == nullptr) {
|
||||||
portClkPath(src_clk_info->clkEdge(),
|
src_clk_path = portClkPath(src_clk_info->clkEdge(),
|
||||||
src_clk_info->clkSrc(),
|
src_clk_info->clkSrc(),
|
||||||
src_path->pathAnalysisPt(this),
|
src_path->pathAnalysisPt(this));
|
||||||
port_clk_path);
|
|
||||||
src_clk_path = &port_clk_path;
|
|
||||||
}
|
}
|
||||||
findCrpr(src_clk_path, tgt_clk_path, same_pin, crpr, crpr_pin);
|
findCrpr(src_clk_path, tgt_clk_path, same_pin, crpr, crpr_pin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the clk path for an input/output port.
|
// Find the clk path for an input/output port.
|
||||||
void
|
Path *
|
||||||
CheckCrpr::portClkPath(const ClockEdge *clk_edge,
|
CheckCrpr::portClkPath(const ClockEdge *clk_edge,
|
||||||
const Pin *clk_src_pin,
|
const Pin *clk_src_pin,
|
||||||
const PathAnalysisPt *path_ap,
|
const PathAnalysisPt *path_ap)
|
||||||
// Return value.
|
|
||||||
PathVertex &genclk_path)
|
|
||||||
{
|
{
|
||||||
Vertex *clk_vertex = graph_->pinDrvrVertex(clk_src_pin);
|
Vertex *clk_vertex = graph_->pinDrvrVertex(clk_src_pin);
|
||||||
VertexPathIterator path_iter(clk_vertex, clk_edge->transition(),
|
VertexPathIterator path_iter(clk_vertex, clk_edge->transition(),
|
||||||
path_ap, this);
|
path_ap, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
if (path->clkEdge(this) == clk_edge
|
if (path->clkEdge(this) == clk_edge
|
||||||
&& path->isClock(this)) {
|
&& path->isClock(this)) {
|
||||||
genclk_path = path;
|
return path;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CheckCrpr::findCrpr(const PathVertex *src_clk_path,
|
CheckCrpr::findCrpr(const Path *src_clk_path,
|
||||||
const PathVertex *tgt_clk_path,
|
const Path *tgt_clk_path,
|
||||||
bool same_pin,
|
bool same_pin,
|
||||||
// Return values.
|
// Return values.
|
||||||
Crpr &crpr,
|
Crpr &crpr,
|
||||||
|
|
@ -232,35 +185,33 @@ CheckCrpr::findCrpr(const PathVertex *src_clk_path,
|
||||||
{
|
{
|
||||||
crpr = 0.0;
|
crpr = 0.0;
|
||||||
crpr_pin = nullptr;
|
crpr_pin = nullptr;
|
||||||
const PathVertex *src_clk_path1 = src_clk_path;
|
const Path *src_clk_path1 = src_clk_path;
|
||||||
const PathVertex *tgt_clk_path1 = tgt_clk_path;
|
const Path *tgt_clk_path1 = tgt_clk_path;
|
||||||
PathVertexSeq src_gclk_paths, tgt_gclk_paths;
|
|
||||||
if (src_clk_path1->clkInfo(this)->clkSrc()
|
if (src_clk_path1->clkInfo(this)->clkSrc()
|
||||||
!= tgt_clk_path1->clkInfo(this)->clkSrc()) {
|
!= tgt_clk_path1->clkInfo(this)->clkSrc()) {
|
||||||
// Push src/tgt genclk src paths into a vector,
|
// Push src/tgt genclk src paths into a vector,
|
||||||
// The last genclk src path is at index 0.
|
// The last genclk src path is at index 0.
|
||||||
genClkSrcPaths(src_clk_path1, src_gclk_paths);
|
ConstPathSeq src_gclk_paths = genClkSrcPaths(src_clk_path1);
|
||||||
genClkSrcPaths(tgt_clk_path1, tgt_gclk_paths);
|
ConstPathSeq tgt_gclk_paths = genClkSrcPaths(tgt_clk_path1);
|
||||||
// Search from the first gen clk toward the end
|
// Search from the first gen clk toward the end
|
||||||
// of the path to find a common root pin.
|
// of the path to find a common root pin.
|
||||||
int i = src_gclk_paths.size() - 1;
|
int i = src_gclk_paths.size() - 1;
|
||||||
int j = tgt_gclk_paths.size() - 1;
|
int j = tgt_gclk_paths.size() - 1;
|
||||||
for (; i >= 0 && j >= 0; i--, j--) {
|
for (; i >= 0 && j >= 0; i--, j--) {
|
||||||
PathVertex &src_path = src_gclk_paths[i];
|
const Path *src_path = src_gclk_paths[i];
|
||||||
PathVertex &tgt_path = tgt_gclk_paths[j];
|
const Path *tgt_path = tgt_gclk_paths[j];
|
||||||
if (src_path.clkInfo(this)->clkSrc()
|
if (src_path->clkInfo(this)->clkSrc()
|
||||||
== tgt_path.clkInfo(this)->clkSrc()) {
|
== tgt_path->clkInfo(this)->clkSrc()) {
|
||||||
src_clk_path1 = &src_gclk_paths[i];
|
src_clk_path1 = src_gclk_paths[i];
|
||||||
tgt_clk_path1 = &tgt_gclk_paths[j];
|
tgt_clk_path1 = tgt_gclk_paths[j];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const PathVertex *src_clk_path2 = src_clk_path1;
|
const Path *src_clk_path2 = src_clk_path1;
|
||||||
const PathVertex *tgt_clk_path2 = tgt_clk_path1;
|
const Path *tgt_clk_path2 = tgt_clk_path1;
|
||||||
PathVertex src_prev, tgt_prev;
|
// src_clk_path2 and tgt_clk_path2 are now in the same (gen)clk src path.
|
||||||
// src_clk_path and tgt_clk_path are now in the same (gen)clk src path.
|
|
||||||
// Use the vertex levels to back up the deeper path to see if they
|
// Use the vertex levels to back up the deeper path to see if they
|
||||||
// overlap.
|
// overlap.
|
||||||
int src_level = src_clk_path2->vertex(this)->level();
|
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)) {
|
while (src_clk_path2->pin(this) != tgt_clk_path2->pin(this)) {
|
||||||
int level_diff = src_level - tgt_level;
|
int level_diff = src_level - tgt_level;
|
||||||
if (level_diff >= 0) {
|
if (level_diff >= 0) {
|
||||||
clkPathPrev(src_clk_path2, src_prev);
|
src_clk_path2 = src_clk_path2->prevPath();
|
||||||
if (src_prev.isNull())
|
if (src_clk_path2 == nullptr)
|
||||||
break;
|
break;
|
||||||
src_clk_path2 = &src_prev;
|
|
||||||
src_level = src_clk_path2->vertex(this)->level();
|
src_level = src_clk_path2->vertex(this)->level();
|
||||||
}
|
}
|
||||||
if (level_diff <= 0) {
|
if (level_diff <= 0) {
|
||||||
clkPathPrev(tgt_clk_path2, tgt_prev);
|
tgt_clk_path2 = tgt_clk_path2->prevPath();
|
||||||
if (tgt_prev.isNull())
|
if (tgt_clk_path2 == nullptr)
|
||||||
break;
|
break;
|
||||||
tgt_clk_path2 = &tgt_prev;
|
|
||||||
tgt_level = tgt_clk_path2->vertex(this)->level();
|
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)
|
&& (src_clk_path2->transition(this) == tgt_clk_path2->transition(this)
|
||||||
|| same_pin)) {
|
|| same_pin)) {
|
||||||
debugPrint(debug_, "crpr", 2, "crpr pin %s",
|
debugPrint(debug_, "crpr", 2, "crpr pin %s",
|
||||||
|
|
@ -292,30 +241,31 @@ CheckCrpr::findCrpr(const PathVertex *src_clk_path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
ConstPathSeq
|
||||||
CheckCrpr::genClkSrcPaths(const PathVertex *path,
|
CheckCrpr::genClkSrcPaths(const Path *path)
|
||||||
PathVertexSeq &gclk_paths)
|
|
||||||
{
|
{
|
||||||
|
ConstPathSeq gclk_paths;
|
||||||
ClkInfo *clk_info = path->clkInfo(this);
|
ClkInfo *clk_info = path->clkInfo(this);
|
||||||
const ClockEdge *clk_edge = clk_info->clkEdge();
|
const ClockEdge *clk_edge = clk_info->clkEdge();
|
||||||
const Pin *clk_src = clk_info->clkSrc();
|
const Pin *clk_src = clk_info->clkSrc();
|
||||||
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
||||||
gclk_paths.push_back(path);
|
gclk_paths.push_back(path);
|
||||||
|
Genclks *genclks = search_->genclks();
|
||||||
while (clk_edge->clock()->isGenerated()) {
|
while (clk_edge->clock()->isGenerated()) {
|
||||||
PathVertex genclk_path =
|
Path *genclk_path = genclks->srcPath(clk_edge, clk_src, path_ap);
|
||||||
search_->genclks()->srcPath(clk_edge, clk_src, path_ap);
|
if (genclk_path == nullptr)
|
||||||
if (genclk_path.isNull())
|
|
||||||
break;
|
break;
|
||||||
clk_info = genclk_path.clkInfo(this);
|
clk_info = genclk_path->clkInfo(this);
|
||||||
clk_src = clk_info->clkSrc();
|
clk_src = clk_info->clkSrc();
|
||||||
clk_edge = clk_info->clkEdge();
|
clk_edge = clk_info->clkEdge();
|
||||||
gclk_paths.push_back(genclk_path);
|
gclk_paths.push_back(genclk_path);
|
||||||
}
|
}
|
||||||
|
return gclk_paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
Crpr
|
Crpr
|
||||||
CheckCrpr::findCrpr1(const PathVertex *src_clk_path,
|
CheckCrpr::findCrpr1(const Path *src_clk_path,
|
||||||
const PathVertex *tgt_clk_path)
|
const Path *tgt_clk_path)
|
||||||
{
|
{
|
||||||
if (pocv_enabled_) {
|
if (pocv_enabled_) {
|
||||||
// Remove variation on the common path.
|
// Remove variation on the common path.
|
||||||
|
|
@ -323,8 +273,8 @@ CheckCrpr::findCrpr1(const PathVertex *src_clk_path,
|
||||||
// sigma of the common clock path.
|
// sigma of the common clock path.
|
||||||
const EarlyLate *src_el = src_clk_path->minMax(this);
|
const EarlyLate *src_el = src_clk_path->minMax(this);
|
||||||
const EarlyLate *tgt_el = tgt_clk_path->minMax(this);
|
const EarlyLate *tgt_el = tgt_clk_path->minMax(this);
|
||||||
Arrival src_arrival = src_clk_path->arrival(this);
|
Arrival src_arrival = src_clk_path->arrival();
|
||||||
Arrival tgt_arrival = tgt_clk_path->arrival(this);
|
Arrival tgt_arrival = tgt_clk_path->arrival();
|
||||||
float src_clk_time = src_clk_path->clkEdge(this)->time();
|
float src_clk_time = src_clk_path->clkEdge(this)->time();
|
||||||
float tgt_clk_time = tgt_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
|
float crpr_mean = abs(delayAsFloat(src_arrival) - src_clk_time
|
||||||
|
|
@ -352,10 +302,10 @@ CheckCrpr::findCrpr1(const PathVertex *src_clk_path,
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
CheckCrpr::crprArrivalDiff(const PathVertex *path)
|
CheckCrpr::crprArrivalDiff(const Path *path)
|
||||||
{
|
{
|
||||||
Arrival other_arrival = otherMinMaxArrival(path);
|
Arrival other_arrival = otherMinMaxArrival(path);
|
||||||
float crpr_diff = abs(delayAsFloat(path->arrival(this))
|
float crpr_diff = abs(delayAsFloat(path->arrival())
|
||||||
- delayAsFloat(other_arrival));
|
- delayAsFloat(other_arrival));
|
||||||
return crpr_diff;
|
return crpr_diff;
|
||||||
}
|
}
|
||||||
|
|
@ -407,13 +357,12 @@ CheckCrpr::outputDelayCrpr1(const Path *src_path,
|
||||||
&& tgt_clk->isGenerated()
|
&& tgt_clk->isGenerated()
|
||||||
&& tgt_clk->isPropagated()
|
&& tgt_clk->isPropagated()
|
||||||
&& crprPossible(src_clk, tgt_clk)) {
|
&& crprPossible(src_clk, tgt_clk)) {
|
||||||
PathVertex tgt_genclk_path;
|
Path *tgt_genclk_path = portClkPath(tgt_clk_edge,
|
||||||
portClkPath(tgt_clk_edge, tgt_clk_edge->clock()->defaultPin(), tgt_path_ap,
|
tgt_clk_edge->clock()->defaultPin(),
|
||||||
tgt_genclk_path);
|
tgt_path_ap);
|
||||||
PathVertex src_clk_path(src_path->clkInfo(this)->crprClkPath(), this);
|
Path *src_clk_path = src_path->clkInfo(this)->crprClkPath(this);
|
||||||
if (!src_clk_path.isNull()) {
|
if (src_clk_path)
|
||||||
findCrpr(&src_clk_path, &tgt_genclk_path, same_pin, crpr, crpr_pin);
|
findCrpr(src_clk_path, tgt_genclk_path, same_pin, crpr, crpr_pin);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,9 @@ public:
|
||||||
Arrival maxCrpr(ClkInfo *clk_info);
|
Arrival maxCrpr(ClkInfo *clk_info);
|
||||||
// Timing check CRPR.
|
// Timing check CRPR.
|
||||||
Crpr checkCrpr(const Path *src_clk_path,
|
Crpr checkCrpr(const Path *src_clk_path,
|
||||||
const PathVertex *tgt_clk_path);
|
const Path *tgt_clk_path);
|
||||||
void checkCrpr(const Path *src_path,
|
void checkCrpr(const Path *src_path,
|
||||||
const PathVertex *tgt_clk_path,
|
const Path *tgt_clk_path,
|
||||||
// Return values.
|
// Return values.
|
||||||
Crpr &crpr,
|
Crpr &crpr,
|
||||||
Pin *&crpr_pin);
|
Pin *&crpr_pin);
|
||||||
|
|
@ -57,18 +57,12 @@ public:
|
||||||
Crpr &crpr,
|
Crpr &crpr,
|
||||||
Pin *&crpr_pin);
|
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:
|
private:
|
||||||
void clkPathPrev(const PathVertex *path,
|
void clkPathPrev(const Path *path,
|
||||||
PathVertex &prev);
|
Path &prev);
|
||||||
Arrival otherMinMaxArrival(const PathVertex *path);
|
Arrival otherMinMaxArrival(const Path *path);
|
||||||
void checkCrpr1(const Path *src_path,
|
void checkCrpr1(const Path *src_path,
|
||||||
const PathVertex *tgt_clk_path,
|
const Path *tgt_clk_path,
|
||||||
bool same_pin,
|
bool same_pin,
|
||||||
// Return values.
|
// Return values.
|
||||||
Crpr &crpr,
|
Crpr &crpr,
|
||||||
|
|
@ -82,22 +76,19 @@ private:
|
||||||
Pin *&crpr_pin);
|
Pin *&crpr_pin);
|
||||||
bool crprPossible(const Clock *clk1,
|
bool crprPossible(const Clock *clk1,
|
||||||
const Clock *clk2);
|
const Clock *clk2);
|
||||||
void genClkSrcPaths(const PathVertex *path,
|
ConstPathSeq genClkSrcPaths(const Path *path);
|
||||||
PathVertexSeq &gclk_paths);
|
void findCrpr(const Path *src_clk_path,
|
||||||
void findCrpr(const PathVertex *src_clk_path,
|
const Path *tgt_clk_path,
|
||||||
const PathVertex *tgt_clk_path,
|
|
||||||
bool same_pin,
|
bool same_pin,
|
||||||
// Return values.
|
// Return values.
|
||||||
Crpr &crpr,
|
Crpr &crpr,
|
||||||
Pin *&common_pin);
|
Pin *&common_pin);
|
||||||
void portClkPath(const ClockEdge *clk_edge,
|
Path *portClkPath(const ClockEdge *clk_edge,
|
||||||
const Pin *clk_src_pin,
|
const Pin *clk_src_pin,
|
||||||
const PathAnalysisPt *path_ap,
|
const PathAnalysisPt *path_ap);
|
||||||
// Return value.
|
Crpr findCrpr1(const Path *src_clk_path,
|
||||||
PathVertex &port_clk_path);
|
const Path *tgt_clk_path);
|
||||||
Crpr findCrpr1(const PathVertex *src_clk_path,
|
float crprArrivalDiff(const Path *path);
|
||||||
const PathVertex *tgt_clk_path);
|
|
||||||
float crprArrivalDiff(const PathVertex *path);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
#include "Corner.hh"
|
#include "Corner.hh"
|
||||||
#include "PathAnalysisPt.hh"
|
#include "PathAnalysisPt.hh"
|
||||||
#include "Levelize.hh"
|
#include "Levelize.hh"
|
||||||
#include "PathVertexPtr.hh"
|
#include "Path.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
@ -137,7 +137,7 @@ Genclks::fanins(const Clock *clk)
|
||||||
}
|
}
|
||||||
|
|
||||||
Vertex *
|
Vertex *
|
||||||
Genclks::srcPathVertex(const Pin *pin) const
|
Genclks::srcPath(const Pin *pin) const
|
||||||
{
|
{
|
||||||
bool is_bidirect = network_->direction(pin)->isBidirect();
|
bool is_bidirect = network_->direction(pin)->isBidirect();
|
||||||
// Insertion delay is to the driver vertex for clks defined on
|
// 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;
|
Level max_level = 0;
|
||||||
for (const Pin *pin : clk->leafPins()) {
|
for (const Pin *pin : clk->leafPins()) {
|
||||||
Vertex *vertex = srcPathVertex(pin);
|
Vertex *vertex = srcPath(pin);
|
||||||
max_level = max(max_level, vertex->level());
|
max_level = max(max_level, vertex->level());
|
||||||
}
|
}
|
||||||
return max_level;
|
return max_level;
|
||||||
|
|
@ -209,9 +209,7 @@ Genclks::ensureInsertionDelays()
|
||||||
// insertion delay, so sort the clocks by source pin level.
|
// insertion delay, so sort the clocks by source pin level.
|
||||||
sort(gclks, ClockPinMaxLevelLess(this));
|
sort(gclks, ClockPinMaxLevelLess(this));
|
||||||
|
|
||||||
ClockSeq::Iterator gclk_iter(gclks);
|
for (Clock *gclk : gclks) {
|
||||||
while (gclk_iter.hasNext()) {
|
|
||||||
Clock *gclk = gclk_iter.next();
|
|
||||||
if (gclk->masterClk()) {
|
if (gclk->masterClk()) {
|
||||||
findInsertionDelays(gclk);
|
findInsertionDelays(gclk);
|
||||||
recordSrcPaths(gclk);
|
recordSrcPaths(gclk);
|
||||||
|
|
@ -546,7 +544,7 @@ Genclks::makeGenclkInfo(Clock *gclk)
|
||||||
VertexSet *fanins = new VertexSet(graph_);
|
VertexSet *fanins = new VertexSet(graph_);
|
||||||
findFanin(gclk, fanins);
|
findFanin(gclk, fanins);
|
||||||
GenclkInfo *genclk_info = new GenclkInfo(gclk, gclk_level, fanins,
|
GenclkInfo *genclk_info = new GenclkInfo(gclk, gclk_level, fanins,
|
||||||
src_filter);
|
src_filter);
|
||||||
genclk_info_map_.insert(gclk, genclk_info);
|
genclk_info_map_.insert(gclk, genclk_info);
|
||||||
return genclk_info;
|
return genclk_info;
|
||||||
}
|
}
|
||||||
|
|
@ -684,12 +682,12 @@ Genclks::seedSrcPins(Clock *gclk,
|
||||||
for (auto path_ap : corners_->pathAnalysisPts()) {
|
for (auto path_ap : corners_->pathAnalysisPts()) {
|
||||||
const MinMax *min_max = path_ap->pathMinMax();
|
const MinMax *min_max = path_ap->pathMinMax();
|
||||||
const EarlyLate *early_late = min_max;
|
const EarlyLate *early_late = min_max;
|
||||||
for (auto rf : RiseFall::range()) {
|
for (const RiseFall *rf : RiseFall::range()) {
|
||||||
Tag *tag = makeTag(gclk, master_clk, master_pin, rf, src_filter,
|
Tag *tag = makeTag(gclk, master_clk, master_pin, rf,
|
||||||
path_ap);
|
src_filter, path_ap);
|
||||||
Arrival insert = search_->clockInsertion(master_clk, master_pin, rf,
|
Arrival insert = search_->clockInsertion(master_clk, master_pin, rf,
|
||||||
min_max, early_late, path_ap);
|
min_max, early_late, path_ap);
|
||||||
tag_bldr.setArrival(tag, insert, nullptr);
|
tag_bldr.setArrival(tag, insert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
search_->setVertexArrivals(vertex, &tag_bldr);
|
search_->setVertexArrivals(vertex, &tag_bldr);
|
||||||
|
|
@ -854,22 +852,14 @@ void
|
||||||
Genclks::copyGenClkSrcPaths(Vertex *vertex,
|
Genclks::copyGenClkSrcPaths(Vertex *vertex,
|
||||||
TagGroupBldr *tag_bldr)
|
TagGroupBldr *tag_bldr)
|
||||||
{
|
{
|
||||||
Arrival *arrivals = graph_->arrivals(vertex);
|
Path *paths = graph_->paths(vertex);
|
||||||
if (arrivals) {
|
if (paths) {
|
||||||
PathPrev *prev_paths = graph_->prevPaths(vertex);
|
|
||||||
TagGroup *tag_group = search_->tagGroup(vertex);
|
TagGroup *tag_group = search_->tagGroup(vertex);
|
||||||
if (tag_group) {
|
if (tag_group) {
|
||||||
ArrivalMap::Iterator arrival_iter(tag_group->arrivalMap());
|
for (auto const [tag, path_index] : *tag_group->pathIndexMap()) {
|
||||||
while (arrival_iter.hasNext()) {
|
|
||||||
Tag *tag;
|
|
||||||
int arrival_index;
|
|
||||||
arrival_iter.next(tag, arrival_index);
|
|
||||||
if (tag->isGenClkSrcPath()) {
|
if (tag->isGenClkSrcPath()) {
|
||||||
Arrival arrival = arrivals[arrival_index];
|
Path &path = paths[path_index];
|
||||||
PathPrev *prev_path = prev_paths
|
tag_bldr->insertPath(path);
|
||||||
? &prev_paths[arrival_index]
|
|
||||||
: nullptr;
|
|
||||||
tag_bldr->setArrival(tag, arrival, prev_path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -881,11 +871,14 @@ Genclks::copyGenClkSrcPaths(Vertex *vertex,
|
||||||
void
|
void
|
||||||
Genclks::clearSrcPaths()
|
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();
|
genclk_src_paths_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
size_t
|
||||||
Genclks::srcPathIndex(const RiseFall *clk_rf,
|
Genclks::srcPathIndex(const RiseFall *clk_rf,
|
||||||
const PathAnalysisPt *path_ap) const
|
const PathAnalysisPt *path_ap) const
|
||||||
{
|
{
|
||||||
|
|
@ -903,14 +896,13 @@ Genclks::recordSrcPaths(Clock *gclk)
|
||||||
bool has_edges = gclk->edges() != nullptr;
|
bool has_edges = gclk->edges() != nullptr;
|
||||||
|
|
||||||
for (const Pin *gclk_pin : gclk->leafPins()) {
|
for (const Pin *gclk_pin : gclk->leafPins()) {
|
||||||
PathVertexPtr *src_paths = new PathVertexPtr[path_count];
|
vector<Path> &src_paths = genclk_src_paths_[ClockPinPair(gclk, gclk_pin)];
|
||||||
genclk_src_paths_.insert(ClockPinPair(gclk, gclk_pin), src_paths);
|
src_paths.resize(path_count);
|
||||||
|
Vertex *gclk_vertex = srcPath(gclk_pin);
|
||||||
Vertex *gclk_vertex = srcPathVertex(gclk_pin);
|
|
||||||
bool found_src_paths = false;
|
bool found_src_paths = false;
|
||||||
VertexPathIterator path_iter(gclk_vertex, this);
|
VertexPathIterator path_iter(gclk_vertex, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
const ClockEdge *src_clk_edge = path->clkEdge(this);
|
const ClockEdge *src_clk_edge = path->clkEdge(this);
|
||||||
if (src_clk_edge
|
if (src_clk_edge
|
||||||
&& matchesSrcFilter(path, gclk)) {
|
&& matchesSrcFilter(path, gclk)) {
|
||||||
|
|
@ -919,24 +911,34 @@ Genclks::recordSrcPaths(Clock *gclk)
|
||||||
const RiseFall *rf = path->transition(this);
|
const RiseFall *rf = path->transition(this);
|
||||||
bool inverting_path = (rf != src_clk_rf);
|
bool inverting_path = (rf != src_clk_rf);
|
||||||
const PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
const PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
||||||
int path_index = srcPathIndex(rf, path_ap);
|
size_t path_index = srcPathIndex(rf, path_ap);
|
||||||
PathVertexPtr &src_path = src_paths[path_index];
|
Path &src_path = src_paths[path_index];
|
||||||
if ((!divide_by_1
|
if ((!divide_by_1
|
||||||
|| (inverting_path == invert))
|
|| (inverting_path == invert))
|
||||||
&& (!has_edges
|
&& (!has_edges
|
||||||
|| src_clk_rf == gclk->masterClkEdgeTr(rf))
|
|| src_clk_rf == gclk->masterClkEdgeTr(rf))
|
||||||
&& (src_path.isNull()
|
&& (src_path.isNull()
|
||||||
|| delayGreater(path->arrival(this),
|
|| delayGreater(path->arrival(),
|
||||||
src_path.arrival(this),
|
src_path.arrival(),
|
||||||
early_late,
|
early_late,
|
||||||
this))) {
|
this))) {
|
||||||
debugPrint(debug_, "genclk", 2, " %s insertion %s %s %s",
|
debugPrint(debug_, "genclk", 2, " %s insertion %s %s %s",
|
||||||
network_->pathName(gclk_pin),
|
network_->pathName(gclk_pin),
|
||||||
early_late->asString(),
|
early_late->asString(),
|
||||||
rf->asString(),
|
rf->asString(),
|
||||||
delayAsString(path->arrival(this), this));
|
delayAsString(path->arrival(), this));
|
||||||
src_path.init(path, this);
|
delete src_path.prevPath();
|
||||||
found_src_paths = true;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PathVertex
|
Path *
|
||||||
Genclks::srcPath(Path *clk_path) const
|
Genclks::srcPath(const Path *clk_path) const
|
||||||
{
|
{
|
||||||
const Pin *src_pin = clk_path->pin(this);
|
const Pin *src_pin = clk_path->pin(this);
|
||||||
const ClockEdge *clk_edge = clk_path->clkEdge(this);
|
const ClockEdge *clk_edge = clk_path->clkEdge(this);
|
||||||
|
|
@ -985,7 +987,7 @@ Genclks::srcPath(Path *clk_path) const
|
||||||
insert_ap);
|
insert_ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathVertex
|
Path *
|
||||||
Genclks::srcPath(const ClockEdge *clk_edge,
|
Genclks::srcPath(const ClockEdge *clk_edge,
|
||||||
const Pin *src_pin,
|
const Pin *src_pin,
|
||||||
const PathAnalysisPt *path_ap) const
|
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);
|
return srcPath(clk_edge->clock(), src_pin, clk_edge->transition(), path_ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathVertex
|
Path *
|
||||||
Genclks::srcPath(const Clock *gclk,
|
Genclks::srcPath(const Clock *gclk,
|
||||||
const Pin *src_pin,
|
const Pin *src_pin,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const PathAnalysisPt *path_ap) const
|
const PathAnalysisPt *path_ap) const
|
||||||
{
|
{
|
||||||
PathVertexPtr *src_paths =
|
auto itr = genclk_src_paths_.find(ClockPinPair(gclk, src_pin));
|
||||||
genclk_src_paths_.findKey(ClockPinPair(gclk, src_pin));
|
if (itr != genclk_src_paths_.end()) {
|
||||||
if (src_paths) {
|
vector<Path> src_paths = itr->second;
|
||||||
int path_index = srcPathIndex(rf, path_ap);
|
if (!src_paths.empty()) {
|
||||||
return PathVertex(src_paths[path_index], this);
|
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
|
Arrival
|
||||||
|
|
@ -1017,9 +1051,9 @@ Genclks::insertionDelay(const Clock *clk,
|
||||||
const PathAnalysisPt *path_ap) const
|
const PathAnalysisPt *path_ap) const
|
||||||
{
|
{
|
||||||
PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late);
|
PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late);
|
||||||
PathVertex src_path = srcPath(clk, pin, rf, insert_ap);
|
Path *src_path = srcPath(clk, pin, rf, insert_ap);
|
||||||
if (!src_path.isNull())
|
if (src_path)
|
||||||
return src_path.arrival(this);
|
return src_path->arrival();
|
||||||
else
|
else
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef Map<Clock*, GenclkInfo*> GenclkInfoMap;
|
typedef Map<Clock*, GenclkInfo*> GenclkInfoMap;
|
||||||
typedef Map<ClockPinPair, PathVertexPtr*, ClockPinPairLess> GenclkSrcPathMap;
|
typedef Map<ClockPinPair, vector<Path>, ClockPinPairLess> GenclkSrcPathMap;
|
||||||
|
|
||||||
class Genclks : public StaState
|
class Genclks : public StaState
|
||||||
{
|
{
|
||||||
|
|
@ -71,19 +71,20 @@ public:
|
||||||
const EarlyLate *early_late,
|
const EarlyLate *early_late,
|
||||||
const PathAnalysisPt *path_ap) const;
|
const PathAnalysisPt *path_ap) const;
|
||||||
// Generated clock source path for a clock path root.
|
// 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.
|
// Generated clock source path.
|
||||||
PathVertex srcPath(const ClockEdge *clk_edge,
|
Path *srcPath(const ClockEdge *clk_edge,
|
||||||
const Pin *src_pin,
|
const Pin *src_pin,
|
||||||
const PathAnalysisPt *path_ap) const;
|
const PathAnalysisPt *path_ap) const;
|
||||||
PathVertex srcPath(const Clock *clk,
|
Path *srcPath(const Clock *clk,
|
||||||
const Pin *src_pin,
|
const Pin *src_pin,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const PathAnalysisPt *path_ap) const;
|
const PathAnalysisPt *path_ap) const;
|
||||||
Vertex *srcPathVertex(const Pin *pin) const;
|
Vertex *srcPath(const Pin *pin) const;
|
||||||
Level clkPinMaxLevel(const Clock *clk) const;
|
Level clkPinMaxLevel(const Clock *clk) const;
|
||||||
void copyGenClkSrcPaths(Vertex *vertex,
|
void copyGenClkSrcPaths(Vertex *vertex,
|
||||||
TagGroupBldr *tag_bldr);
|
TagGroupBldr *tag_bldr);
|
||||||
|
void updateSrcPathPrevs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void findInsertionDelays();
|
void findInsertionDelays();
|
||||||
|
|
@ -94,8 +95,8 @@ private:
|
||||||
void seedClkVertices(Clock *clk,
|
void seedClkVertices(Clock *clk,
|
||||||
BfsBkwdIterator &iter,
|
BfsBkwdIterator &iter,
|
||||||
VertexSet *fanins);
|
VertexSet *fanins);
|
||||||
int srcPathIndex(const RiseFall *clk_rf,
|
size_t srcPathIndex(const RiseFall *clk_rf,
|
||||||
const PathAnalysisPt *path_ap) const;
|
const PathAnalysisPt *path_ap) const;
|
||||||
bool matchesSrcFilter(Path *path,
|
bool matchesSrcFilter(Path *path,
|
||||||
const Clock *gclk) const;
|
const Clock *gclk) const;
|
||||||
void seedSrcPins(Clock *gclk,
|
void seedSrcPins(Clock *gclk,
|
||||||
|
|
@ -129,7 +130,6 @@ private:
|
||||||
VertexSet &visited_vertices,
|
VertexSet &visited_vertices,
|
||||||
EdgeSet *&fdbk_edges);
|
EdgeSet *&fdbk_edges);
|
||||||
|
|
||||||
|
|
||||||
bool found_insertion_delays_;
|
bool found_insertion_delays_;
|
||||||
GenclkSrcPathMap genclk_src_paths_;
|
GenclkSrcPathMap genclk_src_paths_;
|
||||||
GenclkInfoMap genclk_info_map_;
|
GenclkInfoMap genclk_info_map_;
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,8 @@ Latches::Latches(StaState *sta) :
|
||||||
|
|
||||||
void
|
void
|
||||||
Latches::latchRequired(const Path *data_path,
|
Latches::latchRequired(const Path *data_path,
|
||||||
const PathVertex *enable_path,
|
const Path *enable_path,
|
||||||
const PathVertex *disable_path,
|
const Path *disable_path,
|
||||||
const MultiCyclePath *mcp,
|
const MultiCyclePath *mcp,
|
||||||
const PathDelay *path_delay,
|
const PathDelay *path_delay,
|
||||||
Arrival src_clk_latency,
|
Arrival src_clk_latency,
|
||||||
|
|
@ -61,7 +61,7 @@ Latches::latchRequired(const Path *data_path,
|
||||||
Arrival &adjusted_data_arrival,
|
Arrival &adjusted_data_arrival,
|
||||||
Delay &time_given_to_startpoint) const
|
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;
|
float max_delay = 0.0;
|
||||||
bool ignore_clk_latency = false;
|
bool ignore_clk_latency = false;
|
||||||
if (path_delay) {
|
if (path_delay) {
|
||||||
|
|
@ -149,8 +149,8 @@ Latches::latchRequired(const Path *data_path,
|
||||||
|
|
||||||
void
|
void
|
||||||
Latches::latchBorrowInfo(const Path *data_path,
|
Latches::latchBorrowInfo(const Path *data_path,
|
||||||
const PathVertex *enable_path,
|
const Path *enable_path,
|
||||||
const PathVertex *disable_path,
|
const Path *disable_path,
|
||||||
const ArcDelay &margin,
|
const ArcDelay &margin,
|
||||||
bool ignore_clk_latency,
|
bool ignore_clk_latency,
|
||||||
// Return values.
|
// Return values.
|
||||||
|
|
@ -213,8 +213,8 @@ Latches::latchBorrowInfo(const Path *data_path,
|
||||||
|
|
||||||
void
|
void
|
||||||
Latches::latchRequired(const Path *data_path,
|
Latches::latchRequired(const Path *data_path,
|
||||||
const PathVertex *enable_path,
|
const Path *enable_path,
|
||||||
const PathVertex *disable_path,
|
const Path *disable_path,
|
||||||
const PathAnalysisPt *path_ap,
|
const PathAnalysisPt *path_ap,
|
||||||
// Return values.
|
// Return values.
|
||||||
Required &required,
|
Required &required,
|
||||||
|
|
@ -243,11 +243,9 @@ Latches::latchRequired(const Path *data_path,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the latch enable open/close path from the close/open path.
|
// Find the latch enable open/close path from the close/open path.
|
||||||
void
|
Path *
|
||||||
Latches::latchEnableOtherPath(const Path *path,
|
Latches::latchEnableOtherPath(const Path *path,
|
||||||
const PathAnalysisPt *tgt_clk_path_ap,
|
const PathAnalysisPt *tgt_clk_path_ap) const
|
||||||
// Return value.
|
|
||||||
PathVertex &other_path) const
|
|
||||||
{
|
{
|
||||||
Vertex *vertex = path->vertex(this);
|
Vertex *vertex = path->vertex(this);
|
||||||
const ClockEdge *clk_edge = path->clkEdge(this);
|
const ClockEdge *clk_edge = path->clkEdge(this);
|
||||||
|
|
@ -256,20 +254,18 @@ Latches::latchEnableOtherPath(const Path *path,
|
||||||
RiseFall *other_rf = path->transition(this)->opposite();
|
RiseFall *other_rf = path->transition(this)->opposite();
|
||||||
VertexPathIterator path_iter(vertex, other_rf, tgt_clk_path_ap, this);
|
VertexPathIterator path_iter(vertex, other_rf, tgt_clk_path_ap, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
if (path->isClock(this)
|
if (path->isClock(this)
|
||||||
&& path->clkEdge(this) == other_clk_edge) {
|
&& path->clkEdge(this) == other_clk_edge) {
|
||||||
other_path = path;
|
return path;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
Path *
|
||||||
Latches::latchEnablePath(const Path *q_path,
|
Latches::latchEnablePath(const Path *q_path,
|
||||||
const Edge *d_q_edge,
|
const Edge *d_q_edge) const
|
||||||
// Return value.
|
|
||||||
PathVertex &enable_path) const
|
|
||||||
|
|
||||||
{
|
{
|
||||||
const ClockEdge *en_clk_edge = q_path->clkEdge(this);
|
const ClockEdge *en_clk_edge = q_path->clkEdge(this);
|
||||||
|
|
@ -283,15 +279,15 @@ Latches::latchEnablePath(const Path *q_path,
|
||||||
if (state == LatchEnableState::enabled) {
|
if (state == LatchEnableState::enabled) {
|
||||||
VertexPathIterator path_iter(en_vertex, en_rf, tgt_clk_path_ap, this);
|
VertexPathIterator path_iter(en_vertex, en_rf, tgt_clk_path_ap, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
const ClockEdge *clk_edge = path->clkEdge(this);
|
const ClockEdge *clk_edge = path->clkEdge(this);
|
||||||
if (path->isClock(this)
|
if (path->isClock(this)
|
||||||
&& clk_edge == en_clk_edge) {
|
&& clk_edge == en_clk_edge) {
|
||||||
enable_path = path;
|
return path;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The arrival time for a latch D->Q edge is clipped to the window of
|
// 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())) {
|
if (!(excpt && excpt->isFalse())) {
|
||||||
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
|
arc_delay = search_->deratedDelay(data_vertex, d_q_arc, d_q_edge,
|
||||||
false, path_ap);
|
false, path_ap);
|
||||||
q_arrival = data_path->arrival(this) + arc_delay;
|
q_arrival = data_path->arrival() + arc_delay;
|
||||||
q_tag = data_path->tag(this);
|
q_tag = data_path->tag(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -334,7 +330,7 @@ Latches::latchOutArrival(const Path *data_path,
|
||||||
VertexPathIterator enable_iter(enable_vertex, enable_rf,
|
VertexPathIterator enable_iter(enable_vertex, enable_rf,
|
||||||
tgt_clk_path_ap, this);
|
tgt_clk_path_ap, this);
|
||||||
while (enable_iter.hasNext()) {
|
while (enable_iter.hasNext()) {
|
||||||
PathVertex *enable_path = enable_iter.next();
|
Path *enable_path = enable_iter.next();
|
||||||
ClkInfo *en_clk_info = enable_path->clkInfo(this);
|
ClkInfo *en_clk_info = enable_path->clkInfo(this);
|
||||||
const ClockEdge *en_clk_edge = en_clk_info->clkEdge();
|
const ClockEdge *en_clk_edge = en_clk_info->clkEdge();
|
||||||
if (enable_path->isClock(this)) {
|
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.
|
// D->Q is disabled when if there is a path delay -to D or EN clk.
|
||||||
if (!(excpt && (excpt->isFalse()
|
if (!(excpt && (excpt->isFalse()
|
||||||
|| excpt->isPathDelay()))) {
|
|| excpt->isPathDelay()))) {
|
||||||
PathVertex disable_path;
|
Path *disable_path = latchEnableOtherPath(enable_path, tgt_clk_path_ap);
|
||||||
latchEnableOtherPath(enable_path, tgt_clk_path_ap, disable_path);
|
|
||||||
Delay borrow, time_given_to_startpoint;
|
Delay borrow, time_given_to_startpoint;
|
||||||
Arrival adjusted_data_arrival;
|
Arrival adjusted_data_arrival;
|
||||||
Required required;
|
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,
|
required, borrow, adjusted_data_arrival,
|
||||||
time_given_to_startpoint);
|
time_given_to_startpoint);
|
||||||
if (delayGreater(borrow, 0.0, this)) {
|
if (delayGreater(borrow, 0.0, this)) {
|
||||||
|
|
@ -357,7 +352,7 @@ Latches::latchOutArrival(const Path *data_path,
|
||||||
q_arrival = adjusted_data_arrival + arc_delay;
|
q_arrival = adjusted_data_arrival + arc_delay;
|
||||||
// Tag switcheroo - data passing thru gets latch enable tag.
|
// Tag switcheroo - data passing thru gets latch enable tag.
|
||||||
// States and path ap come from Q, everything else from enable.
|
// States and path ap come from Q, everything else from enable.
|
||||||
PathVertex *crpr_clk_path =
|
Path *crpr_clk_path =
|
||||||
sdc_->crprActive() ? enable_path : nullptr;
|
sdc_->crprActive() ? enable_path : nullptr;
|
||||||
ClkInfo *q_clk_info =
|
ClkInfo *q_clk_info =
|
||||||
search_->findClkInfo(en_clk_edge,
|
search_->findClkInfo(en_clk_edge,
|
||||||
|
|
@ -448,24 +443,23 @@ Latches::latchTimeGivenToStartpoint(const Path *d_path,
|
||||||
const Edge *d_q_edge,
|
const Edge *d_q_edge,
|
||||||
// Return values.
|
// Return values.
|
||||||
Arrival &time_given,
|
Arrival &time_given,
|
||||||
PathVertex &enable_path) const
|
Path *&enable_path) const
|
||||||
{
|
{
|
||||||
latchEnablePath(q_path, d_q_edge, enable_path);
|
enable_path = latchEnablePath(q_path, d_q_edge);
|
||||||
if (!enable_path.isNull()
|
if (enable_path
|
||||||
&& enable_path.isClock(this)) {
|
&& enable_path->isClock(this)) {
|
||||||
const PathAnalysisPt *path_ap = q_path->pathAnalysisPt(this);
|
const PathAnalysisPt *path_ap = q_path->pathAnalysisPt(this);
|
||||||
const PathAnalysisPt *tgt_clk_path_ap = path_ap->tgtClkAnalysisPt();
|
const PathAnalysisPt *tgt_clk_path_ap = path_ap->tgtClkAnalysisPt();
|
||||||
PathVertex disable_path;
|
Path *disable_path = latchEnableOtherPath(enable_path, tgt_clk_path_ap);
|
||||||
latchEnableOtherPath(enable_path.path(), tgt_clk_path_ap, disable_path);
|
|
||||||
Delay borrow;
|
Delay borrow;
|
||||||
Required required;
|
Required required;
|
||||||
Arrival adjusted_data_arrival;
|
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);
|
required, borrow, adjusted_data_arrival, time_given);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
time_given = 0.0;
|
time_given = 0.0;
|
||||||
enable_path.init();
|
enable_path = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -517,7 +511,7 @@ Latches::latchDtoQEnable(const Edge *d_q_edge,
|
||||||
}
|
}
|
||||||
|
|
||||||
LatchEnableState
|
LatchEnableState
|
||||||
Latches::latchDtoQState(Edge *edge) const
|
Latches::latchDtoQState(const Edge *edge) const
|
||||||
{
|
{
|
||||||
const Vertex *from_vertex = edge->from(graph_);
|
const Vertex *from_vertex = edge->from(graph_);
|
||||||
const Pin *from_pin = from_vertex->pin();
|
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
|
// Latch D->Q arc looks combinational when the enable pin is disabled
|
||||||
// or constant.
|
// or constant.
|
||||||
bool
|
bool
|
||||||
Latches::isLatchDtoQ(Edge *edge) const
|
Latches::isLatchDtoQ(const Edge *edge) const
|
||||||
{
|
{
|
||||||
return edge->role() == TimingRole::latchDtoQ()
|
return edge->role() == TimingRole::latchDtoQ()
|
||||||
&& latchDtoQState(edge) == LatchEnableState::enabled;
|
&& latchDtoQState(edge) == LatchEnableState::enabled;
|
||||||
|
|
|
||||||
|
|
@ -43,10 +43,10 @@ public:
|
||||||
const Edge *d_q_edge,
|
const Edge *d_q_edge,
|
||||||
// Return values.
|
// Return values.
|
||||||
Arrival &time_given,
|
Arrival &time_given,
|
||||||
PathVertex &enable_path) const;
|
Path *&enable_path) const;
|
||||||
void latchRequired(const Path *data_path,
|
void latchRequired(const Path *data_path,
|
||||||
const PathVertex *enable_path,
|
const Path *enable_path,
|
||||||
const PathVertex *disable_path,
|
const Path *disable_path,
|
||||||
const MultiCyclePath *mcp,
|
const MultiCyclePath *mcp,
|
||||||
const PathDelay *path_delay,
|
const PathDelay *path_delay,
|
||||||
Arrival src_clk_latency,
|
Arrival src_clk_latency,
|
||||||
|
|
@ -57,8 +57,8 @@ public:
|
||||||
Arrival &adjusted_data_arrival,
|
Arrival &adjusted_data_arrival,
|
||||||
Delay &time_given_to_startpoint) const;
|
Delay &time_given_to_startpoint) const;
|
||||||
void latchRequired(const Path *data_path,
|
void latchRequired(const Path *data_path,
|
||||||
const PathVertex *enable_path,
|
const Path *enable_path,
|
||||||
const PathVertex *disable_path,
|
const Path *disable_path,
|
||||||
const PathAnalysisPt *path_ap,
|
const PathAnalysisPt *path_ap,
|
||||||
// Return values.
|
// Return values.
|
||||||
Required &required,
|
Required &required,
|
||||||
|
|
@ -66,8 +66,8 @@ public:
|
||||||
Arrival &adjusted_data_arrival,
|
Arrival &adjusted_data_arrival,
|
||||||
Delay &time_given_to_startpoint) const;
|
Delay &time_given_to_startpoint) const;
|
||||||
void latchBorrowInfo(const Path *data_path,
|
void latchBorrowInfo(const Path *data_path,
|
||||||
const PathVertex *enable_path,
|
const Path *enable_path,
|
||||||
const PathVertex *disable_path,
|
const Path *disable_path,
|
||||||
const ArcDelay &margin,
|
const ArcDelay &margin,
|
||||||
bool ignore_clk_latency,
|
bool ignore_clk_latency,
|
||||||
// Return values.
|
// Return values.
|
||||||
|
|
@ -79,7 +79,7 @@ public:
|
||||||
Crpr &crpr_diff,
|
Crpr &crpr_diff,
|
||||||
Delay &max_borrow,
|
Delay &max_borrow,
|
||||||
bool &borrow_limit_exists) const;
|
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.
|
// Find the latch EN->Q edge for a D->Q edge.
|
||||||
void latchDtoQEnable(const Edge *d_q_edge,
|
void latchDtoQEnable(const Edge *d_q_edge,
|
||||||
const Instance *inst,
|
const Instance *inst,
|
||||||
|
|
@ -87,15 +87,11 @@ public:
|
||||||
Vertex *&enable_vertex,
|
Vertex *&enable_vertex,
|
||||||
const RiseFall *&enable_rf,
|
const RiseFall *&enable_rf,
|
||||||
LatchEnableState &state) const;
|
LatchEnableState &state) const;
|
||||||
LatchEnableState latchDtoQState(Edge *d_q_edge) const;
|
LatchEnableState latchDtoQState(const Edge *d_q_edge) const;
|
||||||
void latchEnableOtherPath(const Path *path,
|
Path *latchEnableOtherPath(const Path *path,
|
||||||
const PathAnalysisPt *tgt_clk_path_ap,
|
const PathAnalysisPt *tgt_clk_path_ap) const;
|
||||||
// Return value.
|
Path *latchEnablePath(const Path *q_path,
|
||||||
PathVertex &other_path) const;
|
const Edge *d_q_edge) const;
|
||||||
void latchEnablePath(const Path *q_path,
|
|
||||||
const Edge *d_q_edge,
|
|
||||||
// Return value.
|
|
||||||
PathVertex &enable_path) const;
|
|
||||||
void latchOutArrival(const Path *data_path,
|
void latchOutArrival(const Path *data_path,
|
||||||
const TimingArc *d_q_arc,
|
const TimingArc *d_q_arc,
|
||||||
const Edge *d_q_edge,
|
const Edge *d_q_edge,
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ MakeEndTimingArcs::visit(PathEnd *path_end)
|
||||||
Network *network = sta_->network();
|
Network *network = sta_->network();
|
||||||
Debug *debug = sta_->debug();
|
Debug *debug = sta_->debug();
|
||||||
const MinMax *min_max = path_end->minMax(sta_);
|
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_);
|
Delay clk_latency = path_end->targetClkDelay(sta_);
|
||||||
ArcDelay check_margin = path_end->margin(sta_);
|
ArcDelay check_margin = path_end->margin(sta_);
|
||||||
Delay margin = min_max == MinMax::max()
|
Delay margin = min_max == MinMax::max()
|
||||||
|
|
@ -377,11 +377,11 @@ MakeTimingModel::findOutputDelays(const RiseFall *input_rf,
|
||||||
Vertex *output_vertex = graph_->pinLoadVertex(output_pin);
|
Vertex *output_vertex = graph_->pinLoadVertex(output_pin);
|
||||||
VertexPathIterator path_iter(output_vertex, this);
|
VertexPathIterator path_iter(output_vertex, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
if (search_->matchesFilter(path, nullptr)) {
|
if (search_->matchesFilter(path, nullptr)) {
|
||||||
const RiseFall *output_rf = path->transition(sta_);
|
const RiseFall *output_rf = path->transition(sta_);
|
||||||
const MinMax *min_max = path->minMax(sta_);
|
const MinMax *min_max = path->minMax(sta_);
|
||||||
Arrival delay = path->arrival(sta_);
|
Arrival delay = path->arrival();
|
||||||
OutputDelays &delays = output_pin_delays[output_pin];
|
OutputDelays &delays = output_pin_delays[output_pin];
|
||||||
delays.delays.mergeValue(output_rf, min_max,
|
delays.delays.mergeValue(output_rf, min_max,
|
||||||
delayAsFloat(delay, min_max, sta_));
|
delayAsFloat(delay, min_max, sta_));
|
||||||
|
|
@ -486,12 +486,12 @@ MakeTimingModel::findClkedOutputPaths()
|
||||||
Vertex *output_vertex = graph_->pinLoadVertex(output_pin);
|
Vertex *output_vertex = graph_->pinLoadVertex(output_pin);
|
||||||
VertexPathIterator path_iter(output_vertex, this);
|
VertexPathIterator path_iter(output_vertex, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
const ClockEdge *clk_edge = path->clkEdge(sta_);
|
const ClockEdge *clk_edge = path->clkEdge(sta_);
|
||||||
if (clk_edge) {
|
if (clk_edge) {
|
||||||
const RiseFall *output_rf = path->transition(sta_);
|
const RiseFall *output_rf = path->transition(sta_);
|
||||||
const MinMax *min_max = path->minMax(sta_);
|
const MinMax *min_max = path->minMax(sta_);
|
||||||
Arrival delay = path->arrival(sta_);
|
Arrival delay = path->arrival();
|
||||||
RiseFallMinMax &delays = clk_delays[clk_edge];
|
RiseFallMinMax &delays = clk_delays[clk_edge];
|
||||||
delays.mergeValue(output_rf, min_max,
|
delays.mergeValue(output_rf, min_max,
|
||||||
delayAsFloat(delay, min_max, sta_));
|
delayAsFloat(delay, min_max, sta_));
|
||||||
|
|
@ -567,7 +567,7 @@ MakeTimingModel::makeClkTreePaths(LibertyPort *lib_port,
|
||||||
const RiseFall *end_rf = (sense == TimingSense::positive_unate)
|
const RiseFall *end_rf = (sense == TimingSense::positive_unate)
|
||||||
? clk_rf
|
? clk_rf
|
||||||
: clk_rf->opposite();
|
: clk_rf->opposite();
|
||||||
PathVertex clk_path;
|
Path clk_path;
|
||||||
Delay insertion, delay, latency;
|
Delay insertion, delay, latency;
|
||||||
float lib_clk_delay;
|
float lib_clk_delay;
|
||||||
bool exists;
|
bool exists;
|
||||||
|
|
|
||||||
591
search/Path.cc
591
search/Path.cc
|
|
@ -33,17 +33,180 @@
|
||||||
#include "Corner.hh"
|
#include "Corner.hh"
|
||||||
#include "PathAnalysisPt.hh"
|
#include "PathAnalysisPt.hh"
|
||||||
#include "Tag.hh"
|
#include "Tag.hh"
|
||||||
#include "PathRef.hh"
|
#include "TagGroup.hh"
|
||||||
|
#include "Search.hh"
|
||||||
|
|
||||||
namespace sta {
|
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 *
|
const char *
|
||||||
Path::name(const StaState *sta) const
|
Path::name(const StaState *sta) const
|
||||||
{
|
{
|
||||||
const Network *network = sta->network();
|
const Network *network = sta->network();
|
||||||
Vertex *vertex1 = vertex(sta);
|
Vertex *vertex = this->vertex(sta);
|
||||||
if (vertex1) {
|
if (vertex) {
|
||||||
const char *vertex_name = vertex1->name(network);
|
const char *vertex_name = vertex->name(network);
|
||||||
const char *tr_str = transition(sta)->asString();
|
const char *tr_str = transition(sta)->asString();
|
||||||
const PathAnalysisPt *path_ap = pathAnalysisPt(sta);
|
const PathAnalysisPt *path_ap = pathAnalysisPt(sta);
|
||||||
int ap_index = path_ap->index();
|
int ap_index = path_ap->index();
|
||||||
|
|
@ -57,16 +220,67 @@ Path::name(const StaState *sta) const
|
||||||
return "NULL";
|
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 *
|
Pin *
|
||||||
Path::pin(const StaState *sta) const
|
Path::pin(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return vertex(sta)->pin();
|
return vertex(sta)->pin();
|
||||||
}
|
}
|
||||||
|
|
||||||
TagIndex
|
Tag *
|
||||||
Path::tagIndex(const StaState *sta) const
|
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 *
|
ClkInfo *
|
||||||
|
|
@ -118,80 +332,187 @@ Path::slew(const StaState *sta) const
|
||||||
dcalcAnalysisPt(sta)->index());
|
dcalcAnalysisPt(sta)->index());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RiseFall *
|
||||||
|
Path::transition(const StaState *sta) const
|
||||||
|
{
|
||||||
|
return tag(sta)->transition();
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Path::rfIndex(const StaState *sta) const
|
Path::rfIndex(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return transition(sta)->index();
|
return transition(sta)->index();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
PathAnalysisPt *
|
||||||
Path::initArrival(const StaState *sta)
|
Path::pathAnalysisPt(const StaState *sta) const
|
||||||
{
|
{
|
||||||
setArrival(delayInitValue(minMax(sta)), sta);
|
return tag(sta)->pathAnalysisPt(sta);
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Path::arrivalIsInitValue(const StaState *sta) const
|
|
||||||
{
|
|
||||||
return delayIsInitValue(arrival(sta), minMax(sta));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Path::initRequired(const StaState *sta)
|
Path::setArrival(Arrival arrival)
|
||||||
{
|
{
|
||||||
setRequired(delayInitValue(minMax(sta)->opposite()), sta);
|
arrival_ = arrival;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
Path::requiredIsInitValue(const StaState *sta) const
|
Path::setRequired(const Required &required)
|
||||||
{
|
{
|
||||||
return delayIsInitValue(required(sta), minMax(sta)->opposite());
|
required_ = required;
|
||||||
}
|
}
|
||||||
|
|
||||||
Slack
|
Slack
|
||||||
Path::slack(const StaState *sta) const
|
Path::slack(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (minMax(sta) == MinMax::max())
|
if (minMax(sta) == MinMax::max())
|
||||||
return required(sta) - arrival(sta);
|
return required_ - arrival_;
|
||||||
else
|
else
|
||||||
return arrival(sta) - required(sta);
|
return arrival_ - required_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path *
|
||||||
|
Path::prevPath() const
|
||||||
|
{
|
||||||
|
return prev_path_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Path::prevPath(const StaState *sta,
|
Path::setPrevPath(Path *prev_path)
|
||||||
// Return values.
|
|
||||||
PathRef &prev_path) const
|
|
||||||
{
|
{
|
||||||
TimingArc *prev_arc;
|
prev_path_ = prev_path;
|
||||||
prevPath(sta, prev_path, prev_arc);
|
}
|
||||||
|
|
||||||
|
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 *
|
TimingArc *
|
||||||
Path::prevArc(const StaState *sta) const
|
Path::prevArc(const StaState *sta) const
|
||||||
{
|
{
|
||||||
PathRef prev_path;
|
if (prev_path_) {
|
||||||
TimingArc *prev_arc;
|
const Graph *graph = sta->graph();
|
||||||
prevPath(sta, prev_path, prev_arc);
|
const Edge *edge = graph->edge(prev_edge_id_);
|
||||||
return prev_arc;
|
TimingArcSet *arc_set = edge->timingArcSet();
|
||||||
|
return arc_set->findTimingArc(prev_arc_idx_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Edge *
|
Edge *
|
||||||
Path::prevEdge(const TimingArc *prev_arc,
|
Path::prevEdge(const StaState *sta) const
|
||||||
const StaState *sta) const
|
|
||||||
{
|
{
|
||||||
if (prev_arc) {
|
if (prev_path_) {
|
||||||
TimingArcSet *arc_set = prev_arc->set();
|
const Graph *graph = sta->graph();
|
||||||
VertexInEdgeIterator edge_iter(vertex(sta), sta->graph());
|
return graph->edge(prev_edge_id_);
|
||||||
while (edge_iter.hasNext()) {
|
}
|
||||||
Edge *edge = edge_iter.next();
|
else
|
||||||
if (edge->timingArcSet() == arc_set)
|
return nullptr;
|
||||||
return edge;
|
}
|
||||||
|
|
||||||
|
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;
|
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
|
int
|
||||||
Path::cmpPinTrClk(const Path *path1,
|
Path::cmpPinTrClk(const Path *path1,
|
||||||
|
|
@ -256,11 +577,9 @@ Path::equal(const Path *path1,
|
||||||
const Path *path2,
|
const Path *path2,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
bool path1_null = (path1 == nullptr || path1->isNull());
|
return (path1 == nullptr && path2 == nullptr)
|
||||||
bool path2_null = (path2 == nullptr || path2->isNull());
|
|| (path1
|
||||||
return (path1_null && path2_null)
|
&& path2
|
||||||
|| (!path1_null
|
|
||||||
&& !path2_null
|
|
||||||
&& path1->vertexId(sta) == path2->vertexId(sta)
|
&& path1->vertexId(sta) == path2->vertexId(sta)
|
||||||
// Tag equal implies transition and path ap equal.
|
// Tag equal implies transition and path ap equal.
|
||||||
&& path1->tagIndex(sta) == path2->tagIndex(sta));
|
&& path1->tagIndex(sta) == path2->tagIndex(sta));
|
||||||
|
|
@ -340,27 +659,27 @@ Path::cmpAll(const Path *path1,
|
||||||
const Path *path2,
|
const Path *path2,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
PathRef p1(path1);
|
const Path *p1 = path1;
|
||||||
PathRef p2(path2);
|
const Path *p2 = path2;
|
||||||
while (!p1.isNull()
|
while (p1 && p2) {
|
||||||
&& !p2.isNull()) {
|
int cmp = Path::cmp(p1, p2, sta);
|
||||||
int cmp = Path::cmp(&p1, &p2, sta);
|
|
||||||
if (cmp != 0)
|
if (cmp != 0)
|
||||||
return cmp;
|
return cmp;
|
||||||
|
|
||||||
TimingArc *prev_arc1, *prev_arc2;
|
TimingArc *prev_arc1 = p1->prevArc(sta);
|
||||||
p1.prevPath(sta, p1, prev_arc1);
|
TimingArc *prev_arc2 = p2->prevArc(sta);
|
||||||
p2.prevPath(sta, p2, prev_arc2);
|
p1 = p1->prevPath();
|
||||||
if (equal(&p1, path1, sta))
|
p2 = p2->prevPath();
|
||||||
|
if (equal(p1, path1, sta))
|
||||||
// Equivalent latch loops.
|
// Equivalent latch loops.
|
||||||
return 0;
|
return 0;
|
||||||
if ((prev_arc1 && prev_arc1->role()->isLatchDtoQ())
|
if ((prev_arc1 && prev_arc1->role()->isLatchDtoQ())
|
||||||
|| (prev_arc2 && prev_arc2->role()->isLatchDtoQ()))
|
|| (prev_arc2 && prev_arc2->role()->isLatchDtoQ()))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (p1.isNull() && p2.isNull())
|
if (p1 == nullptr && p2 == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
else if (p1.isNull() && !p2.isNull())
|
else if (p1 == nullptr && p2 != nullptr)
|
||||||
return -1;
|
return -1;
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -374,4 +693,160 @@ Path::lessAll(const Path *path1,
|
||||||
return cmpAll(path1, path2, sta) < 0;
|
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
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -55,31 +55,32 @@ PathEnd::PathEnd(Path *path) :
|
||||||
|
|
||||||
PathEnd::~PathEnd()
|
PathEnd::~PathEnd()
|
||||||
{
|
{
|
||||||
path_.deleteRep();
|
if (path_->isEnum())
|
||||||
|
delete path_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PathEnd::setPath(const Path *path)
|
PathEnd::setPath(Path *path)
|
||||||
{
|
{
|
||||||
path_.init(path);
|
path_ = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vertex *
|
Vertex *
|
||||||
PathEnd::vertex(const StaState *sta) const
|
PathEnd::vertex(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return path_.vertex(sta);
|
return path_->vertex(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MinMax *
|
const MinMax *
|
||||||
PathEnd::minMax(const StaState *sta) const
|
PathEnd::minMax(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return path_.pathAnalysisPt(sta)->pathMinMax();
|
return path_->pathAnalysisPt(sta)->pathMinMax();
|
||||||
}
|
}
|
||||||
|
|
||||||
const EarlyLate *
|
const EarlyLate *
|
||||||
PathEnd::pathEarlyLate(const StaState *sta) const
|
PathEnd::pathEarlyLate(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return path_.pathAnalysisPt(sta)->pathMinMax();
|
return path_->pathAnalysisPt(sta)->pathMinMax();
|
||||||
}
|
}
|
||||||
|
|
||||||
const EarlyLate *
|
const EarlyLate *
|
||||||
|
|
@ -91,31 +92,31 @@ PathEnd::clkEarlyLate(const StaState *sta) const
|
||||||
const RiseFall *
|
const RiseFall *
|
||||||
PathEnd::transition(const StaState *sta) const
|
PathEnd::transition(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return path_.transition(sta);
|
return path_->transition(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathAPIndex
|
PathAPIndex
|
||||||
PathEnd::pathIndex(const StaState *sta) const
|
PathEnd::pathIndex(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return path_.pathAnalysisPtIndex(sta);
|
return path_->pathAnalysisPtIndex(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathAnalysisPt *
|
PathAnalysisPt *
|
||||||
PathEnd::pathAnalysisPt(const StaState *sta) const
|
PathEnd::pathAnalysisPt(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return path_.pathAnalysisPt(sta);
|
return path_->pathAnalysisPt(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClockEdge *
|
const ClockEdge *
|
||||||
PathEnd::sourceClkEdge(const StaState *sta) const
|
PathEnd::sourceClkEdge(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return path_.clkEdge(sta);
|
return path_->clkEdge(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
PathEnd::dataArrivalTime(const StaState *sta) const
|
PathEnd::dataArrivalTime(const StaState *) const
|
||||||
{
|
{
|
||||||
return path_.arrival(sta);
|
return path_->arrival();
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
|
|
@ -133,7 +134,7 @@ PathEnd::requiredTimeOffset(const StaState *sta) const
|
||||||
const RiseFall *
|
const RiseFall *
|
||||||
PathEnd::targetClkEndTrans(const StaState *sta) const
|
PathEnd::targetClkEndTrans(const StaState *sta) const
|
||||||
{
|
{
|
||||||
const PathVertex *clk_path = targetClkPath();
|
const Path *clk_path = targetClkPath();
|
||||||
if (clk_path)
|
if (clk_path)
|
||||||
return clk_path->transition(sta);
|
return clk_path->transition(sta);
|
||||||
else {
|
else {
|
||||||
|
|
@ -235,13 +236,13 @@ PathEnd::checkRole(const StaState *) const
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PathVertex *
|
Path *
|
||||||
PathEnd::targetClkPath()
|
PathEnd::targetClkPath()
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathVertex *
|
const Path *
|
||||||
PathEnd::targetClkPath() const
|
PathEnd::targetClkPath() const
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -303,7 +304,7 @@ PathEnd::exceptPathCmp(const PathEnd *path_end,
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Delay
|
Delay
|
||||||
PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path,
|
PathEnd::checkTgtClkDelay(const Path *tgt_clk_path,
|
||||||
const ClockEdge *tgt_clk_edge,
|
const ClockEdge *tgt_clk_edge,
|
||||||
const TimingRole *check_role,
|
const TimingRole *check_role,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
|
|
@ -315,7 +316,7 @@ PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path,
|
PathEnd::checkTgtClkDelay(const Path *tgt_clk_path,
|
||||||
const ClockEdge *tgt_clk_edge,
|
const ClockEdge *tgt_clk_edge,
|
||||||
const TimingRole *check_role,
|
const TimingRole *check_role,
|
||||||
const StaState *sta,
|
const StaState *sta,
|
||||||
|
|
@ -340,7 +341,7 @@ PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path,
|
||||||
|| check_role->isDataCheck()) {
|
|| check_role->isDataCheck()) {
|
||||||
// Propagated clock. Propagated arrival is seeded with
|
// Propagated clock. Propagated arrival is seeded with
|
||||||
// early_late==path_min_max insertion delay.
|
// 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,
|
Delay path_insertion = search->clockInsertion(tgt_clk, tgt_src_pin,
|
||||||
tgt_clk_rf, min_max,
|
tgt_clk_rf, min_max,
|
||||||
min_max, tgt_path_ap);
|
min_max, tgt_path_ap);
|
||||||
|
|
@ -359,7 +360,7 @@ PathEnd::checkTgtClkDelay(const PathVertex *tgt_clk_path,
|
||||||
float
|
float
|
||||||
PathEnd::checkClkUncertainty(const ClockEdge *src_clk_edge,
|
PathEnd::checkClkUncertainty(const ClockEdge *src_clk_edge,
|
||||||
const ClockEdge *tgt_clk_edge,
|
const ClockEdge *tgt_clk_edge,
|
||||||
const PathVertex *tgt_clk_path,
|
const Path *tgt_clk_path,
|
||||||
const TimingRole *check_role,
|
const TimingRole *check_role,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
|
|
@ -375,7 +376,7 @@ PathEnd::checkClkUncertainty(const ClockEdge *src_clk_edge,
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
PathEnd::checkTgtClkUncertainty(const PathVertex *tgt_clk_path,
|
PathEnd::checkTgtClkUncertainty(const Path *tgt_clk_path,
|
||||||
const ClockEdge *tgt_clk_edge,
|
const ClockEdge *tgt_clk_edge,
|
||||||
const TimingRole *check_role,
|
const TimingRole *check_role,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
|
|
@ -455,7 +456,7 @@ PathEndUnconstrained::PathEndUnconstrained(Path *path) :
|
||||||
PathEnd *
|
PathEnd *
|
||||||
PathEndUnconstrained::copy()
|
PathEndUnconstrained::copy()
|
||||||
{
|
{
|
||||||
return new PathEndUnconstrained(path_.path());
|
return new PathEndUnconstrained(path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -510,7 +511,7 @@ PathEndUnconstrained::typeName() const
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
PathEndClkConstrained::PathEndClkConstrained(Path *path,
|
PathEndClkConstrained::PathEndClkConstrained(Path *path,
|
||||||
PathVertex *clk_path) :
|
Path *clk_path) :
|
||||||
PathEnd(path),
|
PathEnd(path),
|
||||||
clk_path_(clk_path),
|
clk_path_(clk_path),
|
||||||
crpr_(0.0),
|
crpr_(0.0),
|
||||||
|
|
@ -519,7 +520,7 @@ PathEndClkConstrained::PathEndClkConstrained(Path *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
PathEndClkConstrained::PathEndClkConstrained(Path *path,
|
PathEndClkConstrained::PathEndClkConstrained(Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
Crpr crpr,
|
Crpr crpr,
|
||||||
bool crpr_valid) :
|
bool crpr_valid) :
|
||||||
PathEnd(path),
|
PathEnd(path),
|
||||||
|
|
@ -530,9 +531,9 @@ PathEndClkConstrained::PathEndClkConstrained(Path *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PathEndClkConstrained::setPath(const Path *path)
|
PathEndClkConstrained::setPath(Path *path)
|
||||||
{
|
{
|
||||||
path_.init(path);
|
path_ = path;
|
||||||
crpr_valid_ = false;
|
crpr_valid_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -559,33 +560,27 @@ PathEndClkConstrained::sourceClkOffset(const ClockEdge *src_clk_edge,
|
||||||
Arrival
|
Arrival
|
||||||
PathEndClkConstrained::sourceClkLatency(const StaState *sta) const
|
PathEndClkConstrained::sourceClkLatency(const StaState *sta) const
|
||||||
{
|
{
|
||||||
ClkInfo *clk_info = path_.clkInfo(sta);
|
ClkInfo *clk_info = path_->clkInfo(sta);
|
||||||
return clk_info->latency();
|
return clk_info->latency();
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
PathEndClkConstrained::sourceClkInsertionDelay(const StaState *sta) const
|
PathEndClkConstrained::sourceClkInsertionDelay(const StaState *sta) const
|
||||||
{
|
{
|
||||||
ClkInfo *clk_info = path_.clkInfo(sta);
|
ClkInfo *clk_info = path_->clkInfo(sta);
|
||||||
return clk_info->insertion();
|
return clk_info->insertion();
|
||||||
}
|
}
|
||||||
|
|
||||||
PathVertex *
|
Path *
|
||||||
PathEndClkConstrained::targetClkPath()
|
PathEndClkConstrained::targetClkPath()
|
||||||
{
|
{
|
||||||
if (clk_path_.isNull())
|
return clk_path_;
|
||||||
return nullptr;
|
|
||||||
else
|
|
||||||
return &clk_path_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathVertex *
|
const Path *
|
||||||
PathEndClkConstrained::targetClkPath() const
|
PathEndClkConstrained::targetClkPath() const
|
||||||
{
|
{
|
||||||
if (clk_path_.isNull())
|
return clk_path_;
|
||||||
return nullptr;
|
|
||||||
else
|
|
||||||
return &clk_path_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -602,8 +597,8 @@ PathEndClkConstrained::targetClkOffset(const StaState *sta) const
|
||||||
const ClockEdge *
|
const ClockEdge *
|
||||||
PathEndClkConstrained::targetClkEdge(const StaState *sta) const
|
PathEndClkConstrained::targetClkEdge(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (!clk_path_.isNull())
|
if (clk_path_)
|
||||||
return clk_path_.clkEdge(sta);
|
return clk_path_->clkEdge(sta);
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -708,7 +703,7 @@ PathEndClkConstrained::crpr(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (!crpr_valid_) {
|
if (!crpr_valid_) {
|
||||||
CheckCrpr *check_crpr = sta->search()->checkCrpr();
|
CheckCrpr *check_crpr = sta->search()->checkCrpr();
|
||||||
crpr_ = check_crpr->checkCrpr(path_.path(), targetClkPath());
|
crpr_ = check_crpr->checkCrpr(path_, targetClkPath());
|
||||||
crpr_valid_ = true;
|
crpr_valid_ = true;
|
||||||
}
|
}
|
||||||
return crpr_;
|
return crpr_;
|
||||||
|
|
@ -751,7 +746,7 @@ PathEndClkConstrained::exceptPathCmp(const PathEnd *path_end,
|
||||||
if (cmp == 0) {
|
if (cmp == 0) {
|
||||||
const PathEndClkConstrained *path_end2 =
|
const PathEndClkConstrained *path_end2 =
|
||||||
dynamic_cast<const PathEndClkConstrained*>(path_end);
|
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);
|
return Path::cmp(targetClkPath(), clk_path2, sta);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -761,7 +756,7 @@ PathEndClkConstrained::exceptPathCmp(const PathEnd *path_end,
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path,
|
PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp) :
|
MultiCyclePath *mcp) :
|
||||||
PathEndClkConstrained(path, clk_path),
|
PathEndClkConstrained(path, clk_path),
|
||||||
mcp_(mcp)
|
mcp_(mcp)
|
||||||
|
|
@ -769,7 +764,7 @@ PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path,
|
PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
Crpr crpr,
|
Crpr crpr,
|
||||||
bool crpr_valid) :
|
bool crpr_valid) :
|
||||||
|
|
@ -781,7 +776,7 @@ PathEndClkConstrainedMcp::PathEndClkConstrainedMcp(Path *path,
|
||||||
float
|
float
|
||||||
PathEndClkConstrainedMcp::targetClkMcpAdjustment(const StaState *sta) const
|
PathEndClkConstrainedMcp::targetClkMcpAdjustment(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return checkMcpAdjustment(path_.path(), targetClkEdge(sta), sta);
|
return checkMcpAdjustment(path_, targetClkEdge(sta), sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -887,8 +882,8 @@ PathEndClkConstrainedMcp::findHoldMcps(const ClockEdge *tgt_clk_edge,
|
||||||
const StaState *sta) const
|
const StaState *sta) const
|
||||||
|
|
||||||
{
|
{
|
||||||
Pin *pin = path_.pin(sta);
|
Pin *pin = path_->pin(sta);
|
||||||
const RiseFall *rf = path_.transition(sta);
|
const RiseFall *rf = path_->transition(sta);
|
||||||
// Mcp may be setup, hold or setup_hold, since all match min paths.
|
// Mcp may be setup, hold or setup_hold, since all match min paths.
|
||||||
const MinMaxAll *mcp_min_max = mcp_->minMax();
|
const MinMaxAll *mcp_min_max = mcp_->minMax();
|
||||||
Search *search = sta->search();
|
Search *search = sta->search();
|
||||||
|
|
@ -896,7 +891,7 @@ PathEndClkConstrainedMcp::findHoldMcps(const ClockEdge *tgt_clk_edge,
|
||||||
hold_mcp = mcp_;
|
hold_mcp = mcp_;
|
||||||
setup_mcp =
|
setup_mcp =
|
||||||
dynamic_cast<MultiCyclePath*>(search->exceptionTo(ExceptionPathType::multi_cycle,
|
dynamic_cast<MultiCyclePath*>(search->exceptionTo(ExceptionPathType::multi_cycle,
|
||||||
path_.path(), pin, rf,
|
path_, pin, rf,
|
||||||
tgt_clk_edge,
|
tgt_clk_edge,
|
||||||
MinMax::max(), true,
|
MinMax::max(), true,
|
||||||
false));
|
false));
|
||||||
|
|
@ -905,7 +900,7 @@ PathEndClkConstrainedMcp::findHoldMcps(const ClockEdge *tgt_clk_edge,
|
||||||
setup_mcp = mcp_;
|
setup_mcp = mcp_;
|
||||||
hold_mcp =
|
hold_mcp =
|
||||||
dynamic_cast<MultiCyclePath*>(search->exceptionTo(ExceptionPathType::multi_cycle,
|
dynamic_cast<MultiCyclePath*>(search->exceptionTo(ExceptionPathType::multi_cycle,
|
||||||
path_.path(), pin, rf,
|
path_, pin, rf,
|
||||||
tgt_clk_edge,
|
tgt_clk_edge,
|
||||||
MinMax::min(), true,
|
MinMax::min(), true,
|
||||||
false));
|
false));
|
||||||
|
|
@ -937,7 +932,7 @@ PathEndClkConstrainedMcp::exceptPathCmp(const PathEnd *path_end,
|
||||||
PathEndCheck::PathEndCheck(Path *path,
|
PathEndCheck::PathEndCheck(Path *path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
const StaState *) :
|
const StaState *) :
|
||||||
PathEndClkConstrainedMcp(path, clk_path, mcp),
|
PathEndClkConstrainedMcp(path, clk_path, mcp),
|
||||||
|
|
@ -949,7 +944,7 @@ PathEndCheck::PathEndCheck(Path *path,
|
||||||
PathEndCheck::PathEndCheck(Path *path,
|
PathEndCheck::PathEndCheck(Path *path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
Crpr crpr,
|
Crpr crpr,
|
||||||
bool crpr_valid) :
|
bool crpr_valid) :
|
||||||
|
|
@ -962,8 +957,8 @@ PathEndCheck::PathEndCheck(Path *path,
|
||||||
PathEnd *
|
PathEnd *
|
||||||
PathEndCheck::copy()
|
PathEndCheck::copy()
|
||||||
{
|
{
|
||||||
return new PathEndCheck(path_.path(), check_arc_, check_edge_,
|
return new PathEndCheck(path_, check_arc_, check_edge_,
|
||||||
&clk_path_, mcp_, crpr_, crpr_valid_);
|
clk_path_, mcp_, crpr_, crpr_valid_);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathEnd::Type
|
PathEnd::Type
|
||||||
|
|
@ -999,7 +994,7 @@ PathEndCheck::checkRole(const StaState *) const
|
||||||
ArcDelay
|
ArcDelay
|
||||||
PathEndCheck::margin(const StaState *sta) const
|
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,
|
check_arc_, check_edge_, false,
|
||||||
pathAnalysisPt(sta));
|
pathAnalysisPt(sta));
|
||||||
}
|
}
|
||||||
|
|
@ -1028,20 +1023,20 @@ PathEndCheck::clkSkew(const StaState *sta)
|
||||||
{
|
{
|
||||||
return sourceClkDelay(sta) - targetClkDelay(sta) - crpr(sta)
|
return sourceClkDelay(sta) - targetClkDelay(sta) - crpr(sta)
|
||||||
// Uncertainty decreases slack, but increases skew.
|
// 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
|
Delay
|
||||||
PathEndCheck::sourceClkDelay(const StaState *sta) const
|
PathEndCheck::sourceClkDelay(const StaState *sta) const
|
||||||
{
|
{
|
||||||
PathExpanded expanded(&path_, sta);
|
PathExpanded expanded(path_, sta);
|
||||||
PathRef src_clk_path;
|
const Path *src_clk_path = expanded.clkPath();
|
||||||
expanded.clkPath(src_clk_path);
|
if (src_clk_path) {
|
||||||
if (!src_clk_path.isNull()) {
|
ClkInfo *src_clk_info = path_->tag(sta)->clkInfo();
|
||||||
ClkInfo *src_clk_info = path_.tag(sta)->clkInfo();
|
|
||||||
if (src_clk_info->isPropagated()) {
|
if (src_clk_info->isPropagated()) {
|
||||||
// Propagated clock. Propagated arrival is seeded with insertion delay.
|
// 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();
|
const ClockEdge *src_clk_edge = src_clk_info->clkEdge();
|
||||||
Delay insertion = sourceClkInsertionDelay(sta);
|
Delay insertion = sourceClkInsertionDelay(sta);
|
||||||
return delayRemove(clk_arrival - src_clk_edge->time(), insertion);
|
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 ClockEdge *tgt_clk_edge = targetClkEdge(sta);
|
||||||
const Clock *tgt_clk = tgt_clk_edge->clock();
|
const Clock *tgt_clk = tgt_clk_edge->clock();
|
||||||
const Network *network = sta->network();
|
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 Instance *inst = network->instance(clk_pin);
|
||||||
const LibertyCell *inst_cell = network->libertyCell(inst);
|
const LibertyCell *inst_cell = network->libertyCell(inst);
|
||||||
if (tgt_clk->isIdeal()
|
if (tgt_clk->isIdeal()
|
||||||
&& inst_cell && inst_cell->isMacro()) {
|
&& inst_cell && inst_cell->isMacro()) {
|
||||||
LibertyPort *clk_port = network->libertyPort(clk_pin);
|
LibertyPort *clk_port = network->libertyPort(clk_pin);
|
||||||
if (clk_port) {
|
if (clk_port) {
|
||||||
const MinMax *min_max = clk_path_.minMax(sta);
|
const MinMax *min_max = clk_path_->minMax(sta);
|
||||||
const RiseFall *rf = clk_path_.transition(sta);
|
const RiseFall *rf = clk_path_->transition(sta);
|
||||||
float slew = delayAsFloat(clk_path_.slew(sta));
|
float slew = delayAsFloat(clk_path_->slew(sta));
|
||||||
return clk_port->clkTreeDelay(slew, rf, min_max);
|
return clk_port->clkTreeDelay(slew, rf, min_max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1093,7 +1088,7 @@ PathEndCheck::macroClkTreeDelay(const StaState *sta) const
|
||||||
PathEndLatchCheck::PathEndLatchCheck(Path *path,
|
PathEndLatchCheck::PathEndLatchCheck(Path *path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
PathVertex *disable_path,
|
Path *disable_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
PathDelay *path_delay,
|
PathDelay *path_delay,
|
||||||
const StaState *sta) :
|
const StaState *sta) :
|
||||||
|
|
@ -1102,23 +1097,22 @@ PathEndLatchCheck::PathEndLatchCheck(Path *path,
|
||||||
path_delay_(path_delay),
|
path_delay_(path_delay),
|
||||||
src_clk_arrival_(0.0)
|
src_clk_arrival_(0.0)
|
||||||
{
|
{
|
||||||
PathVertex enable_path;
|
|
||||||
Latches *latches = sta->latches();
|
Latches *latches = sta->latches();
|
||||||
latches->latchEnableOtherPath(disable_path,
|
Path *enable_path =
|
||||||
disable_path->pathAnalysisPt(sta),
|
latches->latchEnableOtherPath(disable_path,
|
||||||
enable_path);
|
disable_path->pathAnalysisPt(sta));
|
||||||
clk_path_ = enable_path;
|
clk_path_ = enable_path;
|
||||||
Search *search = sta->search();
|
Search *search = sta->search();
|
||||||
// Same as PathEndPathDelay::findRequired.
|
// Same as PathEndPathDelay::findRequired.
|
||||||
if (path_delay_ && ignoreClkLatency(sta))
|
if (path_delay_ && ignoreClkLatency(sta))
|
||||||
src_clk_arrival_ = search->pathClkPathArrival(&path_);
|
src_clk_arrival_ = search->pathClkPathArrival(path_);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathEndLatchCheck::PathEndLatchCheck(Path *path,
|
PathEndLatchCheck::PathEndLatchCheck(Path *path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
PathVertex *disable_path,
|
Path *disable_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
PathDelay *path_delay,
|
PathDelay *path_delay,
|
||||||
Delay src_clk_arrival,
|
Delay src_clk_arrival,
|
||||||
|
|
@ -1134,8 +1128,8 @@ PathEndLatchCheck::PathEndLatchCheck(Path *path,
|
||||||
PathEnd *
|
PathEnd *
|
||||||
PathEndLatchCheck::copy()
|
PathEndLatchCheck::copy()
|
||||||
{
|
{
|
||||||
return new PathEndLatchCheck(path_.path(), check_arc_, check_edge_,
|
return new PathEndLatchCheck(path_, check_arc_, check_edge_,
|
||||||
&clk_path_, &disable_path_, mcp_, path_delay_,
|
clk_path_, disable_path_, mcp_, path_delay_,
|
||||||
src_clk_arrival_, crpr_, crpr_valid_);
|
src_clk_arrival_, crpr_, crpr_valid_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1151,22 +1145,16 @@ PathEndLatchCheck::typeName() const
|
||||||
return "latch_check";
|
return "latch_check";
|
||||||
}
|
}
|
||||||
|
|
||||||
PathVertex *
|
Path *
|
||||||
PathEndLatchCheck::latchDisable()
|
PathEndLatchCheck::latchDisable()
|
||||||
{
|
{
|
||||||
if (disable_path_.isNull())
|
return disable_path_;
|
||||||
return nullptr;
|
|
||||||
else
|
|
||||||
return &disable_path_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathVertex *
|
const Path *
|
||||||
PathEndLatchCheck::latchDisable() const
|
PathEndLatchCheck::latchDisable() const
|
||||||
{
|
{
|
||||||
if (disable_path_.isNull())
|
return disable_path_;
|
||||||
return nullptr;
|
|
||||||
else
|
|
||||||
return &disable_path_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1188,7 +1176,7 @@ PathEndLatchCheck::sourceClkOffset(const StaState *sta) const
|
||||||
return pathDelaySrcClkOffset(path_, path_delay_, src_clk_arrival_, sta);
|
return pathDelaySrcClkOffset(path_, path_delay_, src_clk_arrival_, sta);
|
||||||
else
|
else
|
||||||
return PathEndClkConstrained::sourceClkOffset(sourceClkEdge(sta),
|
return PathEndClkConstrained::sourceClkOffset(sourceClkEdge(sta),
|
||||||
disable_path_.clkEdge(sta),
|
disable_path_->clkEdge(sta),
|
||||||
TimingRole::setup(),
|
TimingRole::setup(),
|
||||||
sta);
|
sta);
|
||||||
}
|
}
|
||||||
|
|
@ -1196,7 +1184,7 @@ PathEndLatchCheck::sourceClkOffset(const StaState *sta) const
|
||||||
TimingRole *
|
TimingRole *
|
||||||
PathEndLatchCheck::checkRole(const StaState *sta) const
|
PathEndLatchCheck::checkRole(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (clk_path_.clkInfo(sta)->isPulseClk())
|
if (clk_path_->clkInfo(sta)->isPulseClk())
|
||||||
// Pulse latches use register cycle accounting.
|
// Pulse latches use register cycle accounting.
|
||||||
return TimingRole::setup();
|
return TimingRole::setup();
|
||||||
else
|
else
|
||||||
|
|
@ -1211,7 +1199,7 @@ PathEndLatchCheck::requiredTime(const StaState *sta) const
|
||||||
Required required;
|
Required required;
|
||||||
Arrival borrow, adjusted_data_arrival, time_given_to_startpoint;
|
Arrival borrow, adjusted_data_arrival, time_given_to_startpoint;
|
||||||
Latches *latches = sta->latches();
|
Latches *latches = sta->latches();
|
||||||
latches->latchRequired(path_.path(), targetClkPath(), latchDisable(),
|
latches->latchRequired(path_, targetClkPath(), latchDisable(),
|
||||||
mcp_, path_delay_, src_clk_arrival_, margin(sta),
|
mcp_, path_delay_, src_clk_arrival_, margin(sta),
|
||||||
required, borrow, adjusted_data_arrival,
|
required, borrow, adjusted_data_arrival,
|
||||||
time_given_to_startpoint);
|
time_given_to_startpoint);
|
||||||
|
|
@ -1224,7 +1212,7 @@ PathEndLatchCheck::borrow(const StaState *sta) const
|
||||||
Latches *latches = sta->latches();
|
Latches *latches = sta->latches();
|
||||||
Required required;
|
Required required;
|
||||||
Arrival borrow, adjusted_data_arrival, time_given_to_startpoint;
|
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),
|
mcp_, path_delay_, src_clk_arrival_, margin(sta),
|
||||||
required, borrow, adjusted_data_arrival,
|
required, borrow, adjusted_data_arrival,
|
||||||
time_given_to_startpoint);
|
time_given_to_startpoint);
|
||||||
|
|
@ -1240,7 +1228,7 @@ PathEndLatchCheck::latchRequired(const StaState *sta,
|
||||||
Delay &time_given_to_startpoint) const
|
Delay &time_given_to_startpoint) const
|
||||||
{
|
{
|
||||||
Latches *latches = sta->latches();
|
Latches *latches = sta->latches();
|
||||||
latches->latchRequired(path_.path(), targetClkPath(), latchDisable(),
|
latches->latchRequired(path_, targetClkPath(), latchDisable(),
|
||||||
mcp_, path_delay_, src_clk_arrival_, margin(sta),
|
mcp_, path_delay_, src_clk_arrival_, margin(sta),
|
||||||
required, borrow, adjusted_data_arrival,
|
required, borrow, adjusted_data_arrival,
|
||||||
time_given_to_startpoint);
|
time_given_to_startpoint);
|
||||||
|
|
@ -1259,7 +1247,7 @@ PathEndLatchCheck::latchBorrowInfo(const StaState *sta,
|
||||||
bool &borrow_limit_exists) const
|
bool &borrow_limit_exists) const
|
||||||
{
|
{
|
||||||
Latches *latches = sta->latches();
|
Latches *latches = sta->latches();
|
||||||
latches->latchBorrowInfo(path_.path(), targetClkPath(), latchDisable(),
|
latches->latchBorrowInfo(path_, targetClkPath(), latchDisable(),
|
||||||
margin(sta),
|
margin(sta),
|
||||||
path_delay_ && ignoreClkLatency(sta),
|
path_delay_ && ignoreClkLatency(sta),
|
||||||
nom_pulse_width, open_latency,
|
nom_pulse_width, open_latency,
|
||||||
|
|
@ -1272,9 +1260,9 @@ Arrival
|
||||||
PathEndLatchCheck::targetClkWidth(const StaState *sta) const
|
PathEndLatchCheck::targetClkWidth(const StaState *sta) const
|
||||||
{
|
{
|
||||||
const Search *search = sta->search();
|
const Search *search = sta->search();
|
||||||
Arrival disable_arrival = search->clkPathArrival(&disable_path_);
|
Arrival disable_arrival = search->clkPathArrival(disable_path_);
|
||||||
Arrival enable_arrival = search->clkPathArrival(&clk_path_);
|
Arrival enable_arrival = search->clkPathArrival(clk_path_);
|
||||||
ClkInfo *enable_clk_info = clk_path_.clkInfo(sta);
|
ClkInfo *enable_clk_info = clk_path_->clkInfo(sta);
|
||||||
if (enable_clk_info->isPulseClk())
|
if (enable_clk_info->isPulseClk())
|
||||||
return disable_arrival - enable_arrival;
|
return disable_arrival - enable_arrival;
|
||||||
else {
|
else {
|
||||||
|
|
@ -1297,8 +1285,8 @@ PathEndLatchCheck::exceptPathCmp(const PathEnd *path_end,
|
||||||
dynamic_cast<const PathEndLatchCheck*>(path_end);
|
dynamic_cast<const PathEndLatchCheck*>(path_end);
|
||||||
const TimingArc *check_arc2 = path_end2->check_arc_;
|
const TimingArc *check_arc2 = path_end2->check_arc_;
|
||||||
if (check_arc_ == check_arc2) {
|
if (check_arc_ == check_arc2) {
|
||||||
const Path *disable_path2 = path_end2->disable_path_.path();
|
const Path *disable_path2 = path_end2->disable_path_;
|
||||||
return Path::cmp(disable_path_.path(), disable_path2, sta);
|
return Path::cmp(disable_path_, disable_path2, sta);
|
||||||
}
|
}
|
||||||
else if (check_arc_ < check_arc2)
|
else if (check_arc_ < check_arc2)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -1319,7 +1307,7 @@ PathEndLatchCheck::ignoreClkLatency(const StaState *sta) const
|
||||||
|
|
||||||
PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
|
PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
|
||||||
Path *path,
|
Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
const StaState *) :
|
const StaState *) :
|
||||||
// No target clk_path_ for output delays.
|
// No target clk_path_ for output delays.
|
||||||
|
|
@ -1330,7 +1318,7 @@ PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
|
||||||
|
|
||||||
PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
|
PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
|
||||||
Path *path,
|
Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
Crpr crpr,
|
Crpr crpr,
|
||||||
bool crpr_valid) :
|
bool crpr_valid) :
|
||||||
|
|
@ -1342,7 +1330,7 @@ PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay,
|
||||||
PathEnd *
|
PathEnd *
|
||||||
PathEndOutputDelay::copy()
|
PathEndOutputDelay::copy()
|
||||||
{
|
{
|
||||||
return new PathEndOutputDelay(output_delay_, path_.path(), &clk_path_,
|
return new PathEndOutputDelay(output_delay_, path_, clk_path_,
|
||||||
mcp_, crpr_, crpr_valid_);
|
mcp_, crpr_, crpr_valid_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1373,7 +1361,7 @@ PathEndOutputDelay::reportShort(const ReportPath *report) const
|
||||||
ArcDelay
|
ArcDelay
|
||||||
PathEndOutputDelay::margin(const StaState *sta) const
|
PathEndOutputDelay::margin(const StaState *sta) const
|
||||||
{
|
{
|
||||||
return outputDelayMargin(output_delay_, path_.path(), sta);
|
return outputDelayMargin(output_delay_, path_, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -1393,7 +1381,7 @@ PathEnd::outputDelayMargin(OutputDelay *output_delay,
|
||||||
TimingRole *
|
TimingRole *
|
||||||
PathEndOutputDelay::checkRole(const StaState *sta) const
|
PathEndOutputDelay::checkRole(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (path_.minMax(sta) == MinMax::max())
|
if (path_->minMax(sta) == MinMax::max())
|
||||||
return TimingRole::outputSetup();
|
return TimingRole::outputSetup();
|
||||||
else
|
else
|
||||||
return TimingRole::outputHold();
|
return TimingRole::outputHold();
|
||||||
|
|
@ -1402,8 +1390,8 @@ PathEndOutputDelay::checkRole(const StaState *sta) const
|
||||||
const ClockEdge *
|
const ClockEdge *
|
||||||
PathEndOutputDelay::targetClkEdge(const StaState *sta) const
|
PathEndOutputDelay::targetClkEdge(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (!clk_path_.isNull())
|
if (clk_path_)
|
||||||
return clk_path_.clkEdge(sta);
|
return clk_path_->clkEdge(sta);
|
||||||
else
|
else
|
||||||
return output_delay_->clkEdge();
|
return output_delay_->clkEdge();
|
||||||
}
|
}
|
||||||
|
|
@ -1411,7 +1399,7 @@ PathEndOutputDelay::targetClkEdge(const StaState *sta) const
|
||||||
Arrival
|
Arrival
|
||||||
PathEndOutputDelay::targetClkArrivalNoCrpr(const StaState *sta) const
|
PathEndOutputDelay::targetClkArrivalNoCrpr(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (!clk_path_.isNull())
|
if (clk_path_)
|
||||||
return PathEndClkConstrained::targetClkArrivalNoCrpr(sta);
|
return PathEndClkConstrained::targetClkArrivalNoCrpr(sta);
|
||||||
else {
|
else {
|
||||||
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
|
const ClockEdge *tgt_clk_edge = targetClkEdge(sta);
|
||||||
|
|
@ -1419,7 +1407,7 @@ PathEndOutputDelay::targetClkArrivalNoCrpr(const StaState *sta) const
|
||||||
return targetClkTime(sta)
|
return targetClkTime(sta)
|
||||||
+ tgtClkDelay(tgt_clk_edge, check_role, sta)
|
+ tgtClkDelay(tgt_clk_edge, check_role, sta)
|
||||||
+ targetClkUncertainty(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_) {
|
if (!crpr_valid_) {
|
||||||
CheckCrpr *check_crpr = sta->search()->checkCrpr();
|
CheckCrpr *check_crpr = sta->search()->checkCrpr();
|
||||||
crpr_ = check_crpr->outputDelayCrpr(path_.path(), targetClkEdge(sta));
|
crpr_ = check_crpr->outputDelayCrpr(path_, targetClkEdge(sta));
|
||||||
crpr_valid_ = true;
|
crpr_valid_ = true;
|
||||||
}
|
}
|
||||||
return crpr_;
|
return crpr_;
|
||||||
|
|
@ -1437,7 +1425,7 @@ PathEndOutputDelay::crpr(const StaState *sta) const
|
||||||
Delay
|
Delay
|
||||||
PathEndOutputDelay::targetClkDelay(const StaState *sta) const
|
PathEndOutputDelay::targetClkDelay(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (!clk_path_.isNull())
|
if (clk_path_)
|
||||||
return PathEndClkConstrained::targetClkDelay(sta);
|
return PathEndClkConstrained::targetClkDelay(sta);
|
||||||
else
|
else
|
||||||
return tgtClkDelay(targetClkEdge(sta), checkRole(sta), sta);
|
return tgtClkDelay(targetClkEdge(sta), checkRole(sta), sta);
|
||||||
|
|
@ -1465,7 +1453,7 @@ PathEndOutputDelay::tgtClkDelay(const ClockEdge *tgt_clk_edge,
|
||||||
// Early late: setup early, hold late.
|
// Early late: setup early, hold late.
|
||||||
const EarlyLate *early_late = check_role->tgtClkEarlyLate();
|
const EarlyLate *early_late = check_role->tgtClkEarlyLate();
|
||||||
// Latency min_max depends on bc_wc or ocv.
|
// 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();
|
const MinMax *latency_min_max = path_ap->tgtClkAnalysisPt()->pathMinMax();
|
||||||
Clock *tgt_clk = tgt_clk_edge->clock();
|
Clock *tgt_clk = tgt_clk_edge->clock();
|
||||||
RiseFall *tgt_clk_rf = tgt_clk_edge->transition();
|
RiseFall *tgt_clk_rf = tgt_clk_edge->transition();
|
||||||
|
|
@ -1488,7 +1476,7 @@ PathEndOutputDelay::tgtClkDelay(const ClockEdge *tgt_clk_edge,
|
||||||
Delay
|
Delay
|
||||||
PathEndOutputDelay::targetClkInsertionDelay(const StaState *sta) const
|
PathEndOutputDelay::targetClkInsertionDelay(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (!clk_path_.isNull())
|
if (clk_path_)
|
||||||
return PathEndClkConstrained::targetClkInsertionDelay(sta);
|
return PathEndClkConstrained::targetClkInsertionDelay(sta);
|
||||||
else {
|
else {
|
||||||
Arrival insertion, latency;
|
Arrival insertion, latency;
|
||||||
|
|
@ -1521,7 +1509,7 @@ PathEndOutputDelay::exceptPathCmp(const PathEnd *path_end,
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
|
PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
TimingRole *check_role,
|
TimingRole *check_role,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
ArcDelay margin,
|
ArcDelay margin,
|
||||||
|
|
@ -1533,7 +1521,7 @@ PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
|
||||||
}
|
}
|
||||||
|
|
||||||
PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
|
PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
TimingRole *check_role,
|
TimingRole *check_role,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
ArcDelay margin,
|
ArcDelay margin,
|
||||||
|
|
@ -1548,7 +1536,7 @@ PathEndGatedClock::PathEndGatedClock(Path *gating_ref,
|
||||||
PathEnd *
|
PathEnd *
|
||||||
PathEndGatedClock::copy()
|
PathEndGatedClock::copy()
|
||||||
{
|
{
|
||||||
return new PathEndGatedClock(path_.path(), &clk_path_, check_role_,
|
return new PathEndGatedClock(path_, clk_path_, check_role_,
|
||||||
mcp_, margin_, crpr_, crpr_valid_);
|
mcp_, margin_, crpr_, crpr_valid_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1606,59 +1594,52 @@ PathEndGatedClock::exceptPathCmp(const PathEnd *path_end,
|
||||||
|
|
||||||
PathEndDataCheck::PathEndDataCheck(DataCheck *check,
|
PathEndDataCheck::PathEndDataCheck(DataCheck *check,
|
||||||
Path *data_path,
|
Path *data_path,
|
||||||
PathVertex *data_clk_path,
|
Path *data_clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
const StaState *sta) :
|
const StaState *sta) :
|
||||||
PathEndClkConstrainedMcp(data_path, nullptr, mcp),
|
PathEndClkConstrainedMcp(data_path, nullptr, mcp),
|
||||||
data_clk_path_(data_clk_path),
|
data_clk_path_(data_clk_path),
|
||||||
check_(check)
|
check_(check)
|
||||||
{
|
{
|
||||||
clkPath(data_clk_path, sta, clk_path_);
|
clk_path_ = clkPath(data_clk_path, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// PathExpanded::expand() and PathExpanded::clkPath().
|
// PathExpanded::expand() and PathExpanded::clkPath().
|
||||||
void
|
Path *
|
||||||
PathEndDataCheck::clkPath(PathVertex *path,
|
PathEndDataCheck::clkPath(Path *path,
|
||||||
const StaState *sta,
|
const StaState *sta)
|
||||||
// Return value.
|
|
||||||
PathVertex &clk_path)
|
|
||||||
{
|
{
|
||||||
PathVertex p(path);
|
Path *p = path;
|
||||||
while (!p.isNull()) {
|
while (p) {
|
||||||
PathVertex prev_path;
|
Path *prev_path = p->prevPath();
|
||||||
TimingArc *prev_arc;
|
TimingArc *prev_arc = p->prevArc(sta);
|
||||||
p.prevPath(sta, prev_path, prev_arc);
|
|
||||||
|
|
||||||
if (p.isClock(sta)) {
|
if (p->isClock(sta))
|
||||||
clk_path = p;
|
return p;
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (prev_arc) {
|
if (prev_arc) {
|
||||||
TimingRole *prev_role = prev_arc->role();
|
TimingRole *prev_role = prev_arc->role();
|
||||||
if (prev_role == TimingRole::regClkToQ()
|
if (prev_role == TimingRole::regClkToQ()
|
||||||
|| prev_role == TimingRole::latchEnToQ()) {
|
|| prev_role == TimingRole::latchEnToQ()) {
|
||||||
p.prevPath(sta, prev_path, prev_arc);
|
prev_path = p->prevPath();
|
||||||
clk_path = prev_path;
|
return prev_path;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else if (prev_role == TimingRole::latchDtoQ()) {
|
else if (prev_role == TimingRole::latchDtoQ()) {
|
||||||
const Latches *latches = sta->latches();
|
const Latches *latches = sta->latches();
|
||||||
Edge *prev_edge = p.prevEdge(prev_arc, sta);
|
Edge *prev_edge = p->prevEdge(sta);
|
||||||
PathVertex enable_path;
|
Path *enable_path = latches->latchEnablePath(p, prev_edge);
|
||||||
latches->latchEnablePath(&p, prev_edge, enable_path);
|
return enable_path;
|
||||||
clk_path = enable_path;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p = prev_path;
|
p = prev_path;
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PathEndDataCheck::PathEndDataCheck(DataCheck *check,
|
PathEndDataCheck::PathEndDataCheck(DataCheck *check,
|
||||||
Path *data_path,
|
Path *data_path,
|
||||||
PathVertex *data_clk_path,
|
Path *data_clk_path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
MultiCyclePath *mcp,
|
MultiCyclePath *mcp,
|
||||||
Crpr crpr,
|
Crpr crpr,
|
||||||
bool crpr_valid) :
|
bool crpr_valid) :
|
||||||
|
|
@ -1671,8 +1652,8 @@ PathEndDataCheck::PathEndDataCheck(DataCheck *check,
|
||||||
PathEnd *
|
PathEnd *
|
||||||
PathEndDataCheck::copy()
|
PathEndDataCheck::copy()
|
||||||
{
|
{
|
||||||
return new PathEndDataCheck(check_, path_.path(), &data_clk_path_,
|
return new PathEndDataCheck(check_, path_, data_clk_path_,
|
||||||
&clk_path_, mcp_, crpr_, crpr_valid_);
|
clk_path_, mcp_, crpr_, crpr_valid_);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathEnd::Type
|
PathEnd::Type
|
||||||
|
|
@ -1691,14 +1672,14 @@ const ClockEdge *
|
||||||
PathEndDataCheck::targetClkEdge(const StaState *sta) const
|
PathEndDataCheck::targetClkEdge(const StaState *sta) const
|
||||||
{
|
{
|
||||||
// clk_path_ can be null if data_clk_path is from an input port.
|
// 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
|
Arrival
|
||||||
PathEndDataCheck::requiredTimeNoCrpr(const StaState *sta) const
|
PathEndDataCheck::requiredTimeNoCrpr(const StaState *sta) const
|
||||||
{
|
{
|
||||||
Arrival data_clk_arrival = data_clk_path_.arrival(sta);
|
Arrival data_clk_arrival = data_clk_path_->arrival();
|
||||||
float data_clk_time = data_clk_path_.clkEdge(sta)->time();
|
float data_clk_time = data_clk_path_->clkEdge(sta)->time();
|
||||||
Arrival data_clk_delay = data_clk_arrival - data_clk_time;
|
Arrival data_clk_delay = data_clk_arrival - data_clk_time;
|
||||||
Arrival tgt_clk_arrival = targetClkTime(sta)
|
Arrival tgt_clk_arrival = targetClkTime(sta)
|
||||||
+ data_clk_delay
|
+ data_clk_delay
|
||||||
|
|
@ -1717,9 +1698,9 @@ PathEndDataCheck::margin(const StaState *sta) const
|
||||||
{
|
{
|
||||||
float margin;
|
float margin;
|
||||||
bool margin_exists;
|
bool margin_exists;
|
||||||
check_->margin(data_clk_path_.transition(sta),
|
check_->margin(data_clk_path_->transition(sta),
|
||||||
path_.transition(sta),
|
path_->transition(sta),
|
||||||
path_.minMax(sta),
|
path_->minMax(sta),
|
||||||
margin, margin_exists);
|
margin, margin_exists);
|
||||||
return margin;
|
return margin;
|
||||||
}
|
}
|
||||||
|
|
@ -1727,7 +1708,7 @@ PathEndDataCheck::margin(const StaState *sta) const
|
||||||
TimingRole *
|
TimingRole *
|
||||||
PathEndDataCheck::checkRole(const StaState *sta) const
|
PathEndDataCheck::checkRole(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (path_.minMax(sta) == MinMax::max())
|
if (path_->minMax(sta) == MinMax::max())
|
||||||
return TimingRole::dataCheckSetup();
|
return TimingRole::dataCheckSetup();
|
||||||
else
|
else
|
||||||
return TimingRole::dataCheckHold();
|
return TimingRole::dataCheckHold();
|
||||||
|
|
@ -1794,7 +1775,7 @@ PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
|
||||||
|
|
||||||
PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
|
PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
|
||||||
Path *path,
|
Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
const StaState *sta) :
|
const StaState *sta) :
|
||||||
|
|
@ -1809,7 +1790,7 @@ PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
|
||||||
|
|
||||||
PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
|
PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
|
||||||
Path *path,
|
Path *path,
|
||||||
PathVertex *clk_path,
|
Path *clk_path,
|
||||||
TimingArc *check_arc,
|
TimingArc *check_arc,
|
||||||
Edge *check_edge,
|
Edge *check_edge,
|
||||||
OutputDelay *output_delay,
|
OutputDelay *output_delay,
|
||||||
|
|
@ -1828,7 +1809,7 @@ PathEndPathDelay::PathEndPathDelay(PathDelay *path_delay,
|
||||||
PathEnd *
|
PathEnd *
|
||||||
PathEndPathDelay::copy()
|
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_,
|
check_arc_, check_edge_, output_delay_,
|
||||||
src_clk_arrival_, crpr_, crpr_valid_);
|
src_clk_arrival_, crpr_, crpr_valid_);
|
||||||
}
|
}
|
||||||
|
|
@ -1850,7 +1831,7 @@ PathEndPathDelay::findSrcClkArrival(const StaState *sta)
|
||||||
{
|
{
|
||||||
if (ignoreClkLatency(sta)) {
|
if (ignoreClkLatency(sta)) {
|
||||||
Search *search = sta->search();
|
Search *search = sta->search();
|
||||||
src_clk_arrival_ = search->pathClkPathArrival(&path_);
|
src_clk_arrival_ = search->pathClkPathArrival(path_);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
src_clk_arrival_ = 0.0;
|
src_clk_arrival_ = 0.0;
|
||||||
|
|
@ -1895,7 +1876,7 @@ PathEndPathDelay::margin(const StaState *sta) const
|
||||||
pathAnalysisPt(sta));
|
pathAnalysisPt(sta));
|
||||||
}
|
}
|
||||||
else if (output_delay_)
|
else if (output_delay_)
|
||||||
return outputDelayMargin(output_delay_, path_.path(), sta);
|
return outputDelayMargin(output_delay_, path_, sta);
|
||||||
else
|
else
|
||||||
return delay_zero;
|
return delay_zero;
|
||||||
}
|
}
|
||||||
|
|
@ -1914,13 +1895,13 @@ PathEnd::clkSkew(const StaState *)
|
||||||
|
|
||||||
// Helper shared by PathEndLatchCheck.
|
// Helper shared by PathEndLatchCheck.
|
||||||
float
|
float
|
||||||
PathEnd::pathDelaySrcClkOffset(const PathRef &path,
|
PathEnd::pathDelaySrcClkOffset(const Path *path,
|
||||||
PathDelay *path_delay,
|
PathDelay *path_delay,
|
||||||
Arrival src_clk_arrival,
|
Arrival src_clk_arrival,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
float offset = 0.0;
|
float offset = 0.0;
|
||||||
const ClockEdge *clk_edge = path.clkEdge(sta);
|
const ClockEdge *clk_edge = path->clkEdge(sta);
|
||||||
if (clk_edge) {
|
if (clk_edge) {
|
||||||
if (ignoreClkLatency(path, path_delay, sta))
|
if (ignoreClkLatency(path, path_delay, sta))
|
||||||
offset = -delayAsFloat(src_clk_arrival);
|
offset = -delayAsFloat(src_clk_arrival);
|
||||||
|
|
@ -1933,18 +1914,18 @@ PathEnd::pathDelaySrcClkOffset(const PathRef &path,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PathEnd::ignoreClkLatency(const PathRef &path,
|
PathEnd::ignoreClkLatency(const Path *path,
|
||||||
PathDelay *path_delay,
|
PathDelay *path_delay,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
return path_delay->ignoreClkLatency() && !path.isClock(sta);
|
return path_delay->ignoreClkLatency() && !path->isClock(sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClockEdge *
|
const ClockEdge *
|
||||||
PathEndPathDelay::targetClkEdge(const StaState *sta) const
|
PathEndPathDelay::targetClkEdge(const StaState *sta) const
|
||||||
{
|
{
|
||||||
if (!clk_path_.isNull())
|
if (clk_path_)
|
||||||
return clk_path_.clkEdge(sta);
|
return clk_path_->clkEdge(sta);
|
||||||
else if (output_delay_)
|
else if (output_delay_)
|
||||||
return output_delay_->clkEdge();
|
return output_delay_->clkEdge();
|
||||||
else
|
else
|
||||||
|
|
@ -1968,8 +1949,8 @@ PathEndPathDelay::targetClkArrivalNoCrpr(const StaState *sta) const
|
||||||
if (tgt_clk_edge)
|
if (tgt_clk_edge)
|
||||||
return targetClkDelay(sta)
|
return targetClkDelay(sta)
|
||||||
+ targetClkUncertainty(sta);
|
+ targetClkUncertainty(sta);
|
||||||
else if (!clk_path_.isNull())
|
else if (clk_path_)
|
||||||
return clk_path_.arrival(sta);
|
return clk_path_->arrival();
|
||||||
else
|
else
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
@ -1985,8 +1966,8 @@ PathEndPathDelay::requiredTime(const StaState *sta) const
|
||||||
{
|
{
|
||||||
float delay = path_delay_->delay();
|
float delay = path_delay_->delay();
|
||||||
if (path_delay_->ignoreClkLatency()) {
|
if (path_delay_->ignoreClkLatency()) {
|
||||||
Required src_offset = path_.isClock(sta)
|
Required src_offset = path_->isClock(sta)
|
||||||
? path_.clkEdge(sta)->time()
|
? path_->clkEdge(sta)->time()
|
||||||
: src_clk_arrival_;
|
: src_clk_arrival_;
|
||||||
return src_offset + delay
|
return src_offset + delay
|
||||||
+ ((minMax(sta) == MinMax::max()) ? -margin(sta) : margin(sta));
|
+ ((minMax(sta) == MinMax::max()) ? -margin(sta) : margin(sta));
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,7 @@
|
||||||
#include "Tag.hh"
|
#include "Tag.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
#include "PathEnd.hh"
|
#include "PathEnd.hh"
|
||||||
#include "PathRef.hh"
|
#include "Path.hh"
|
||||||
#include "PathEnumed.hh"
|
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -104,8 +103,8 @@ deleteDiversionPathEnd(Diversion *div)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
PathEnum::PathEnum(int group_path_count,
|
PathEnum::PathEnum(size_t group_path_count,
|
||||||
int endpoint_path_count,
|
size_t endpoint_path_count,
|
||||||
bool unique_pins,
|
bool unique_pins,
|
||||||
bool cmp_slack,
|
bool cmp_slack,
|
||||||
const StaState *sta) :
|
const StaState *sta) :
|
||||||
|
|
@ -214,17 +213,16 @@ PathEnum::reportDiversionPath(Diversion *div)
|
||||||
{
|
{
|
||||||
PathEnd *path_end = div->pathEnd();
|
PathEnd *path_end = div->pathEnd();
|
||||||
Path *path = path_end->path();
|
Path *path = path_end->path();
|
||||||
PathRef p;
|
Path *p = path->prevPath();
|
||||||
path->prevPath(this, p);
|
|
||||||
Path *after_div = div->divPath();
|
Path *after_div = div->divPath();
|
||||||
while (!p.isNull()) {
|
while (p) {
|
||||||
report_->reportLine("path_enum: %s %s%s",
|
report_->reportLine("path_enum: %s %s%s",
|
||||||
p.name(this),
|
p->name(this),
|
||||||
delayAsString(p.arrival(this), this),
|
delayAsString(p->arrival(), this),
|
||||||
Path::equal(&p, after_div, this) ? " <-diversion" : "");
|
Path::equal(p, after_div, this) ? " <-diversion" : "");
|
||||||
if (network_->isLatchData(p.pin(this)))
|
if (network_->isLatchData(p->pin(this)))
|
||||||
break;
|
break;
|
||||||
p.prevPath(this, p);
|
p = p->prevPath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -234,19 +232,19 @@ class PathEnumFaninVisitor : public PathVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PathEnumFaninVisitor(PathEnd *path_end,
|
PathEnumFaninVisitor(PathEnd *path_end,
|
||||||
PathRef &before_div,
|
Path *before_div,
|
||||||
bool unique_pins,
|
bool unique_pins,
|
||||||
PathEnum *path_enum);
|
PathEnum *path_enum);
|
||||||
virtual VertexVisitor *copy() const;
|
virtual VertexVisitor *copy() const;
|
||||||
virtual void visit(Vertex *) {} // Not used.
|
virtual void visit(Vertex *) {} // Not used.
|
||||||
void visitFaninPathsThru(Vertex *vertex,
|
void visitFaninPathsThru(Path *before_div,
|
||||||
Vertex *prev_vertex,
|
Vertex *prev_vertex,
|
||||||
TimingArc *prev_arc);
|
TimingArc *prev_arc);
|
||||||
virtual bool visitFromToPath(const Pin *from_pin,
|
virtual bool visitFromToPath(const Pin *from_pin,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
const Arrival &from_arrival,
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
|
|
@ -260,16 +258,18 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void makeDivertedPathEnd(Path *after_div,
|
void makeDivertedPathEnd(Path *after_div,
|
||||||
|
Edge *div_edge,
|
||||||
TimingArc *div_arc,
|
TimingArc *div_arc,
|
||||||
// Return values.
|
// Return values.
|
||||||
PathEnd *&div_end,
|
PathEnd *&div_end,
|
||||||
PathEnumed *&after_div_copy);
|
Path *&after_div_copy);
|
||||||
void reportDiversion(TimingArc *div_arc,
|
void reportDiversion(const Edge *edge,
|
||||||
|
const TimingArc *div_arc,
|
||||||
Path *after_div);
|
Path *after_div);
|
||||||
|
|
||||||
PathEnd *path_end_;
|
PathEnd *path_end_;
|
||||||
Slack path_end_slack_;
|
Slack path_end_slack_;
|
||||||
PathRef &before_div_;
|
Path *before_div_;
|
||||||
bool unique_pins_;
|
bool unique_pins_;
|
||||||
int before_div_rf_index_;
|
int before_div_rf_index_;
|
||||||
Tag *before_div_tag_;
|
Tag *before_div_tag_;
|
||||||
|
|
@ -282,7 +282,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
PathEnumFaninVisitor::PathEnumFaninVisitor(PathEnd *path_end,
|
PathEnumFaninVisitor::PathEnumFaninVisitor(PathEnd *path_end,
|
||||||
PathRef &before_div,
|
Path *before_div,
|
||||||
bool unique_pins,
|
bool unique_pins,
|
||||||
PathEnum *path_enum) :
|
PathEnum *path_enum) :
|
||||||
PathVisitor(path_enum),
|
PathVisitor(path_enum),
|
||||||
|
|
@ -290,27 +290,28 @@ PathEnumFaninVisitor::PathEnumFaninVisitor(PathEnd *path_end,
|
||||||
path_end_slack_(path_end->slack(this)),
|
path_end_slack_(path_end->slack(this)),
|
||||||
before_div_(before_div),
|
before_div_(before_div),
|
||||||
unique_pins_(unique_pins),
|
unique_pins_(unique_pins),
|
||||||
before_div_rf_index_(before_div_.rfIndex(this)),
|
before_div_rf_index_(before_div_->rfIndex(this)),
|
||||||
before_div_tag_(before_div_.tag(this)),
|
before_div_tag_(before_div_->tag(this)),
|
||||||
before_div_ap_index_(before_div_.pathAnalysisPtIndex(this)),
|
before_div_ap_index_(before_div_->pathAnalysisPtIndex(this)),
|
||||||
before_div_arrival_(before_div_.arrival(this)),
|
before_div_arrival_(before_div_->arrival()),
|
||||||
path_enum_(path_enum),
|
path_enum_(path_enum),
|
||||||
crpr_active_(sdc_->crprActive())
|
crpr_active_(sdc_->crprActive())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PathEnumFaninVisitor::visitFaninPathsThru(Vertex *vertex,
|
PathEnumFaninVisitor::visitFaninPathsThru(Path *before_div,
|
||||||
Vertex *prev_vertex,
|
Vertex *prev_vertex,
|
||||||
TimingArc *prev_arc)
|
TimingArc *prev_arc)
|
||||||
{
|
{
|
||||||
before_div_rf_index_ = before_div_.rfIndex(this);
|
before_div_ = before_div;
|
||||||
before_div_tag_ = before_div_.tag(this);
|
before_div_rf_index_ = before_div_->rfIndex(this);
|
||||||
before_div_ap_index_ = before_div_.pathAnalysisPtIndex(this);
|
before_div_tag_ = before_div_->tag(this);
|
||||||
before_div_arrival_ = before_div_.arrival(this);
|
before_div_ap_index_ = before_div_->pathAnalysisPtIndex(this);
|
||||||
|
before_div_arrival_ = before_div_->arrival();
|
||||||
prev_arc_ = prev_arc;
|
prev_arc_ = prev_arc;
|
||||||
prev_vertex_ = prev_vertex;
|
prev_vertex_ = prev_vertex;
|
||||||
visitFaninPaths(vertex);
|
visitFaninPaths(before_div_->vertex(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexVisitor *
|
VertexVisitor *
|
||||||
|
|
@ -325,7 +326,7 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *,
|
const RiseFall *,
|
||||||
Tag *,
|
Tag *,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
const Arrival &,
|
const Arrival &,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
|
|
@ -351,13 +352,13 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *,
|
||||||
&& tagMatchNoCrpr(to_tag, before_div_tag_)) {
|
&& tagMatchNoCrpr(to_tag, before_div_tag_)) {
|
||||||
if (crpr_active_) {
|
if (crpr_active_) {
|
||||||
PathEnd *div_end;
|
PathEnd *div_end;
|
||||||
PathEnumed *after_div_copy;
|
Path *after_div_copy;
|
||||||
// Make the diverted path end to check slack with from_path crpr.
|
// 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) {
|
if (div_end) {
|
||||||
// Only enumerate paths with greater slack.
|
// Only enumerate paths with greater slack.
|
||||||
if (delayGreaterEqual(div_end->slack(this), path_end_slack_, this)) {
|
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);
|
path_enum_->makeDiversion(div_end, after_div_copy);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -367,9 +368,9 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *,
|
||||||
// Only enumerate slower/faster paths.
|
// Only enumerate slower/faster paths.
|
||||||
else if (delayLessEqual(to_arrival, before_div_arrival_, min_max, this)) {
|
else if (delayLessEqual(to_arrival, before_div_arrival_, min_max, this)) {
|
||||||
PathEnd *div_end;
|
PathEnd *div_end;
|
||||||
PathEnumed *after_div_copy;
|
Path *after_div_copy;
|
||||||
makeDivertedPathEnd(from_path, arc, div_end, after_div_copy);
|
makeDivertedPathEnd(from_path, edge, arc, div_end, after_div_copy);
|
||||||
reportDiversion(arc, from_path);
|
reportDiversion(edge, arc, from_path);
|
||||||
path_enum_->makeDiversion(div_end, after_div_copy);
|
path_enum_->makeDiversion(div_end, after_div_copy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -378,14 +379,15 @@ PathEnumFaninVisitor::visitFromToPath(const Pin *,
|
||||||
|
|
||||||
void
|
void
|
||||||
PathEnumFaninVisitor::makeDivertedPathEnd(Path *after_div,
|
PathEnumFaninVisitor::makeDivertedPathEnd(Path *after_div,
|
||||||
|
Edge *div_edge,
|
||||||
TimingArc *div_arc,
|
TimingArc *div_arc,
|
||||||
// Return values.
|
// Return values.
|
||||||
PathEnd *&div_end,
|
PathEnd *&div_end,
|
||||||
PathEnumed *&after_div_copy)
|
Path *&after_div_copy)
|
||||||
{
|
{
|
||||||
PathEnumed *div_path;
|
Path *div_path;
|
||||||
path_enum_->makeDivertedPath(path_end_->path(), &before_div_, after_div,
|
path_enum_->makeDivertedPath(path_end_->path(), before_div_, after_div,
|
||||||
div_arc, div_path, after_div_copy);
|
div_edge, div_arc, div_path, after_div_copy);
|
||||||
if (after_div_copy) {
|
if (after_div_copy) {
|
||||||
div_end = path_end_->copy();
|
div_end = path_end_->copy();
|
||||||
div_end->setPath(div_path);
|
div_end->setPath(div_path);
|
||||||
|
|
@ -395,7 +397,8 @@ PathEnumFaninVisitor::makeDivertedPathEnd(Path *after_div,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PathEnumFaninVisitor::reportDiversion(TimingArc *div_arc,
|
PathEnumFaninVisitor::reportDiversion(const Edge *div_edge,
|
||||||
|
const TimingArc *div_arc,
|
||||||
Path *after_div)
|
Path *after_div)
|
||||||
{
|
{
|
||||||
if (debug_->check("path_enum", 3)) {
|
if (debug_->check("path_enum", 3)) {
|
||||||
|
|
@ -404,19 +407,18 @@ PathEnumFaninVisitor::reportDiversion(TimingArc *div_arc,
|
||||||
Arrival path_delay = path_enum_->cmp_slack_
|
Arrival path_delay = path_enum_->cmp_slack_
|
||||||
? path_end_->slack(this)
|
? path_end_->slack(this)
|
||||||
: path_end_->dataArrivalTime(this);
|
: path_end_->dataArrivalTime(this);
|
||||||
Arrival div_delay = path_delay - path_enum_->divSlack(&before_div_,
|
Arrival div_delay = path_delay - path_enum_->divSlack(before_div_,
|
||||||
after_div,
|
after_div, div_edge,
|
||||||
div_arc, path_ap);
|
div_arc, path_ap);
|
||||||
PathRef div_prev;
|
Path *div_prev = before_div_->prevPath();
|
||||||
before_div_.prevPath(this, div_prev);
|
|
||||||
report_->reportLine("path_enum: diversion %s %s %s -> %s",
|
report_->reportLine("path_enum: diversion %s %s %s -> %s",
|
||||||
path->name(this),
|
path->name(this),
|
||||||
path_enum_->cmp_slack_ ? "slack" : "delay",
|
path_enum_->cmp_slack_ ? "slack" : "delay",
|
||||||
delayAsString(path_delay, this),
|
delayAsString(path_delay, this),
|
||||||
delayAsString(div_delay, this));
|
delayAsString(div_delay, this));
|
||||||
report_->reportLine("path_enum: from %s -> %s",
|
report_->reportLine("path_enum: from %s -> %s",
|
||||||
div_prev.name(this),
|
div_prev->name(this),
|
||||||
before_div_.name(this));
|
before_div_->name(this));
|
||||||
report_->reportLine("path_enum: to %s",
|
report_->reportLine("path_enum: to %s",
|
||||||
after_div->name(this));
|
after_div->name(this));
|
||||||
}
|
}
|
||||||
|
|
@ -431,13 +433,13 @@ PathEnumFaninVisitor::reportDiversion(TimingArc *div_arc,
|
||||||
// <--...--before_div<--...--path<---path_end
|
// <--...--before_div<--...--path<---path_end
|
||||||
void
|
void
|
||||||
PathEnum::makeDiversion(PathEnd *div_end,
|
PathEnum::makeDiversion(PathEnd *div_end,
|
||||||
PathEnumed *after_div_copy)
|
Path *after_div_copy)
|
||||||
{
|
{
|
||||||
Diversion *div = new Diversion(div_end, after_div_copy);
|
Diversion *div = new Diversion(div_end, after_div_copy);
|
||||||
div_queue_.push(div);
|
div_queue_.push(div);
|
||||||
div_count_++;
|
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.
|
// We have more potenial paths than we will need.
|
||||||
pruneDiversionQueue();
|
pruneDiversionQueue();
|
||||||
}
|
}
|
||||||
|
|
@ -447,7 +449,7 @@ PathEnum::pruneDiversionQueue()
|
||||||
{
|
{
|
||||||
debugPrint(debug_, "path_enum", 2, "prune queue");
|
debugPrint(debug_, "path_enum", 2, "prune queue");
|
||||||
VertexPathCountMap path_counts;
|
VertexPathCountMap path_counts;
|
||||||
int end_count = 0;
|
size_t end_count = 0;
|
||||||
// Collect endpoint_path_count diversions per vertex.
|
// Collect endpoint_path_count diversions per vertex.
|
||||||
DiversionSeq divs;
|
DiversionSeq divs;
|
||||||
while (!div_queue_.empty()) {
|
while (!div_queue_.empty()) {
|
||||||
|
|
@ -476,11 +478,11 @@ PathEnum::pruneDiversionQueue()
|
||||||
Arrival
|
Arrival
|
||||||
PathEnum::divSlack(Path *before_div,
|
PathEnum::divSlack(Path *before_div,
|
||||||
Path *after_div,
|
Path *after_div,
|
||||||
TimingArc *div_arc,
|
const Edge *div_edge,
|
||||||
|
const TimingArc *div_arc,
|
||||||
const PathAnalysisPt *path_ap)
|
const PathAnalysisPt *path_ap)
|
||||||
{
|
{
|
||||||
Arrival arc_arrival = before_div->arrival(this);
|
Arrival arc_arrival = before_div->arrival();
|
||||||
Edge *div_edge = divEdge(before_div, div_arc);
|
|
||||||
if (div_edge) {
|
if (div_edge) {
|
||||||
ArcDelay div_delay = search_->deratedDelay(div_edge->from(graph_),
|
ArcDelay div_delay = search_->deratedDelay(div_edge->from(graph_),
|
||||||
div_arc, div_edge,
|
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
|
// Make diversions for all arcs that merge into path for paths
|
||||||
// starting at "before" to the beginning of the path.
|
// starting at "before" to the beginning of the path.
|
||||||
void
|
void
|
||||||
PathEnum::makeDiversions(PathEnd *path_end,
|
PathEnum::makeDiversions(PathEnd *path_end,
|
||||||
Path *before)
|
Path *before)
|
||||||
{
|
{
|
||||||
PathRef path(before);
|
Path *path = before;
|
||||||
PathRef prev_path;
|
Path *prev_path = path->prevPath();
|
||||||
TimingArc *prev_arc;
|
TimingArc *prev_arc = path->prevArc(this);
|
||||||
path.prevPath(this, prev_path, prev_arc);
|
|
||||||
PathEnumFaninVisitor fanin_visitor(path_end, path, unique_pins_, this);
|
PathEnumFaninVisitor fanin_visitor(path_end, path, unique_pins_, this);
|
||||||
while (prev_arc
|
while (prev_path
|
||||||
// Do not enumerate paths in the clk network.
|
// Do not enumerate paths in the clk network.
|
||||||
&& !path.isClock(this)) {
|
&& !path->isClock(this)) {
|
||||||
// Fanin visitor does all the work.
|
// Fanin visitor does all the work.
|
||||||
// While visiting the fanins the fanin_visitor finds the
|
// While visiting the fanins the fanin_visitor finds the
|
||||||
// previous path and arc as well as diversions.
|
// previous path and arc as well as diversions.
|
||||||
fanin_visitor.visitFaninPathsThru(path.vertex(this),
|
fanin_visitor.visitFaninPathsThru(path, prev_path->vertex(this), prev_arc);
|
||||||
prev_path.vertex(this), prev_arc);
|
|
||||||
// Do not enumerate beyond latch D to Q edges.
|
// Do not enumerate beyond latch D to Q edges.
|
||||||
// This breaks latch loop paths.
|
// This breaks latch loop paths.
|
||||||
if (prev_arc->role() == TimingRole::latchDtoQ())
|
if (prev_arc->role() == TimingRole::latchDtoQ())
|
||||||
break;
|
break;
|
||||||
path.init(prev_path);
|
path = prev_path;
|
||||||
path.prevPath(this, prev_path, prev_arc);
|
prev_path = path->prevPath();
|
||||||
|
prev_arc = path->prevArc(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -540,47 +527,52 @@ void
|
||||||
PathEnum::makeDivertedPath(Path *path,
|
PathEnum::makeDivertedPath(Path *path,
|
||||||
Path *before_div,
|
Path *before_div,
|
||||||
Path *after_div,
|
Path *after_div,
|
||||||
|
Edge *div_edge,
|
||||||
TimingArc *div_arc,
|
TimingArc *div_arc,
|
||||||
// Returned values.
|
// Returned values.
|
||||||
PathEnumed *&div_path,
|
Path *&div_path,
|
||||||
PathEnumed *&after_div_copy)
|
Path *&after_div_copy)
|
||||||
{
|
{
|
||||||
div_path = nullptr;
|
div_path = nullptr;
|
||||||
after_div_copy = nullptr;
|
after_div_copy = nullptr;
|
||||||
// Copy the diversion path.
|
// Copy the diversion path.
|
||||||
bool found_div = false;
|
bool found_div = false;
|
||||||
PathEnumedSeq copies;
|
PathSeq copies;
|
||||||
PathRef p(path);
|
Path *p = path;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
PathEnumed *prev_copy = nullptr;
|
Path *prev_copy = nullptr;
|
||||||
while (!p.isNull()) {
|
while (p) {
|
||||||
PathRef prev;
|
// prev_path made in next pass.
|
||||||
TimingArc *prev_arc;
|
Path *copy = new Path(p->vertex(this),
|
||||||
p.prevPath(this, prev, prev_arc);
|
p->tag(this),
|
||||||
PathEnumed *copy = new PathEnumed(p.vertexId(this),
|
p->arrival(),
|
||||||
p.tagIndex(this),
|
// Replaced on next pass.
|
||||||
p.arrival(this),
|
p->prevPath(),
|
||||||
nullptr, // prev_path made in next pass.
|
p->prevEdge(this),
|
||||||
prev_arc);
|
p->prevArc(this),
|
||||||
|
true, this);
|
||||||
if (prev_copy)
|
if (prev_copy)
|
||||||
prev_copy->setPrevPath(copy);
|
prev_copy->setPrevPath(copy);
|
||||||
copies.push_back(copy);
|
copies.push_back(copy);
|
||||||
|
|
||||||
if (Path::equal(&p, after_div, this))
|
if (Path::equal(p, after_div, this))
|
||||||
after_div_copy = copy;
|
after_div_copy = copy;
|
||||||
if (first)
|
if (first)
|
||||||
div_path = copy;
|
div_path = copy;
|
||||||
else if (network_->isLatchData(p.pin(this)))
|
else if (network_->isLatchData(p->pin(this)))
|
||||||
break;
|
break;
|
||||||
if (Path::equal(&p, before_div, this)) {
|
if (Path::equal(p, before_div, this)) {
|
||||||
copy->setPrevArc(div_arc);
|
// 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.
|
// Update the delays forward from before_div to the end of the path.
|
||||||
updatePathHeadDelays(copies, after_div);
|
updatePathHeadDelays(copies, after_div);
|
||||||
p.init(after_div);
|
p = after_div;
|
||||||
found_div = true;
|
found_div = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
p.init(prev);
|
p = p->prevPath();
|
||||||
|
|
||||||
prev_copy = copy;
|
prev_copy = copy;
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
@ -589,16 +581,16 @@ PathEnum::makeDivertedPath(Path *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PathEnum::updatePathHeadDelays(PathEnumedSeq &paths,
|
PathEnum::updatePathHeadDelays(PathSeq &paths,
|
||||||
Path *after_div)
|
Path *after_div)
|
||||||
{
|
{
|
||||||
Tag *prev_tag = after_div->tag(this);
|
Tag *prev_tag = after_div->tag(this);
|
||||||
ClkInfo *prev_clk_info = prev_tag->clkInfo();
|
ClkInfo *prev_clk_info = prev_tag->clkInfo();
|
||||||
Arrival prev_arrival = search_->clkPathArrival(after_div);
|
Arrival prev_arrival = search_->clkPathArrival(after_div);
|
||||||
for (int i = paths.size() - 1; i >= 0; i--) {
|
for (int i = paths.size() - 1; i >= 0; i--) {
|
||||||
PathEnumed *path = paths[i];
|
Path *path = paths[i];
|
||||||
TimingArc *arc = path->prevArc(this);
|
TimingArc *arc = path->prevArc(this);
|
||||||
Edge *edge = path->prevEdge(arc, this);
|
Edge *edge = path->prevEdge(this);
|
||||||
if (edge) {
|
if (edge) {
|
||||||
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
||||||
ArcDelay arc_delay = search_->deratedDelay(edge->from(graph_),
|
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",
|
debugPrint(debug_, "path_enum", 5, "update arrival %s %s %s -> %s",
|
||||||
path->vertex(this)->name(network_),
|
path->vertex(this)->name(network_),
|
||||||
path->tag(this)->asString(this),
|
path->tag(this)->asString(this),
|
||||||
delayAsString(path->arrival(this), this),
|
delayAsString(path->arrival(), this),
|
||||||
delayAsString(arrival, this));
|
delayAsString(arrival, this));
|
||||||
path->setArrival(arrival, this);
|
path->setArrival(arrival);
|
||||||
prev_arrival = arrival;
|
prev_arrival = arrival;
|
||||||
if (sdc_->crprActive()
|
if (sdc_->crprActive()
|
||||||
// D->Q paths use the EN->Q clk info so no need to update.
|
// D->Q paths use the EN->Q clk info so no need to update.
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,9 @@ namespace sta {
|
||||||
|
|
||||||
class Diversion;
|
class Diversion;
|
||||||
class PathEnumFaninVisitor;
|
class PathEnumFaninVisitor;
|
||||||
class PathEnumed;
|
|
||||||
class DiversionGreater;
|
class DiversionGreater;
|
||||||
|
|
||||||
typedef Vector<Diversion*> DiversionSeq;
|
typedef Vector<Diversion*> DiversionSeq;
|
||||||
typedef Vector<PathEnumed*> PathEnumedSeq;
|
|
||||||
typedef std::priority_queue<Diversion*,DiversionSeq,
|
typedef std::priority_queue<Diversion*,DiversionSeq,
|
||||||
DiversionGreater> DiversionQueue;
|
DiversionGreater> DiversionQueue;
|
||||||
|
|
||||||
|
|
@ -60,8 +58,8 @@ private:
|
||||||
class PathEnum : public Iterator<PathEnd*>, StaState
|
class PathEnum : public Iterator<PathEnd*>, StaState
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PathEnum(int group_path_count,
|
PathEnum(size_t group_path_count,
|
||||||
int endpoint_path_count,
|
size_t endpoint_path_count,
|
||||||
bool unique_pins,
|
bool unique_pins,
|
||||||
bool cmp_slack,
|
bool cmp_slack,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
|
@ -75,29 +73,29 @@ private:
|
||||||
void makeDiversions(PathEnd *path_end,
|
void makeDiversions(PathEnd *path_end,
|
||||||
Path *before);
|
Path *before);
|
||||||
void makeDiversion(PathEnd *div_end,
|
void makeDiversion(PathEnd *div_end,
|
||||||
PathEnumed *after_div_copy);
|
Path *after_div_copy);
|
||||||
void makeDivertedPath(Path *path,
|
void makeDivertedPath(Path *path,
|
||||||
Path *before_div,
|
Path *before_div,
|
||||||
Path *after_div,
|
Path *after_div,
|
||||||
|
Edge *div_edge,
|
||||||
TimingArc *div_arc,
|
TimingArc *div_arc,
|
||||||
// Returned values.
|
// Returned values.
|
||||||
PathEnumed *&div_path,
|
Path *&div_path,
|
||||||
PathEnumed *&after_div_copy);
|
Path *&after_div_copy);
|
||||||
void updatePathHeadDelays(PathEnumedSeq &path,
|
void updatePathHeadDelays(PathSeq &path,
|
||||||
Path *after_div);
|
Path *after_div);
|
||||||
Arrival divSlack(Path *path,
|
Arrival divSlack(Path *path,
|
||||||
Path *after_div,
|
Path *after_div,
|
||||||
TimingArc *div_arc,
|
const Edge *div_edge,
|
||||||
|
const TimingArc *div_arc,
|
||||||
const PathAnalysisPt *path_ap);
|
const PathAnalysisPt *path_ap);
|
||||||
void reportDiversionPath(Diversion *div);
|
void reportDiversionPath(Diversion *div);
|
||||||
void pruneDiversionQueue();
|
void pruneDiversionQueue();
|
||||||
Edge *divEdge(Path *before_div,
|
|
||||||
TimingArc *div_arc);
|
|
||||||
void findNext();
|
void findNext();
|
||||||
|
|
||||||
bool cmp_slack_;
|
bool cmp_slack_;
|
||||||
int group_path_count_;
|
size_t group_path_count_;
|
||||||
int endpoint_path_count_;
|
size_t endpoint_path_count_;
|
||||||
bool unique_pins_;
|
bool unique_pins_;
|
||||||
DiversionQueue div_queue_;
|
DiversionQueue div_queue_;
|
||||||
int div_count_;
|
int div_count_;
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
#include "Network.hh"
|
#include "Network.hh"
|
||||||
#include "Clock.hh"
|
#include "Clock.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
#include "PathRef.hh"
|
#include "Path.hh"
|
||||||
#include "Latches.hh"
|
#include "Latches.hh"
|
||||||
#include "Genclks.hh"
|
#include "Genclks.hh"
|
||||||
|
|
||||||
|
|
@ -61,35 +61,32 @@ PathExpanded::expand(const Path *path,
|
||||||
bool expand_genclks)
|
bool expand_genclks)
|
||||||
{
|
{
|
||||||
const Latches *latches = sta_->latches();
|
const Latches *latches = sta_->latches();
|
||||||
// Push the paths from the end into an array of PathRefs.
|
// Push the paths from the end into an array of Paths.
|
||||||
PathRef p(path);
|
const Path *p = path;
|
||||||
PathRef last_path;
|
const Path *last_path = nullptr;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
bool found_start = false;
|
bool found_start = false;
|
||||||
while (!p.isNull()) {
|
while (p) {
|
||||||
PathRef prev_path;
|
const Path *prev_path = p->prevPath();
|
||||||
TimingArc *prev_arc;
|
const TimingArc *prev_arc = p->prevArc(sta_);
|
||||||
p.prevPath(sta_, prev_path, prev_arc);
|
|
||||||
|
|
||||||
if (!found_start) {
|
if (!found_start) {
|
||||||
if (prev_arc) {
|
if (prev_arc) {
|
||||||
TimingRole *prev_role = prev_arc->role();
|
const TimingRole *prev_role = prev_arc->role();
|
||||||
if (prev_role == TimingRole::regClkToQ()
|
if (prev_role == TimingRole::regClkToQ()
|
||||||
|| prev_role == TimingRole::latchEnToQ()) {
|
|| prev_role == TimingRole::latchEnToQ()) {
|
||||||
start_index_ = i;
|
start_index_ = i;
|
||||||
found_start = true;
|
found_start = true;
|
||||||
}
|
}
|
||||||
else if (prev_role == TimingRole::latchDtoQ()) {
|
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)) {
|
if (prev_edge && latches->isLatchDtoQ(prev_edge)) {
|
||||||
start_index_ = i;
|
start_index_ = i;
|
||||||
found_start = true;
|
found_start = true;
|
||||||
|
|
||||||
paths_.push_back(p);
|
paths_.push_back(p);
|
||||||
prev_arcs_.push_back(prev_arc);
|
|
||||||
// Push latch D path.
|
// Push latch D path.
|
||||||
paths_.push_back(prev_path);
|
paths_.push_back(prev_path);
|
||||||
prev_arcs_.push_back(nullptr);
|
|
||||||
// This breaks latch loop paths.
|
// This breaks latch loop paths.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -97,43 +94,37 @@ PathExpanded::expand(const Path *path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
paths_.push_back(p);
|
paths_.push_back(p);
|
||||||
prev_arcs_.push_back(prev_arc);
|
last_path = p;
|
||||||
last_path.init(p);
|
p = prev_path;
|
||||||
p.init(prev_path);
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (!found_start)
|
if (!found_start)
|
||||||
start_index_ = i - 1;
|
start_index_ = i - 1;
|
||||||
|
|
||||||
if (expand_genclks)
|
if (expand_genclks)
|
||||||
expandGenclk(&last_path);
|
expandGenclk(last_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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_);
|
const Clock *src_clk = clk_path->clock(sta_);
|
||||||
if (src_clk && src_clk->isGenerated()) {
|
if (src_clk && src_clk->isGenerated()) {
|
||||||
PathVertex src_path = sta_->search()->genclks()->srcPath(clk_path);
|
const Path *src_path = sta_->search()->genclks()->srcPath(clk_path);
|
||||||
if (!src_path.isNull()) {
|
if (src_path) {
|
||||||
// The head of the genclk src path is already in paths_,
|
// The head of the genclk src path is already in paths_,
|
||||||
// so skip past it.
|
// so skip past it.
|
||||||
PathRef prev_path;
|
Path *prev_path = src_path->prevPath();
|
||||||
TimingArc *prev_arc;
|
Path *p = prev_path;
|
||||||
src_path.prevPath(sta_, prev_path, prev_arc);
|
Path *last_path = nullptr;
|
||||||
|
while (p) {
|
||||||
PathRef p(prev_path);
|
prev_path = p->prevPath();
|
||||||
PathRef last_path;
|
|
||||||
while (!p.isNull()) {
|
|
||||||
p.prevPath(sta_, prev_path, prev_arc);
|
|
||||||
|
|
||||||
paths_.push_back(p);
|
paths_.push_back(p);
|
||||||
prev_arcs_.push_back(prev_arc);
|
last_path = p;
|
||||||
last_path.init(p);
|
p = prev_path;
|
||||||
p.init(prev_path);
|
|
||||||
}
|
}
|
||||||
expandGenclk(&last_path);
|
expandGenclk(last_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -153,91 +144,84 @@ PathExpanded::startIndex() const
|
||||||
return pathsIndex(start_index_);
|
return pathsIndex(start_index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathRef *
|
const Path *
|
||||||
PathExpanded::path(size_t index) const
|
PathExpanded::path(size_t index) const
|
||||||
{
|
{
|
||||||
if (index < paths_.size())
|
if (index < paths_.size())
|
||||||
return &paths_[pathsIndex(index)];
|
return paths_[pathsIndex(index)];
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingArc *
|
const Path *
|
||||||
PathExpanded::prevArc(size_t index) const
|
|
||||||
{
|
|
||||||
return prev_arcs_[pathsIndex(index)];
|
|
||||||
}
|
|
||||||
|
|
||||||
const PathRef *
|
|
||||||
PathExpanded::startPath() const
|
PathExpanded::startPath() const
|
||||||
{
|
{
|
||||||
return &paths_[start_index_];
|
return paths_[start_index_];
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathRef *
|
const Path *
|
||||||
PathExpanded::endPath() const
|
PathExpanded::endPath() const
|
||||||
{
|
{
|
||||||
return &paths_[0];
|
return paths_[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingArc *
|
const TimingArc *
|
||||||
PathExpanded::startPrevArc() const
|
PathExpanded::startPrevArc() const
|
||||||
{
|
{
|
||||||
return prev_arcs_[start_index_];
|
return paths_[start_index_]->prevArc(sta_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathRef *
|
const Path *
|
||||||
PathExpanded::startPrevPath() const
|
PathExpanded::startPrevPath() const
|
||||||
{
|
{
|
||||||
size_t start1 = start_index_ + 1;
|
size_t start1 = start_index_ + 1;
|
||||||
if (start1 < paths_.size())
|
if (start1 < paths_.size())
|
||||||
return &paths_[start1];
|
return paths_[start1];
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
const Path *
|
||||||
PathExpanded::clkPath(PathRef &clk_path) const
|
PathExpanded::clkPath() const
|
||||||
{
|
{
|
||||||
const Latches *latches = sta_->latches();
|
const Latches *latches = sta_->latches();
|
||||||
const PathRef *start = startPath();
|
const Path *start = startPath();
|
||||||
const TimingArc *prev_arc = startPrevArc();
|
const TimingArc *prev_arc = startPrevArc();
|
||||||
if (start && prev_arc) {
|
if (start && prev_arc) {
|
||||||
TimingRole *role = prev_arc->role();
|
TimingRole *role = prev_arc->role();
|
||||||
if (role == TimingRole::latchDtoQ()) {
|
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)) {
|
if (prev_edge && latches->isLatchDtoQ(prev_edge)) {
|
||||||
PathVertex enable_path;
|
return latches->latchEnablePath(start, prev_edge);
|
||||||
latches->latchEnablePath(start, prev_edge, enable_path);
|
|
||||||
clk_path.init(enable_path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (role == TimingRole::regClkToQ()
|
else if (role == TimingRole::regClkToQ()
|
||||||
|| role == TimingRole::latchEnToQ()) {
|
|| role == TimingRole::latchEnToQ()) {
|
||||||
const PathRef *start_prev = startPrevPath();
|
const Path *start_prev = startPrevPath();
|
||||||
if (start_prev)
|
if (start_prev)
|
||||||
clk_path.init(start_prev);
|
return start_prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (start && start->isClock(sta_))
|
else if (start && start->isClock(sta_))
|
||||||
clk_path.init(start);
|
return start;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PathExpanded::latchPaths(// Return values.
|
PathExpanded::latchPaths(// Return values.
|
||||||
const PathRef *&d_path,
|
const Path *&d_path,
|
||||||
const PathRef *&q_path,
|
const Path *&q_path,
|
||||||
Edge *&d_q_edge) const
|
Edge *&d_q_edge) const
|
||||||
{
|
{
|
||||||
d_path = nullptr;
|
d_path = nullptr;
|
||||||
q_path = nullptr;
|
q_path = nullptr;
|
||||||
d_q_edge = nullptr;
|
d_q_edge = nullptr;
|
||||||
const PathRef *start = startPath();
|
const Path *start = startPath();
|
||||||
const TimingArc *prev_arc = startPrevArc();
|
const TimingArc *prev_arc = startPrevArc();
|
||||||
if (start
|
if (start
|
||||||
&& prev_arc
|
&& prev_arc
|
||||||
&& prev_arc->role() == TimingRole::latchDtoQ()) {
|
&& prev_arc->role() == TimingRole::latchDtoQ()) {
|
||||||
Edge *prev_edge = start->prevEdge(prev_arc, sta_);
|
Edge *prev_edge = start->prevEdge(sta_);
|
||||||
// This breaks latch loop paths.
|
// This breaks latch loop paths.
|
||||||
if (prev_edge
|
if (prev_edge
|
||||||
&& sta_->latches()->isLatchDtoQ(prev_edge)) {
|
&& sta_->latches()->isLatchDtoQ(prev_edge)) {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
|
|
||||||
namespace sta {
|
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 *
|
||||||
PathGroup::makePathGroupSlack(const char *name,
|
PathGroup::makePathGroupSlack(const char *name,
|
||||||
|
|
@ -74,8 +74,8 @@ PathGroup::makePathGroupArrival(const char *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
PathGroup::PathGroup(const char *name,
|
PathGroup::PathGroup(const char *name,
|
||||||
int group_path_count,
|
size_t group_path_count,
|
||||||
int endpoint_path_count,
|
size_t endpoint_path_count,
|
||||||
bool unique_pins,
|
bool unique_pins,
|
||||||
float slack_min,
|
float slack_min,
|
||||||
float slack_max,
|
float slack_max,
|
||||||
|
|
@ -148,7 +148,7 @@ PathGroup::enumMinSlackUnderMin(PathEnd *path_end)
|
||||||
path->transition(sta_),
|
path->transition(sta_),
|
||||||
other_ap, sta_);
|
other_ap, sta_);
|
||||||
while (other_iter.hasNext()) {
|
while (other_iter.hasNext()) {
|
||||||
PathVertex *other = other_iter.next();
|
Path *other = other_iter.next();
|
||||||
if (tagMatchCrpr(other->tag(sta_), tag)) {
|
if (tagMatchCrpr(other->tag(sta_), tag)) {
|
||||||
PathEnd *end_min = path_end->copy();
|
PathEnd *end_min = path_end->copy();
|
||||||
end_min->setPath(other);
|
end_min->setPath(other);
|
||||||
|
|
@ -168,7 +168,7 @@ PathGroup::insert(PathEnd *path_end)
|
||||||
LockGuard lock(lock_);
|
LockGuard lock(lock_);
|
||||||
path_ends_.push_back(path_end);
|
path_ends_.push_back(path_end);
|
||||||
if (group_path_count_ != group_path_count_max
|
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();
|
prune();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,7 +177,7 @@ PathGroup::prune()
|
||||||
{
|
{
|
||||||
sort();
|
sort();
|
||||||
VertexPathCountMap path_counts;
|
VertexPathCountMap path_counts;
|
||||||
int end_count = 0;
|
size_t end_count = 0;
|
||||||
for (unsigned i = 0; i < path_ends_.size(); i++) {
|
for (unsigned i = 0; i < path_ends_.size(); i++) {
|
||||||
PathEnd *path_end = path_ends_[i];
|
PathEnd *path_end = path_ends_[i];
|
||||||
Vertex *vertex = path_end->vertex(sta_);
|
Vertex *vertex = path_end->vertex(sta_);
|
||||||
|
|
@ -220,7 +220,7 @@ PathGroup::iterator()
|
||||||
void
|
void
|
||||||
PathGroup::ensureSortedMaxPaths()
|
PathGroup::ensureSortedMaxPaths()
|
||||||
{
|
{
|
||||||
if (static_cast<int>(path_ends_.size()) > group_path_count_)
|
if (path_ends_.size() > group_path_count_)
|
||||||
prune();
|
prune();
|
||||||
else
|
else
|
||||||
sort();
|
sort();
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
#include "Corner.hh"
|
#include "Corner.hh"
|
||||||
#include "PathEnd.hh"
|
#include "PathEnd.hh"
|
||||||
#include "PathExpanded.hh"
|
#include "PathExpanded.hh"
|
||||||
#include "PathRef.hh"
|
#include "Path.hh"
|
||||||
#include "power/Power.hh"
|
#include "power/Power.hh"
|
||||||
#include "Sta.hh"
|
#include "Sta.hh"
|
||||||
|
|
||||||
|
|
@ -318,9 +318,9 @@ PropertyValue::PropertyValue(ClockSet *value) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyValue::PropertyValue(PathRefSeq *value) :
|
PropertyValue::PropertyValue(ConstPathSeq *value) :
|
||||||
type_(type_path_refs),
|
type_(type_paths),
|
||||||
path_refs_(new PathRefSeq(*value)),
|
paths_(new ConstPathSeq(*value)),
|
||||||
unit_(nullptr)
|
unit_(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -384,8 +384,8 @@ PropertyValue::PropertyValue(const PropertyValue &value) :
|
||||||
case Type::type_clks:
|
case Type::type_clks:
|
||||||
clks_ = value.clks_ ? new ClockSeq(*value.clks_) : nullptr;
|
clks_ = value.clks_ ? new ClockSeq(*value.clks_) : nullptr;
|
||||||
break;
|
break;
|
||||||
case Type::type_path_refs:
|
case Type::type_paths:
|
||||||
path_refs_ = value.path_refs_ ? new PathRefSeq(*value.path_refs_) : nullptr;
|
paths_ = value.paths_ ? new ConstPathSeq(*value.paths_) : nullptr;
|
||||||
break;
|
break;
|
||||||
case Type::type_pwr_activity:
|
case Type::type_pwr_activity:
|
||||||
pwr_activity_ = value.pwr_activity_;
|
pwr_activity_ = value.pwr_activity_;
|
||||||
|
|
@ -450,8 +450,8 @@ PropertyValue::PropertyValue(PropertyValue &&value) :
|
||||||
// Steal the value.
|
// Steal the value.
|
||||||
value.clks_ = nullptr;
|
value.clks_ = nullptr;
|
||||||
break;
|
break;
|
||||||
case Type::type_path_refs:
|
case Type::type_paths:
|
||||||
path_refs_ = value.path_refs_;
|
paths_ = value.paths_;
|
||||||
// Steal the value.
|
// Steal the value.
|
||||||
value.clks_ = nullptr;
|
value.clks_ = nullptr;
|
||||||
break;
|
break;
|
||||||
|
|
@ -473,8 +473,8 @@ PropertyValue::~PropertyValue()
|
||||||
case Type::type_pins:
|
case Type::type_pins:
|
||||||
delete pins_;
|
delete pins_;
|
||||||
break;
|
break;
|
||||||
case Type::type_path_refs:
|
case Type::type_paths:
|
||||||
delete path_refs_;
|
delete paths_;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -535,8 +535,8 @@ PropertyValue::operator=(const PropertyValue &value)
|
||||||
case Type::type_clks:
|
case Type::type_clks:
|
||||||
clks_ = value.clks_ ? new ClockSeq(*value.clks_) : nullptr;
|
clks_ = value.clks_ ? new ClockSeq(*value.clks_) : nullptr;
|
||||||
break;
|
break;
|
||||||
case Type::type_path_refs:
|
case Type::type_paths:
|
||||||
path_refs_ = value.path_refs_ ? new PathRefSeq(*value.path_refs_) : nullptr;
|
paths_ = value.paths_ ? new ConstPathSeq(*value.paths_) : nullptr;
|
||||||
break;
|
break;
|
||||||
case Type::type_pwr_activity:
|
case Type::type_pwr_activity:
|
||||||
pwr_activity_ = value.pwr_activity_;
|
pwr_activity_ = value.pwr_activity_;
|
||||||
|
|
@ -602,8 +602,8 @@ PropertyValue::operator=(PropertyValue &&value)
|
||||||
clks_ = value.clks_;
|
clks_ = value.clks_;
|
||||||
value.clks_ = nullptr;
|
value.clks_ = nullptr;
|
||||||
break;
|
break;
|
||||||
case Type::type_path_refs:
|
case Type::type_paths:
|
||||||
path_refs_ = value.path_refs_;
|
paths_ = value.paths_;
|
||||||
value.clks_ = nullptr;
|
value.clks_ = nullptr;
|
||||||
break;
|
break;
|
||||||
case Type::type_pwr_activity:
|
case Type::type_pwr_activity:
|
||||||
|
|
@ -650,7 +650,7 @@ PropertyValue::asString(const Network *network) const
|
||||||
case Type::type_none:
|
case Type::type_none:
|
||||||
case Type::type_pins:
|
case Type::type_pins:
|
||||||
case Type::type_clks:
|
case Type::type_clks:
|
||||||
case Type::type_path_refs:
|
case Type::type_paths:
|
||||||
case Type::type_pwr_activity:
|
case Type::type_pwr_activity:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -1271,10 +1271,10 @@ getProperty(PathEnd *end,
|
||||||
return PropertyValue(delayPropertyValue(end->slack(sta), sta));
|
return PropertyValue(delayPropertyValue(end->slack(sta), sta));
|
||||||
else if (stringEqual(property, "points")) {
|
else if (stringEqual(property, "points")) {
|
||||||
PathExpanded expanded(end->path(), sta);
|
PathExpanded expanded(end->path(), sta);
|
||||||
PathRefSeq paths;
|
ConstPathSeq paths;
|
||||||
for (size_t i = expanded.startIndex(); i < expanded.size(); i++) {
|
for (size_t i = expanded.startIndex(); i < expanded.size(); i++) {
|
||||||
const PathRef *path = expanded.path(i);
|
const Path *path = expanded.path(i);
|
||||||
paths.push_back(*path);
|
paths.push_back(path);
|
||||||
}
|
}
|
||||||
return PropertyValue(&paths);
|
return PropertyValue(&paths);
|
||||||
}
|
}
|
||||||
|
|
@ -1283,16 +1283,16 @@ getProperty(PathEnd *end,
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyValue
|
PropertyValue
|
||||||
getProperty(PathRef *path,
|
getProperty(Path *path,
|
||||||
const char *property,
|
const char *property,
|
||||||
Sta *sta)
|
Sta *sta)
|
||||||
{
|
{
|
||||||
if (stringEqual(property, "pin"))
|
if (stringEqual(property, "pin"))
|
||||||
return PropertyValue(path->pin(sta));
|
return PropertyValue(path->pin(sta));
|
||||||
else if (stringEqual(property, "arrival"))
|
else if (stringEqual(property, "arrival"))
|
||||||
return PropertyValue(delayPropertyValue(path->arrival(sta), sta));
|
return PropertyValue(delayPropertyValue(path->arrival(), sta));
|
||||||
else if (stringEqual(property, "required"))
|
else if (stringEqual(property, "required"))
|
||||||
return PropertyValue(delayPropertyValue(path->required(sta), sta));
|
return PropertyValue(delayPropertyValue(path->required(), sta));
|
||||||
else if (stringEqual(property, "slack"))
|
else if (stringEqual(property, "slack"))
|
||||||
return PropertyValue(delayPropertyValue(path->slack(sta), sta));
|
return PropertyValue(delayPropertyValue(path->slack(sta), sta));
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,12 @@
|
||||||
#include "GraphDelayCalc.hh"
|
#include "GraphDelayCalc.hh"
|
||||||
#include "ClkInfo.hh"
|
#include "ClkInfo.hh"
|
||||||
#include "Tag.hh"
|
#include "Tag.hh"
|
||||||
#include "PathVertex.hh"
|
|
||||||
#include "PathAnalysisPt.hh"
|
#include "PathAnalysisPt.hh"
|
||||||
#include "PathGroup.hh"
|
#include "PathGroup.hh"
|
||||||
#include "CheckMinPulseWidths.hh"
|
#include "CheckMinPulseWidths.hh"
|
||||||
#include "CheckMinPeriods.hh"
|
#include "CheckMinPeriods.hh"
|
||||||
#include "CheckMaxSkews.hh"
|
#include "CheckMaxSkews.hh"
|
||||||
#include "PathRef.hh"
|
#include "Path.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
#include "PathExpanded.hh"
|
#include "PathExpanded.hh"
|
||||||
#include "Latches.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 like a target because crpr and uncertainty are reported.
|
||||||
// It is always propagated, even if the clock is ideal.
|
// It is always propagated, even if the clock is ideal.
|
||||||
reportTgtClk(end, 0.0, true);
|
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)) {
|
if (!data_clk_path->isClock(this)) {
|
||||||
// Report the path from the clk network to the data check.
|
// Report the path from the clk network to the data check.
|
||||||
PathExpanded clk_expanded(data_clk_path, this);
|
PathExpanded clk_expanded(data_clk_path, this);
|
||||||
|
|
@ -1037,7 +1036,7 @@ string
|
||||||
ReportPath::pathStartpoint(const PathEnd *end,
|
ReportPath::pathStartpoint(const PathEnd *end,
|
||||||
const PathExpanded &expanded) const
|
const PathExpanded &expanded) const
|
||||||
{
|
{
|
||||||
const PathRef *start = expanded.startPath();
|
const Path *start = expanded.startPath();
|
||||||
Pin *pin = start->pin(graph_);
|
Pin *pin = start->pin(graph_);
|
||||||
const char *pin_name = cmd_network_->pathName(pin);
|
const char *pin_name = cmd_network_->pathName(pin);
|
||||||
if (network_->isTopLevelPort(pin)) {
|
if (network_->isTopLevelPort(pin)) {
|
||||||
|
|
@ -1103,7 +1102,7 @@ ReportPath::reportJson(const PathEnd *end,
|
||||||
sdc_network_->pathName(endpoint));
|
sdc_network_->pathName(endpoint));
|
||||||
|
|
||||||
const ClockEdge *src_clk_edge = end->sourceClkEdge(this);
|
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) {
|
if (src_clk_edge) {
|
||||||
stringAppend(result, " \"source_clock\": \"%s\",\n",
|
stringAppend(result, " \"source_clock\": \"%s\",\n",
|
||||||
src_clk_edge->clock()->name());
|
src_clk_edge->clock()->name());
|
||||||
|
|
@ -1181,7 +1180,7 @@ ReportPath::reportJson(const PathExpanded &expanded,
|
||||||
{
|
{
|
||||||
stringAppend(result, "%*s\"%s\": [\n", indent, "", path_name);
|
stringAppend(result, "%*s\"%s\": [\n", indent, "", path_name);
|
||||||
for (size_t i = 0; i < expanded.size(); i++) {
|
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 Pin *pin = path->vertex(this)->pin();
|
||||||
const Net *net = network_->net(pin);
|
const Net *net = network_->net(pin);
|
||||||
const Instance *inst = network_->instance(pin);
|
const Instance *inst = network_->instance(pin);
|
||||||
|
|
@ -1238,7 +1237,7 @@ ReportPath::reportJson(const PathExpanded &expanded,
|
||||||
|
|
||||||
stringAppend(result, "%*s \"arrival\": %.3e,\n",
|
stringAppend(result, "%*s \"arrival\": %.3e,\n",
|
||||||
indent, "",
|
indent, "",
|
||||||
delayAsFloat(path->arrival(this)));
|
delayAsFloat(path->arrival()));
|
||||||
if (is_driver)
|
if (is_driver)
|
||||||
stringAppend(result, "%*s \"capacitance\": %.3e,\n",
|
stringAppend(result, "%*s \"capacitance\": %.3e,\n",
|
||||||
indent, "",
|
indent, "",
|
||||||
|
|
@ -1592,7 +1591,7 @@ ReportPath::reportShort(const MaxSkewCheck *check) const
|
||||||
reportDescription(what.c_str(), line);
|
reportDescription(what.c_str(), line);
|
||||||
const EarlyLate *early_late = EarlyLate::early();
|
const EarlyLate *early_late = EarlyLate::early();
|
||||||
reportSpaceFieldDelay(check->maxSkew(this), early_late, line);
|
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);
|
reportSpaceSlack(check->slack(this), line);
|
||||||
report_->reportLineString(line);
|
report_->reportLineString(line);
|
||||||
}
|
}
|
||||||
|
|
@ -1621,7 +1620,7 @@ ReportPath::reportVerbose(const MaxSkewCheck *check) const
|
||||||
|
|
||||||
reportDashLine();
|
reportDashLine();
|
||||||
reportLine("allowable skew", check->maxSkew(this), EarlyLate::early());
|
reportLine("allowable skew", check->maxSkew(this), EarlyLate::early());
|
||||||
reportLine("actual skew", check->skew(this), EarlyLate::late());
|
reportLine("actual skew", check->skew(), EarlyLate::late());
|
||||||
reportDashLine();
|
reportDashLine();
|
||||||
reportSlack(check->slack(this));
|
reportSlack(check->slack(this));
|
||||||
}
|
}
|
||||||
|
|
@ -1629,7 +1628,7 @@ ReportPath::reportVerbose(const MaxSkewCheck *check) const
|
||||||
// Based on reportTgtClk.
|
// Based on reportTgtClk.
|
||||||
void
|
void
|
||||||
ReportPath::reportSkewClkPath(const char *arrival_msg,
|
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 ClockEdge *clk_edge = clk_path->clkEdge(this);
|
||||||
const Clock *clk = clk_edge->clock();
|
const Clock *clk = clk_edge->clock();
|
||||||
|
|
@ -1767,9 +1766,9 @@ ReportPath::reportStartpoint(const PathEnd *end,
|
||||||
const PathExpanded &expanded) const
|
const PathExpanded &expanded) const
|
||||||
{
|
{
|
||||||
const Path *path = end->path();
|
const Path *path = end->path();
|
||||||
const PathRef *start = expanded.startPath();
|
const Path *start = expanded.startPath();
|
||||||
const TimingArc *prev_arc = expanded.startPrevArc();
|
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 Pin *pin = start->pin(graph_);
|
||||||
const ClockEdge *clk_edge = path->clkEdge(this);
|
const ClockEdge *clk_edge = path->clkEdge(this);
|
||||||
const Clock *clk = path->clock(search_);
|
const Clock *clk = path->clock(search_);
|
||||||
|
|
@ -1795,10 +1794,9 @@ ReportPath::reportStartpoint(const PathEnd *end,
|
||||||
const char *inst_name = cmd_network_->pathName(inst);
|
const char *inst_name = cmd_network_->pathName(inst);
|
||||||
if (clk_edge) {
|
if (clk_edge) {
|
||||||
const RiseFall *clk_rf = clk_edge->transition();
|
const RiseFall *clk_rf = clk_edge->transition();
|
||||||
PathRef clk_path;
|
const Path *clk_path = expanded.clkPath();
|
||||||
expanded.clkPath(clk_path);
|
bool clk_inverted = clk_path
|
||||||
bool clk_inverted = !clk_path.isNull()
|
&& clk_rf != clk_path->transition(this);
|
||||||
&& clk_rf != clk_path.transition(this);
|
|
||||||
string clk_name = clkName(clk, clk_inverted);
|
string clk_name = clkName(clk, clk_inverted);
|
||||||
const char *reg_desc = edgeRegLatchDesc(prev_edge, prev_arc);
|
const char *reg_desc = edgeRegLatchDesc(prev_edge, prev_arc);
|
||||||
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
auto reason = stdstrPrint("%s clocked by %s", reg_desc, clk_name.c_str());
|
||||||
|
|
@ -1830,8 +1828,8 @@ ReportPath::reportStartpoint(const PathEnd *end,
|
||||||
bool
|
bool
|
||||||
ReportPath::pathFromClkPin(const PathExpanded &expanded) const
|
ReportPath::pathFromClkPin(const PathExpanded &expanded) const
|
||||||
{
|
{
|
||||||
const PathRef *start = expanded.startPath();
|
const Path *start = expanded.startPath();
|
||||||
const PathRef *end = expanded.endPath();
|
const Path *end = expanded.endPath();
|
||||||
const Pin *start_pin = start->pin(graph_);
|
const Pin *start_pin = start->pin(graph_);
|
||||||
return pathFromClkPin(end, start_pin);
|
return pathFromClkPin(end, start_pin);
|
||||||
}
|
}
|
||||||
|
|
@ -2069,13 +2067,12 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
||||||
bool path_from_input = false;
|
bool path_from_input = false;
|
||||||
bool input_has_ref_path = false;
|
bool input_has_ref_path = false;
|
||||||
Arrival clk_delay, clk_end_time;
|
Arrival clk_delay, clk_end_time;
|
||||||
PathRef clk_path;
|
const Path *clk_path = expanded.clkPath();
|
||||||
expanded.clkPath(clk_path);
|
|
||||||
const RiseFall *clk_end_rf;
|
const RiseFall *clk_end_rf;
|
||||||
if (!clk_path.isNull()) {
|
if (clk_path) {
|
||||||
clk_end_time = search_->clkPathArrival(&clk_path) + time_offset;
|
clk_end_time = search_->clkPathArrival(clk_path) + time_offset;
|
||||||
clk_delay = clk_end_time - clk_time;
|
clk_delay = clk_end_time - clk_time;
|
||||||
clk_end_rf = clk_path.transition(this);
|
clk_end_rf = clk_path->transition(this);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Path from input port or clk used as data.
|
// 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_delay = clk_insertion + clk_latency;
|
||||||
clk_end_time = clk_time + clk_delay;
|
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);
|
const InputDelay *input_delay = pathInputDelay(first_path);
|
||||||
if (input_delay) {
|
if (input_delay) {
|
||||||
path_from_input = true;
|
path_from_input = true;
|
||||||
const Pin *ref_pin = input_delay->refPin();
|
const Pin *ref_pin = input_delay->refPin();
|
||||||
if (ref_pin && clk->isPropagated()) {
|
if (ref_pin && clk->isPropagated()) {
|
||||||
PathRef ref_path;
|
Path ref_path;
|
||||||
pathInputDelayRefPath(first_path, input_delay, ref_path);
|
pathInputDelayRefPath(first_path, input_delay, ref_path);
|
||||||
if (!ref_path.isNull()) {
|
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_delay = ref_end_time - clk_time;
|
||||||
clk_end_time = ref_end_time + time_offset;
|
clk_end_time = ref_end_time + time_offset;
|
||||||
input_has_ref_path = true;
|
input_has_ref_path = true;
|
||||||
|
|
@ -2105,8 +2102,7 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
||||||
bool clk_used_as_data = pathFromClkPin(expanded);
|
bool clk_used_as_data = pathFromClkPin(expanded);
|
||||||
bool is_prop = isPropagated(path);
|
bool is_prop = isPropagated(path);
|
||||||
const EarlyLate *early_late = min_max;
|
const EarlyLate *early_late = min_max;
|
||||||
if (reportGenClkSrcPath(clk_path.isNull() ? nullptr : &clk_path,
|
if (reportGenClkSrcPath(clk_path, clk, clk_rf, min_max, early_late)
|
||||||
clk, clk_rf, min_max, early_late)
|
|
||||||
&& !(path_from_input && !input_has_ref_path)) {
|
&& !(path_from_input && !input_has_ref_path)) {
|
||||||
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time,
|
reportClkLine(clk, clk_name.c_str(), clk_end_rf, clk_time,
|
||||||
min_max);
|
min_max);
|
||||||
|
|
@ -2137,7 +2133,7 @@ ReportPath::reportSrcClkAndPath(const Path *path,
|
||||||
reportPath1(path, expanded, true, time_offset);
|
reportPath1(path, expanded, true, time_offset);
|
||||||
else {
|
else {
|
||||||
Arrival clk_arrival = clk_end_time;
|
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;
|
Delay clk_delay = end_arrival - clk_arrival;
|
||||||
reportLine("clock network delay", clk_delay,
|
reportLine("clock network delay", clk_delay,
|
||||||
end_arrival, early_late);
|
end_arrival, early_late);
|
||||||
|
|
@ -2395,10 +2391,10 @@ ReportPath::reportGenClkSrcPath1(const Clock *clk,
|
||||||
{
|
{
|
||||||
PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late);
|
PathAnalysisPt *insert_ap = path_ap->insertionAnalysisPt(early_late);
|
||||||
const MinMax *min_max = path_ap->pathMinMax();
|
const MinMax *min_max = path_ap->pathMinMax();
|
||||||
PathVertex src_path =
|
Path *src_path = search_->genclks()->srcPath(clk, clk_pin,
|
||||||
search_->genclks()->srcPath(clk, clk_pin, clk_rf, insert_ap);
|
clk_rf, insert_ap);
|
||||||
if (!src_path.isNull()) {
|
if (src_path) {
|
||||||
ClkInfo *src_clk_info = src_path.clkInfo(search_);
|
ClkInfo *src_clk_info = src_path->clkInfo(this);
|
||||||
const ClockEdge *src_clk_edge = src_clk_info->clkEdge();
|
const ClockEdge *src_clk_edge = src_clk_info->clkEdge();
|
||||||
const Clock *src_clk = src_clk_info->clock();
|
const Clock *src_clk = src_clk_info->clock();
|
||||||
if (src_clk) {
|
if (src_clk) {
|
||||||
|
|
@ -2419,12 +2415,12 @@ ReportPath::reportGenClkSrcPath1(const Clock *clk,
|
||||||
early_late, path_ap);
|
early_late, path_ap);
|
||||||
reportClkSrcLatency(insertion, gclk_time, early_late);
|
reportClkSrcLatency(insertion, gclk_time, early_late);
|
||||||
}
|
}
|
||||||
PathExpanded src_expanded(&src_path, this);
|
PathExpanded src_expanded(src_path, this);
|
||||||
reportPath4(&src_path, src_expanded, skip_first_path, false,
|
reportPath4(src_path, src_expanded, skip_first_path, false,
|
||||||
clk_used_as_data, gclk_time);
|
clk_used_as_data, gclk_time);
|
||||||
if (!clk->isPropagated())
|
if (!clk->isPropagated())
|
||||||
reportLine("clock network delay (ideal)", 0.0,
|
reportLine("clock network delay (ideal)", 0.0,
|
||||||
src_path.arrival(this), min_max);
|
src_path->arrival(), min_max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -2433,7 +2429,7 @@ ReportPath::reportGenClkSrcPath1(const Clock *clk,
|
||||||
else if (!clk_used_as_data)
|
else if (!clk_used_as_data)
|
||||||
reportLine("clock network delay (ideal)", 0.0, gclk_time, min_max);
|
reportLine("clock network delay (ideal)", 0.0, gclk_time, min_max);
|
||||||
}
|
}
|
||||||
return !src_path.isNull();
|
return src_path != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -2610,22 +2606,21 @@ ReportPath::reportPath1(const Path *path,
|
||||||
bool clk_used_as_data,
|
bool clk_used_as_data,
|
||||||
float time_offset) const
|
float time_offset) const
|
||||||
{
|
{
|
||||||
const PathRef *d_path, *q_path;
|
const Path *d_path, *q_path;
|
||||||
Edge *d_q_edge;
|
Edge *d_q_edge;
|
||||||
expanded.latchPaths(d_path, q_path, d_q_edge);
|
expanded.latchPaths(d_path, q_path, d_q_edge);
|
||||||
if (d_path) {
|
if (d_path) {
|
||||||
Arrival latch_time_given, latch_enable_time;
|
Arrival latch_time_given, latch_enable_time;
|
||||||
PathVertex latch_enable_path;
|
Path *latch_enable_path;
|
||||||
latches_->latchTimeGivenToStartpoint(d_path, q_path, d_q_edge,
|
latches_->latchTimeGivenToStartpoint(d_path, q_path, d_q_edge,
|
||||||
latch_time_given,
|
latch_time_given, latch_enable_path);
|
||||||
latch_enable_path);
|
if (latch_enable_path) {
|
||||||
if (!latch_enable_path.isNull()) {
|
const EarlyLate *early_late = latch_enable_path->minMax(this);
|
||||||
const EarlyLate *early_late = latch_enable_path.minMax(this);
|
latch_enable_time = search_->clkPathArrival(latch_enable_path);
|
||||||
latch_enable_time = search_->clkPathArrival(&latch_enable_path);
|
|
||||||
if (reportClkPath()) {
|
if (reportClkPath()) {
|
||||||
PathExpanded enable_expanded(&latch_enable_path, this);
|
PathExpanded enable_expanded(latch_enable_path, this);
|
||||||
// Report the path to the latch enable.
|
// Report the path to the latch enable.
|
||||||
reportPath2(&latch_enable_path, enable_expanded, false,
|
reportPath2(latch_enable_path, enable_expanded, false,
|
||||||
time_offset);
|
time_offset);
|
||||||
}
|
}
|
||||||
Arrival time = latch_enable_time + latch_time_given;
|
Arrival time = latch_enable_time + latch_time_given;
|
||||||
|
|
@ -2689,8 +2684,8 @@ ReportPath::reportPath4(const Path *path,
|
||||||
Arrival prev_time(0.0);
|
Arrival prev_time(0.0);
|
||||||
if (skip_first_path) {
|
if (skip_first_path) {
|
||||||
path_first_index = 1;
|
path_first_index = 1;
|
||||||
const PathRef *start = expanded.path(0);
|
const Path *start = expanded.path(0);
|
||||||
prev_time = start->arrival(this) + time_offset;
|
prev_time = start->arrival() + time_offset;
|
||||||
}
|
}
|
||||||
size_t path_last_index = expanded.size() - 1;
|
size_t path_last_index = expanded.size() - 1;
|
||||||
if (skip_last_path
|
if (skip_last_path
|
||||||
|
|
@ -2719,15 +2714,14 @@ ReportPath::reportPath5(const Path *path,
|
||||||
const MinMax *min_max = path->minMax(this);
|
const MinMax *min_max = path->minMax(this);
|
||||||
DcalcAnalysisPt *dcalc_ap = path->pathAnalysisPt(this)->dcalcAnalysisPt();
|
DcalcAnalysisPt *dcalc_ap = path->pathAnalysisPt(this)->dcalcAnalysisPt();
|
||||||
DcalcAPIndex ap_index = dcalc_ap->index();
|
DcalcAPIndex ap_index = dcalc_ap->index();
|
||||||
PathRef clk_path;
|
const Path *clk_path = expanded.clkPath();
|
||||||
expanded.clkPath(clk_path);
|
Vertex *clk_start = clk_path ? clk_path->vertex(this) : nullptr;
|
||||||
Vertex *clk_start = clk_path.vertex(this);
|
|
||||||
for (size_t i = path_first_index; i <= path_last_index; i++) {
|
for (size_t i = path_first_index; i <= path_last_index; i++) {
|
||||||
const PathRef *path1 = expanded.path(i);
|
const Path *path1 = expanded.path(i);
|
||||||
TimingArc *prev_arc = expanded.prevArc(i);
|
const TimingArc *prev_arc = path1->prevArc(this);
|
||||||
Vertex *vertex = path1->vertex(this);
|
Vertex *vertex = path1->vertex(this);
|
||||||
Pin *pin = vertex->pin();
|
Pin *pin = vertex->pin();
|
||||||
Arrival time = path1->arrival(this) + time_offset;
|
Arrival time = path1->arrival() + time_offset;
|
||||||
Delay incr = 0.0;
|
Delay incr = 0.0;
|
||||||
const char *line_case = nullptr;
|
const char *line_case = nullptr;
|
||||||
bool is_clk_start = path1->vertex(this) == clk_start;
|
bool is_clk_start = path1->vertex(this) == clk_start;
|
||||||
|
|
@ -2747,7 +2741,7 @@ ReportPath::reportPath5(const Path *path,
|
||||||
// First path.
|
// First path.
|
||||||
reportInputExternalDelay(path1, time_offset);
|
reportInputExternalDelay(path1, time_offset);
|
||||||
size_t next_index = i + 1;
|
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)
|
if (network_->isTopLevelPort(pin)
|
||||||
&& next_path
|
&& next_path
|
||||||
&& !nextArcAnnotated(next_path, next_index, expanded, ap_index)
|
&& !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
|
// The delay calculator annotates wire delays on the edges
|
||||||
// from the input to the loads. Report the wire delay on the
|
// from the input to the loads. Report the wire delay on the
|
||||||
// input pin instead.
|
// 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);
|
incr = delayIncr(next_time, time, min_max);
|
||||||
time = next_time;
|
time = next_time;
|
||||||
line_case = "input_drive";
|
line_case = "input_drive";
|
||||||
|
|
@ -2833,7 +2827,7 @@ ReportPath::reportPath5(const Path *path,
|
||||||
prev_time = time;
|
prev_time = time;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
reportHierPinsThru(path1, prev_arc);
|
reportHierPinsThru(path1);
|
||||||
if (report_input_pin_
|
if (report_input_pin_
|
||||||
|| (i == 0)
|
|| (i == 0)
|
||||||
|| (i == path_last_index)
|
|| (i == path_last_index)
|
||||||
|
|
@ -2852,11 +2846,10 @@ ReportPath::reportPath5(const Path *path,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ReportPath::reportHierPinsThru(const Path *path,
|
ReportPath::reportHierPinsThru(const Path *path) const
|
||||||
const TimingArc *prev_arc) const
|
|
||||||
{
|
{
|
||||||
if (report_hier_pins_) {
|
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()) {
|
if (prev_edge && prev_edge->isWire()) {
|
||||||
for (const Pin *hpin : hierPinsThruEdge(prev_edge, network_, graph_)) {
|
for (const Pin *hpin : hierPinsThruEdge(prev_edge, network_, graph_)) {
|
||||||
const string what = descriptionField(hpin);
|
const string what = descriptionField(hpin);
|
||||||
|
|
@ -2880,13 +2873,13 @@ ReportPath::delayIncr(Delay time,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ReportPath::nextArcAnnotated(const PathRef *next_path,
|
ReportPath::nextArcAnnotated(const Path *next_path,
|
||||||
size_t next_index,
|
size_t next_index,
|
||||||
const PathExpanded &expanded,
|
const PathExpanded &expanded,
|
||||||
DcalcAPIndex ap_index) const
|
DcalcAPIndex ap_index) const
|
||||||
{
|
{
|
||||||
TimingArc *arc = expanded.prevArc(next_index);
|
const TimingArc *arc = expanded.path(next_index)->prevArc(this);
|
||||||
Edge *edge = next_path->prevEdge(arc, this);
|
Edge *edge = next_path->prevEdge(this);
|
||||||
return graph_->arcDelayAnnotated(edge, arc, ap_index);
|
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_);
|
const Pin *first_pin = first_path->pin(graph_);
|
||||||
if (!pathFromClkPin(first_path, first_pin)) {
|
if (!pathFromClkPin(first_path, first_pin)) {
|
||||||
const RiseFall *rf = first_path->transition(this);
|
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);
|
const EarlyLate *early_late = first_path->minMax(this);
|
||||||
InputDelay *input_delay = pathInputDelay(first_path);
|
InputDelay *input_delay = pathInputDelay(first_path);
|
||||||
if (input_delay) {
|
if (input_delay) {
|
||||||
const Pin *ref_pin = input_delay->refPin();
|
const Pin *ref_pin = input_delay->refPin();
|
||||||
if (ref_pin) {
|
if (ref_pin) {
|
||||||
PathRef ref_path;
|
Path ref_path;
|
||||||
pathInputDelayRefPath(first_path, input_delay, ref_path);
|
pathInputDelayRefPath(first_path, input_delay, ref_path);
|
||||||
if (!ref_path.isNull() && reportClkPath()) {
|
if (!ref_path.isNull() && reportClkPath()) {
|
||||||
PathExpanded ref_expanded(&ref_path, this);
|
PathExpanded ref_expanded(&ref_path, this);
|
||||||
|
|
@ -3018,7 +3011,7 @@ void
|
||||||
ReportPath::pathInputDelayRefPath(const Path *path,
|
ReportPath::pathInputDelayRefPath(const Path *path,
|
||||||
const InputDelay *input_delay,
|
const InputDelay *input_delay,
|
||||||
// Return value.
|
// Return value.
|
||||||
PathRef &ref_path) const
|
Path &ref_path) const
|
||||||
{
|
{
|
||||||
const Pin *ref_pin = input_delay->refPin();
|
const Pin *ref_pin = input_delay->refPin();
|
||||||
const RiseFall *ref_rf = input_delay->refTransition();
|
const RiseFall *ref_rf = input_delay->refTransition();
|
||||||
|
|
@ -3028,10 +3021,10 @@ ReportPath::pathInputDelayRefPath(const Path *path,
|
||||||
const ClockEdge *clk_edge = path->clkEdge(this);
|
const ClockEdge *clk_edge = path->clkEdge(this);
|
||||||
VertexPathIterator path_iter(ref_vertex, ref_rf, path_ap, this);
|
VertexPathIterator path_iter(ref_vertex, ref_rf, path_ap, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
if (path->isClock(this)
|
if (path->isClock(this)
|
||||||
&& path->clkEdge(this) == clk_edge) {
|
&& path->clkEdge(this) == clk_edge) {
|
||||||
ref_path.init(path);
|
ref_path = path;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -326,8 +326,7 @@ protected:
|
||||||
bool report_clk_path,
|
bool report_clk_path,
|
||||||
Arrival prev_time,
|
Arrival prev_time,
|
||||||
float time_offset) const;
|
float time_offset) const;
|
||||||
void reportHierPinsThru(const Path *path,
|
void reportHierPinsThru(const Path *path) const;
|
||||||
const TimingArc *prev_arc) const;
|
|
||||||
void reportInputExternalDelay(const Path *path,
|
void reportInputExternalDelay(const Path *path,
|
||||||
float time_offset) const;
|
float time_offset) const;
|
||||||
void reportLine(const char *what,
|
void reportLine(const char *what,
|
||||||
|
|
@ -426,7 +425,7 @@ protected:
|
||||||
const MinMax *min_max) const;
|
const MinMax *min_max) const;
|
||||||
const char *mpwCheckHiLow(const MinPulseWidthCheck *check) const;
|
const char *mpwCheckHiLow(const MinPulseWidthCheck *check) const;
|
||||||
void reportSkewClkPath(const char *arrival_msg,
|
void reportSkewClkPath(const char *arrival_msg,
|
||||||
const PathVertex *clk_path) const;
|
const Path *clk_path) const;
|
||||||
const char *edgeRegLatchDesc(const Edge *edge,
|
const char *edgeRegLatchDesc(const Edge *edge,
|
||||||
const TimingArc *arc) const;
|
const TimingArc *arc) const;
|
||||||
const char *checkRegLatchDesc(const TimingRole *role,
|
const char *checkRegLatchDesc(const TimingRole *role,
|
||||||
|
|
@ -434,7 +433,7 @@ protected:
|
||||||
const char *regDesc(const RiseFall *clk_rf) const;
|
const char *regDesc(const RiseFall *clk_rf) const;
|
||||||
const char *latchDesc(const RiseFall *clk_rf) const;
|
const char *latchDesc(const RiseFall *clk_rf) const;
|
||||||
void pathClkPath(const Path *path,
|
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;
|
||||||
bool isPropagated(const Path *clk_path,
|
bool isPropagated(const Path *clk_path,
|
||||||
const Clock *clk) const;
|
const Clock *clk) const;
|
||||||
|
|
@ -443,10 +442,10 @@ protected:
|
||||||
const Pin *start_pin) const;
|
const Pin *start_pin) const;
|
||||||
void latchPaths(const Path *path,
|
void latchPaths(const Path *path,
|
||||||
// Return values.
|
// Return values.
|
||||||
PathRef &d_path,
|
Path &d_path,
|
||||||
PathRef &q_path,
|
Path &q_path,
|
||||||
Edge *&d_q_edge) const;
|
Edge *&d_q_edge) const;
|
||||||
bool nextArcAnnotated(const PathRef *next_path,
|
bool nextArcAnnotated(const Path *next_path,
|
||||||
size_t next_index,
|
size_t next_index,
|
||||||
const PathExpanded &expanded,
|
const PathExpanded &expanded,
|
||||||
DcalcAPIndex ap_index) const;
|
DcalcAPIndex ap_index) const;
|
||||||
|
|
@ -458,7 +457,7 @@ protected:
|
||||||
void pathInputDelayRefPath(const Path *path,
|
void pathInputDelayRefPath(const Path *path,
|
||||||
const InputDelay *input_delay,
|
const InputDelay *input_delay,
|
||||||
// Return value.
|
// Return value.
|
||||||
PathRef &ref_path) const;
|
Path &ref_path) const;
|
||||||
const char *asRisingFalling(const RiseFall *rf) const;
|
const char *asRisingFalling(const RiseFall *rf) const;
|
||||||
const char *asRiseFall(const RiseFall *rf) const;
|
const char *asRiseFall(const RiseFall *rf) const;
|
||||||
Delay delayIncr(Delay time,
|
Delay delayIncr(Delay time,
|
||||||
|
|
|
||||||
467
search/Search.cc
467
search/Search.cc
|
|
@ -54,9 +54,7 @@
|
||||||
#include "Bfs.hh"
|
#include "Bfs.hh"
|
||||||
#include "Corner.hh"
|
#include "Corner.hh"
|
||||||
#include "Sim.hh"
|
#include "Sim.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "PathPrev.hh"
|
|
||||||
#include "PathRef.hh"
|
|
||||||
#include "ClkInfo.hh"
|
#include "ClkInfo.hh"
|
||||||
#include "Tag.hh"
|
#include "Tag.hh"
|
||||||
#include "TagGroup.hh"
|
#include "TagGroup.hh"
|
||||||
|
|
@ -142,11 +140,7 @@ DynLoopSrchPred::hasPendingLoopPaths(Edge *edge,
|
||||||
Corners *corners = search->corners();
|
Corners *corners = search->corners();
|
||||||
Vertex *from_vertex = edge->from(graph);
|
Vertex *from_vertex = edge->from(graph);
|
||||||
TagGroup *prev_tag_group = search->tagGroup(from_vertex);
|
TagGroup *prev_tag_group = search->tagGroup(from_vertex);
|
||||||
ArrivalMap::Iterator arrival_iter(tag_bldr_->arrivalMap());
|
for (auto const [from_tag, path_index] : tag_bldr_->pathIndexMap()) {
|
||||||
while (arrival_iter.hasNext()) {
|
|
||||||
Tag *from_tag;
|
|
||||||
int arrival_index;
|
|
||||||
arrival_iter.next(from_tag, arrival_index);
|
|
||||||
if (from_tag->isLoop()) {
|
if (from_tag->isLoop()) {
|
||||||
// Loop false path exceptions apply to rise/fall edges so to_rf
|
// Loop false path exceptions apply to rise/fall edges so to_rf
|
||||||
// does not matter.
|
// does not matter.
|
||||||
|
|
@ -255,7 +249,6 @@ Search::init(StaState *sta)
|
||||||
path_groups_ = nullptr;
|
path_groups_ = nullptr;
|
||||||
endpoints_ = nullptr;
|
endpoints_ = nullptr;
|
||||||
invalid_endpoints_ = nullptr;
|
invalid_endpoints_ = nullptr;
|
||||||
always_save_prev_paths_ = true;
|
|
||||||
filter_ = nullptr;
|
filter_ = nullptr;
|
||||||
filter_from_ = nullptr;
|
filter_from_ = nullptr;
|
||||||
filter_to_ = nullptr;
|
filter_to_ = nullptr;
|
||||||
|
|
@ -274,6 +267,7 @@ Search::initVars()
|
||||||
|
|
||||||
Search::~Search()
|
Search::~Search()
|
||||||
{
|
{
|
||||||
|
deletePathGroups();
|
||||||
deletePaths();
|
deletePaths();
|
||||||
deleteTags();
|
deleteTags();
|
||||||
delete tag_set_;
|
delete tag_set_;
|
||||||
|
|
@ -299,7 +293,6 @@ Search::~Search()
|
||||||
delete genclks_;
|
delete genclks_;
|
||||||
delete filtered_arrivals_;
|
delete filtered_arrivals_;
|
||||||
deleteFilter();
|
deleteFilter();
|
||||||
deletePathGroups();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -433,6 +426,8 @@ Search::deletePathsIncr(Vertex *vertex)
|
||||||
void
|
void
|
||||||
Search::deletePaths(Vertex *vertex)
|
Search::deletePaths(Vertex *vertex)
|
||||||
{
|
{
|
||||||
|
debugPrint(debug_, "search", 4, "delete paths %s",
|
||||||
|
vertex->name(network_));
|
||||||
TagGroup *tag_group = tagGroup(vertex);
|
TagGroup *tag_group = tagGroup(vertex);
|
||||||
if (tag_group)
|
if (tag_group)
|
||||||
graph_->deletePaths(vertex);
|
graph_->deletePaths(vertex);
|
||||||
|
|
@ -450,8 +445,8 @@ Search::findPathEnds(ExceptionFrom *from,
|
||||||
bool unconstrained,
|
bool unconstrained,
|
||||||
const Corner *corner,
|
const Corner *corner,
|
||||||
const MinMaxAll *min_max,
|
const MinMaxAll *min_max,
|
||||||
int group_path_count,
|
size_t group_path_count,
|
||||||
int endpoint_path_count,
|
size_t endpoint_path_count,
|
||||||
bool unique_pins,
|
bool unique_pins,
|
||||||
float slack_min,
|
float slack_min,
|
||||||
float slack_max,
|
float slack_max,
|
||||||
|
|
@ -490,9 +485,6 @@ Search::findFilteredArrivals(ExceptionFrom *from,
|
||||||
bool thru_latches)
|
bool thru_latches)
|
||||||
{
|
{
|
||||||
unconstrained_paths_ = unconstrained;
|
unconstrained_paths_ = unconstrained;
|
||||||
// Delete results from last findPathEnds.
|
|
||||||
// Filtered arrivals are deleted by Sta::searchPreamble.
|
|
||||||
deletePathGroups();
|
|
||||||
checkFromThrusTo(from, thrus, to);
|
checkFromThrusTo(from, thrus, to);
|
||||||
filter_from_ = from;
|
filter_from_ = from;
|
||||||
filter_to_ = to;
|
filter_to_ = to;
|
||||||
|
|
@ -618,6 +610,7 @@ Search::findFilteredArrivals(bool thru_latches)
|
||||||
int arrival_count = arrival_iter_->visitParallel(max_level,
|
int arrival_count = arrival_iter_->visitParallel(max_level,
|
||||||
arrival_visitor_);
|
arrival_visitor_);
|
||||||
deleteTagsPrev();
|
deleteTagsPrev();
|
||||||
|
genclks_->updateSrcPathPrevs();
|
||||||
debugPrint(debug_, "search", 1, "found %d arrivals", arrival_count);
|
debugPrint(debug_, "search", 1, "found %d arrivals", arrival_count);
|
||||||
}
|
}
|
||||||
arrivals_exist_ = true;
|
arrivals_exist_ = true;
|
||||||
|
|
@ -725,6 +718,20 @@ Search::deleteVertexBefore(Vertex *vertex)
|
||||||
invalid_endpoints_->erase(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
|
bool
|
||||||
Search::arrivalsValid()
|
Search::arrivalsValid()
|
||||||
{
|
{
|
||||||
|
|
@ -740,6 +747,7 @@ Search::arrivalsInvalid()
|
||||||
// Delete paths to make sure no state is left over.
|
// Delete paths to make sure no state is left over.
|
||||||
// For example, set_disable_timing strands a vertex, which means
|
// For example, set_disable_timing strands a vertex, which means
|
||||||
// the search won't revisit it to clear the previous arrival.
|
// the search won't revisit it to clear the previous arrival.
|
||||||
|
deletePathGroups();
|
||||||
deletePaths();
|
deletePaths();
|
||||||
deleteTags();
|
deleteTags();
|
||||||
genclks_->clear();
|
genclks_->clear();
|
||||||
|
|
@ -865,6 +873,7 @@ Search::findClkArrivals()
|
||||||
arrival_visitor_->init(false, &search_clk);
|
arrival_visitor_->init(false, &search_clk);
|
||||||
arrival_iter_->visitParallel(levelize_->maxLevel(), arrival_visitor_);
|
arrival_iter_->visitParallel(levelize_->maxLevel(), arrival_visitor_);
|
||||||
deleteTagsPrev();
|
deleteTagsPrev();
|
||||||
|
genclks_->updateSrcPathPrevs();
|
||||||
arrivals_exist_ = true;
|
arrivals_exist_ = true;
|
||||||
stats.report("Find clk arrivals");
|
stats.report("Find clk arrivals");
|
||||||
}
|
}
|
||||||
|
|
@ -1036,6 +1045,7 @@ Search::findArrivals1(Level level)
|
||||||
Stats stats(debug_, report_);
|
Stats stats(debug_, report_);
|
||||||
int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_);
|
int arrival_count = arrival_iter_->visitParallel(level, arrival_visitor_);
|
||||||
deleteTagsPrev();
|
deleteTagsPrev();
|
||||||
|
genclks_->updateSrcPathPrevs();
|
||||||
stats.report("Find arrivals");
|
stats.report("Find arrivals");
|
||||||
if (arrival_iter_->empty()
|
if (arrival_iter_->empty()
|
||||||
&& invalid_arrivals_->empty()) {
|
&& invalid_arrivals_->empty()) {
|
||||||
|
|
@ -1043,7 +1053,7 @@ Search::findArrivals1(Level level)
|
||||||
arrivals_at_endpoints_exist_ = true;
|
arrivals_at_endpoints_exist_ = true;
|
||||||
}
|
}
|
||||||
arrivals_exist_ = true;
|
arrivals_exist_ = true;
|
||||||
debugPrint(debug_, "search", 1, "found %u arrivals", arrival_count);
|
debugPrint(debug_, "search", 1, "found %d arrivals", arrival_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1066,8 +1076,7 @@ Search::findArrivalsSeed()
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ArrivalVisitor::ArrivalVisitor(const StaState *sta) :
|
ArrivalVisitor::ArrivalVisitor(const StaState *sta) :
|
||||||
PathVisitor(nullptr, sta),
|
PathVisitor(nullptr, sta)
|
||||||
always_save_prev_paths_(true)
|
|
||||||
{
|
{
|
||||||
init0();
|
init0();
|
||||||
init(true);
|
init(true);
|
||||||
|
|
@ -1104,8 +1113,6 @@ ArrivalVisitor::init(bool always_to_endpoints,
|
||||||
always_to_endpoints_ = always_to_endpoints;
|
always_to_endpoints_ = always_to_endpoints;
|
||||||
pred_ = pred;
|
pred_ = pred;
|
||||||
crpr_active_ = sdc_->crprActive();
|
crpr_active_ = sdc_->crprActive();
|
||||||
if (search_)
|
|
||||||
always_save_prev_paths_ = search_->alwaysSavePrevPaths();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1187,9 +1194,7 @@ ArrivalVisitor::visit(Vertex *vertex)
|
||||||
|| arrivals_changed)
|
|| arrivals_changed)
|
||||||
search_->arrivalIterator()->enqueueAdjacentVertices(vertex, adj_pred_);
|
search_->arrivalIterator()->enqueueAdjacentVertices(vertex, adj_pred_);
|
||||||
if (arrivals_changed) {
|
if (arrivals_changed) {
|
||||||
debugPrint(debug_, "search", 4, "arrival changed");
|
debugPrint(debug_, "search", 4, "arrivals changed");
|
||||||
// Only update arrivals when delays change by more than
|
|
||||||
// fuzzyEqual can distinguish.
|
|
||||||
search_->setVertexArrivals(vertex, tag_bldr_);
|
search_->setVertexArrivals(vertex, tag_bldr_);
|
||||||
search_->tnsInvalid(vertex);
|
search_->tnsInvalid(vertex);
|
||||||
constrainedRequiredsInvalid(vertex, is_clk);
|
constrainedRequiredsInvalid(vertex, is_clk);
|
||||||
|
|
@ -1239,28 +1244,21 @@ bool
|
||||||
Search::arrivalsChanged(Vertex *vertex,
|
Search::arrivalsChanged(Vertex *vertex,
|
||||||
TagGroupBldr *tag_bldr)
|
TagGroupBldr *tag_bldr)
|
||||||
{
|
{
|
||||||
Arrival *arrivals1 = graph_->arrivals(vertex);
|
Path *paths1 = graph_->paths(vertex);
|
||||||
PathPrev *prev_paths1 = graph_->prevPaths(vertex);
|
if (paths1) {
|
||||||
if (arrivals1) {
|
|
||||||
TagGroup *tag_group = tagGroup(vertex);
|
TagGroup *tag_group = tagGroup(vertex);
|
||||||
if (tag_group == nullptr
|
if (tag_group == nullptr
|
||||||
|| tag_group->arrivalMap()->size() != tag_bldr->arrivalMap()->size())
|
|| tag_group->pathCount() != tag_bldr->pathCount())
|
||||||
return true;
|
return true;
|
||||||
ArrivalMap::Iterator arrival_iter1(tag_group->arrivalMap());
|
for (auto const [tag1, path_index1] : *tag_group->pathIndexMap()) {
|
||||||
while (arrival_iter1.hasNext()) {
|
Path *path1 = &paths1[path_index1];
|
||||||
Tag *tag1;
|
Path *path2 = tag_bldr->tagMatchPath(tag1);
|
||||||
int arrival_index1;
|
if (path2 == nullptr
|
||||||
arrival_iter1.next(tag1, arrival_index1);
|
|| path1->tag(this) != path2->tag(this)
|
||||||
Arrival &arrival1 = arrivals1[arrival_index1];
|
|| !delayEqual(path1->arrival(), path2->arrival())
|
||||||
Tag *tag2;
|
|| path1->prevEdge(this) != path2->prevEdge(this)
|
||||||
Arrival arrival2;
|
|| path1->prevArc(this) != path2->prevArc(this)
|
||||||
int arrival_index2;
|
|| path1->prevPath() != path2->prevPath())
|
||||||
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))))
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1270,11 +1268,11 @@ Search::arrivalsChanged(Vertex *vertex,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ArrivalVisitor::visitFromToPath(const Pin *,
|
ArrivalVisitor::visitFromToPath(const Pin * /* from_pin */,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
const Arrival &from_arrival,
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
|
|
@ -1298,39 +1296,27 @@ ArrivalVisitor::visitFromToPath(const Pin *,
|
||||||
to_tag->asString(this));
|
to_tag->asString(this));
|
||||||
ClkInfo *to_clk_info = to_tag->clkInfo();
|
ClkInfo *to_clk_info = to_tag->clkInfo();
|
||||||
bool to_is_clk = to_tag->isClock();
|
bool to_is_clk = to_tag->isClock();
|
||||||
Arrival arrival;
|
Path *match;
|
||||||
int arrival_index;
|
size_t path_index;
|
||||||
Tag *tag_match;
|
tag_bldr_->tagMatchPath(to_tag, match, path_index);
|
||||||
tag_bldr_->tagMatchArrival(to_tag, tag_match, arrival, arrival_index);
|
if (match == nullptr
|
||||||
if (tag_match == nullptr
|
|| delayGreater(to_arrival, match->arrival(), min_max, this)) {
|
||||||
|| delayGreater(to_arrival, arrival, min_max, this)) {
|
|
||||||
debugPrint(debug_, "search", 3, " %s + %s = %s %s %s",
|
debugPrint(debug_, "search", 3, " %s + %s = %s %s %s",
|
||||||
delayAsString(from_arrival, this),
|
delayAsString(from_arrival, this),
|
||||||
delayAsString(arc_delay, this),
|
delayAsString(arc_delay, this),
|
||||||
delayAsString(to_arrival, this),
|
delayAsString(to_arrival, this),
|
||||||
min_max == MinMax::max() ? ">" : "<",
|
min_max == MinMax::max() ? ">" : "<",
|
||||||
tag_match ? delayAsString(arrival, this) : "MIA");
|
match ? delayAsString(match->arrival(), this) : "MIA");
|
||||||
PathPrev prev_path;
|
tag_bldr_->setMatchPath(match, path_index, to_tag, to_arrival, from_path, edge, arc);
|
||||||
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);
|
|
||||||
if (crpr_active_
|
if (crpr_active_
|
||||||
&& !has_fanin_one_
|
&& !has_fanin_one_
|
||||||
&& to_clk_info->hasCrprClkPin()
|
&& to_clk_info->hasCrprClkPin()
|
||||||
&& !to_is_clk) {
|
&& !to_is_clk) {
|
||||||
tag_bldr_no_crpr_->tagMatchArrival(to_tag, tag_match,
|
tag_bldr_no_crpr_->tagMatchPath(to_tag, match, path_index);
|
||||||
arrival, arrival_index);
|
if (match == nullptr
|
||||||
if (tag_match == nullptr
|
|| delayGreater(to_arrival, match->arrival(), min_max, this)) {
|
||||||
|| delayGreater(to_arrival, arrival, min_max, this)) {
|
tag_bldr_no_crpr_->setMatchPath(match, path_index, to_tag, to_arrival,
|
||||||
tag_bldr_no_crpr_->setMatchArrival(to_tag, tag_match,
|
from_path, edge, arc);
|
||||||
to_arrival, arrival_index,
|
|
||||||
&prev_path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1341,23 +1327,20 @@ void
|
||||||
ArrivalVisitor::pruneCrprArrivals()
|
ArrivalVisitor::pruneCrprArrivals()
|
||||||
{
|
{
|
||||||
CheckCrpr *crpr = search_->checkCrpr();
|
CheckCrpr *crpr = search_->checkCrpr();
|
||||||
ArrivalMap *arrival_map = tag_bldr_->arrivalMap();
|
PathIndexMap &path_index_map = tag_bldr_->pathIndexMap();
|
||||||
for (auto arrival_itr = arrival_map->cbegin(); arrival_itr != arrival_map->cend(); ) {
|
for (auto path_itr = path_index_map.cbegin(); path_itr != path_index_map.cend(); ) {
|
||||||
Tag *tag = arrival_itr->first;
|
Tag *tag = path_itr->first;
|
||||||
int arrival_index = arrival_itr->second;
|
size_t path_index = path_itr->second;
|
||||||
ClkInfo *clk_info = tag->clkInfo();
|
ClkInfo *clk_info = tag->clkInfo();
|
||||||
bool deleted_tag = false;
|
bool deleted_tag = false;
|
||||||
if (!tag->isClock()
|
if (!tag->isClock()
|
||||||
&& clk_info->hasCrprClkPin()) {
|
&& clk_info->hasCrprClkPin()) {
|
||||||
PathAnalysisPt *path_ap = tag->pathAnalysisPt(this);
|
PathAnalysisPt *path_ap = tag->pathAnalysisPt(this);
|
||||||
const MinMax *min_max = path_ap->pathMinMax();
|
const MinMax *min_max = path_ap->pathMinMax();
|
||||||
Tag *tag_no_crpr;
|
Path *path_no_crpr = tag_bldr_no_crpr_->tagMatchPath(tag);
|
||||||
Arrival max_arrival;
|
if (path_no_crpr) {
|
||||||
int max_arrival_index;
|
Arrival max_arrival = path_no_crpr->arrival();
|
||||||
tag_bldr_no_crpr_->tagMatchArrival(tag, tag_no_crpr,
|
ClkInfo *clk_info_no_crpr = path_no_crpr->clkInfo(this);
|
||||||
max_arrival, max_arrival_index);
|
|
||||||
if (tag_no_crpr) {
|
|
||||||
ClkInfo *clk_info_no_crpr = tag_no_crpr->clkInfo();
|
|
||||||
Arrival max_crpr = crpr->maxCrpr(clk_info_no_crpr);
|
Arrival max_crpr = crpr->maxCrpr(clk_info_no_crpr);
|
||||||
Arrival max_arrival_max_crpr = (min_max == MinMax::max())
|
Arrival max_arrival_max_crpr = (min_max == MinMax::max())
|
||||||
? max_arrival - max_crpr
|
? max_arrival - max_crpr
|
||||||
|
|
@ -1367,17 +1350,17 @@ ArrivalVisitor::pruneCrprArrivals()
|
||||||
delayAsString(max_arrival, this),
|
delayAsString(max_arrival, this),
|
||||||
delayAsString(max_crpr, this),
|
delayAsString(max_crpr, this),
|
||||||
delayAsString(max_arrival_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)) {
|
if (delayGreater(max_arrival_max_crpr, arrival, min_max, this)) {
|
||||||
debugPrint(debug_, "search", 3, " pruned %s",
|
debugPrint(debug_, "search", 3, " pruned %s",
|
||||||
tag->asString(this));
|
tag->asString(this));
|
||||||
arrival_itr = arrival_map->erase(arrival_itr);
|
path_itr = path_index_map.erase(path_itr);
|
||||||
deleted_tag = true;
|
deleted_tag = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!deleted_tag)
|
if (!deleted_tag)
|
||||||
arrival_itr++;
|
path_itr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1506,8 +1489,9 @@ Search::seedArrival(Vertex *vertex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
debugPrint(debug_, "search", 2, "arrival enqueue %s",
|
debugPrint(debug_, "search", 4, "arrival enqueue %s %u",
|
||||||
network_->pathName(pin));
|
network_->pathName(pin),
|
||||||
|
vertex->level());
|
||||||
arrival_iter_->enqueue(vertex);
|
arrival_iter_->enqueue(vertex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1599,7 +1583,7 @@ Search::seedClkArrival(const Pin *pin,
|
||||||
sdc_->exceptionFromClkStates(pin,rf,clk,rf,min_max,states);
|
sdc_->exceptionFromClkStates(pin,rf,clk,rf,min_max,states);
|
||||||
Tag *tag = findTag(rf, path_ap, clk_info, true, nullptr, false, states, true);
|
Tag *tag = findTag(rf, path_ap, clk_info, true, nullptr, false, states, true);
|
||||||
Arrival arrival(clk_edge->time() + insertion);
|
Arrival arrival(clk_edge->time() + insertion);
|
||||||
tag_bldr->setArrival(tag, arrival, nullptr);
|
tag_bldr->setArrival(tag, arrival);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1616,7 +1600,7 @@ Search::seedClkDataArrival(const Pin *pin,
|
||||||
if (tag) {
|
if (tag) {
|
||||||
// Data arrivals include insertion delay.
|
// Data arrivals include insertion delay.
|
||||||
Arrival arrival(clk_edge->time() + insertion);
|
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,
|
is_segment_start,
|
||||||
require_exception);
|
require_exception);
|
||||||
if (tag) {
|
if (tag) {
|
||||||
tag_bldr->setArrival(tag, delay_zero, nullptr);
|
tag_bldr->setArrival(tag, delay_zero);
|
||||||
search_from = true;
|
search_from = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1869,7 +1853,7 @@ Search::inputDelayRefPinArrival(Path *ref_path,
|
||||||
Clock *clk = clk_edge->clock();
|
Clock *clk = clk_edge->clock();
|
||||||
if (clk->isPropagated()) {
|
if (clk->isPropagated()) {
|
||||||
ClkInfo *clk_info = ref_path->clkInfo(this);
|
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_insertion = delayAsFloat(clk_info->insertion());
|
||||||
ref_latency = clk_info->latency();
|
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,
|
Tag *tag = inputDelayTag(pin, rf, clk_edge, clk_insertion, clk_latency,
|
||||||
input_delay, is_segment_start, min_max, path_ap);
|
input_delay, is_segment_start, min_max, path_ap);
|
||||||
if (tag)
|
if (tag)
|
||||||
tag_bldr->setArrival(tag, arrival, nullptr);
|
tag_bldr->setArrival(tag, arrival);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -2075,7 +2059,7 @@ PathVisitor::visitEdge(const Pin *from_pin,
|
||||||
TimingArcSet *arc_set = edge->timingArcSet();
|
TimingArcSet *arc_set = edge->timingArcSet();
|
||||||
VertexPathIterator from_iter(from_vertex, search_);
|
VertexPathIterator from_iter(from_vertex, search_);
|
||||||
while (from_iter.hasNext()) {
|
while (from_iter.hasNext()) {
|
||||||
PathVertex *from_path = from_iter.next();
|
Path *from_path = from_iter.next();
|
||||||
PathAnalysisPt *path_ap = from_path->pathAnalysisPt(this);
|
PathAnalysisPt *path_ap = from_path->pathAnalysisPt(this);
|
||||||
const MinMax *min_max = path_ap->pathMinMax();
|
const MinMax *min_max = path_ap->pathMinMax();
|
||||||
const RiseFall *from_rf = from_path->transition(this);
|
const RiseFall *from_rf = from_path->transition(this);
|
||||||
|
|
@ -2098,7 +2082,7 @@ bool
|
||||||
PathVisitor::visitArc(const Pin *from_pin,
|
PathVisitor::visitArc(const Pin *from_pin,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
const Pin *to_pin,
|
const Pin *to_pin,
|
||||||
|
|
@ -2120,7 +2104,7 @@ bool
|
||||||
PathVisitor::visitFromPath(const Pin *from_pin,
|
PathVisitor::visitFromPath(const Pin *from_pin,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
const Pin *to_pin,
|
const Pin *to_pin,
|
||||||
|
|
@ -2135,7 +2119,7 @@ PathVisitor::visitFromPath(const Pin *from_pin,
|
||||||
Tag *to_tag = nullptr;
|
Tag *to_tag = nullptr;
|
||||||
const ClockEdge *clk_edge = from_clk_info->clkEdge();
|
const ClockEdge *clk_edge = from_clk_info->clkEdge();
|
||||||
const Clock *clk = from_clk_info->clock();
|
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;
|
ArcDelay arc_delay = 0.0;
|
||||||
Arrival to_arrival;
|
Arrival to_arrival;
|
||||||
if (from_clk_info->isGenClkSrcPath()) {
|
if (from_clk_info->isGenClkSrcPath()) {
|
||||||
|
|
@ -2202,7 +2186,7 @@ PathVisitor::visitFromPath(const Pin *from_pin,
|
||||||
&& from_tag->isClock())) {
|
&& from_tag->isClock())) {
|
||||||
const RiseFall *clk_rf = clk_edge ? clk_edge->transition() : nullptr;
|
const RiseFall *clk_rf = clk_edge ? clk_edge->transition() : nullptr;
|
||||||
ClkInfo *to_clk_info = from_clk_info;
|
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())
|
|| network_->direction(to_pin)->isInternal())
|
||||||
to_clk_info = search_->clkInfoWithCrprClkPath(from_clk_info,
|
to_clk_info = search_->clkInfoWithCrprClkPath(from_clk_info,
|
||||||
from_path, path_ap);
|
from_path, path_ap);
|
||||||
|
|
@ -2308,7 +2292,7 @@ Search::clkPathArrival(const Path *clk_path,
|
||||||
+ clk_info->latency();
|
+ clk_info->latency();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return clk_path->arrival(this);
|
return clk_path->arrival();
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
|
|
@ -2316,9 +2300,9 @@ Search::pathClkPathArrival(const Path *path) const
|
||||||
{
|
{
|
||||||
ClkInfo *clk_info = path->clkInfo(this);
|
ClkInfo *clk_info = path->clkInfo(this);
|
||||||
if (clk_info->isPropagated()) {
|
if (clk_info->isPropagated()) {
|
||||||
PathRef src_clk_path = pathClkPathArrival1(path);
|
const Path *src_clk_path = pathClkPathArrival1(path);
|
||||||
if (!src_clk_path.isNull())
|
if (src_clk_path)
|
||||||
return clkPathArrival(&src_clk_path);
|
return clkPathArrival(src_clk_path);
|
||||||
}
|
}
|
||||||
// Check for input arrival clock.
|
// Check for input arrival clock.
|
||||||
const ClockEdge *clk_edge = path->clkEdge(this);
|
const ClockEdge *clk_edge = path->clkEdge(this);
|
||||||
|
|
@ -2328,34 +2312,30 @@ Search::pathClkPathArrival(const Path *path) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// PathExpanded::expand() and PathExpanded::clkPath().
|
// PathExpanded::expand() and PathExpanded::clkPath().
|
||||||
PathRef
|
const Path *
|
||||||
Search::pathClkPathArrival1(const Path *path) const
|
Search::pathClkPathArrival1(const Path *path) const
|
||||||
{
|
{
|
||||||
PathRef p(path);
|
const Path *p = path;
|
||||||
while (!p.isNull()) {
|
while (p) {
|
||||||
PathRef prev_path;
|
Path *prev_path = p->prevPath();
|
||||||
TimingArc *prev_arc;
|
Edge *prev_edge = p->prevEdge(this);
|
||||||
p.prevPath(this, prev_path, prev_arc);
|
|
||||||
|
|
||||||
if (p.isClock(this))
|
if (p->isClock(this))
|
||||||
return p;
|
return p;
|
||||||
if (prev_arc) {
|
if (prev_edge) {
|
||||||
TimingRole *prev_role = prev_arc->role();
|
TimingRole *prev_role = prev_edge->role();
|
||||||
if (prev_role == TimingRole::regClkToQ()
|
if (prev_role == TimingRole::regClkToQ()
|
||||||
|| prev_role == TimingRole::latchEnToQ()) {
|
|| prev_role == TimingRole::latchEnToQ()) {
|
||||||
p.prevPath(this, prev_path, prev_arc);
|
return p->prevPath();
|
||||||
return prev_path;
|
|
||||||
}
|
}
|
||||||
else if (prev_role == TimingRole::latchDtoQ()) {
|
else if (prev_role == TimingRole::latchDtoQ()) {
|
||||||
Edge *prev_edge = p.prevEdge(prev_arc, this);
|
Path *enable_path = latches_->latchEnablePath(p, prev_edge);
|
||||||
PathVertex enable_path;
|
|
||||||
latches_->latchEnablePath(&p, prev_edge, enable_path);
|
|
||||||
return enable_path;
|
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.
|
// Insert from_path as ClkInfo crpr_clk_path.
|
||||||
ClkInfo *
|
ClkInfo *
|
||||||
Search::clkInfoWithCrprClkPath(ClkInfo *from_clk_info,
|
Search::clkInfoWithCrprClkPath(ClkInfo *from_clk_info,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
const PathAnalysisPt *path_ap)
|
const PathAnalysisPt *path_ap)
|
||||||
{
|
{
|
||||||
if (sdc_->crprActive())
|
if (sdc_->crprActive())
|
||||||
|
|
@ -2447,7 +2427,7 @@ Search::thruTag(Tag *from_tag,
|
||||||
|
|
||||||
// thruTag for clocks.
|
// thruTag for clocks.
|
||||||
Tag *
|
Tag *
|
||||||
Search::thruClkTag(PathVertex *from_path,
|
Search::thruClkTag(Path *from_path,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
bool to_propagates_clk,
|
bool to_propagates_clk,
|
||||||
|
|
@ -2479,7 +2459,7 @@ Search::thruClkTag(PathVertex *from_path,
|
||||||
}
|
}
|
||||||
|
|
||||||
ClkInfo *
|
ClkInfo *
|
||||||
Search::thruClkInfo(PathVertex *from_path,
|
Search::thruClkInfo(Path *from_path,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
ClkInfo *from_clk_info,
|
ClkInfo *from_clk_info,
|
||||||
bool from_is_clk,
|
bool from_is_clk,
|
||||||
|
|
@ -2516,7 +2496,7 @@ Search::thruClkInfo(PathVertex *from_path,
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PathVertex *to_crpr_clk_path = nullptr;
|
Path *to_crpr_clk_path = nullptr;
|
||||||
if (sdc_->crprActive()
|
if (sdc_->crprActive()
|
||||||
// Update crpr clk path for combinational paths leaving the clock
|
// Update crpr clk path for combinational paths leaving the clock
|
||||||
// network (ie, tristate en->out) and buffer driving reg clk.
|
// network (ie, tristate en->out) and buffer driving reg clk.
|
||||||
|
|
@ -2747,54 +2727,27 @@ Search::setVertexArrivals(Vertex *vertex,
|
||||||
deletePathsIncr(vertex);
|
deletePathsIncr(vertex);
|
||||||
else {
|
else {
|
||||||
TagGroup *prev_tag_group = tagGroup(vertex);
|
TagGroup *prev_tag_group = tagGroup(vertex);
|
||||||
Arrival *prev_arrivals = graph_->arrivals(vertex);
|
Path *prev_paths = graph_->paths(vertex);
|
||||||
PathPrev *prev_paths = graph_->prevPaths(vertex);
|
|
||||||
bool save_prev = always_save_prev_paths_
|
|
||||||
|| tag_bldr->hasClkTag()
|
|
||||||
|| tag_bldr->hasGenClkSrcTag();
|
|
||||||
|
|
||||||
TagGroup *tag_group = findTagGroup(tag_bldr);
|
TagGroup *tag_group = findTagGroup(tag_bldr);
|
||||||
int arrival_count = tag_group->arrivalCount();
|
size_t path_count = tag_group->pathCount();
|
||||||
bool has_requireds = vertex->hasRequireds();
|
// Reuse path array if it is the same size.
|
||||||
// Reuse arrival array if it is the same size.
|
|
||||||
if (prev_tag_group
|
if (prev_tag_group
|
||||||
&& arrival_count == prev_tag_group->arrivalCount()) {
|
&& path_count == prev_tag_group->pathCount()) {
|
||||||
if (save_prev) {
|
tag_bldr->copyPaths(tag_group, prev_paths);
|
||||||
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);
|
|
||||||
vertex->setTagGroupIndex(tag_group->index());
|
vertex->setTagGroupIndex(tag_group->index());
|
||||||
if (tag_group->hasFilterTag()) {
|
if (tag_group->hasFilterTag()) {
|
||||||
LockGuard lock(filtered_arrivals_lock_);
|
LockGuard lock(filtered_arrivals_lock_);
|
||||||
filtered_arrivals_->insert(vertex);
|
filtered_arrivals_->insert(vertex);
|
||||||
}
|
}
|
||||||
|
requiredInvalid(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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (prev_tag_group) {
|
if (prev_tag_group) {
|
||||||
graph_->deleteArrivals(vertex);
|
graph_->deletePaths(vertex);
|
||||||
if (has_requireds) {
|
requiredInvalid(vertex);
|
||||||
requiredInvalid(vertex);
|
|
||||||
graph_->deleteRequireds(vertex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Arrival *arrivals = graph_->makeArrivals(vertex, arrival_count);
|
Path *paths = graph_->makePaths(vertex, path_count);
|
||||||
prev_paths = nullptr;
|
tag_bldr->copyPaths(tag_group, paths);
|
||||||
if (save_prev)
|
|
||||||
prev_paths = graph_->makePrevPaths(vertex, arrival_count);
|
|
||||||
tag_bldr->copyArrivals(tag_group, arrivals, prev_paths);
|
|
||||||
|
|
||||||
vertex->setTagGroupIndex(tag_group->index());
|
vertex->setTagGroupIndex(tag_group->index());
|
||||||
if (tag_group->hasFilterTag()) {
|
if (tag_group->hasFilterTag()) {
|
||||||
|
|
@ -2810,56 +2763,38 @@ Search::reportArrivals(Vertex *vertex) const
|
||||||
{
|
{
|
||||||
report_->reportLine("Vertex %s", vertex->name(sdc_network_));
|
report_->reportLine("Vertex %s", vertex->name(sdc_network_));
|
||||||
TagGroup *tag_group = tagGroup(vertex);
|
TagGroup *tag_group = tagGroup(vertex);
|
||||||
Arrival *arrivals = graph_->arrivals(vertex);
|
|
||||||
Required *requireds = graph_->requireds(vertex);
|
|
||||||
PathPrev *prev_paths = graph_->prevPaths(vertex);
|
|
||||||
if (tag_group) {
|
if (tag_group) {
|
||||||
report_->reportLine("Group %u", tag_group->index());
|
report_->reportLine("Group %u", tag_group->index());
|
||||||
ArrivalMap::Iterator arrival_iter(tag_group->arrivalMap());
|
VertexPathIterator path_iter(vertex, this);
|
||||||
while (arrival_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
Tag *tag;
|
const Path *path = path_iter.next();
|
||||||
int arrival_index;
|
const Tag *tag = path->tag(this);
|
||||||
arrival_iter.next(tag, arrival_index);
|
const PathAnalysisPt *path_ap = tag->pathAnalysisPt(this);
|
||||||
PathAnalysisPt *path_ap = tag->pathAnalysisPt(this);
|
|
||||||
const RiseFall *rf = tag->transition();
|
const RiseFall *rf = tag->transition();
|
||||||
const char *req = "?";
|
const char *req = delayAsString(path->required(), this);
|
||||||
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);
|
|
||||||
}
|
|
||||||
string prev_str;
|
string prev_str;
|
||||||
if (prev_paths) {
|
Path *prev_path = path->prevPath();
|
||||||
PathPrev &prev = prev_paths[arrival_index];
|
if (prev_path) {
|
||||||
if (!prev.isNull()) {
|
prev_str += prev_path->name(this);
|
||||||
prev_str += prev.name(this);
|
prev_str += " ";
|
||||||
prev_str += " ";
|
const Edge *prev_edge = path->prevEdge(this);
|
||||||
const Edge *prev_edge = prev.prevEdge(this);
|
TimingArc *arc = path->prevArc(this);
|
||||||
TimingArc *arc = prev.prevArc(this);
|
prev_str += prev_edge->from(graph_)->name(network_);
|
||||||
prev_str += prev_edge->from(graph_)->name(network_);
|
prev_str += " ";
|
||||||
prev_str += " ";
|
prev_str += arc->fromEdge()->asString();
|
||||||
prev_str += arc->fromEdge()->asString();
|
prev_str += " -> ";
|
||||||
prev_str += " -> ";
|
prev_str += prev_edge->to(graph_)->name(network_);
|
||||||
prev_str += prev_edge->to(graph_)->name(network_);
|
prev_str += " ";
|
||||||
prev_str += " ";
|
prev_str += arc->toEdge()->asString();
|
||||||
prev_str += arc->toEdge()->asString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
prev_str = "NULL";
|
|
||||||
}
|
}
|
||||||
report_->reportLine(" %d %s %s %s / %s %s %s prev %s",
|
else
|
||||||
arrival_index,
|
prev_str = "NULL";
|
||||||
|
report_->reportLine(" %s %s %s / %s %s prev %s",
|
||||||
rf->asString(),
|
rf->asString(),
|
||||||
path_ap->pathMinMax()->asString(),
|
path_ap->pathMinMax()->asString(),
|
||||||
delayAsString(arrivals[arrival_index], this),
|
delayAsString(path->arrival(), this),
|
||||||
req,
|
req,
|
||||||
tag->asString(true, false, this),
|
tag->asString(true, false, this),
|
||||||
clk_prev,
|
|
||||||
prev_str.c_str());
|
prev_str.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2913,7 +2848,7 @@ Search::reportTagGroups() const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Search::reportArrivalCountHistogram() const
|
Search::reportPathCountHistogram() const
|
||||||
{
|
{
|
||||||
Vector<int> vertex_counts(10);
|
Vector<int> vertex_counts(10);
|
||||||
VertexIterator vertex_iter(graph_);
|
VertexIterator vertex_iter(graph_);
|
||||||
|
|
@ -2921,17 +2856,17 @@ Search::reportArrivalCountHistogram() const
|
||||||
Vertex *vertex = vertex_iter.next();
|
Vertex *vertex = vertex_iter.next();
|
||||||
TagGroup *tag_group = tagGroup(vertex);
|
TagGroup *tag_group = tagGroup(vertex);
|
||||||
if (tag_group) {
|
if (tag_group) {
|
||||||
size_t arrival_count = tag_group->arrivalCount();
|
size_t path_count = tag_group->pathCount();
|
||||||
if (arrival_count >= vertex_counts.size())
|
if (path_count >= vertex_counts.size())
|
||||||
vertex_counts.resize(arrival_count * 2);
|
vertex_counts.resize(path_count * 2);
|
||||||
vertex_counts[arrival_count]++;
|
vertex_counts[path_count]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t arrival_count = 0; arrival_count < vertex_counts.size(); arrival_count++) {
|
for (size_t path_count = 0; path_count < vertex_counts.size(); path_count++) {
|
||||||
int vertex_count = vertex_counts[arrival_count];
|
int vertex_count = vertex_counts[path_count];
|
||||||
if (vertex_count > 0)
|
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,
|
float latency,
|
||||||
ClockUncertainties *uncertainties,
|
ClockUncertainties *uncertainties,
|
||||||
const PathAnalysisPt *path_ap,
|
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,
|
ClkInfo probe(clk_edge, clk_src, is_propagated, gen_clk_src, gen_clk_src_path,
|
||||||
pulse_clk_sense, insertion, latency, uncertainties,
|
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_);
|
LockGuard lock(clk_info_lock_);
|
||||||
ClkInfo *clk_info = clk_info_set_->findKey(&probe);
|
ClkInfo *clk_info = clk_info_set_->findKey(&probe);
|
||||||
if (clk_info == nullptr) {
|
if (clk_info == nullptr) {
|
||||||
clk_info = new ClkInfo(clk_edge, clk_src,
|
clk_info = new ClkInfo(clk_edge, clk_src,
|
||||||
is_propagated, gen_clk_src, gen_clk_src_path,
|
is_propagated, gen_clk_src, gen_clk_src_path,
|
||||||
pulse_clk_sense, insertion, latency, uncertainties,
|
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);
|
clk_info_set_->insert(clk_info);
|
||||||
}
|
}
|
||||||
return clk_info;
|
return clk_info;
|
||||||
|
|
@ -3234,6 +3168,7 @@ Search::findRequireds(Level level)
|
||||||
seedInvalidRequireds();
|
seedInvalidRequireds();
|
||||||
int required_count = required_iter_->visitParallel(level, &req_visitor);
|
int required_count = required_iter_->visitParallel(level, &req_visitor);
|
||||||
deleteTagsPrev();
|
deleteTagsPrev();
|
||||||
|
genclks_->updateSrcPathPrevs();
|
||||||
requireds_exist_ = true;
|
requireds_exist_ = true;
|
||||||
debugPrint(debug_, "search", 1, "found %d requireds", required_count);
|
debugPrint(debug_, "search", 1, "found %d requireds", required_count);
|
||||||
stats.report("Find requireds");
|
stats.report("Find requireds");
|
||||||
|
|
@ -3398,13 +3333,11 @@ void
|
||||||
FindEndRequiredVisitor::visit(PathEnd *path_end)
|
FindEndRequiredVisitor::visit(PathEnd *path_end)
|
||||||
{
|
{
|
||||||
if (!path_end->isUnconstrained()) {
|
if (!path_end->isUnconstrained()) {
|
||||||
PathRef &path = path_end->pathRef();
|
Path *path = path_end->path();
|
||||||
const MinMax *req_min = path.minMax(sta_)->opposite();
|
const MinMax *min_max = path->minMax(sta_)->opposite();
|
||||||
int arrival_index;
|
size_t path_index = path->pathIndex(sta_);
|
||||||
bool arrival_exists;
|
|
||||||
path.arrivalIndex(arrival_index, arrival_exists);
|
|
||||||
Required required = path_end->requiredTime(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();
|
Search *search = sta->search();
|
||||||
TagGroup *tag_group = search->tagGroup(vertex);
|
TagGroup *tag_group = search->tagGroup(vertex);
|
||||||
if (tag_group) {
|
if (tag_group) {
|
||||||
requireds_.resize(tag_group->arrivalCount());
|
size_t path_count = tag_group->pathCount();
|
||||||
ArrivalMap *arrival_entries = tag_group->arrivalMap();
|
requireds_.resize(path_count);
|
||||||
ArrivalMap::Iterator arrival_iter(arrival_entries);
|
for (auto const [tag, path_index] : *tag_group->pathIndexMap()) {
|
||||||
while (arrival_iter.hasNext()) {
|
|
||||||
Tag *tag;
|
|
||||||
int arrival_index;
|
|
||||||
arrival_iter.next(tag, arrival_index);
|
|
||||||
PathAnalysisPt *path_ap = tag->pathAnalysisPt(sta);
|
PathAnalysisPt *path_ap = tag->pathAnalysisPt(sta);
|
||||||
const MinMax *min_max = path_ap->pathMinMax();
|
const MinMax *min_max = path_ap->pathMinMax();
|
||||||
requireds_[arrival_index] = delayInitValue(min_max->opposite());
|
requireds_[path_index] = delayInitValue(min_max->opposite());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
requireds_.resize(0);
|
requireds_.clear();
|
||||||
have_requireds_ = false;
|
have_requireds_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RequiredCmp::requiredSet(int arrival_index,
|
RequiredCmp::requiredSet(size_t path_index,
|
||||||
Required required,
|
Required &required,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
if (delayGreater(required, requireds_[arrival_index], min_max, sta)) {
|
if (delayGreater(required, requireds_[path_index], min_max, sta)) {
|
||||||
requireds_[arrival_index] = required;
|
requireds_[path_index] = required;
|
||||||
have_requireds_ = true;
|
have_requireds_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3483,53 +3412,26 @@ RequiredCmp::requiredsSave(Vertex *vertex,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
bool requireds_changed = false;
|
bool requireds_changed = false;
|
||||||
bool prev_reqs = vertex->hasRequireds();
|
Debug *debug = sta->debug();
|
||||||
if (have_requireds_) {
|
VertexPathIterator path_iter(vertex, sta);
|
||||||
if (!prev_reqs)
|
while (path_iter.hasNext()) {
|
||||||
requireds_changed = true;
|
Path *path = path_iter.next();
|
||||||
Debug *debug = sta->debug();
|
size_t path_index = path->pathIndex(sta);
|
||||||
VertexPathIterator path_iter(vertex, sta);
|
Required req = requireds_[path_index];
|
||||||
while (path_iter.hasNext()) {
|
Required &prev_req = path->required();
|
||||||
PathVertex *path = path_iter.next();
|
debugPrint(debug, "search", 3, "required save %s -> %s",
|
||||||
int arrival_index;
|
delayAsString(prev_req, sta),
|
||||||
bool arrival_exists;
|
delayAsString(req, sta));
|
||||||
path->arrivalIndex(arrival_index, arrival_exists);
|
requireds_changed |= !delayEqual(prev_req, req);
|
||||||
Required req = requireds_[arrival_index];
|
path->setRequired(req);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return requireds_changed;
|
return requireds_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
Required
|
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
|
bool
|
||||||
RequiredVisitor::visitFromToPath(const Pin *,
|
RequiredVisitor::visitFromToPath(const Pin *,
|
||||||
Vertex *,
|
Vertex * /* from_vertex */,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
const Arrival &,
|
const Arrival &,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *,
|
TimingArc *,
|
||||||
|
|
@ -3599,15 +3501,14 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
||||||
debugPrint(debug_, "search", 3, " from tag %2u: %s",
|
debugPrint(debug_, "search", 3, " from tag %2u: %s",
|
||||||
from_tag->index(),
|
from_tag->index(),
|
||||||
from_tag->asString(this));
|
from_tag->asString(this));
|
||||||
int arrival_index;
|
size_t path_index = from_path->pathIndex(this);
|
||||||
bool arrival_exists;
|
|
||||||
from_path->arrivalIndex(arrival_index, arrival_exists);
|
|
||||||
const MinMax *req_min = min_max->opposite();
|
const MinMax *req_min = min_max->opposite();
|
||||||
TagGroup *to_tag_group = search_->tagGroup(to_vertex);
|
TagGroup *to_tag_group = search_->tagGroup(to_vertex);
|
||||||
// Check to see if to_tag was pruned.
|
// Check to see if to_tag was pruned.
|
||||||
if (to_tag_group && to_tag_group->hasTag(to_tag)) {
|
if (to_tag_group && to_tag_group->hasTag(to_tag)) {
|
||||||
PathVertex to_path(to_vertex, to_tag, this);
|
size_t to_path_index = to_tag_group->pathIndex(to_tag);
|
||||||
Required to_required = to_path.required(this);
|
Path &to_path = to_vertex->paths()[to_path_index];
|
||||||
|
Required &to_required = to_path.required();
|
||||||
Required from_required = to_required - arc_delay;
|
Required from_required = to_required - arc_delay;
|
||||||
debugPrint(debug_, "search", 3, " to tag %2u: %s",
|
debugPrint(debug_, "search", 3, " to tag %2u: %s",
|
||||||
to_tag->index(),
|
to_tag->index(),
|
||||||
|
|
@ -3617,8 +3518,8 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
||||||
delayAsString(arc_delay, this),
|
delayAsString(arc_delay, this),
|
||||||
delayAsString(from_required, this),
|
delayAsString(from_required, this),
|
||||||
min_max == MinMax::max() ? "<" : ">",
|
min_max == MinMax::max() ? "<" : ">",
|
||||||
delayAsString(required_cmp_->required(arrival_index), this));
|
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);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (search_->crprApproxMissingRequireds()) {
|
if (search_->crprApproxMissingRequireds()) {
|
||||||
|
|
@ -3627,10 +3528,10 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
||||||
// as an appromate required.
|
// as an appromate required.
|
||||||
VertexPathIterator to_iter(to_vertex, to_rf, path_ap, this);
|
VertexPathIterator to_iter(to_vertex, to_rf, path_ap, this);
|
||||||
while (to_iter.hasNext()) {
|
while (to_iter.hasNext()) {
|
||||||
PathVertex *to_path = to_iter.next();
|
Path *to_path = to_iter.next();
|
||||||
Tag *to_path_tag = to_path->tag(this);
|
Tag *to_path_tag = to_path->tag(this);
|
||||||
if (tagMatchNoCrpr(to_path_tag, to_tag)) {
|
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;
|
Required from_required = to_required - arc_delay;
|
||||||
debugPrint(debug_, "search", 3, " to tag %2u: %s",
|
debugPrint(debug_, "search", 3, " to tag %2u: %s",
|
||||||
to_path_tag->index(),
|
to_path_tag->index(),
|
||||||
|
|
@ -3640,9 +3541,9 @@ RequiredVisitor::visitFromToPath(const Pin *,
|
||||||
delayAsString(arc_delay, this),
|
delayAsString(arc_delay, this),
|
||||||
delayAsString(from_required, this),
|
delayAsString(from_required, this),
|
||||||
min_max == MinMax::max() ? "<" : ">",
|
min_max == MinMax::max() ? "<" : ">",
|
||||||
delayAsString(required_cmp_->required(arrival_index),
|
delayAsString(required_cmp_->required(path_index),
|
||||||
this));
|
this));
|
||||||
required_cmp_->requiredSet(arrival_index, from_required, req_min, this);
|
required_cmp_->requiredSet(path_index, from_required, req_min, this);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4024,8 +3925,8 @@ void
|
||||||
FindEndSlackVisitor::visit(PathEnd *path_end)
|
FindEndSlackVisitor::visit(PathEnd *path_end)
|
||||||
{
|
{
|
||||||
if (!path_end->isUnconstrained()) {
|
if (!path_end->isUnconstrained()) {
|
||||||
PathRef &path = path_end->pathRef();
|
Path *path = path_end->path();
|
||||||
PathAPIndex path_ap_index = path.pathAnalysisPtIndex(sta_);
|
PathAPIndex path_ap_index = path->pathAnalysisPtIndex(sta_);
|
||||||
Slack slack = path_end->slack(sta_);
|
Slack slack = path_end->slack(sta_);
|
||||||
if (delayLess(slack, slacks_[path_ap_index], sta_))
|
if (delayLess(slack, slacks_[path_ap_index], sta_))
|
||||||
slacks_[path_ap_index] = slack;
|
slacks_[path_ap_index] = slack;
|
||||||
|
|
|
||||||
|
|
@ -51,11 +51,11 @@ private:
|
||||||
~VertexPathIterator();
|
~VertexPathIterator();
|
||||||
};
|
};
|
||||||
|
|
||||||
class PathRef
|
class Path
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
PathRef();
|
Path();
|
||||||
~PathRef();
|
~Path();
|
||||||
};
|
};
|
||||||
|
|
||||||
class PathEnd
|
class PathEnd
|
||||||
|
|
@ -221,44 +221,32 @@ worst_slack_corner(const Corner *corner,
|
||||||
return worst_slack;
|
return worst_slack;
|
||||||
}
|
}
|
||||||
|
|
||||||
PathRef *
|
Path *
|
||||||
vertex_worst_arrival_path(Vertex *vertex,
|
vertex_worst_arrival_path(Vertex *vertex,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
Sta *sta = Sta::sta();
|
||||||
sta->ensureLibLinked();
|
sta->ensureLibLinked();
|
||||||
PathRef path = sta->vertexWorstArrivalPath(vertex, min_max);
|
return sta->vertexWorstArrivalPath(vertex, min_max);
|
||||||
if (!path.isNull())
|
|
||||||
return new PathRef(path);
|
|
||||||
else
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PathRef *
|
Path *
|
||||||
vertex_worst_arrival_path_rf(Vertex *vertex,
|
vertex_worst_arrival_path_rf(Vertex *vertex,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
MinMax *min_max)
|
MinMax *min_max)
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
Sta *sta = Sta::sta();
|
||||||
sta->ensureLibLinked();
|
sta->ensureLibLinked();
|
||||||
PathRef path = sta->vertexWorstArrivalPath(vertex, rf, min_max);
|
return sta->vertexWorstArrivalPath(vertex, rf, min_max);
|
||||||
if (!path.isNull())
|
|
||||||
return new PathRef(path);
|
|
||||||
else
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PathRef *
|
Path *
|
||||||
vertex_worst_slack_path(Vertex *vertex,
|
vertex_worst_slack_path(Vertex *vertex,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
Sta *sta = Sta::sta();
|
||||||
sta->ensureLibLinked();
|
sta->ensureLibLinked();
|
||||||
PathRef path = sta->vertexWorstSlackPath(vertex, min_max);
|
return sta->vertexWorstSlackPath(vertex, min_max);
|
||||||
if (!path.isNull())
|
|
||||||
return new PathRef(path);
|
|
||||||
else
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -280,9 +268,9 @@ report_tag_arrivals_cmd(Vertex *vertex)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
report_arrival_count_histogram()
|
report_path_count_histogram()
|
||||||
{
|
{
|
||||||
Sta::sta()->search()->reportArrivalCountHistogram();
|
Sta::sta()->search()->reportPathCountHistogram();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -310,15 +298,9 @@ clk_info_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
arrival_count()
|
path_count()
|
||||||
{
|
{
|
||||||
return Sta::sta()->arrivalCount();
|
return Sta::sta()->pathCount();
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
required_count()
|
|
||||||
{
|
|
||||||
return Sta::sta()->requiredCount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -494,13 +476,7 @@ set_report_path_sigmas(bool report_sigmas)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
delete_path_ref(PathRef *path)
|
report_path_cmd(Path *path)
|
||||||
{
|
|
||||||
delete path;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
report_path_cmd(PathRef *path)
|
|
||||||
{
|
{
|
||||||
Sta::sta()->reportPath(path);
|
Sta::sta()->reportPath(path);
|
||||||
}
|
}
|
||||||
|
|
@ -1245,7 +1221,7 @@ path_end_property(PathEnd *end,
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyValue
|
PropertyValue
|
||||||
path_ref_property(PathRef *path,
|
path_ref_property(Path *path,
|
||||||
const char *property)
|
const char *property)
|
||||||
{
|
{
|
||||||
return getProperty(path, property, Sta::sta());
|
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_path_delay() { return self->isPathDelay(); }
|
||||||
bool is_gated_clock() { return self->isGatedClock(); }
|
bool is_gated_clock() { return self->isGatedClock(); }
|
||||||
Vertex *vertex() { return self->vertex(Sta::sta()); }
|
Vertex *vertex() { return self->vertex(Sta::sta()); }
|
||||||
PathRef *path() { return &self->pathRef(); }
|
Path *path() { return self->path(); }
|
||||||
RiseFall *end_transition()
|
RiseFall *end_transition()
|
||||||
{ return const_cast<RiseFall*>(self->path()->transition(Sta::sta())); }
|
{ return const_cast<RiseFall*>(self->path()->transition(Sta::sta())); }
|
||||||
Slack slack() { return self->slack(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
|
float
|
||||||
arrival()
|
arrival()
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
return delayAsFloat(self->arrival());
|
||||||
return delayAsFloat(self->arrival(sta));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
required()
|
required()
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
return delayAsFloat(self->required());
|
||||||
return delayAsFloat(self->required(sta));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
|
|
@ -1354,12 +1328,10 @@ pins()
|
||||||
{
|
{
|
||||||
Sta *sta = Sta::sta();
|
Sta *sta = Sta::sta();
|
||||||
PinSeq pins;
|
PinSeq pins;
|
||||||
PathRef path1(self);
|
Path *path1 = self;
|
||||||
while (!path1.isNull()) {
|
while (path1) {
|
||||||
pins.push_back(path1.vertex(sta)->pin());
|
pins.push_back(path1->vertex(sta)->pin());
|
||||||
PathRef prev_path;
|
path1 = path1->prevPath();
|
||||||
path1.prevPath(sta, prev_path);
|
|
||||||
path1.init(prev_path);
|
|
||||||
}
|
}
|
||||||
return pins;
|
return pins;
|
||||||
}
|
}
|
||||||
|
|
@ -1368,11 +1340,10 @@ pins()
|
||||||
|
|
||||||
%extend VertexPathIterator {
|
%extend VertexPathIterator {
|
||||||
bool has_next() { return self->hasNext(); }
|
bool has_next() { return self->hasNext(); }
|
||||||
PathRef *
|
Path *
|
||||||
next()
|
next()
|
||||||
{
|
{
|
||||||
Path *path = self->next();
|
return self->next();
|
||||||
return new PathRef(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void finish() { delete self; }
|
void finish() { delete self; }
|
||||||
|
|
|
||||||
|
|
@ -854,7 +854,6 @@ proc_redirect report_path {
|
||||||
report_line "Tag: [$path tag]"
|
report_line "Tag: [$path tag]"
|
||||||
}
|
}
|
||||||
report_path_cmd $path
|
report_path_cmd $path
|
||||||
delete_path_ref $path
|
|
||||||
set first 0
|
set first 0
|
||||||
}
|
}
|
||||||
$path_iter finish
|
$path_iter finish
|
||||||
|
|
@ -865,7 +864,6 @@ proc_redirect report_path {
|
||||||
report_line "Tag: [$worst_path tag]"
|
report_line "Tag: [$worst_path tag]"
|
||||||
}
|
}
|
||||||
report_path_cmd $worst_path
|
report_path_cmd $worst_path
|
||||||
delete_path_ref $worst_path
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2488,6 +2488,8 @@ Sta::searchPreamble()
|
||||||
findDelays();
|
findDelays();
|
||||||
updateGeneratedClks();
|
updateGeneratedClks();
|
||||||
sdc_->searchPreamble();
|
sdc_->searchPreamble();
|
||||||
|
// Delete results from last findPathEnds because they point to filtered arrivals.
|
||||||
|
search_->deletePathGroups();
|
||||||
search_->deleteFilteredArrivals();
|
search_->deleteFilteredArrivals();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2759,82 +2761,82 @@ Sta::vertexPathIterator(Vertex *vertex,
|
||||||
return new VertexPathIterator(vertex, rf, min_max, this);
|
return new VertexPathIterator(vertex, rf, min_max, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathRef
|
Path *
|
||||||
Sta::vertexWorstArrivalPath(Vertex *vertex,
|
Sta::vertexWorstArrivalPath(Vertex *vertex,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
return vertexWorstArrivalPath(vertex, nullptr, min_max);
|
return vertexWorstArrivalPath(vertex, nullptr, min_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathRef
|
Path *
|
||||||
Sta::vertexWorstArrivalPath(Vertex *vertex,
|
Sta::vertexWorstArrivalPath(Vertex *vertex,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
PathRef worst_path;
|
Path *worst_path = nullptr;
|
||||||
Arrival worst_arrival = min_max->initValue();
|
Arrival worst_arrival = min_max->initValue();
|
||||||
VertexPathIterator path_iter(vertex, rf, min_max, this);
|
VertexPathIterator path_iter(vertex, rf, min_max, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
Arrival arrival = path->arrival(this);
|
Arrival arrival = path->arrival();
|
||||||
if (!path->tag(this)->isGenClkSrcPath()
|
if (!path->tag(this)->isGenClkSrcPath()
|
||||||
&& delayGreater(arrival, worst_arrival, min_max, this)) {
|
&& delayGreater(arrival, worst_arrival, min_max, this)) {
|
||||||
worst_arrival = arrival;
|
worst_arrival = arrival;
|
||||||
worst_path.init(path);
|
worst_path = path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return worst_path;
|
return worst_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
PathRef
|
Path *
|
||||||
Sta::vertexWorstRequiredPath(Vertex *vertex,
|
Sta::vertexWorstRequiredPath(Vertex *vertex,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
return vertexWorstRequiredPath(vertex, nullptr, min_max);
|
return vertexWorstRequiredPath(vertex, nullptr, min_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathRef
|
Path *
|
||||||
Sta::vertexWorstRequiredPath(Vertex *vertex,
|
Sta::vertexWorstRequiredPath(Vertex *vertex,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
PathRef worst_path;
|
Path *worst_path = nullptr;
|
||||||
const MinMax *req_min_max = min_max->opposite();
|
const MinMax *req_min_max = min_max->opposite();
|
||||||
Arrival worst_req = req_min_max->initValue();
|
Arrival worst_req = req_min_max->initValue();
|
||||||
VertexPathIterator path_iter(vertex, rf, min_max, this);
|
VertexPathIterator path_iter(vertex, rf, min_max, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
const Required path_req = path->required(this);
|
const Required path_req = path->required();
|
||||||
if (!path->tag(this)->isGenClkSrcPath()
|
if (!path->tag(this)->isGenClkSrcPath()
|
||||||
&& delayGreater(path_req, worst_req, req_min_max, this)) {
|
&& delayGreater(path_req, worst_req, req_min_max, this)) {
|
||||||
worst_req = path_req;
|
worst_req = path_req;
|
||||||
worst_path.init(path);
|
worst_path = path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return worst_path;
|
return worst_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
PathRef
|
Path *
|
||||||
Sta::vertexWorstSlackPath(Vertex *vertex,
|
Sta::vertexWorstSlackPath(Vertex *vertex,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
{
|
{
|
||||||
PathRef worst_path;
|
Path *worst_path = nullptr;
|
||||||
Slack min_slack = MinMax::min()->initValue();
|
Slack min_slack = MinMax::min()->initValue();
|
||||||
VertexPathIterator path_iter(vertex, rf, min_max, this);
|
VertexPathIterator path_iter(vertex, rf, min_max, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
Slack slack = path->slack(this);
|
Slack slack = path->slack(this);
|
||||||
if (!path->tag(this)->isGenClkSrcPath()
|
if (!path->tag(this)->isGenClkSrcPath()
|
||||||
&& delayLess(slack, min_slack, this)) {
|
&& delayLess(slack, min_slack, this)) {
|
||||||
min_slack = slack;
|
min_slack = slack;
|
||||||
worst_path.init(path);
|
worst_path = path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return worst_path;
|
return worst_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
PathRef
|
Path *
|
||||||
Sta::vertexWorstSlackPath(Vertex *vertex,
|
Sta::vertexWorstSlackPath(Vertex *vertex,
|
||||||
const MinMax *min_max)
|
const MinMax *min_max)
|
||||||
|
|
||||||
|
|
@ -2891,12 +2893,12 @@ Sta::vertexArrival(Vertex *vertex,
|
||||||
VertexPathIterator path_iter(vertex, rf, path_ap, this);
|
VertexPathIterator path_iter(vertex, rf, path_ap, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
Path *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
const Arrival &path_arrival = path->arrival(this);
|
const Arrival &path_arrival = path->arrival();
|
||||||
ClkInfo *clk_info = path->clkInfo(search_);
|
ClkInfo *clk_info = path->clkInfo(search_);
|
||||||
if ((clk_edge == clk_edge_wildcard
|
if ((clk_edge == clk_edge_wildcard
|
||||||
|| clk_info->clkEdge() == clk_edge)
|
|| clk_info->clkEdge() == clk_edge)
|
||||||
&& !clk_info->isGenClkSrcPath()
|
&& !clk_info->isGenClkSrcPath()
|
||||||
&& delayGreater(path->arrival(this), arrival, min_max, this))
|
&& delayGreater(path->arrival(), arrival, min_max, this))
|
||||||
arrival = path_arrival;
|
arrival = path_arrival;
|
||||||
}
|
}
|
||||||
return arrival;
|
return arrival;
|
||||||
|
|
@ -2949,7 +2951,7 @@ Sta::vertexRequired(Vertex *vertex,
|
||||||
VertexPathIterator path_iter(vertex, rf, path_ap, min_max, this);
|
VertexPathIterator path_iter(vertex, rf, path_ap, min_max, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
const Path *path = path_iter.next();
|
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
|
if ((clk_edge == clk_edge_wildcard
|
||||||
|| path->clkEdge(search_) == clk_edge)
|
|| path->clkEdge(search_) == clk_edge)
|
||||||
&& delayGreater(path_required, required, req_min_max, this))
|
&& delayGreater(path_required, required, req_min_max, this))
|
||||||
|
|
@ -3177,7 +3179,7 @@ bool
|
||||||
MinPeriodEndVisitor::pathIsFromInputPort(PathEnd *path_end)
|
MinPeriodEndVisitor::pathIsFromInputPort(PathEnd *path_end)
|
||||||
{
|
{
|
||||||
PathExpanded expanded(path_end->path(), sta_);
|
PathExpanded expanded(path_end->path(), sta_);
|
||||||
const PathRef *start = expanded.startPath();
|
const Path *start = expanded.startPath();
|
||||||
Graph *graph = sta_->graph();
|
Graph *graph = sta_->graph();
|
||||||
const Pin *first_pin = start->pin(graph);
|
const Pin *first_pin = start->pin(graph);
|
||||||
Network *network = sta_->network();
|
Network *network = sta_->network();
|
||||||
|
|
@ -3539,14 +3541,14 @@ Sta::pathDcalcAnalysisPt(Path *path)
|
||||||
}
|
}
|
||||||
|
|
||||||
Vertex *
|
Vertex *
|
||||||
Sta::maxArrivalCountVertex() const
|
Sta::maxPathCountVertex() const
|
||||||
{
|
{
|
||||||
Vertex *max_vertex = nullptr;
|
Vertex *max_vertex = nullptr;
|
||||||
int max_count = 0;
|
int max_count = 0;
|
||||||
VertexIterator vertex_iter(graph_);
|
VertexIterator vertex_iter(graph_);
|
||||||
while (vertex_iter.hasNext()) {
|
while (vertex_iter.hasNext()) {
|
||||||
Vertex *vertex = vertex_iter.next();
|
Vertex *vertex = vertex_iter.next();
|
||||||
int count = vertexArrivalCount(vertex);
|
int count = vertexPathCount(vertex);
|
||||||
if (count > max_count) {
|
if (count > max_count) {
|
||||||
max_count = count;
|
max_count = count;
|
||||||
max_vertex = vertex;
|
max_vertex = vertex;
|
||||||
|
|
@ -3556,36 +3558,23 @@ Sta::maxArrivalCountVertex() const
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Sta::vertexArrivalCount(Vertex *vertex) const
|
Sta::vertexPathCount(Vertex *vertex) const
|
||||||
{
|
{
|
||||||
TagGroup *tag_group = search_->tagGroup(vertex);
|
TagGroup *tag_group = search_->tagGroup(vertex);
|
||||||
if (tag_group)
|
if (tag_group)
|
||||||
return tag_group->arrivalCount();
|
return tag_group->pathCount();
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Sta::arrivalCount() const
|
Sta::pathCount() const
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
VertexIterator vertex_iter(graph_);
|
VertexIterator vertex_iter(graph_);
|
||||||
while (vertex_iter.hasNext()) {
|
while (vertex_iter.hasNext()) {
|
||||||
Vertex *vertex = vertex_iter.next();
|
Vertex *vertex = vertex_iter.next();
|
||||||
count += vertexArrivalCount(vertex);
|
count += vertexPathCount(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);
|
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
@ -4195,6 +4184,8 @@ Sta::makePortPin(const char *port_name,
|
||||||
void
|
void
|
||||||
Sta::makeInstanceAfter(const Instance *inst)
|
Sta::makeInstanceAfter(const Instance *inst)
|
||||||
{
|
{
|
||||||
|
debugPrint(debug_, "network_edit", 1, "make instance %s",
|
||||||
|
sdc_network_->pathName(inst));
|
||||||
if (graph_) {
|
if (graph_) {
|
||||||
LibertyCell *lib_cell = network_->libertyCell(inst);
|
LibertyCell *lib_cell = network_->libertyCell(inst);
|
||||||
if (lib_cell) {
|
if (lib_cell) {
|
||||||
|
|
@ -4367,6 +4358,9 @@ Sta::replaceCellAfter(const Instance *inst)
|
||||||
void
|
void
|
||||||
Sta::connectPinAfter(const Pin *pin)
|
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 (graph_) {
|
||||||
if (network_->isHierarchical(pin)) {
|
if (network_->isHierarchical(pin)) {
|
||||||
graph_->makeWireEdgesThruPin(pin);
|
graph_->makeWireEdgesThruPin(pin);
|
||||||
|
|
@ -4453,6 +4447,9 @@ Sta::connectLoadPinAfter(Vertex *vertex)
|
||||||
void
|
void
|
||||||
Sta::disconnectPinBefore(const Pin *pin)
|
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_);
|
parasitics_->disconnectPinBefore(pin, network_);
|
||||||
sdc_->disconnectPinBefore(pin);
|
sdc_->disconnectPinBefore(pin);
|
||||||
sim_->disconnectPinBefore(pin);
|
sim_->disconnectPinBefore(pin);
|
||||||
|
|
@ -4500,10 +4497,11 @@ Sta::disconnectPinBefore(const Pin *pin)
|
||||||
void
|
void
|
||||||
Sta::deleteEdge(Edge *edge)
|
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_);
|
Vertex *to = edge->to(graph_);
|
||||||
search_->arrivalInvalid(to);
|
search_->deleteEdgeBefore(edge);
|
||||||
search_->requiredInvalid(from);
|
|
||||||
graph_delay_calc_->delayInvalid(to);
|
graph_delay_calc_->delayInvalid(to);
|
||||||
levelize_->relevelizeFrom(to);
|
levelize_->relevelizeFrom(to);
|
||||||
levelize_->deleteEdgeBefore(edge);
|
levelize_->deleteEdgeBefore(edge);
|
||||||
|
|
@ -4514,6 +4512,8 @@ Sta::deleteEdge(Edge *edge)
|
||||||
void
|
void
|
||||||
Sta::deleteNetBefore(const Net *net)
|
Sta::deleteNetBefore(const Net *net)
|
||||||
{
|
{
|
||||||
|
debugPrint(debug_, "network_edit", 1, "delete net %s",
|
||||||
|
sdc_network_->pathName(net));
|
||||||
if (graph_) {
|
if (graph_) {
|
||||||
NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net);
|
NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net);
|
||||||
while (pin_iter->hasNext()) {
|
while (pin_iter->hasNext()) {
|
||||||
|
|
@ -4540,6 +4540,8 @@ Sta::deleteNetBefore(const Net *net)
|
||||||
void
|
void
|
||||||
Sta::deleteInstanceBefore(const Instance *inst)
|
Sta::deleteInstanceBefore(const Instance *inst)
|
||||||
{
|
{
|
||||||
|
debugPrint(debug_, "network_edit", 1, "delete instance %s",
|
||||||
|
sdc_network_->pathName(inst));
|
||||||
if (network_->isLeaf(inst)) {
|
if (network_->isLeaf(inst)) {
|
||||||
deleteInstancePinsBefore(inst);
|
deleteInstancePinsBefore(inst);
|
||||||
deleteLeafInstanceBefore(inst);
|
deleteLeafInstanceBefore(inst);
|
||||||
|
|
@ -5715,7 +5717,7 @@ Sta::activity(const Pin *pin)
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void
|
void
|
||||||
Sta::writePathSpice(PathRef *path,
|
Sta::writePathSpice(Path *path,
|
||||||
const char *spice_filename,
|
const char *spice_filename,
|
||||||
const char *subckt_filename,
|
const char *subckt_filename,
|
||||||
const char *lib_subckt_filename,
|
const char *lib_subckt_filename,
|
||||||
|
|
|
||||||
|
|
@ -148,10 +148,10 @@ Tag::asString(bool report_index,
|
||||||
result += network->pathName(clk_src);
|
result += network->pathName(clk_src);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathVertex crpr_clk_path(clk_info_->crprClkPath(), sta);
|
const Path *crpr_clk_path = clk_info_->crprClkPath(sta);
|
||||||
if (!crpr_clk_path.isNull()) {
|
if (crpr_clk_path != nullptr) {
|
||||||
result += " crpr_pin ";
|
result += " crpr_pin ";
|
||||||
result += network->pathName(crpr_clk_path.pin(sta));
|
result += network->pathName(crpr_clk_path->pin(sta));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input_delay_) {
|
if (input_delay_) {
|
||||||
|
|
@ -280,11 +280,12 @@ Tag::findHash()
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
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)
|
if (match_crpr_clk_pin)
|
||||||
// match_hash_ with crpr clk pin thrown in.
|
// match_hash_ with crpr clk pin thrown in.
|
||||||
return hashSum(match_hash_, clk_info_->crprClkVertexId());
|
return hashSum(match_hash_, clk_info_->crprClkVertexId(sta));
|
||||||
else
|
else
|
||||||
return match_hash_;
|
return match_hash_;
|
||||||
}
|
}
|
||||||
|
|
@ -421,7 +422,7 @@ tagMatch(const Tag *tag1,
|
||||||
&& clk_info1->isGenClkSrcPath() == clk_info2->isGenClkSrcPath()
|
&& clk_info1->isGenClkSrcPath() == clk_info2->isGenClkSrcPath()
|
||||||
&& (!match_crpr_clk_pin
|
&& (!match_crpr_clk_pin
|
||||||
|| !sta->sdc()->crprActive()
|
|| !sta->sdc()->crprActive()
|
||||||
|| clk_info1->crprClkVertexId() == clk_info2->crprClkVertexId())
|
|| clk_info1->crprClkVertexId(sta) == clk_info2->crprClkVertexId(sta))
|
||||||
&& tagStateEqual(tag1, tag2));
|
&& tagStateEqual(tag1, tag2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -482,8 +483,8 @@ tagMatchCmp(const Tag *tag1,
|
||||||
|
|
||||||
if (match_crpr_clk_pin
|
if (match_crpr_clk_pin
|
||||||
&& sta->sdc()->crprActive()) {
|
&& sta->sdc()->crprActive()) {
|
||||||
VertexId crpr_vertex1 = clk_info1->crprClkVertexId();
|
VertexId crpr_vertex1 = clk_info1->crprClkVertexId(sta);
|
||||||
VertexId crpr_vertex2 = clk_info2->crprClkVertexId();
|
VertexId crpr_vertex2 = clk_info2->crprClkVertexId(sta);
|
||||||
if (crpr_vertex1 < crpr_vertex2)
|
if (crpr_vertex1 < crpr_vertex2)
|
||||||
return -1;
|
return -1;
|
||||||
if (crpr_vertex1 > crpr_vertex2)
|
if (crpr_vertex1 > crpr_vertex2)
|
||||||
|
|
@ -676,7 +677,7 @@ TagMatchHash::TagMatchHash(bool match_crpr_clk_pin,
|
||||||
size_t
|
size_t
|
||||||
TagMatchHash::operator()(const Tag *tag) const
|
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,
|
TagMatchEqual::TagMatchEqual(bool match_crpr_clk_pin,
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
#include "Transition.hh"
|
#include "Transition.hh"
|
||||||
#include "SdcClass.hh"
|
#include "SdcClass.hh"
|
||||||
#include "SearchClass.hh"
|
#include "SearchClass.hh"
|
||||||
#include "PathRef.hh"
|
#include "Path.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
|
|
@ -86,7 +86,8 @@ public:
|
||||||
bool isFilter() const { return is_filter_; }
|
bool isFilter() const { return is_filter_; }
|
||||||
bool isSegmentStart() const { return is_segment_start_; }
|
bool isSegmentStart() const { return is_segment_start_; }
|
||||||
size_t hash() const { return hash_; }
|
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:
|
protected:
|
||||||
void findHash();
|
void findHash();
|
||||||
|
|
|
||||||
|
|
@ -32,66 +32,70 @@
|
||||||
#include "Tag.hh"
|
#include "Tag.hh"
|
||||||
#include "Corner.hh"
|
#include "Corner.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
#include "PathPrev.hh"
|
#include "Path.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
TagGroup::TagGroup(TagGroupIndex index,
|
TagGroup::TagGroup(TagGroupIndex index,
|
||||||
ArrivalMap *arrival_map,
|
PathIndexMap *path_index_map,
|
||||||
bool has_clk_tag,
|
bool has_clk_tag,
|
||||||
bool has_genclk_src_tag,
|
bool has_genclk_src_tag,
|
||||||
bool has_filter_tag,
|
bool has_filter_tag,
|
||||||
bool has_loop_tag) :
|
bool has_loop_tag) :
|
||||||
arrival_map_(arrival_map),
|
path_index_map_(path_index_map),
|
||||||
hash_(arrivalMapHash(arrival_map_)),
|
hash_(pathIndexMapHash(path_index_map)),
|
||||||
index_(index),
|
index_(index),
|
||||||
has_clk_tag_(has_clk_tag),
|
has_clk_tag_(has_clk_tag),
|
||||||
has_genclk_src_tag_(has_genclk_src_tag),
|
has_genclk_src_tag_(has_genclk_src_tag),
|
||||||
has_filter_tag_(has_filter_tag),
|
has_filter_tag_(has_filter_tag),
|
||||||
has_loop_tag_(has_loop_tag),
|
has_loop_tag_(has_loop_tag),
|
||||||
own_arrival_map_(true)
|
own_path_map_(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
TagGroup::TagGroup(TagGroupBldr *tag_bldr) :
|
TagGroup::TagGroup(TagGroupBldr *tag_bldr) :
|
||||||
arrival_map_(tag_bldr->arrivalMap()),
|
path_index_map_(&tag_bldr->pathIndexMap()),
|
||||||
hash_(arrivalMapHash(arrival_map_)),
|
hash_(pathIndexMapHash(path_index_map_)),
|
||||||
own_arrival_map_(false)
|
own_path_map_(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
TagGroup::~TagGroup()
|
TagGroup::~TagGroup()
|
||||||
{
|
{
|
||||||
if (own_arrival_map_)
|
if (own_path_map_)
|
||||||
delete arrival_map_;
|
delete path_index_map_;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
TagGroup::arrivalMapHash(ArrivalMap *arrival_map)
|
TagGroup::pathIndexMapHash(PathIndexMap *path_index_map)
|
||||||
{
|
{
|
||||||
size_t hash = 0;
|
size_t hash = 0;
|
||||||
ArrivalMap::Iterator arrival_iter(arrival_map);
|
for (auto const [tag, path_index] : *path_index_map)
|
||||||
while (arrival_iter.hasNext()) {
|
|
||||||
Tag *tag;
|
|
||||||
int arrival_index;
|
|
||||||
arrival_iter.next(tag, arrival_index);
|
|
||||||
hash += tag->hash();
|
hash += tag->hash();
|
||||||
}
|
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TagGroup::hasTag(Tag *tag) const
|
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
|
void
|
||||||
TagGroup::arrivalIndex(Tag *tag,
|
TagGroup::pathIndex(Tag *tag,
|
||||||
int &arrival_index,
|
size_t &path_index,
|
||||||
bool &exists) const
|
bool &exists) const
|
||||||
{
|
{
|
||||||
arrival_map_->findKey(tag, arrival_index, exists);
|
path_index_map_->findKey(tag, path_index, exists);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -99,29 +103,24 @@ TagGroup::report(const StaState *sta) const
|
||||||
{
|
{
|
||||||
Report *report = sta->report();
|
Report *report = sta->report();
|
||||||
report->reportLine("Group %u hash = %zu", index_, hash_);
|
report->reportLine("Group %u hash = %zu", index_, hash_);
|
||||||
arrivalMapReport(arrival_map_, sta);
|
pathIndexMapReport(path_index_map_, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TagGroup::reportArrivalMap(const StaState *sta) const
|
TagGroup::reportArrivalMap(const StaState *sta) const
|
||||||
{
|
{
|
||||||
arrivalMapReport(arrival_map_, sta);
|
pathIndexMapReport(path_index_map_, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arrivalMapReport(const ArrivalMap *arrival_map,
|
pathIndexMapReport(const PathIndexMap *path_index_map,
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
Report *report = sta->report();
|
Report *report = sta->report();
|
||||||
ArrivalMap::ConstIterator arrival_iter(arrival_map);
|
for (auto const [tag, path_index] : *path_index_map)
|
||||||
while (arrival_iter.hasNext()) {
|
report->reportLine(" %2zu %s",
|
||||||
Tag *tag;
|
path_index,
|
||||||
int arrival_index;
|
|
||||||
arrival_iter.next(tag, arrival_index);
|
|
||||||
report->reportLine(" %2u %s",
|
|
||||||
arrival_index,
|
|
||||||
tag->asString(sta));
|
tag->asString(sta));
|
||||||
}
|
|
||||||
report->reportBlankLine();
|
report->reportBlankLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,14 +128,13 @@ arrivalMapReport(const ArrivalMap *arrival_map,
|
||||||
|
|
||||||
TagGroupBldr::TagGroupBldr(bool match_crpr_clk_pin,
|
TagGroupBldr::TagGroupBldr(bool match_crpr_clk_pin,
|
||||||
const StaState *sta) :
|
const StaState *sta) :
|
||||||
default_arrival_count_(sta->corners()->count()
|
default_path_count_(sta->corners()->count()
|
||||||
* RiseFall::index_count
|
* RiseFall::index_count
|
||||||
* MinMax::index_count),
|
* MinMax::index_count),
|
||||||
arrival_map_(default_arrival_count_,
|
path_index_map_(default_path_count_,
|
||||||
TagMatchHash(match_crpr_clk_pin, sta),
|
TagMatchHash(match_crpr_clk_pin, sta),
|
||||||
TagMatchEqual(match_crpr_clk_pin, sta)),
|
TagMatchEqual(match_crpr_clk_pin, sta)),
|
||||||
arrivals_(default_arrival_count_),
|
paths_(default_path_count_),
|
||||||
prev_paths_(default_arrival_count_),
|
|
||||||
has_clk_tag_(false),
|
has_clk_tag_(false),
|
||||||
has_genclk_src_tag_(false),
|
has_genclk_src_tag_(false),
|
||||||
has_filter_tag_(false),
|
has_filter_tag_(false),
|
||||||
|
|
@ -149,16 +147,15 @@ TagGroupBldr::TagGroupBldr(bool match_crpr_clk_pin,
|
||||||
bool
|
bool
|
||||||
TagGroupBldr::empty()
|
TagGroupBldr::empty()
|
||||||
{
|
{
|
||||||
return arrival_map_.empty();
|
return path_index_map_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TagGroupBldr::init(Vertex *vertex)
|
TagGroupBldr::init(Vertex *vertex)
|
||||||
{
|
{
|
||||||
vertex_ = vertex;
|
vertex_ = vertex;
|
||||||
arrival_map_.clear();
|
path_index_map_.clear();
|
||||||
arrivals_.clear();
|
paths_.clear();
|
||||||
prev_paths_.clear();
|
|
||||||
has_clk_tag_ = false;
|
has_clk_tag_ = false;
|
||||||
has_genclk_src_tag_ = false;
|
has_genclk_src_tag_ = false;
|
||||||
has_filter_tag_ = false;
|
has_filter_tag_ = false;
|
||||||
|
|
@ -168,147 +165,152 @@ TagGroupBldr::init(Vertex *vertex)
|
||||||
void
|
void
|
||||||
TagGroupBldr::reportArrivalEntries() const
|
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
|
void
|
||||||
TagGroupBldr::tagMatchArrival(Tag *tag,
|
TagGroupBldr::tagMatchPath(Tag *tag,
|
||||||
// Return values.
|
// Return values.
|
||||||
Tag *&tag_match,
|
Path *&match,
|
||||||
Arrival &arrival,
|
size_t &path_index)
|
||||||
int &arrival_index) const
|
|
||||||
{
|
{
|
||||||
// Find matching group tag.
|
// Find matching group tag.
|
||||||
// Match is not necessarily equal to original tag because it
|
// Match is not necessarily equal to original tag because it
|
||||||
// must only satisfy tagMatch.
|
// must only satisfy tagMatch.
|
||||||
bool exists;
|
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)
|
if (exists)
|
||||||
arrival = arrivals_[arrival_index];
|
match = &paths_[path_index];
|
||||||
else {
|
else {
|
||||||
tag_match = nullptr;
|
match = nullptr;
|
||||||
arrival = -1.0;
|
path_index = 0;
|
||||||
arrival_index = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrival
|
Arrival
|
||||||
TagGroupBldr::arrival(int arrival_index) const
|
TagGroupBldr::arrival(size_t path_index) const
|
||||||
{
|
{
|
||||||
return arrivals_[arrival_index];
|
return paths_[path_index].arrival();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TagGroupBldr::setArrival(Tag *tag,
|
TagGroupBldr::setArrival(Tag *tag,
|
||||||
const Arrival &arrival,
|
const Arrival &arrival)
|
||||||
PathPrev *prev_path)
|
|
||||||
{
|
{
|
||||||
Tag *tag_match;
|
|
||||||
Arrival ignore;
|
|
||||||
int arrival_index;
|
|
||||||
// Find matching group tag (not necessarily equal to original tag).
|
// Find matching group tag (not necessarily equal to original tag).
|
||||||
tagMatchArrival(tag, tag_match, ignore, arrival_index);
|
Path *match;
|
||||||
setMatchArrival(tag, tag_match, arrival, arrival_index, prev_path);
|
size_t path_index;
|
||||||
|
tagMatchPath(tag, match, path_index);
|
||||||
|
setMatchPath(match, path_index, tag, arrival, nullptr, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TagGroupBldr::setMatchArrival(Tag *tag,
|
TagGroupBldr::setMatchPath(Path *match,
|
||||||
Tag *tag_match,
|
size_t path_index,
|
||||||
const Arrival &arrival,
|
Tag *tag,
|
||||||
int arrival_index,
|
Arrival arrival,
|
||||||
PathPrev *prev_path)
|
Path *prev_path,
|
||||||
|
Edge *prev_edge,
|
||||||
|
TimingArc *prev_arc)
|
||||||
{
|
{
|
||||||
if (tag_match) {
|
if (match) {
|
||||||
// If the group_tag exists there has to be an arrival map entry for it.
|
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) {
|
if (tag_match != tag) {
|
||||||
// Replace tag in arrival map.
|
// Replace tag in arrival map.
|
||||||
arrival_map_.erase(tag_match);
|
path_index_map_.erase(tag_match);
|
||||||
arrival_map_.insert(tag, arrival_index);
|
path_index_map_.insert(tag, path_index);
|
||||||
}
|
}
|
||||||
arrivals_[arrival_index] = arrival;
|
paths_[path_index].init(vertex_, tag, arrival, prev_path,
|
||||||
prev_paths_[arrival_index].init(prev_path);
|
prev_edge, prev_arc, sta_);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
arrival_index = arrivals_.size();
|
insertPath(tag, arrival, prev_path, prev_edge, prev_arc);
|
||||||
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());
|
|
||||||
|
|
||||||
if (tag->isClock())
|
void
|
||||||
has_clk_tag_ = true;
|
TagGroupBldr::insertPath(Tag *tag,
|
||||||
if (tag->isGenClkSrcPath())
|
Arrival arrival,
|
||||||
has_genclk_src_tag_ = true;
|
Path *prev_path,
|
||||||
if (tag->isFilter()
|
Edge *prev_edge,
|
||||||
|| tag->clkInfo()->refsFilter(sta_))
|
TimingArc *prev_arc)
|
||||||
has_filter_tag_ = true;
|
|
||||||
if (tag->isLoop())
|
{
|
||||||
has_loop_tag_ = true;
|
size_t path_index = paths_.size();
|
||||||
if (tag->clkInfo()->isPropagated())
|
path_index_map_.insert(tag, path_index);
|
||||||
has_propagated_clk_ = true;
|
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 *
|
TagGroup *
|
||||||
TagGroupBldr::makeTagGroup(TagGroupIndex index,
|
TagGroupBldr::makeTagGroup(TagGroupIndex index,
|
||||||
const StaState *sta)
|
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_clk_tag_, has_genclk_src_tag_, has_filter_tag_,
|
||||||
has_loop_tag_);
|
has_loop_tag_);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrivalMap *
|
PathIndexMap *
|
||||||
TagGroupBldr::makeArrivalMap(const StaState *sta)
|
TagGroupBldr::makePathIndexMap(const StaState *sta)
|
||||||
{
|
{
|
||||||
ArrivalMap *arrival_map = new ArrivalMap(arrival_map_.size(),
|
PathIndexMap *path_index_map = new PathIndexMap(path_index_map_.size(),
|
||||||
TagMatchHash(true, sta),
|
TagMatchHash(true, sta),
|
||||||
TagMatchEqual(true, sta));
|
TagMatchEqual(true, sta));
|
||||||
int arrival_index = 0;
|
|
||||||
ArrivalMap::Iterator arrival_iter(arrival_map_);
|
size_t path_index = 0;
|
||||||
while (arrival_iter.hasNext()) {
|
for (auto const [tag, path_index1] : path_index_map_) {
|
||||||
Tag *tag;
|
path_index_map->insert(tag, path_index);
|
||||||
int arrival_index1;
|
path_index++;
|
||||||
arrival_iter.next(tag, arrival_index1);
|
|
||||||
arrival_map->insert(tag, arrival_index);
|
|
||||||
arrival_index++;
|
|
||||||
}
|
}
|
||||||
return arrival_map;
|
return path_index_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TagGroupBldr::copyArrivals(TagGroup *tag_group,
|
TagGroupBldr::copyPaths(TagGroup *tag_group,
|
||||||
Arrival *arrivals,
|
Path *paths)
|
||||||
PathPrev *prev_paths)
|
|
||||||
{
|
{
|
||||||
ArrivalMap::Iterator arrival_iter1(arrival_map_);
|
for (auto const [tag1, path_index1] : path_index_map_) {
|
||||||
while (arrival_iter1.hasNext()) {
|
size_t path_index2;
|
||||||
Tag *tag1;
|
|
||||||
int arrival_index1, arrival_index2;
|
|
||||||
arrival_iter1.next(tag1, arrival_index1);
|
|
||||||
bool exists2;
|
bool exists2;
|
||||||
tag_group->arrivalIndex(tag1, arrival_index2, exists2);
|
tag_group->pathIndex(tag1, path_index2, exists2);
|
||||||
if (exists2) {
|
if (exists2)
|
||||||
arrivals[arrival_index2] = arrivals_[arrival_index1];
|
paths[path_index2] = paths_[path_index1];
|
||||||
if (prev_paths) {
|
|
||||||
PathPrev *prev_path = &prev_paths_[arrival_index1];
|
|
||||||
prev_paths[arrival_index2].init(prev_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
sta_->report()->critical(1351, "tag group missing tag");
|
sta_->report()->critical(1351, "tag group missing tag");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PathPrev &
|
|
||||||
TagGroupBldr::prevPath(int arrival_index)
|
|
||||||
{
|
|
||||||
return prev_paths_[arrival_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
|
|
@ -318,19 +320,15 @@ TagGroupHash::operator()(const TagGroup *group) const
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
arrivalMapEqual(const ArrivalMap *arrival_map1,
|
pathIndexMapEqual(const PathIndexMap *path_index_map1,
|
||||||
const ArrivalMap *arrival_map2)
|
const PathIndexMap *path_index_map2)
|
||||||
{
|
{
|
||||||
int arrival_count1 = arrival_map1->size();
|
if (path_index_map1->size() == path_index_map2->size()) {
|
||||||
int arrival_count2 = arrival_map2->size();
|
for (auto const [tag1, path_index1] : *path_index_map1) {
|
||||||
if (arrival_count1 == arrival_count2) {
|
Tag *tag2;
|
||||||
ArrivalMap::ConstIterator arrival_iter1(arrival_map1);
|
size_t path_index2;
|
||||||
while (arrival_iter1.hasNext()) {
|
|
||||||
Tag *tag1, *tag2;
|
|
||||||
int arrival_index1, arrival_index2;
|
|
||||||
arrival_iter1.next(tag1, arrival_index1);
|
|
||||||
bool exists2;
|
bool exists2;
|
||||||
arrival_map2->findKey(tag1, tag2, arrival_index2, exists2);
|
path_index_map2->findKey(tag1, tag2, path_index2, exists2);
|
||||||
if (!exists2
|
if (!exists2
|
||||||
// ArrivalMap equal function is TagMatchEqual, so make sure
|
// ArrivalMap equal function is TagMatchEqual, so make sure
|
||||||
// the tag is an exact match.
|
// the tag is an exact match.
|
||||||
|
|
@ -349,8 +347,8 @@ TagGroupEqual::operator()(const TagGroup *tag_group1,
|
||||||
{
|
{
|
||||||
return tag_group1 == tag_group2
|
return tag_group1 == tag_group2
|
||||||
|| (tag_group1->hash() == tag_group2->hash()
|
|| (tag_group1->hash() == tag_group2->hash()
|
||||||
&& arrivalMapEqual(tag_group1->arrivalMap(),
|
&& pathIndexMapEqual(tag_group1->pathIndexMap(),
|
||||||
tag_group2->arrivalMap()));
|
tag_group2->pathIndexMap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -37,13 +37,11 @@ namespace sta {
|
||||||
|
|
||||||
class TagGroupBldr;
|
class TagGroupBldr;
|
||||||
|
|
||||||
typedef Vector<PathPrev> PathPrevSeq;
|
|
||||||
|
|
||||||
class TagGroup
|
class TagGroup
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TagGroup(TagGroupIndex index,
|
TagGroup(TagGroupIndex index,
|
||||||
ArrivalMap *arrival_map,
|
PathIndexMap *path_index_map,
|
||||||
bool has_clk_tag,
|
bool has_clk_tag,
|
||||||
bool has_genclk_src_tag,
|
bool has_genclk_src_tag,
|
||||||
bool has_filter_tag,
|
bool has_filter_tag,
|
||||||
|
|
@ -59,26 +57,27 @@ public:
|
||||||
bool hasGenClkSrcTag() const { return has_genclk_src_tag_; }
|
bool hasGenClkSrcTag() const { return has_genclk_src_tag_; }
|
||||||
bool hasFilterTag() const { return has_filter_tag_; }
|
bool hasFilterTag() const { return has_filter_tag_; }
|
||||||
bool hasLoopTag() const { return has_loop_tag_; }
|
bool hasLoopTag() const { return has_loop_tag_; }
|
||||||
bool ownArrivalMap() const { return own_arrival_map_; }
|
bool ownPathMap() const { return own_path_map_; }
|
||||||
int arrivalCount() const { return arrival_map_->size(); }
|
size_t pathCount() const { return path_index_map_->size(); }
|
||||||
void arrivalIndex(Tag *tag,
|
void pathIndex(Tag *tag,
|
||||||
int &arrival_index,
|
size_t &path_index,
|
||||||
bool &exists) const;
|
bool &exists) const;
|
||||||
ArrivalMap *arrivalMap() const { return arrival_map_; }
|
size_t pathIndex(Tag *tag) const;
|
||||||
|
PathIndexMap *pathIndexMap() const { return path_index_map_; }
|
||||||
bool hasTag(Tag *tag) const;
|
bool hasTag(Tag *tag) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
size_t arrivalMapHash(ArrivalMap *arrival_map);
|
static size_t pathIndexMapHash(PathIndexMap *path_index_map);
|
||||||
|
|
||||||
// tag -> arrival index
|
// tag -> path index
|
||||||
ArrivalMap *arrival_map_;
|
PathIndexMap *path_index_map_;
|
||||||
size_t hash_;
|
size_t hash_;
|
||||||
unsigned int index_:tag_group_index_bits;
|
unsigned int index_:tag_group_index_bits;
|
||||||
bool has_clk_tag_:1;
|
bool has_clk_tag_:1;
|
||||||
bool has_genclk_src_tag_:1;
|
bool has_genclk_src_tag_:1;
|
||||||
bool has_filter_tag_:1;
|
bool has_filter_tag_:1;
|
||||||
bool has_loop_tag_:1;
|
bool has_loop_tag_:1;
|
||||||
bool own_arrival_map_:1;
|
bool own_path_map_:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TagGroupHash
|
class TagGroupHash
|
||||||
|
|
@ -106,40 +105,46 @@ public:
|
||||||
void reportArrivalEntries() const;
|
void reportArrivalEntries() const;
|
||||||
TagGroup *makeTagGroup(TagGroupIndex index,
|
TagGroup *makeTagGroup(TagGroupIndex index,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
size_t pathCount() const { return path_index_map_.size();; }
|
||||||
bool hasClkTag() const { return has_clk_tag_; }
|
bool hasClkTag() const { return has_clk_tag_; }
|
||||||
bool hasGenClkSrcTag() const { return has_genclk_src_tag_; }
|
bool hasGenClkSrcTag() const { return has_genclk_src_tag_; }
|
||||||
bool hasFilterTag() const { return has_filter_tag_; }
|
bool hasFilterTag() const { return has_filter_tag_; }
|
||||||
bool hasLoopTag() const { return has_loop_tag_; }
|
bool hasLoopTag() const { return has_loop_tag_; }
|
||||||
bool hasPropagatedClk() const { return has_propagated_clk_; }
|
bool hasPropagatedClk() const { return has_propagated_clk_; }
|
||||||
void tagMatchArrival(Tag *tag,
|
Path *tagMatchPath(Tag *tag);
|
||||||
// Return values.
|
void tagMatchPath(Tag *tag,
|
||||||
Tag *&tag_match,
|
// Return values.
|
||||||
Arrival &arrival,
|
Path *&match,
|
||||||
int &arrival_index) const;
|
size_t &path_index);
|
||||||
Arrival arrival(int arrival_index) const;
|
Arrival arrival(size_t path_index) const;
|
||||||
|
// prev_path == hull
|
||||||
void setArrival(Tag *tag,
|
void setArrival(Tag *tag,
|
||||||
const Arrival &arrival,
|
const Arrival &arrival);
|
||||||
PathPrev *prev_path);
|
void setMatchPath(Path *match,
|
||||||
void setMatchArrival(Tag *tag,
|
size_t path_index,
|
||||||
Tag *tag_match,
|
Tag *tag,
|
||||||
const Arrival &arrival,
|
Arrival arrival,
|
||||||
int arrival_index,
|
Path *prev_path,
|
||||||
PathPrev *prev_path);
|
Edge *prev_edge,
|
||||||
ArrivalMap *arrivalMap() { return &arrival_map_; }
|
TimingArc *prev_arc);
|
||||||
PathPrev &prevPath(int arrival_index);
|
void insertPath(Tag *tag,
|
||||||
void copyArrivals(TagGroup *tag_group,
|
Arrival arrival,
|
||||||
Arrival *arrivals,
|
Path *prev_path,
|
||||||
PathPrev *prev_paths);
|
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:
|
protected:
|
||||||
int tagMatchIndex();
|
int tagMatchIndex();
|
||||||
ArrivalMap *makeArrivalMap(const StaState *sta);
|
PathIndexMap *makePathIndexMap(const StaState *sta);
|
||||||
|
|
||||||
Vertex *vertex_;
|
Vertex *vertex_;
|
||||||
int default_arrival_count_;
|
int default_path_count_;
|
||||||
ArrivalMap arrival_map_;
|
PathIndexMap path_index_map_;
|
||||||
ArrivalSeq arrivals_;
|
vector<Path> paths_;
|
||||||
PathPrevSeq prev_paths_;
|
|
||||||
bool has_clk_tag_;
|
bool has_clk_tag_;
|
||||||
bool has_genclk_src_tag_;
|
bool has_genclk_src_tag_;
|
||||||
bool has_filter_tag_;
|
bool has_filter_tag_;
|
||||||
|
|
@ -149,7 +154,7 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
arrivalMapReport(const ArrivalMap *arrival_map,
|
pathIndexMapReport(const PathIndexMap *path_index_map,
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
#include "Graph.hh"
|
#include "Graph.hh"
|
||||||
#include "ClkInfo.hh"
|
#include "ClkInfo.hh"
|
||||||
#include "Tag.hh"
|
#include "Tag.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "PathAnalysisPt.hh"
|
#include "PathAnalysisPt.hh"
|
||||||
#include "PathEnd.hh"
|
#include "PathEnd.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
|
|
@ -91,7 +91,7 @@ VisitPathEnds::visitClkedPathEnds(const Pin *pin,
|
||||||
bool is_segment_start = search_->isSegmentStart(pin);
|
bool is_segment_start = search_->isSegmentStart(pin);
|
||||||
VertexPathIterator path_iter(vertex, this);
|
VertexPathIterator path_iter(vertex, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
||||||
const MinMax *path_min_max = path_ap->pathMinMax();
|
const MinMax *path_min_max = path_ap->pathMinMax();
|
||||||
const RiseFall *end_rf = path->transition(this);
|
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,
|
VertexPathIterator tgt_clk_path_iter(tgt_clk_vertex, clk_rf,
|
||||||
tgt_clk_path_ap, this);
|
tgt_clk_path_ap, this);
|
||||||
while (tgt_clk_path_iter.hasNext()) {
|
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);
|
ClkInfo *tgt_clk_info = tgt_clk_path->clkInfo(this);
|
||||||
const ClockEdge *tgt_clk_edge = tgt_clk_path->clkEdge(this);
|
const ClockEdge *tgt_clk_edge = tgt_clk_path->clkEdge(this);
|
||||||
const Clock *tgt_clk = tgt_clk_path->clock(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();
|
RiseFall *ref_rf = output_delay->refTransition();
|
||||||
VertexPathIterator ref_path_iter(ref_vertex,ref_rf,path_ap,this);
|
VertexPathIterator ref_path_iter(ref_vertex,ref_rf,path_ap,this);
|
||||||
while (ref_path_iter.hasNext()) {
|
while (ref_path_iter.hasNext()) {
|
||||||
PathVertex *ref_path = ref_path_iter.next();
|
Path *ref_path = ref_path_iter.next();
|
||||||
if (ref_path->isClock(this)
|
if (ref_path->isClock(this)
|
||||||
&& (tgt_clk == nullptr
|
&& (tgt_clk == nullptr
|
||||||
|| ref_path->clock(this) == tgt_clk))
|
|| ref_path->clock(this) == tgt_clk))
|
||||||
|
|
@ -343,7 +343,7 @@ VisitPathEnds::visitOutputDelayEnd1(OutputDelay *output_delay,
|
||||||
Path *path,
|
Path *path,
|
||||||
const RiseFall *end_rf,
|
const RiseFall *end_rf,
|
||||||
const ClockEdge *tgt_clk_edge,
|
const ClockEdge *tgt_clk_edge,
|
||||||
PathVertex *ref_path,
|
Path *ref_path,
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
PathEndVisitor *visitor,
|
PathEndVisitor *visitor,
|
||||||
bool &is_constrained)
|
bool &is_constrained)
|
||||||
|
|
@ -414,7 +414,7 @@ VisitPathEnds::visitGatedClkEnd(const Pin *pin,
|
||||||
min_max);
|
min_max);
|
||||||
VertexPathIterator clk_path_iter(clk_vertex, clk_rf, clk_path_ap, this);
|
VertexPathIterator clk_path_iter(clk_vertex, clk_rf, clk_path_ap, this);
|
||||||
while (clk_path_iter.hasNext()) {
|
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 ClockEdge *clk_edge = clk_path->clkEdge(this);
|
||||||
const Clock *clk = clk_edge ? clk_edge->clock() : nullptr;
|
const Clock *clk = clk_edge ? clk_edge->clock() : nullptr;
|
||||||
if (clk_path->isClock(this)
|
if (clk_path->isClock(this)
|
||||||
|
|
@ -544,7 +544,7 @@ VisitPathEnds::visitDataCheckEnd1(DataCheck *check,
|
||||||
bool found_from_path = false;
|
bool found_from_path = false;
|
||||||
VertexPathIterator tgt_clk_path_iter(from_vertex,from_rf,clk_ap,this);
|
VertexPathIterator tgt_clk_path_iter(from_vertex,from_rf,clk_ap,this);
|
||||||
while (tgt_clk_path_iter.hasNext()) {
|
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);
|
const ClockEdge *tgt_clk_edge = tgt_clk_path->clkEdge(this);
|
||||||
// Ignore generated clock source paths.
|
// Ignore generated clock source paths.
|
||||||
if (tgt_clk_edge
|
if (tgt_clk_edge
|
||||||
|
|
@ -584,7 +584,7 @@ VisitPathEnds::visitUnconstrainedPathEnds(const Pin *pin,
|
||||||
{
|
{
|
||||||
VertexPathIterator path_iter(vertex, this);
|
VertexPathIterator path_iter(vertex, this);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
|
||||||
const MinMax *path_min_max = path_ap->pathMinMax();
|
const MinMax *path_min_max = path_ap->pathMinMax();
|
||||||
if ((corner == nullptr
|
if ((corner == nullptr
|
||||||
|
|
|
||||||
|
|
@ -28,21 +28,20 @@
|
||||||
#include "Graph.hh"
|
#include "Graph.hh"
|
||||||
#include "Bfs.hh"
|
#include "Bfs.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "PathEnd.hh"
|
#include "PathEnd.hh"
|
||||||
#include "Tag.hh"
|
#include "Tag.hh"
|
||||||
#include "VisitPathEnds.hh"
|
#include "VisitPathEnds.hh"
|
||||||
|
|
||||||
namespace sta {
|
namespace sta {
|
||||||
|
|
||||||
typedef Set<PathVertex*, PathLess> PathVertexSet;
|
typedef Set<Path*, PathLess> PathSet;
|
||||||
typedef Map<Vertex*, PathVertexSet*> VertexPathSetMap;
|
typedef Map<Vertex*, PathSet*> VertexPathSetMap;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
|
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
|
||||||
Vertex *vertex,
|
Vertex *vertex,
|
||||||
Tag *tag,
|
Tag *tag,
|
||||||
int arrival_index,
|
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
|
||||||
// Visit each path end for a vertex and add the worst one in each
|
// Visit each path end for a vertex and add the worst one in each
|
||||||
|
|
@ -87,7 +86,7 @@ protected:
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
Path *from_path,
|
||||||
const Arrival &from_arrival,
|
const Arrival &from_arrival,
|
||||||
Edge *edge,
|
Edge *edge,
|
||||||
TimingArc *arc,
|
TimingArc *arc,
|
||||||
|
|
@ -99,8 +98,7 @@ protected:
|
||||||
const MinMax *min_max,
|
const MinMax *min_max,
|
||||||
const PathAnalysisPt *path_ap);
|
const PathAnalysisPt *path_ap);
|
||||||
void fromMatches(Vertex *from_vertex,
|
void fromMatches(Vertex *from_vertex,
|
||||||
Tag *from_tag,
|
Tag *from_tag);
|
||||||
int from_arrival_index);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VertexVisitor *visitor_;
|
VertexVisitor *visitor_;
|
||||||
|
|
@ -139,10 +137,10 @@ visitPathGroupVertices(PathGroup *path_group,
|
||||||
// Cleanup.
|
// Cleanup.
|
||||||
VertexPathSetMap::Iterator matching_iter(matching_path_map);
|
VertexPathSetMap::Iterator matching_iter(matching_path_map);
|
||||||
while (matching_iter.hasNext()) {
|
while (matching_iter.hasNext()) {
|
||||||
PathVertexSet *paths = matching_iter.next();
|
PathSet *paths = matching_iter.next();
|
||||||
PathVertexSet::Iterator path_iter(paths);
|
PathSet::Iterator path_iter(paths);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathVertex *path = path_iter.next();
|
Path *path = path_iter.next();
|
||||||
delete path;
|
delete path;
|
||||||
}
|
}
|
||||||
delete paths;
|
delete paths;
|
||||||
|
|
@ -181,14 +179,9 @@ VisitPathGroupEnds::visit(PathEnd *path_end)
|
||||||
{
|
{
|
||||||
PathGroup *group = sta_->search()->pathGroup(path_end);
|
PathGroup *group = sta_->search()->pathGroup(path_end);
|
||||||
if (group == path_group_) {
|
if (group == path_group_) {
|
||||||
PathRef path(path_end->pathRef());
|
Path *path = path_end->path();
|
||||||
Vertex *vertex = path.vertex(sta_);
|
Vertex *vertex = path->vertex(sta_);
|
||||||
|
vertexPathSetMapInsertPath(matching_path_map_, vertex, path->tag(sta_), sta_);
|
||||||
int arrival_index;
|
|
||||||
bool arrival_exists;
|
|
||||||
path.arrivalIndex(arrival_index, arrival_exists);
|
|
||||||
vertexPathSetMapInsertPath(matching_path_map_, vertex, path.tag(sta_),
|
|
||||||
arrival_index, sta_);
|
|
||||||
vertex_matches_ = true;
|
vertex_matches_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -197,16 +190,15 @@ static void
|
||||||
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
|
vertexPathSetMapInsertPath(VertexPathSetMap *matching_path_map,
|
||||||
Vertex *vertex,
|
Vertex *vertex,
|
||||||
Tag *tag,
|
Tag *tag,
|
||||||
int arrival_index,
|
|
||||||
const StaState *sta)
|
const StaState *sta)
|
||||||
{
|
{
|
||||||
PathVertexSet *matching_paths = matching_path_map->findKey(vertex);
|
PathSet *matching_paths = matching_path_map->findKey(vertex);
|
||||||
if (matching_paths == nullptr) {
|
if (matching_paths == nullptr) {
|
||||||
PathLess path_less(sta);
|
PathLess path_less(sta);
|
||||||
matching_paths = new PathVertexSet(path_less);
|
matching_paths = new PathSet(path_less);
|
||||||
(*matching_path_map)[vertex] = matching_paths;
|
(*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);
|
matching_paths->insert(vpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,7 +254,7 @@ PathGroupPathVisitor::visitFromToPath(const Pin *,
|
||||||
Vertex *from_vertex,
|
Vertex *from_vertex,
|
||||||
const RiseFall *,
|
const RiseFall *,
|
||||||
Tag *from_tag,
|
Tag *from_tag,
|
||||||
PathVertex *from_path,
|
Path *,
|
||||||
const Arrival &,
|
const Arrival &,
|
||||||
Edge *,
|
Edge *,
|
||||||
TimingArc *,
|
TimingArc *,
|
||||||
|
|
@ -274,12 +266,9 @@ PathGroupPathVisitor::visitFromToPath(const Pin *,
|
||||||
const MinMax *,
|
const MinMax *,
|
||||||
const PathAnalysisPt *path_ap)
|
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) {
|
if (matching_paths) {
|
||||||
int arrival_index;
|
Path to_path(to_vertex, to_tag, this);
|
||||||
bool arrival_exists;
|
|
||||||
from_path->arrivalIndex(arrival_index, arrival_exists);
|
|
||||||
PathVertex to_path(to_vertex, to_tag, this);
|
|
||||||
if (!to_path.isNull()) {
|
if (!to_path.isNull()) {
|
||||||
if (matching_paths->hasKey(&to_path)) {
|
if (matching_paths->hasKey(&to_path)) {
|
||||||
debugPrint(debug_, "visit_path_group", 2, "match %s %s -> %s %s",
|
debugPrint(debug_, "visit_path_group", 2, "match %s %s -> %s %s",
|
||||||
|
|
@ -287,13 +276,13 @@ PathGroupPathVisitor::visitFromToPath(const Pin *,
|
||||||
from_tag->asString(this),
|
from_tag->asString(this),
|
||||||
to_vertex->name(network_),
|
to_vertex->name(network_),
|
||||||
to_tag->asString(this));
|
to_tag->asString(this));
|
||||||
fromMatches(from_vertex, from_tag, arrival_index);
|
fromMatches(from_vertex, from_tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
VertexPathIterator to_iter(to_vertex, to_rf, path_ap, this);
|
VertexPathIterator to_iter(to_vertex, to_rf, path_ap, this);
|
||||||
while (to_iter.hasNext()) {
|
while (to_iter.hasNext()) {
|
||||||
PathVertex *to_path = to_iter.next();
|
Path *to_path = to_iter.next();
|
||||||
if (tagMatchNoCrpr(to_path->tag(this), to_tag)
|
if (tagMatchNoCrpr(to_path->tag(this), to_tag)
|
||||||
&& matching_paths->hasKey(to_path)) {
|
&& matching_paths->hasKey(to_path)) {
|
||||||
debugPrint(debug_, "visit_path_group", 2,
|
debugPrint(debug_, "visit_path_group", 2,
|
||||||
|
|
@ -302,7 +291,7 @@ PathGroupPathVisitor::visitFromToPath(const Pin *,
|
||||||
from_tag->asString(this),
|
from_tag->asString(this),
|
||||||
to_vertex->name(network_),
|
to_vertex->name(network_),
|
||||||
to_tag->asString(this));
|
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
|
void
|
||||||
PathGroupPathVisitor::fromMatches(Vertex *from_vertex,
|
PathGroupPathVisitor::fromMatches(Vertex *from_vertex,
|
||||||
Tag *from_tag,
|
Tag *from_tag)
|
||||||
int from_arrival_index)
|
|
||||||
{
|
{
|
||||||
vertex_matches_ = true;
|
vertex_matches_ = true;
|
||||||
vertexPathSetMapInsertPath(matching_path_map_, from_vertex,
|
vertexPathSetMapInsertPath(matching_path_map_, from_vertex,
|
||||||
from_tag, from_arrival_index, this);
|
from_tag, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@
|
||||||
#include "Parasitics.hh"
|
#include "Parasitics.hh"
|
||||||
#include "PathAnalysisPt.hh"
|
#include "PathAnalysisPt.hh"
|
||||||
#include "Path.hh"
|
#include "Path.hh"
|
||||||
#include "PathRef.hh"
|
|
||||||
#include "PathExpanded.hh"
|
#include "PathExpanded.hh"
|
||||||
#include "StaState.hh"
|
#include "StaState.hh"
|
||||||
#include "search/Sim.hh"
|
#include "search/Sim.hh"
|
||||||
|
|
@ -118,11 +117,11 @@ private:
|
||||||
int stageGateInputPathIndex(Stage stage);
|
int stageGateInputPathIndex(Stage stage);
|
||||||
int stageDrvrPathIndex(Stage stage);
|
int stageDrvrPathIndex(Stage stage);
|
||||||
int stageLoadPathIndex(Stage stage);
|
int stageLoadPathIndex(Stage stage);
|
||||||
const PathRef *stageGateInputPath(Stage stage);
|
const Path *stageGateInputPath(Stage stage);
|
||||||
const PathRef *stageDrvrPath(Stage stage);
|
const Path *stageDrvrPath(Stage stage);
|
||||||
const PathRef *stageLoadPath(Stage stage);
|
const Path *stageLoadPath(Stage stage);
|
||||||
TimingArc *stageGateArc(Stage stage);
|
const TimingArc *stageGateArc(Stage stage);
|
||||||
TimingArc *stageWireArc(Stage stage);
|
const TimingArc *stageWireArc(Stage stage);
|
||||||
Edge *stageGateEdge(Stage stage);
|
Edge *stageGateEdge(Stage stage);
|
||||||
Edge *stageWireEdge(Stage stage);
|
Edge *stageWireEdge(Stage stage);
|
||||||
Pin *stageGateInputPin(Stage stage);
|
Pin *stageGateInputPin(Stage stage);
|
||||||
|
|
@ -139,7 +138,7 @@ private:
|
||||||
float findSlew(const Path *path);
|
float findSlew(const Path *path);
|
||||||
float findSlew(const Path *path,
|
float findSlew(const Path *path,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
TimingArc *next_arc);
|
const TimingArc *next_arc);
|
||||||
Path *path_;
|
Path *path_;
|
||||||
PathExpanded path_expanded_;
|
PathExpanded path_expanded_;
|
||||||
// Input clock waveform cycles.
|
// Input clock waveform cycles.
|
||||||
|
|
@ -246,7 +245,7 @@ float
|
||||||
WritePathSpice::maxTime()
|
WritePathSpice::maxTime()
|
||||||
{
|
{
|
||||||
Stage input_stage = stageFirst();
|
Stage input_stage = stageFirst();
|
||||||
const PathRef *input_path = stageDrvrPath(input_stage);
|
const Path *input_path = stageDrvrPath(input_stage);
|
||||||
if (input_path->isClock(this)) {
|
if (input_path->isClock(this)) {
|
||||||
const Clock *clk = input_path->clock(this);
|
const Clock *clk = input_path->clock(this);
|
||||||
float period = clk->period();
|
float period = clk->period();
|
||||||
|
|
@ -264,7 +263,7 @@ WritePathSpice::pathMaxTime()
|
||||||
{
|
{
|
||||||
float max_time = 0.0;
|
float max_time = 0.0;
|
||||||
for (size_t i = 0; i < path_expanded_.size(); i++) {
|
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);
|
const RiseFall *rf = path->transition(this);
|
||||||
Vertex *vertex = path->vertex(this);
|
Vertex *vertex = path->vertex(this);
|
||||||
float path_max_slew = railToRailSlew(findSlew(vertex,rf,nullptr), rf);
|
float path_max_slew = railToRailSlew(findSlew(vertex,rf,nullptr), rf);
|
||||||
|
|
@ -278,7 +277,7 @@ WritePathSpice::pathMaxTime()
|
||||||
path_max_slew = load_slew;
|
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)
|
if (path_max_time > max_time)
|
||||||
max_time = path_max_time;
|
max_time = path_max_time;
|
||||||
}
|
}
|
||||||
|
|
@ -321,7 +320,7 @@ WritePathSpice::writeInputSource()
|
||||||
streamPrint(spice_stream_, "**************\n\n");
|
streamPrint(spice_stream_, "**************\n\n");
|
||||||
|
|
||||||
Stage input_stage = stageFirst();
|
Stage input_stage = stageFirst();
|
||||||
const PathRef *input_path = stageDrvrPath(input_stage);
|
const Path *input_path = stageDrvrPath(input_stage);
|
||||||
if (input_path->isClock(this))
|
if (input_path->isClock(this))
|
||||||
writeClkWaveform();
|
writeClkWaveform();
|
||||||
else
|
else
|
||||||
|
|
@ -333,9 +332,9 @@ void
|
||||||
WritePathSpice::writeInputWaveform()
|
WritePathSpice::writeInputWaveform()
|
||||||
{
|
{
|
||||||
Stage input_stage = stageFirst();
|
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);
|
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 slew0 = findSlew(input_path, rf, next_arc);
|
||||||
|
|
||||||
float threshold = default_library_->inputThreshold(rf);
|
float threshold = default_library_->inputThreshold(rf);
|
||||||
|
|
@ -358,8 +357,8 @@ void
|
||||||
WritePathSpice::writeClkWaveform()
|
WritePathSpice::writeClkWaveform()
|
||||||
{
|
{
|
||||||
Stage input_stage = stageFirst();
|
Stage input_stage = stageFirst();
|
||||||
const PathRef *input_path = stageDrvrPath(input_stage);
|
const Path *input_path = stageDrvrPath(input_stage);
|
||||||
TimingArc *next_arc = stageGateArc(input_stage + 1);
|
const TimingArc *next_arc = stageGateArc(input_stage + 1);
|
||||||
const ClockEdge *clk_edge = input_path->clkEdge(this);
|
const ClockEdge *clk_edge = input_path->clkEdge(this);
|
||||||
|
|
||||||
const Clock *clk = clk_edge->clock();
|
const Clock *clk = clk_edge->clock();
|
||||||
|
|
@ -403,7 +402,7 @@ WritePathSpice::findSlew(const Path *path)
|
||||||
float
|
float
|
||||||
WritePathSpice::findSlew(const Path *path,
|
WritePathSpice::findSlew(const Path *path,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
TimingArc *next_arc)
|
const TimingArc *next_arc)
|
||||||
{
|
{
|
||||||
Vertex *vertex = path->vertex(this);
|
Vertex *vertex = path->vertex(this);
|
||||||
return findSlew(vertex, rf, next_arc);
|
return findSlew(vertex, rf, next_arc);
|
||||||
|
|
@ -419,9 +418,9 @@ WritePathSpice::writeMeasureStmts()
|
||||||
streamPrint(spice_stream_, "********************\n\n");
|
streamPrint(spice_stream_, "********************\n\n");
|
||||||
|
|
||||||
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
|
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
|
||||||
const PathRef *gate_input_path = stageGateInputPath(stage);
|
const Path *gate_input_path = stageGateInputPath(stage);
|
||||||
const PathRef *drvr_path = stageDrvrPath(stage);
|
const Path *drvr_path = stageDrvrPath(stage);
|
||||||
const PathRef *load_path = stageLoadPath(stage);
|
const Path *load_path = stageLoadPath(stage);
|
||||||
if (gate_input_path) {
|
if (gate_input_path) {
|
||||||
// gate input -> gate output
|
// gate input -> gate output
|
||||||
writeMeasureSlewStmt(stage, gate_input_path);
|
writeMeasureSlewStmt(stage, gate_input_path);
|
||||||
|
|
@ -520,7 +519,7 @@ WritePathSpice::writeGateStage(Stage stage)
|
||||||
drvr_port->name());
|
drvr_port->name());
|
||||||
writeSubcktInst(inst);
|
writeSubcktInst(inst);
|
||||||
|
|
||||||
const PathRef *drvr_path = stageDrvrPath(stage);
|
const Path *drvr_path = stageDrvrPath(stage);
|
||||||
const RiseFall *drvr_rf = drvr_path->transition(this);
|
const RiseFall *drvr_rf = drvr_path->transition(this);
|
||||||
Edge *gate_edge = stageGateEdge(stage);
|
Edge *gate_edge = stageGateEdge(stage);
|
||||||
|
|
||||||
|
|
@ -550,7 +549,7 @@ WritePathSpice::writeGateStage(Stage stage)
|
||||||
void
|
void
|
||||||
WritePathSpice::writeStageParasitics(Stage stage)
|
WritePathSpice::writeStageParasitics(Stage stage)
|
||||||
{
|
{
|
||||||
const PathRef *drvr_path = stageDrvrPath(stage);
|
const Path *drvr_path = stageDrvrPath(stage);
|
||||||
DcalcAnalysisPt *dcalc_ap = drvr_path->dcalcAnalysisPt(this);
|
DcalcAnalysisPt *dcalc_ap = drvr_path->dcalcAnalysisPt(this);
|
||||||
ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
|
ParasiticAnalysisPt *parasitic_ap = dcalc_ap->parasiticAnalysisPt();
|
||||||
const Pin *drvr_pin = stageDrvrPin(stage);
|
const Pin *drvr_pin = stageDrvrPin(stage);
|
||||||
|
|
@ -579,7 +578,7 @@ WritePathSpice::findPathCellNames()
|
||||||
{
|
{
|
||||||
StdStringSet path_cell_names;
|
StdStringSet path_cell_names;
|
||||||
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
|
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
|
||||||
TimingArc *arc = stageGateArc(stage);
|
const TimingArc *arc = stageGateArc(stage);
|
||||||
if (arc) {
|
if (arc) {
|
||||||
LibertyCell *cell = arc->set()->libertyCell();
|
LibertyCell *cell = arc->set()->libertyCell();
|
||||||
if (cell) {
|
if (cell) {
|
||||||
|
|
@ -643,64 +642,62 @@ WritePathSpice::stageLoadPathIndex(Stage stage)
|
||||||
return stage * 2 - 1;
|
return stage * 2 - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathRef *
|
const Path *
|
||||||
WritePathSpice::stageGateInputPath(Stage stage)
|
WritePathSpice::stageGateInputPath(Stage stage)
|
||||||
{
|
{
|
||||||
int path_index = stageGateInputPathIndex(stage);
|
int path_index = stageGateInputPathIndex(stage);
|
||||||
return path_expanded_.path(path_index);
|
return path_expanded_.path(path_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathRef *
|
const Path *
|
||||||
WritePathSpice::stageDrvrPath(Stage stage)
|
WritePathSpice::stageDrvrPath(Stage stage)
|
||||||
{
|
{
|
||||||
int path_index = stageDrvrPathIndex(stage);
|
int path_index = stageDrvrPathIndex(stage);
|
||||||
return path_expanded_.path(path_index);
|
return path_expanded_.path(path_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PathRef *
|
const Path *
|
||||||
WritePathSpice::stageLoadPath(Stage stage)
|
WritePathSpice::stageLoadPath(Stage stage)
|
||||||
{
|
{
|
||||||
int path_index = stageLoadPathIndex(stage);
|
int path_index = stageLoadPathIndex(stage);
|
||||||
return path_expanded_.path(path_index);
|
return path_expanded_.path(path_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingArc *
|
const TimingArc *
|
||||||
WritePathSpice::stageGateArc(Stage stage)
|
WritePathSpice::stageGateArc(Stage stage)
|
||||||
{
|
{
|
||||||
int path_index = stageDrvrPathIndex(stage);
|
int path_index = stageDrvrPathIndex(stage);
|
||||||
if (path_index >= 0)
|
if (path_index >= 0)
|
||||||
return path_expanded_.prevArc(path_index);
|
return path_expanded_.path(path_index)->prevArc(this);
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TimingArc *
|
const TimingArc *
|
||||||
WritePathSpice::stageWireArc(Stage stage)
|
WritePathSpice::stageWireArc(Stage stage)
|
||||||
{
|
{
|
||||||
int path_index = stageLoadPathIndex(stage);
|
int path_index = stageLoadPathIndex(stage);
|
||||||
return path_expanded_.prevArc(path_index);
|
return path_expanded_.path(path_index)->prevArc(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Edge *
|
Edge *
|
||||||
WritePathSpice::stageGateEdge(Stage stage)
|
WritePathSpice::stageGateEdge(Stage stage)
|
||||||
{
|
{
|
||||||
const PathRef *path = stageDrvrPath(stage);
|
const Path *path = stageDrvrPath(stage);
|
||||||
TimingArc *arc = stageGateArc(stage);
|
return path->prevEdge(this);
|
||||||
return path->prevEdge(arc, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Edge *
|
Edge *
|
||||||
WritePathSpice::stageWireEdge(Stage stage)
|
WritePathSpice::stageWireEdge(Stage stage)
|
||||||
{
|
{
|
||||||
const PathRef *path = stageLoadPath(stage);
|
const Path *path = stageLoadPath(stage);
|
||||||
TimingArc *arc = stageWireArc(stage);
|
return path->prevEdge(this);
|
||||||
return path->prevEdge(arc, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Pin *
|
Pin *
|
||||||
WritePathSpice::stageGateInputPin(Stage stage)
|
WritePathSpice::stageGateInputPin(Stage stage)
|
||||||
{
|
{
|
||||||
const PathRef *path = stageGateInputPath(stage);
|
const Path *path = stageGateInputPath(stage);
|
||||||
return path->pin(this);
|
return path->pin(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -714,7 +711,7 @@ WritePathSpice::stageGateInputPort(Stage stage)
|
||||||
Pin *
|
Pin *
|
||||||
WritePathSpice::stageDrvrPin(Stage stage)
|
WritePathSpice::stageDrvrPin(Stage stage)
|
||||||
{
|
{
|
||||||
const PathRef *path = stageDrvrPath(stage);
|
const Path *path = stageDrvrPath(stage);
|
||||||
return path->pin(this);
|
return path->pin(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -728,7 +725,7 @@ WritePathSpice::stageDrvrPort(Stage stage)
|
||||||
Pin *
|
Pin *
|
||||||
WritePathSpice::stageLoadPin(Stage stage)
|
WritePathSpice::stageLoadPin(Stage stage)
|
||||||
{
|
{
|
||||||
const PathRef *path = stageLoadPath(stage);
|
const Path *path = stageLoadPath(stage);
|
||||||
return path->pin(this);
|
return path->pin(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
#include "Graph.hh"
|
#include "Graph.hh"
|
||||||
#include "search/Sim.hh"
|
#include "search/Sim.hh"
|
||||||
#include "Clock.hh"
|
#include "Clock.hh"
|
||||||
#include "PathVertex.hh"
|
#include "Path.hh"
|
||||||
#include "DcalcAnalysisPt.hh"
|
#include "DcalcAnalysisPt.hh"
|
||||||
#include "Bdd.hh"
|
#include "Bdd.hh"
|
||||||
|
|
||||||
|
|
@ -474,7 +474,7 @@ WriteSpice::pgPortVoltage(LibertyPgPort *pg_port)
|
||||||
float
|
float
|
||||||
WriteSpice::findSlew(Vertex *vertex,
|
WriteSpice::findSlew(Vertex *vertex,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
TimingArc *next_arc)
|
const TimingArc *next_arc)
|
||||||
{
|
{
|
||||||
float slew = delayAsFloat(graph_->slew(vertex, rf, dcalc_ap_->index()));
|
float slew = delayAsFloat(graph_->slew(vertex, rf, dcalc_ap_->index()));
|
||||||
if (slew == 0.0 && next_arc)
|
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.
|
// Look up the smallest slew axis value in the timing arc delay table.
|
||||||
float
|
float
|
||||||
WriteSpice::slewAxisMinValue(TimingArc *arc)
|
WriteSpice::slewAxisMinValue(const TimingArc *arc)
|
||||||
{
|
{
|
||||||
GateTableModel *gate_model = arc->gateTableModel(dcalc_ap_);
|
GateTableModel *gate_model = arc->gateTableModel(dcalc_ap_);
|
||||||
if (gate_model) {
|
if (gate_model) {
|
||||||
|
|
|
||||||
|
|
@ -135,8 +135,8 @@ protected:
|
||||||
const char *spiceTrans(const RiseFall *rf);
|
const char *spiceTrans(const RiseFall *rf);
|
||||||
float findSlew(Vertex *vertex,
|
float findSlew(Vertex *vertex,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
TimingArc *next_arc);
|
const TimingArc *next_arc);
|
||||||
float slewAxisMinValue(TimingArc *arc);
|
float slewAxisMinValue(const TimingArc *arc);
|
||||||
float clkWaveformTimeOffset(const Clock *clk);
|
float clkWaveformTimeOffset(const Clock *clk);
|
||||||
|
|
||||||
void gatePortValues(const Pin *input_pin,
|
void gatePortValues(const Pin *input_pin,
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
%inline %{
|
%inline %{
|
||||||
|
|
||||||
void
|
void
|
||||||
write_path_spice_cmd(PathRef *path,
|
write_path_spice_cmd(Path *path,
|
||||||
const char *spice_filename,
|
const char *spice_filename,
|
||||||
const char *subckt_filename,
|
const char *subckt_filename,
|
||||||
const char *lib_subckt_filename,
|
const char *lib_subckt_filename,
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ proc get_object_property { object prop } {
|
||||||
return [edge_property $object $prop]
|
return [edge_property $object $prop]
|
||||||
} elseif { $object_type == "PathEnd" } {
|
} elseif { $object_type == "PathEnd" } {
|
||||||
return [path_end_property $object $prop]
|
return [path_end_property $object $prop]
|
||||||
} elseif { $object_type == "PathRef" } {
|
} elseif { $object_type == "Path" } {
|
||||||
return [path_ref_property $object $prop]
|
return [path_ref_property $object $prop]
|
||||||
} elseif { $object_type == "TimingArcSet" } {
|
} elseif { $object_type == "TimingArcSet" } {
|
||||||
return [timing_arc_set_property $object $prop]
|
return [timing_arc_set_property $object $prop]
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
#include "Clock.hh"
|
#include "Clock.hh"
|
||||||
#include "Corner.hh"
|
#include "Corner.hh"
|
||||||
#include "Search.hh"
|
#include "Search.hh"
|
||||||
#include "PathRef.hh"
|
#include "Path.hh"
|
||||||
#include "search/Tag.hh"
|
#include "search/Tag.hh"
|
||||||
#include "PathEnd.hh"
|
#include "PathEnd.hh"
|
||||||
#include "SearchClass.hh"
|
#include "SearchClass.hh"
|
||||||
|
|
@ -1138,17 +1138,17 @@ using namespace sta;
|
||||||
Tcl_SetObjResult(interp, obj);
|
Tcl_SetObjResult(interp, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
%typemap(out) PathRefSeq* {
|
%typemap(out) PathSeq* {
|
||||||
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
Tcl_Obj *obj = SWIG_NewInstanceObj($1, $1_descriptor, false);
|
||||||
Tcl_SetObjResult(interp, obj);
|
Tcl_SetObjResult(interp, obj);
|
||||||
|
|
||||||
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
||||||
PathRefSeq *paths = $1;
|
PathSeq *paths = $1;
|
||||||
PathRefSeq::Iterator path_iter(paths);
|
PathSeq::Iterator path_iter(paths);
|
||||||
while (path_iter.hasNext()) {
|
while (path_iter.hasNext()) {
|
||||||
PathRef *path = &path_iter.next();
|
Path *path = &path_iter.next();
|
||||||
PathRef *copy = new PathRef(path);
|
Path *copy = new Path(path);
|
||||||
Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false);
|
Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_Path, false);
|
||||||
Tcl_ListObjAppendElement(interp, list, obj);
|
Tcl_ListObjAppendElement(interp, list, obj);
|
||||||
}
|
}
|
||||||
Tcl_SetObjResult(interp, list);
|
Tcl_SetObjResult(interp, list);
|
||||||
|
|
@ -1354,11 +1354,10 @@ using namespace sta;
|
||||||
Tcl_SetObjResult(interp, list);
|
Tcl_SetObjResult(interp, list);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PropertyValue::Type::type_path_refs: {
|
case PropertyValue::Type::type_paths: {
|
||||||
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
Tcl_Obj *list = Tcl_NewListObj(0, nullptr);
|
||||||
for (PathRef &path : *value.pathRefs()) {
|
for (const Path *path : *value.paths()) {
|
||||||
PathRef *copy = new PathRef(path);
|
Tcl_Obj *obj = SWIG_NewInstanceObj(const_cast<Path*>(path), SWIGTYPE_p_Path, false);
|
||||||
Tcl_Obj *obj = SWIG_NewInstanceObj(copy, SWIGTYPE_p_PathRef, false);
|
|
||||||
Tcl_ListObjAppendElement(interp, list, obj);
|
Tcl_ListObjAppendElement(interp, list, obj);
|
||||||
}
|
}
|
||||||
Tcl_SetObjResult(interp, list);
|
Tcl_SetObjResult(interp, list);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue