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