1 // OpenSTA, Static Timing Analyzer
2 // Copyright (c) 2021, Parallax Software, Inc.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17 #include "PathVertex.hh"
18
19 #include <cmath>
20
21 #include "DisallowCopyAssign.hh"
22 #include "Fuzzy.hh"
23 #include "Graph.hh"
24 #include "ExceptionPath.hh"
25 #include "Sdc.hh"
26 #include "GraphDelayCalc.hh"
27 #include "Corner.hh"
28 #include "Tag.hh"
29 #include "TagGroup.hh"
30 #include "PathAnalysisPt.hh"
31 #include "PathRef.hh"
32 #include "PathVertexRep.hh"
33 #include "Search.hh"
34
35 namespace sta {
36
PathVertex()37 PathVertex::PathVertex() :
38 vertex_(nullptr),
39 tag_(nullptr),
40 arrival_index_(0)
41 {
42 }
43
PathVertex(const PathVertex & path)44 PathVertex::PathVertex(const PathVertex &path) :
45 vertex_(path.vertex_),
46 tag_(path.tag_),
47 arrival_index_(path.arrival_index_)
48 {
49 }
50
PathVertex(const PathVertex * path)51 PathVertex::PathVertex(const PathVertex *path) :
52 vertex_(nullptr),
53 tag_(nullptr),
54 arrival_index_(0)
55 {
56 if (path) {
57 vertex_ = path->vertex_;
58 tag_ = path->tag_;
59 arrival_index_ = path->arrival_index_;
60 }
61 }
62
PathVertex(Vertex * vertex,Tag * tag,const StaState * sta)63 PathVertex::PathVertex(Vertex *vertex,
64 Tag *tag,
65 const StaState *sta)
66 {
67 init(vertex, tag, sta);
68 }
69
PathVertex(Vertex * vertex,Tag * tag,int arrival_index)70 PathVertex::PathVertex(Vertex *vertex,
71 Tag *tag,
72 int arrival_index) :
73 vertex_(vertex),
74 tag_(tag),
75 arrival_index_(arrival_index)
76 {
77 }
78
PathVertex(const PathVertexRep * path,const StaState * sta)79 PathVertex::PathVertex(const PathVertexRep *path,
80 const StaState *sta)
81 {
82 if (path)
83 init(path->vertex(sta), path->tag(sta), sta);
84 }
85
PathVertex(const PathVertexRep & path,const StaState * sta)86 PathVertex::PathVertex(const PathVertexRep &path,
87 const StaState *sta)
88 {
89 if (path.isNull())
90 init();
91 else
92 init(path.vertex(sta), path.tag(sta), sta);
93 }
94
95 void
init()96 PathVertex::init()
97 {
98 vertex_ = nullptr;
99 tag_ = nullptr;
100 arrival_index_ = 0;
101 }
102
103 void
init(Vertex * vertex,Tag * tag,const StaState * sta)104 PathVertex::init(Vertex *vertex,
105 Tag *tag,
106 const StaState *sta)
107 {
108 vertex_ = nullptr;
109 tag_ = nullptr;
110 arrival_index_ = 0;
111 const Search *search = sta->search();
112 TagGroup *tag_group = search->tagGroup(vertex);
113 if (tag_group) {
114 bool arrival_exists;
115 tag_group->arrivalIndex(tag, arrival_index_, arrival_exists);
116 if (arrival_exists) {
117 vertex_ = vertex;
118 tag_ = tag;
119 }
120 }
121 }
122
123 void
init(Vertex * vertex,Tag * tag,int arrival_index)124 PathVertex::init(Vertex *vertex,
125 Tag *tag,
126 int arrival_index)
127 {
128 vertex_ = vertex;
129 tag_ = tag;
130 arrival_index_ = arrival_index;
131 }
132
133 void
init(const PathVertexRep * path,const StaState * sta)134 PathVertex::init(const PathVertexRep *path,
135 const StaState *sta)
136 {
137 if (path)
138 init(path->vertex(sta), path->tag(sta), sta);
139 else
140 init();
141 }
142
143 void
init(const PathVertexRep & path,const StaState * sta)144 PathVertex::init(const PathVertexRep &path,
145 const StaState *sta)
146 {
147 if (!path.isNull())
148 init(path.vertex(sta), path.tag(sta), sta);
149 else
150 init();
151 }
152
153 void
operator =(const PathVertex & path)154 PathVertex::operator=(const PathVertex &path)
155 {
156 vertex_ = path.vertex_;
157 tag_ = path.tag_;
158 arrival_index_ = path.arrival_index_;
159 }
160
161 bool
isNull() const162 PathVertex::isNull() const
163 {
164 return tag_ == nullptr;
165 }
166
167 void
setRef(PathRef * ref) const168 PathVertex::setRef(PathRef *ref) const
169 {
170 ref->init(vertex_, tag_, arrival_index_);
171 }
172
173 VertexId
vertexId(const StaState * sta) const174 PathVertex::vertexId(const StaState *sta) const
175 {
176 const Graph *graph = sta->graph();
177 return graph->id(vertex_);
178 }
179
180 TagIndex
tagIndex(const StaState *) const181 PathVertex::tagIndex(const StaState *) const
182 {
183 return tag_->index();
184 }
185
186 const RiseFall *
transition(const StaState *) const187 PathVertex::transition(const StaState *) const
188 {
189 return tag_->transition();
190 }
191
192 int
rfIndex(const StaState *) const193 PathVertex::rfIndex(const StaState *) const
194 {
195 return tag_->trIndex();
196 }
197
198 PathAnalysisPt *
pathAnalysisPt(const StaState * sta) const199 PathVertex::pathAnalysisPt(const StaState *sta) const
200 {
201 return tag_->pathAnalysisPt(sta);
202 }
203
204 PathAPIndex
pathAnalysisPtIndex(const StaState *) const205 PathVertex::pathAnalysisPtIndex(const StaState *) const
206 {
207 return tag_->pathAPIndex();
208 }
209
210 void
arrivalIndex(int & arrival_index,bool & arrival_exists) const211 PathVertex::arrivalIndex(int &arrival_index,
212 bool &arrival_exists) const
213 {
214 if (tag_) {
215 arrival_index = arrival_index_;
216 arrival_exists = true;
217 }
218 else
219 arrival_exists = false;
220 }
221
222 void
setArrivalIndex(int arrival_index)223 PathVertex::setArrivalIndex(int arrival_index)
224 {
225 arrival_index_ = arrival_index;
226 }
227
228 Arrival
arrival(const StaState * sta) const229 PathVertex::arrival(const StaState *sta) const
230 {
231 Arrival *arrivals = sta->graph()->arrivals(vertex_);
232 return arrivals[arrival_index_];
233 }
234
235 void
setArrival(Arrival arrival,const StaState * sta)236 PathVertex::setArrival(Arrival arrival,
237 const StaState *sta)
238 {
239 if (tag_) {
240 Arrival *arrivals = sta->graph()->arrivals(vertex_);
241 arrivals[arrival_index_] = arrival;
242 }
243 }
244
245 const Required &
required(const StaState * sta) const246 PathVertex::required(const StaState *sta) const
247 {
248 if (tag_ && vertex_->hasRequireds()) {
249 const Search *search = sta->search();
250 TagGroup *tag_group = search->tagGroup(vertex_);
251 int req_index = tag_group->requiredIndex(arrival_index_);
252 Arrival *arrivals = sta->graph()->arrivals(vertex_);
253 return arrivals[req_index];
254 }
255 else
256 return delayInitValue(minMax(sta)->opposite());
257 }
258
259 void
setRequired(const Required & required,const StaState * sta)260 PathVertex::setRequired(const Required &required,
261 const StaState *sta)
262 {
263 Graph *graph = sta->graph();
264 const Search *search = sta->search();
265 TagGroup *tag_group = search->tagGroup(vertex_);
266 Arrival *arrivals = graph->arrivals(vertex_);
267 int arrival_count = tag_group->arrivalCount();
268 if (!vertex_->hasRequireds()) {
269 Arrival *new_arrivals = graph->makeArrivals(vertex_, arrival_count * 2);
270 for (int i = 0; i < arrival_count; i++)
271 new_arrivals[i] =arrivals[i];
272 vertex_->setHasRequireds(true);
273 arrivals = new_arrivals;
274 }
275 int req_index = arrival_index_ + arrival_count;
276 arrivals[req_index] = required;
277 }
278
279 void
deleteRequireds(Vertex * vertex,const StaState *)280 PathVertex::deleteRequireds(Vertex *vertex,
281 const StaState *)
282 {
283 vertex->setHasRequireds(false);
284 // Don't bother reclaiming requieds from arrival table.
285 }
286
287 bool
equal(const PathVertex * path1,const PathVertex * path2)288 PathVertex::equal(const PathVertex *path1,
289 const PathVertex *path2)
290 {
291 return path1->vertex_ == path2->vertex_
292 && path1->tag_ == path2->tag_;
293 }
294
295 ////////////////////////////////////////////////////////////////
296
297 // EvalPred but search to clk source pin.
298 class PrevPred2 : public SearchPred0
299 {
300 public:
301 explicit PrevPred2(const StaState *sta);
302 virtual bool searchThru(Edge *edge);
303
304 private:
305 DISALLOW_COPY_AND_ASSIGN(PrevPred2);
306 };
307
PrevPred2(const StaState * sta)308 PrevPred2::PrevPred2(const StaState *sta) :
309 SearchPred0(const_cast<StaState*>(sta))
310 {
311 }
312
313 bool
searchThru(Edge * edge)314 PrevPred2::searchThru(Edge *edge)
315 {
316 const Sdc *sdc = sta_->sdc();
317 TimingRole *role = edge->role();
318 return SearchPred0::searchThru(edge)
319 && (sdc->dynamicLoopBreaking()
320 || !edge->isDisabledLoop())
321 && !role->isTimingCheck();
322 }
323
324 class PrevPathVisitor : public PathVisitor
325 {
326 public:
327 PrevPathVisitor(const Path *path,
328 SearchPred *pred,
329 const StaState *sta);
330 virtual VertexVisitor *copy();
visit(Vertex *)331 virtual void visit(Vertex *) {}
332 virtual bool visitFromToPath(const Pin *from_pin,
333 Vertex *from_vertex,
334 const RiseFall *from_rf,
335 Tag *from_tag,
336 PathVertex *from_path,
337 Edge *edge,
338 TimingArc *arc,
339 ArcDelay arc_delay,
340 Vertex *to_vertex,
341 const RiseFall *to_rf,
342 Tag *to_tag,
343 Arrival &to_arrival,
344 const MinMax *min_max,
345 const PathAnalysisPt *path_ap);
prevPath()346 PathVertex &prevPath() { return prev_path_; }
prevArc() const347 TimingArc *prevArc() const { return prev_arc_; }
348
349 protected:
350 Tag *unfilteredTag(const Tag *tag) const;
351
352 const Path *path_;
353 Arrival path_arrival_;
354 Tag *path_tag_;
355 int path_rf_index_;
356 PathAPIndex path_ap_index_;
357 PathVertex prev_path_;
358 TimingArc *prev_arc_;
359 float dcalc_tol_;
360
361 private:
362 DISALLOW_COPY_AND_ASSIGN(PrevPathVisitor);
363 };
364
PrevPathVisitor(const Path * path,SearchPred * pred,const StaState * sta)365 PrevPathVisitor::PrevPathVisitor(const Path *path,
366 SearchPred *pred,
367 const StaState *sta) :
368 PathVisitor(pred, sta),
369 path_(path),
370 path_arrival_(path->arrival(sta)),
371 path_tag_(path->tag(sta)),
372 path_rf_index_(path->rfIndex(sta)),
373 path_ap_index_(path->pathAnalysisPtIndex(sta)),
374 prev_path_(),
375 prev_arc_(nullptr),
376 dcalc_tol_(sta->graphDelayCalc()->incrementalDelayTolerance())
377 {
378 }
379
380 VertexVisitor *
copy()381 PrevPathVisitor::copy()
382 {
383 return new PrevPathVisitor(path_, pred_, sta_);
384 }
385
386 bool
visitFromToPath(const Pin *,Vertex *,const RiseFall *,Tag * from_tag,PathVertex * from_path,Edge *,TimingArc * arc,ArcDelay,Vertex *,const RiseFall * to_rf,Tag * to_tag,Arrival & to_arrival,const MinMax *,const PathAnalysisPt * path_ap)387 PrevPathVisitor::visitFromToPath(const Pin *,
388 Vertex *,
389 const RiseFall *,
390 Tag *from_tag,
391 PathVertex *from_path,
392 Edge *,
393 TimingArc *arc,
394 ArcDelay,
395 Vertex *,
396 const RiseFall *to_rf,
397 Tag *to_tag,
398 Arrival &to_arrival,
399 const MinMax *,
400 const PathAnalysisPt *path_ap)
401 {
402 PathAPIndex path_ap_index = path_ap->index();
403 if (to_rf->index() == path_rf_index_
404 && path_ap_index == path_ap_index_
405 && (dcalc_tol_ > 0.0
406 ? std::abs(delayAsFloat(to_arrival - path_arrival_)) < dcalc_tol_
407 : delayEqual(to_arrival, path_arrival_))
408 && (tagMatch(to_tag, path_tag_, sta_)
409 // If the filter exception became active searching from
410 // from_path to to_path the tag includes the filter, but
411 // to_vertex still has paths from previous searches that do
412 // not have the filter.
413 || (!from_tag->isFilter()
414 && to_tag->isFilter()
415 && tagMatch(unfilteredTag(to_tag), path_tag_, sta_)))) {
416 int arrival_index;
417 bool arrival_exists;
418 from_path->arrivalIndex(arrival_index, arrival_exists);
419 if (arrival_exists) {
420 prev_path_ = from_path;
421 prev_arc_ = arc;
422 // Stop looking for the previous path/arc.
423 return false;
424 }
425 }
426 return true;
427 }
428
429 Tag *
unfilteredTag(const Tag * tag) const430 PrevPathVisitor::unfilteredTag(const Tag *tag) const
431 {
432 Search *search = sta_->search();
433 const Corners *corners = sta_->corners();
434 ExceptionStateSet *unfiltered_states = nullptr;
435 const ExceptionStateSet *states = tag->states();
436 ExceptionStateSet::ConstIterator state_iter(states);
437 while (state_iter.hasNext()) {
438 ExceptionState *state = state_iter.next();
439 ExceptionPath *except = state->exception();
440 if (!except->isFilter()) {
441 if (unfiltered_states == nullptr)
442 unfiltered_states = new ExceptionStateSet;
443 unfiltered_states->insert(state);
444 }
445 }
446 return search->findTag(tag->transition(),
447 corners->findPathAnalysisPt(tag->pathAPIndex()),
448 tag->clkInfo(),
449 tag->isClock(),
450 tag->inputDelay(),
451 tag->isSegmentStart(),
452 unfiltered_states, true);
453 }
454
455 ////////////////////////////////////////////////////////////////
456
457 void
prevPath(const StaState * sta,PathVertex & prev_path,TimingArc * & prev_arc) const458 PathVertex::prevPath(const StaState *sta,
459 // Return values.
460 PathVertex &prev_path,
461 TimingArc *&prev_arc) const
462 {
463 PrevPred2 pred(sta);
464 PrevPathVisitor visitor(this, &pred, sta);
465 visitor.visitFaninPaths(vertex(sta));
466 prev_path = visitor.prevPath();
467 prev_arc = visitor.prevArc();
468 }
469
470 void
prevPath(const StaState * sta,PathVertex & prev_path) const471 PathVertex::prevPath(const StaState *sta,
472 // Return values.
473 PathVertex &prev_path) const
474 {
475 PrevPred2 pred(sta);
476 PrevPathVisitor visitor(this, &pred, sta);
477 visitor.visitFaninPaths(vertex(sta));
478 prev_path = visitor.prevPath();
479 }
480
481 void
prevPath(const StaState * sta,PathRef & prev_path,TimingArc * & prev_arc) const482 PathVertex::prevPath(const StaState *sta,
483 // Return values.
484 PathRef &prev_path,
485 TimingArc *&prev_arc) const
486 {
487 PathVertex prev;
488 prevPath(sta, prev, prev_arc);
489 prev.setRef(prev_path);
490 }
491
492 ////////////////////////////////////////////////////////////////
493
VertexPathIterator(Vertex * vertex,const StaState * sta)494 VertexPathIterator::VertexPathIterator(Vertex *vertex,
495 const StaState *sta) :
496 search_(sta->search()),
497 vertex_(vertex),
498 rf_(nullptr),
499 path_ap_(nullptr),
500 min_max_(nullptr)
501 {
502 TagGroup *tag_group = search_->tagGroup(vertex);
503 if (tag_group) {
504 arrival_iter_.init(tag_group->arrivalMap());
505 findNext();
506 }
507 }
508
509 // Iterate over vertex paths with the same transition and
510 // analysis pt but different but different tags.
VertexPathIterator(Vertex * vertex,const RiseFall * rf,const PathAnalysisPt * path_ap,const StaState * sta)511 VertexPathIterator::VertexPathIterator(Vertex *vertex,
512 const RiseFall *rf,
513 const PathAnalysisPt *path_ap,
514 const StaState *sta) :
515 search_(sta->search()),
516 vertex_(vertex),
517 rf_(rf),
518 path_ap_(path_ap),
519 min_max_(nullptr)
520 {
521 TagGroup *tag_group = search_->tagGroup(vertex);
522 if (tag_group) {
523 arrival_iter_.init(tag_group->arrivalMap());
524 findNext();
525 }
526 }
527
VertexPathIterator(Vertex * vertex,const RiseFall * rf,const MinMax * min_max,const StaState * sta)528 VertexPathIterator::VertexPathIterator(Vertex *vertex,
529 const RiseFall *rf,
530 const MinMax *min_max,
531 const StaState *sta) :
532 search_(sta->search()),
533 vertex_(vertex),
534 rf_(rf),
535 path_ap_(nullptr),
536 min_max_(min_max)
537 {
538 TagGroup *tag_group = search_->tagGroup(vertex);
539 if (tag_group) {
540 arrival_iter_.init(tag_group->arrivalMap());
541 findNext();
542 }
543 }
544
VertexPathIterator(Vertex * vertex,const RiseFall * rf,const PathAnalysisPt * path_ap,const MinMax * min_max,const StaState * sta)545 VertexPathIterator::VertexPathIterator(Vertex *vertex,
546 const RiseFall *rf,
547 const PathAnalysisPt *path_ap,
548 const MinMax *min_max,
549 const StaState *sta) :
550 search_(sta->search()),
551 vertex_(vertex),
552 rf_(rf),
553 path_ap_(path_ap),
554 min_max_(min_max)
555 {
556 TagGroup *tag_group = search_->tagGroup(vertex);
557 if (tag_group) {
558 arrival_iter_.init(tag_group->arrivalMap());
559 findNext();
560 }
561 }
562
~VertexPathIterator()563 VertexPathIterator::~VertexPathIterator()
564 {
565 }
566
567 bool
hasNext()568 VertexPathIterator::hasNext()
569 {
570 return !next_.isNull();
571 }
572
573 void
findNext()574 VertexPathIterator::findNext()
575 {
576 while (arrival_iter_.hasNext()) {
577 Tag *tag;
578 int arrival_index;
579 arrival_iter_.next(tag, arrival_index);
580 if ((rf_ == nullptr
581 || tag->trIndex() == rf_->index())
582 && (path_ap_ == nullptr
583 || tag->pathAPIndex() == path_ap_->index())
584 && (min_max_ == nullptr
585 || tag->pathAnalysisPt(search_)->pathMinMax() == min_max_)) {
586 next_.init(vertex_, tag, arrival_index);
587 return;
588 }
589 }
590 next_.init();
591 }
592
593 PathVertex *
next()594 VertexPathIterator::next()
595 {
596 path_ = next_;
597 findNext();
598 return &path_;
599 }
600
601 } // namespace
602