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