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 "CheckMaxSkews.hh"
18
19 #include "DisallowCopyAssign.hh"
20 #include "TimingRole.hh"
21 #include "TimingArc.hh"
22 #include "Liberty.hh"
23 #include "Network.hh"
24 #include "Graph.hh"
25 #include "Clock.hh"
26 #include "PathVertex.hh"
27 #include "PathAnalysisPt.hh"
28 #include "Search.hh"
29
30 namespace sta {
31
32 // Abstract base class.
33 class MaxSkewCheckVisitor
34 {
35 public:
MaxSkewCheckVisitor()36 MaxSkewCheckVisitor() {}
~MaxSkewCheckVisitor()37 virtual ~MaxSkewCheckVisitor() {}
38 virtual void visit(MaxSkewCheck &check,
39 const StaState *sta) = 0;
40
41 private:
42 DISALLOW_COPY_AND_ASSIGN(MaxSkewCheckVisitor);
43 };
44
CheckMaxSkews(StaState * sta)45 CheckMaxSkews::CheckMaxSkews(StaState *sta) :
46 sta_(sta)
47 {
48 }
49
~CheckMaxSkews()50 CheckMaxSkews::~CheckMaxSkews()
51 {
52 checks_.deleteContents();
53 }
54
55 void
clear()56 CheckMaxSkews::clear()
57 {
58 checks_.deleteContentsClear();
59 }
60
61 class MaxSkewChecksVisitor : public MaxSkewCheckVisitor
62 {
63 public:
64 explicit MaxSkewChecksVisitor(MaxSkewCheckSeq &checks);
65 virtual void visit(MaxSkewCheck &check,
66 const StaState *sta);
67
68 private:
69 DISALLOW_COPY_AND_ASSIGN(MaxSkewChecksVisitor);
70
71 MaxSkewCheckSeq &checks_;
72 };
73
MaxSkewChecksVisitor(MaxSkewCheckSeq & checks)74 MaxSkewChecksVisitor::MaxSkewChecksVisitor(MaxSkewCheckSeq &checks) :
75 MaxSkewCheckVisitor(),
76 checks_(checks)
77 {
78 }
79
80 void
visit(MaxSkewCheck & check,const StaState *)81 MaxSkewChecksVisitor::visit(MaxSkewCheck &check,
82 const StaState *)
83 {
84 checks_.push_back(new MaxSkewCheck(check));
85 }
86
87 class MaxSkewViolatorsVisititor : public MaxSkewCheckVisitor
88 {
89 public:
90 explicit MaxSkewViolatorsVisititor(MaxSkewCheckSeq &checks);
91 virtual void visit(MaxSkewCheck &check,
92 const StaState *sta);
93
94 private:
95 DISALLOW_COPY_AND_ASSIGN(MaxSkewViolatorsVisititor);
96 MaxSkewCheckSeq &checks_;
97 };
98
99 MaxSkewViolatorsVisititor::
MaxSkewViolatorsVisititor(MaxSkewCheckSeq & checks)100 MaxSkewViolatorsVisititor(MaxSkewCheckSeq &checks) :
101 MaxSkewCheckVisitor(),
102 checks_(checks)
103 {
104 }
105
106 void
visit(MaxSkewCheck & check,const StaState * sta)107 MaxSkewViolatorsVisititor::visit(MaxSkewCheck &check,
108 const StaState *sta)
109 {
110 if (delayLess(check.slack(sta), 0.0, sta))
111 checks_.push_back(new MaxSkewCheck(check));
112 }
113
114 MaxSkewCheckSeq &
violations()115 CheckMaxSkews::violations()
116 {
117 clear();
118 MaxSkewViolatorsVisititor visitor(checks_);
119 visitMaxSkewChecks(&visitor);
120 sort(checks_, MaxSkewSlackLess(sta_));
121 return checks_;
122 }
123
124 class MaxSkewSlackVisitor : public MaxSkewCheckVisitor
125 {
126 public:
127 MaxSkewSlackVisitor();
128 virtual void visit(MaxSkewCheck &check,
129 const StaState *sta);
130 MaxSkewCheck *minSlackCheck();
131
132 private:
133 DISALLOW_COPY_AND_ASSIGN(MaxSkewSlackVisitor);
134
135 MaxSkewCheck *min_slack_check_;
136 };
137
MaxSkewSlackVisitor()138 MaxSkewSlackVisitor::MaxSkewSlackVisitor() :
139 MaxSkewCheckVisitor(),
140 min_slack_check_(nullptr)
141 {
142 }
143
144 void
visit(MaxSkewCheck & check,const StaState * sta)145 MaxSkewSlackVisitor::visit(MaxSkewCheck &check,
146 const StaState *sta)
147 {
148 MaxSkewSlackLess slack_less(sta);
149 if (min_slack_check_ == nullptr
150 || slack_less(&check, min_slack_check_)) {
151 delete min_slack_check_;
152 min_slack_check_ = new MaxSkewCheck(check);
153 }
154 }
155
156 MaxSkewCheck *
minSlackCheck()157 MaxSkewSlackVisitor::minSlackCheck()
158 {
159 return min_slack_check_;
160 }
161
162 MaxSkewCheck *
minSlackCheck()163 CheckMaxSkews::minSlackCheck()
164 {
165 clear();
166 MaxSkewSlackVisitor visitor;
167 visitMaxSkewChecks(&visitor);
168 MaxSkewCheck *check = visitor.minSlackCheck();
169 // Save check for cleanup.
170 checks_.push_back(check);
171 return check;
172 }
173
174 void
visitMaxSkewChecks(MaxSkewCheckVisitor * visitor)175 CheckMaxSkews::visitMaxSkewChecks(MaxSkewCheckVisitor *visitor)
176 {
177 Graph *graph = sta_->graph();
178 VertexIterator vertex_iter(graph);
179 while (vertex_iter.hasNext()) {
180 Vertex *vertex = vertex_iter.next();
181 visitMaxSkewChecks(vertex, visitor);
182 }
183 }
184
185 void
visitMaxSkewChecks(Vertex * vertex,MaxSkewCheckVisitor * visitor)186 CheckMaxSkews:: visitMaxSkewChecks(Vertex *vertex,
187 MaxSkewCheckVisitor *visitor)
188 {
189 Graph *graph = sta_->graph();
190 Search *search = sta_->search();
191 const MinMax *clk_min_max = MinMax::max();
192 VertexInEdgeIterator edge_iter(vertex, graph);
193 while (edge_iter.hasNext()) {
194 Edge *edge = edge_iter.next();
195 if (edge->role() == TimingRole::skew()) {
196 Vertex *ref_vertex = edge->from(graph);
197 TimingArcSet *arc_set = edge->timingArcSet();
198 TimingArcSetArcIterator arc_iter(arc_set);
199 while (arc_iter.hasNext()) {
200 TimingArc *arc = arc_iter.next();
201 RiseFall *clk_rf = arc->fromTrans()->asRiseFall();
202 RiseFall *ref_rf = arc->toTrans()->asRiseFall();
203 VertexPathIterator clk_path_iter(vertex, clk_rf, clk_min_max, search);
204 while (clk_path_iter.hasNext()) {
205 PathVertex *clk_path = clk_path_iter.next();
206 if (clk_path->isClock(search)) {
207 const PathAnalysisPt *clk_ap = clk_path->pathAnalysisPt(sta_);
208 PathAnalysisPt *ref_ap = clk_ap->tgtClkAnalysisPt();
209 VertexPathIterator ref_path_iter(ref_vertex, ref_rf, ref_ap, sta_);
210 while (ref_path_iter.hasNext()) {
211 PathVertex *ref_path = ref_path_iter.next();
212 if (ref_path->isClock(search)) {
213 MaxSkewCheck check(clk_path, ref_path, arc, edge);
214 visitor->visit(check, sta_);
215 }
216 }
217 }
218 }
219 }
220 }
221 }
222 }
223
224 ////////////////////////////////////////////////////////////////
225
MaxSkewCheck(PathVertex * clk_path,PathVertex * ref_path,TimingArc * check_arc,Edge * check_edge)226 MaxSkewCheck::MaxSkewCheck(PathVertex *clk_path,
227 PathVertex *ref_path,
228 TimingArc *check_arc,
229 Edge *check_edge) :
230 clk_path_(clk_path),
231 ref_path_(ref_path),
232 check_arc_(check_arc),
233 check_edge_(check_edge)
234 {
235 }
236
237 Pin *
clkPin(const StaState * sta) const238 MaxSkewCheck::clkPin(const StaState *sta) const
239 {
240 return clk_path_.pin(sta);
241 }
242
243 Pin *
refPin(const StaState * sta) const244 MaxSkewCheck::refPin(const StaState *sta) const
245 {
246 return ref_path_.pin(sta);
247 }
248
249 ArcDelay
maxSkew(const StaState * sta) const250 MaxSkewCheck::maxSkew(const StaState *sta) const
251 {
252 Search *search = sta->search();
253 return search->deratedDelay(ref_path_.vertex(sta),
254 check_arc_, check_edge_, false,
255 clk_path_.pathAnalysisPt(sta));
256 }
257
258 Delay
skew(const StaState * sta) const259 MaxSkewCheck::skew(const StaState *sta) const
260 {
261 return Delay(clk_path_.arrival(sta) - ref_path_.arrival(sta));
262 }
263
264 Slack
slack(const StaState * sta) const265 MaxSkewCheck::slack(const StaState *sta) const
266 {
267 return maxSkew(sta) - skew(sta);
268 }
269
270 ////////////////////////////////////////////////////////////////
271
MaxSkewSlackLess(const StaState * sta)272 MaxSkewSlackLess::MaxSkewSlackLess(const StaState *sta) :
273 sta_(sta)
274 {
275 }
276
277 bool
operator ()(const MaxSkewCheck * check1,const MaxSkewCheck * check2) const278 MaxSkewSlackLess::operator()(const MaxSkewCheck *check1,
279 const MaxSkewCheck *check2) const
280 {
281 Slack slack1 = check1->slack(sta_);
282 Slack slack2 = check2->slack(sta_);
283 return delayLess(slack1, slack2, sta_)
284 || (delayEqual(slack1, slack2)
285 // Break ties based on constrained pin names.
286 && sta_->network()->pinLess(check1->clkPin(sta_),check2->clkPin(sta_)));
287 }
288
289 } // namespace
290