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 "VisitPathEnds.hh"
18
19 #include "Debug.hh"
20 #include "Liberty.hh"
21 #include "Network.hh"
22 #include "TimingArc.hh"
23 #include "ExceptionPath.hh"
24 #include "PortDelay.hh"
25 #include "Sdc.hh"
26 #include "Graph.hh"
27 #include "ClkInfo.hh"
28 #include "Tag.hh"
29 #include "PathVertex.hh"
30 #include "PathAnalysisPt.hh"
31 #include "PathEnd.hh"
32 #include "Search.hh"
33 #include "GatedClk.hh"
34
35 namespace sta {
36
VisitPathEnds(const StaState * sta)37 VisitPathEnds::VisitPathEnds(const StaState *sta) :
38 StaState(sta)
39 {
40 }
41
42 void
visitPathEnds(Vertex * vertex,PathEndVisitor * visitor)43 VisitPathEnds::visitPathEnds(Vertex *vertex,
44 PathEndVisitor *visitor)
45 {
46 visitPathEnds(vertex, nullptr, MinMaxAll::all(), false, visitor);
47 }
48
49 void
visitPathEnds(Vertex * vertex,const Corner * corner,const MinMaxAll * min_max,bool filtered,PathEndVisitor * visitor)50 VisitPathEnds::visitPathEnds(Vertex *vertex,
51 const Corner *corner,
52 const MinMaxAll *min_max,
53 bool filtered,
54 PathEndVisitor *visitor)
55 {
56 // Ignore slack on bidirect driver vertex. The load vertex gets the slack.
57 if (!vertex->isBidirectDriver()) {
58 const Pin *pin = vertex->pin();
59 debugPrint(debug_, "search", 2, "find end slack %s",
60 vertex->name(sdc_network_));
61 visitor->vertexBegin(vertex);
62 bool is_constrained = false;
63 visitClkedPathEnds(pin, vertex, corner, min_max, filtered, visitor,
64 is_constrained);
65 if (search_->unconstrainedPaths()
66 && !is_constrained
67 && !vertex->isDisabledConstraint())
68 visitUnconstrainedPathEnds(pin, vertex, corner, min_max, filtered,
69 visitor);
70 visitor->vertexEnd(vertex);
71 }
72 }
73
74 void
visitClkedPathEnds(const Pin * pin,Vertex * vertex,const Corner * corner,const MinMaxAll * min_max,bool filtered,PathEndVisitor * visitor,bool & is_constrained)75 VisitPathEnds::visitClkedPathEnds(const Pin *pin,
76 Vertex *vertex,
77 const Corner *corner,
78 const MinMaxAll *min_max,
79 bool filtered,
80 PathEndVisitor *visitor,
81 bool &is_constrained)
82 {
83 bool is_segment_start = search_->isSegmentStart(pin);
84 VertexPathIterator path_iter(vertex, this);
85 while (path_iter.hasNext()) {
86 PathVertex *path = path_iter.next();
87 PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
88 const MinMax *path_min_max = path_ap->pathMinMax();
89 const RiseFall *end_rf = path->transition(this);
90 Tag *tag = path->tag(this);
91 if ((corner == nullptr
92 || path_ap->corner() == corner)
93 && min_max->matches(path_min_max)
94 // Ignore generated clock source paths.
95 && !path->clkInfo(this)->isGenClkSrcPath()
96 && !falsePathTo(path, pin, end_rf, path_min_max)
97 // Ignore segment startpoint paths.
98 && (!is_segment_start
99 || !tag->isSegmentStart())) {
100 // set_output_delay to timing check has precidence.
101 if (sdc_->hasOutputDelay(pin))
102 visitOutputDelayEnd(pin, path, end_rf, path_ap, filtered, visitor,
103 is_constrained);
104 else if (vertex->hasChecks())
105 visitCheckEnd(pin, vertex, path, end_rf, path_ap, filtered, visitor,
106 is_constrained);
107 else if (!sdc_->exceptionToInvalid(pin)
108 && (!filtered
109 || search_->matchesFilter(path, nullptr))) {
110 PathDelay *path_delay = pathDelayTo(path, pin, end_rf, path_min_max);
111 if (path_delay) {
112 PathEndPathDelay path_end(path_delay, path, this);
113 visitor->visit(&path_end);
114 is_constrained = true;
115 }
116 }
117 if (sdc_->gatedClkChecksEnabled())
118 visitGatedClkEnd(pin, vertex, path, end_rf, path_ap, filtered, visitor,
119 is_constrained);
120 visitDataCheckEnd(pin, path, end_rf, path_ap, filtered, visitor,
121 is_constrained);
122 }
123 }
124 }
125
126 void
visitCheckEnd(const Pin * pin,Vertex * vertex,Path * path,const RiseFall * end_rf,const PathAnalysisPt * path_ap,bool filtered,PathEndVisitor * visitor,bool & is_constrained)127 VisitPathEnds::visitCheckEnd(const Pin *pin,
128 Vertex *vertex,
129 Path *path,
130 const RiseFall *end_rf,
131 const PathAnalysisPt *path_ap,
132 bool filtered,
133 PathEndVisitor *visitor,
134 bool &is_constrained)
135 {
136 ClockEdge *src_clk_edge = path->clkEdge(this);
137 Clock *src_clk = path->clock(this);
138 const MinMax *min_max = path_ap->pathMinMax();
139 const PathAnalysisPt *tgt_clk_path_ap = path_ap->tgtClkAnalysisPt();
140 bool check_clked = false;
141 VertexInEdgeIterator edge_iter(vertex, graph_);
142 while (edge_iter.hasNext()) {
143 Edge *edge = edge_iter.next();
144 Vertex *tgt_clk_vertex = edge->from(graph_);
145 const TimingRole *check_role = edge->role();
146 if (checkEdgeEnabled(edge)
147 && check_role->pathMinMax() == min_max) {
148 TimingArcSet *arc_set = edge->timingArcSet();
149 TimingArcSetArcIterator arc_iter(arc_set);
150 while (arc_iter.hasNext()) {
151 TimingArc *check_arc = arc_iter.next();
152 RiseFall *clk_rf = check_arc->fromTrans()->asRiseFall();
153 if (check_arc->toTrans()->asRiseFall() == end_rf
154 && clk_rf) {
155 VertexPathIterator tgt_clk_path_iter(tgt_clk_vertex, clk_rf,
156 tgt_clk_path_ap, this);
157 while (tgt_clk_path_iter.hasNext()) {
158 PathVertex *tgt_clk_path = tgt_clk_path_iter.next();
159 ClkInfo *tgt_clk_info = tgt_clk_path->clkInfo(this);
160 const ClockEdge *tgt_clk_edge = tgt_clk_path->clkEdge(this);
161 const Clock *tgt_clk = tgt_clk_path->clock(this);
162 const Pin *tgt_pin = tgt_clk_vertex->pin();
163 ExceptionPath *exception = exceptionTo(path, pin, end_rf,
164 tgt_clk_edge, min_max);
165 // Ignore generated clock source paths.
166 if (!tgt_clk_info->isGenClkSrcPath()
167 && !search_->pathPropagatedToClkSrc(tgt_pin, tgt_clk_path)) {
168 if (tgt_clk_path->isClock(this)) {
169 check_clked = true;
170 if (!filtered
171 || search_->matchesFilter(path, tgt_clk_edge)) {
172 if (src_clk_edge
173 && tgt_clk != sdc_->defaultArrivalClock()
174 && sdc_->sameClockGroup(src_clk, tgt_clk)
175 && !sdc_->clkStopPropagation(tgt_pin, tgt_clk)
176 && (search_->checkDefaultArrivalPaths()
177 || src_clk_edge
178 != sdc_->defaultArrivalClockEdge())
179 // False paths and path delays override
180 // paths.
181 && (exception == nullptr
182 || exception->isFilter()
183 || exception->isGroupPath()
184 || exception->isMultiCycle())) {
185 MultiCyclePath *mcp=dynamic_cast<MultiCyclePath*>(exception);
186 if (network_->isLatchData(pin)
187 && check_role == TimingRole::setup()) {
188 PathEndLatchCheck path_end(path, check_arc, edge,
189 tgt_clk_path, mcp, nullptr,
190 this);
191 visitor->visit(&path_end);
192 is_constrained = true;
193 }
194 else {
195 PathEndCheck path_end(path, check_arc, edge,
196 tgt_clk_path, mcp, this);
197 visitor->visit(&path_end);
198 is_constrained = true;
199 }
200 }
201 else if (exception
202 && exception->isPathDelay()
203 && (src_clk == nullptr
204 || sdc_->sameClockGroup(src_clk,
205 tgt_clk))) {
206 PathDelay *path_delay = dynamic_cast<PathDelay*>(exception);
207 if (network_->isLatchData(pin)
208 && check_role == TimingRole::setup()) {
209 PathEndLatchCheck path_end(path, check_arc, edge,
210 tgt_clk_path, nullptr,
211 path_delay, this);
212 visitor->visit(&path_end);
213 }
214 else {
215 PathEndPathDelay path_end(path_delay, path, tgt_clk_path,
216 check_arc, edge, this);
217 visitor->visit(&path_end);
218 is_constrained = true;
219 }
220 }
221 }
222 }
223 }
224 }
225 }
226 }
227 }
228 }
229 if (!check_clked
230 && !sdc_->exceptionToInvalid(pin))
231 visitCheckEndUnclked(pin, vertex, path, end_rf, path_ap, filtered,
232 visitor, is_constrained);
233 }
234
235 void
visitCheckEndUnclked(const Pin * pin,Vertex * vertex,Path * path,const RiseFall * end_rf,const PathAnalysisPt * path_ap,bool filtered,PathEndVisitor * visitor,bool & is_constrained)236 VisitPathEnds::visitCheckEndUnclked(const Pin *pin,
237 Vertex *vertex,
238 Path *path,
239 const RiseFall *end_rf,
240 const PathAnalysisPt *path_ap,
241 bool filtered,
242 PathEndVisitor *visitor,
243 bool &is_constrained)
244 {
245 const MinMax *min_max = path_ap->pathMinMax();
246 VertexInEdgeIterator edge_iter(vertex, graph_);
247 while (edge_iter.hasNext()) {
248 Edge *edge = edge_iter.next();
249 const TimingRole *check_role = edge->role();
250 if (checkEdgeEnabled(edge)
251 && check_role->pathMinMax() == min_max) {
252 TimingArcSet *arc_set = edge->timingArcSet();
253 TimingArcSetArcIterator arc_iter(arc_set);
254 while (arc_iter.hasNext()) {
255 TimingArc *check_arc = arc_iter.next();
256 RiseFall *clk_rf = check_arc->fromTrans()->asRiseFall();
257 if (check_arc->toTrans()->asRiseFall() == end_rf
258 && clk_rf
259 && (!filtered
260 || search_->matchesFilter(path, nullptr))) {
261 ExceptionPath *exception = exceptionTo(path, pin, end_rf,
262 nullptr, min_max);
263 // False paths and path delays override multicycle paths.
264 if (exception
265 && exception->isPathDelay()) {
266 PathDelay *path_delay = dynamic_cast<PathDelay*>(exception);
267 PathEndPathDelay path_end(path_delay, path, nullptr,
268 check_arc, edge, this);
269 visitor->visit(&path_end);
270 is_constrained = true;
271 }
272 }
273 }
274 }
275 }
276 }
277
278 bool
checkEdgeEnabled(Edge * edge) const279 VisitPathEnds::checkEdgeEnabled(Edge *edge) const
280 {
281 const TimingRole *check_role = edge->role();
282 return check_role->isTimingCheck()
283 && search_->evalPred()->searchFrom(edge->from(graph_))
284 && !edge->isDisabledConstraint()
285 && !edge->isDisabledCond()
286 && !sdc_->isDisabledCondDefault(edge)
287 && !((check_role == TimingRole::recovery()
288 || check_role == TimingRole::removal())
289 && !sdc_->recoveryRemovalChecksEnabled());
290 }
291
292 void
visitOutputDelayEnd(const Pin * pin,Path * path,const RiseFall * end_rf,const PathAnalysisPt * path_ap,bool filtered,PathEndVisitor * visitor,bool & is_constrained)293 VisitPathEnds::visitOutputDelayEnd(const Pin *pin,
294 Path *path,
295 const RiseFall *end_rf,
296 const PathAnalysisPt *path_ap,
297 bool filtered,
298 PathEndVisitor *visitor,
299 bool &is_constrained)
300 {
301 const MinMax *min_max = path_ap->pathMinMax();
302 OutputDelaySet *output_delays = sdc_->outputDelaysLeafPin(pin);
303 if (output_delays) {
304 for (OutputDelay *output_delay : *output_delays) {
305 float margin;
306 bool exists;
307 output_delay->delays()->value(end_rf, min_max, margin, exists);
308 if (exists) {
309 const Pin *ref_pin = output_delay->refPin();
310 ClockEdge *tgt_clk_edge = output_delay->clkEdge();
311 if (!filtered
312 || search_->matchesFilter(path, tgt_clk_edge)) {
313 if (ref_pin) {
314 Clock *tgt_clk = output_delay->clock();
315 Vertex *ref_vertex = graph_->pinLoadVertex(ref_pin);
316 RiseFall *ref_rf = output_delay->refTransition();
317 VertexPathIterator ref_path_iter(ref_vertex,ref_rf,path_ap,this);
318 while (ref_path_iter.hasNext()) {
319 PathVertex *ref_path = ref_path_iter.next();
320 if (ref_path->isClock(this)
321 && (tgt_clk == nullptr
322 || ref_path->clock(this) == tgt_clk))
323 visitOutputDelayEnd1(output_delay, pin, path, end_rf,
324 ref_path->clkEdge(this), ref_path, min_max,
325 visitor, is_constrained);
326 }
327 }
328 else
329 visitOutputDelayEnd1(output_delay, pin, path, end_rf,
330 tgt_clk_edge, nullptr, min_max,
331 visitor, is_constrained);
332 }
333 }
334 }
335 }
336 }
337
338 void
visitOutputDelayEnd1(OutputDelay * output_delay,const Pin * pin,Path * path,const RiseFall * end_rf,const ClockEdge * tgt_clk_edge,PathVertex * ref_path,const MinMax * min_max,PathEndVisitor * visitor,bool & is_constrained)339 VisitPathEnds::visitOutputDelayEnd1(OutputDelay *output_delay,
340 const Pin *pin,
341 Path *path,
342 const RiseFall *end_rf,
343 const ClockEdge *tgt_clk_edge,
344 PathVertex *ref_path,
345 const MinMax *min_max,
346 PathEndVisitor *visitor,
347 bool &is_constrained)
348 {
349 // Target clk is not required for path delay,
350 // but the exception may be -to clk.
351 ExceptionPath *exception = exceptionTo(path, pin, end_rf, tgt_clk_edge,
352 min_max);
353 if (exception
354 && exception->isPathDelay()) {
355 PathDelay *path_delay = dynamic_cast<PathDelay*>(exception);
356 PathEndPathDelay path_end(path_delay, path, output_delay, this);
357 visitor->visit(&path_end);
358 is_constrained = true;
359 }
360 else if (tgt_clk_edge
361 && sdc_->sameClockGroup(path->clock(this), tgt_clk_edge->clock())
362 // False paths and path delays override.
363 && (exception == nullptr
364 || exception->isFilter()
365 || exception->isGroupPath()
366 || exception->isMultiCycle())) {
367 MultiCyclePath *mcp = dynamic_cast<MultiCyclePath*>(exception);
368 PathEndOutputDelay path_end(output_delay, path, ref_path, mcp, this);
369 visitor->visit(&path_end);
370 is_constrained = true;
371 }
372 }
373
374 ////////////////////////////////////////////////////////////////
375
376 // Look for clock gating functions where path is the clock enable.
377 void
visitGatedClkEnd(const Pin * pin,Vertex * vertex,Path * path,const RiseFall * end_rf,const PathAnalysisPt * path_ap,bool filtered,PathEndVisitor * visitor,bool & is_constrained)378 VisitPathEnds::visitGatedClkEnd(const Pin *pin,
379 Vertex *vertex,
380 Path *path,
381 const RiseFall *end_rf,
382 const PathAnalysisPt *path_ap,
383 bool filtered,
384 PathEndVisitor *visitor,
385 bool &is_constrained)
386 {
387 ClockEdge *src_clk_edge = path->clkEdge(this);
388 if (src_clk_edge) {
389 GatedClk *gated_clk = search_->gatedClk();
390 Clock *src_clk = src_clk_edge->clock();
391 bool is_gated_clk_enable;
392 const Pin *clk_pin;
393 LogicValue logic_active_value;
394 gated_clk->isGatedClkEnable(vertex,
395 is_gated_clk_enable, clk_pin, logic_active_value);
396 if (is_gated_clk_enable) {
397 const PathAnalysisPt *clk_path_ap = path_ap->tgtClkAnalysisPt();
398 const MinMax *min_max = path_ap->pathMinMax();
399 Vertex *clk_vertex = graph_->pinLoadVertex(clk_pin);
400 LogicValue active_value =
401 sdc_->clockGatingActiveValue(clk_pin, pin);
402 RiseFall *clk_rf =
403 // Clock active value specified by set_clock_gating_check
404 // overrides the library cell function active value.
405 gated_clk->gatedClkActiveTrans((active_value == LogicValue::unknown) ?
406 logic_active_value : active_value,
407 min_max);
408 VertexPathIterator clk_path_iter(clk_vertex, clk_rf, clk_path_ap, this);
409 while (clk_path_iter.hasNext()) {
410 PathVertex *clk_path = clk_path_iter.next();
411 const ClockEdge *clk_edge = clk_path->clkEdge(this);
412 const Clock *clk = clk_edge ? clk_edge->clock() : nullptr;
413 if (clk_path->isClock(this)
414 // Ignore unclocked paths (from path delay constraints).
415 && clk_edge
416 && clk_edge != sdc_->defaultArrivalClockEdge()
417 // Ignore generated clock source paths.
418 && !path->clkInfo(this)->isGenClkSrcPath()
419 && !search_->pathPropagatedToClkSrc(clk_pin, clk_path)
420 && !sdc_->clkStopPropagation(pin, clk)
421 && clk_vertex->hasDownstreamClkPin()) {
422 TimingRole *check_role = (min_max == MinMax::max())
423 ? TimingRole::gatedClockSetup()
424 : TimingRole::gatedClockHold();
425 float margin = clockGatingMargin(clk, clk_pin,
426 pin, end_rf, min_max);
427 ExceptionPath *exception = exceptionTo(path, pin, end_rf,
428 clk_edge, min_max);
429 if (sdc_->sameClockGroup(src_clk, clk)
430 // False paths and path delays override.
431 && (exception == nullptr
432 || exception->isFilter()
433 || exception->isGroupPath()
434 || exception->isMultiCycle())
435 && (!filtered
436 || search_->matchesFilter(path, clk_edge))) {
437 MultiCyclePath *mcp =
438 dynamic_cast<MultiCyclePath *>(exception);
439 PathEndGatedClock path_end(path, clk_path, check_role,
440 mcp, margin, this);
441 visitor->visit(&path_end);
442 is_constrained = true;
443 }
444 }
445 }
446 }
447 }
448 }
449
450 // Gated clock setup/hold margin respecting precedence rules.
451 // Look for margin from highest precedence level to lowest.
452 float
clockGatingMargin(const Clock * clk,const Pin * clk_pin,const Pin * enable_pin,const RiseFall * enable_rf,const SetupHold * setup_hold)453 VisitPathEnds::clockGatingMargin(const Clock *clk,
454 const Pin *clk_pin,
455 const Pin *enable_pin,
456 const RiseFall *enable_rf,
457 const SetupHold *setup_hold)
458 {
459 bool exists;
460 float margin;
461 sdc_->clockGatingMarginEnablePin(enable_pin, enable_rf,
462 setup_hold, exists, margin);
463 if (exists)
464 return margin;
465 Instance *inst = network_->instance(enable_pin);
466 sdc_->clockGatingMarginInstance(inst, enable_rf, setup_hold,
467 exists, margin);
468 if (exists)
469 return margin;
470 sdc_->clockGatingMarginClkPin(clk_pin, enable_rf, setup_hold,
471 exists, margin);
472 if (exists)
473 return margin;
474 sdc_->clockGatingMarginClk(clk, enable_rf, setup_hold,
475 exists, margin);
476 if (exists)
477 return margin;
478 sdc_->clockGatingMargin(enable_rf, setup_hold,
479 exists, margin);
480 if (exists)
481 return margin;
482 else
483 return 0.0;
484 }
485
486 ////////////////////////////////////////////////////////////////
487
488 void
visitDataCheckEnd(const Pin * pin,Path * path,const RiseFall * end_rf,const PathAnalysisPt * path_ap,bool filtered,PathEndVisitor * visitor,bool & is_constrained)489 VisitPathEnds::visitDataCheckEnd(const Pin *pin,
490 Path *path,
491 const RiseFall *end_rf,
492 const PathAnalysisPt *path_ap,
493 bool filtered,
494 PathEndVisitor *visitor,
495 bool &is_constrained)
496 {
497 ClockEdge *src_clk_edge = path->clkEdge(this);
498 if (src_clk_edge) {
499 DataCheckSet *checks = sdc_->dataChecksTo(pin);
500 if (checks) {
501 const Clock *src_clk = src_clk_edge->clock();
502 const MinMax *min_max = path_ap->pathMinMax();
503 const PathAnalysisPt *clk_ap = path_ap->tgtClkAnalysisPt();
504 DataCheckSet::Iterator check_iter(checks);
505 while (check_iter.hasNext()) {
506 DataCheck *check = check_iter.next();
507 const Pin *from_pin = check->from();
508 Vertex *from_vertex = graph_->pinLoadVertex(from_pin);
509 for (auto from_rf : RiseFall::range()) {
510 float margin;
511 bool margin_exists;
512 check->margin(from_rf, end_rf, min_max, margin, margin_exists);
513 if (margin_exists)
514 visitDataCheckEnd1(check, pin, path, src_clk, end_rf,
515 min_max, clk_ap, from_pin, from_vertex,
516 from_rf, filtered, visitor, is_constrained);
517 }
518 }
519 }
520 }
521 }
522
523 bool
visitDataCheckEnd1(DataCheck * check,const Pin * pin,Path * path,const Clock * src_clk,const RiseFall * end_rf,const MinMax * min_max,const PathAnalysisPt * clk_ap,const Pin * from_pin,Vertex * from_vertex,RiseFall * from_rf,bool filtered,PathEndVisitor * visitor,bool & is_constrained)524 VisitPathEnds::visitDataCheckEnd1(DataCheck *check,
525 const Pin *pin,
526 Path *path,
527 const Clock *src_clk,
528 const RiseFall *end_rf,
529 const MinMax *min_max,
530 const PathAnalysisPt *clk_ap,
531 const Pin *from_pin,
532 Vertex *from_vertex,
533 RiseFall *from_rf,
534 bool filtered,
535 PathEndVisitor *visitor,
536 bool &is_constrained)
537 {
538 bool found_from_path = false;
539 VertexPathIterator tgt_clk_path_iter(from_vertex,from_rf,clk_ap,this);
540 while (tgt_clk_path_iter.hasNext()) {
541 PathVertex *tgt_clk_path = tgt_clk_path_iter.next();
542 const ClockEdge *tgt_clk_edge = tgt_clk_path->clkEdge(this);
543 const Clock *tgt_clk = tgt_clk_edge ? tgt_clk_edge->clock() : nullptr;
544 ExceptionPath *exception = exceptionTo(path, pin, end_rf,
545 tgt_clk_edge, min_max);
546 // Ignore generated clock source paths.
547 if (!tgt_clk_path->clkInfo(this)->isGenClkSrcPath()
548 && !search_->pathPropagatedToClkSrc(from_pin, tgt_clk_path)) {
549 found_from_path = true;
550 if (sdc_->sameClockGroup(src_clk, tgt_clk)
551 && !sdc_->clkStopPropagation(from_pin, tgt_clk)
552 // False paths and path delays override.
553 && (exception == 0
554 || exception->isFilter()
555 || exception->isGroupPath()
556 || exception->isMultiCycle())
557 && (!filtered
558 || search_->matchesFilter(path, tgt_clk_edge))) {
559 MultiCyclePath *mcp=dynamic_cast<MultiCyclePath*>(exception);
560 PathEndDataCheck path_end(check, path, tgt_clk_path, mcp, this);
561 visitor->visit(&path_end);
562 is_constrained = true;
563 }
564 }
565 }
566 return found_from_path;
567 }
568
569 ////////////////////////////////////////////////////////////////
570
571 void
visitUnconstrainedPathEnds(const Pin * pin,Vertex * vertex,const Corner * corner,const MinMaxAll * min_max,bool filtered,PathEndVisitor * visitor)572 VisitPathEnds::visitUnconstrainedPathEnds(const Pin *pin,
573 Vertex *vertex,
574 const Corner *corner,
575 const MinMaxAll *min_max,
576 bool filtered,
577 PathEndVisitor *visitor)
578 {
579 VertexPathIterator path_iter(vertex, this);
580 while (path_iter.hasNext()) {
581 PathVertex *path = path_iter.next();
582 PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
583 const MinMax *path_min_max = path_ap->pathMinMax();
584 if ((corner == nullptr
585 || path_ap->corner() == corner)
586 && min_max->matches(path_min_max)
587 // Ignore generated clock source paths.
588 && !path->clkInfo(this)->isGenClkSrcPath()
589 && !search_->pathPropagatedToClkSrc(pin, path)
590 && (!filtered
591 || search_->matchesFilter(path, nullptr))
592 && !falsePathTo(path, pin, path->transition(this),
593 path->minMax(this))) {
594 PathEndUnconstrained path_end(path);
595 visitor->visit(&path_end);
596 }
597 }
598 }
599
600 ////////////////////////////////////////////////////////////////
601
602 bool
falsePathTo(Path * path,const Pin * pin,const RiseFall * rf,const MinMax * min_max)603 VisitPathEnds::falsePathTo(Path *path,
604 const Pin *pin,
605 const RiseFall *rf,
606 const MinMax *min_max)
607 {
608 ExceptionPath *exception = search_->exceptionTo(ExceptionPathType::false_path, path,
609 pin, rf, nullptr, min_max,
610 false, false);
611 return exception != nullptr;
612 }
613
614 PathDelay *
pathDelayTo(Path * path,const Pin * pin,const RiseFall * rf,const MinMax * min_max)615 VisitPathEnds::pathDelayTo(Path *path,
616 const Pin *pin,
617 const RiseFall *rf,
618 const MinMax *min_max)
619 {
620 ExceptionPath *exception = search_->exceptionTo(ExceptionPathType::path_delay,
621 path, pin, rf, nullptr,
622 min_max, false,
623 // Register clk pins only
624 // match with -to pin.
625 network_->isRegClkPin(pin));
626 return dynamic_cast<PathDelay*>(exception);
627 }
628
629 ExceptionPath *
exceptionTo(const Path * path,const Pin * pin,const RiseFall * rf,const ClockEdge * clk_edge,const MinMax * min_max) const630 VisitPathEnds::exceptionTo(const Path *path,
631 const Pin *pin,
632 const RiseFall *rf,
633 const ClockEdge *clk_edge,
634 const MinMax *min_max) const
635 {
636 return search_->exceptionTo(ExceptionPathType::any, path, pin, rf, clk_edge,
637 min_max, false, false);
638 }
639
640 } // namespace
641