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 "CheckCapacitanceLimits.hh"
18 
19 #include "Fuzzy.hh"
20 #include "Liberty.hh"
21 #include "Network.hh"
22 #include "Sdc.hh"
23 #include "DcalcAnalysisPt.hh"
24 #include "GraphDelayCalc.hh"
25 #include "StaState.hh"
26 #include "Corner.hh"
27 #include "PortDirection.hh"
28 #include "Sim.hh"
29 #include "Graph.hh"
30 #include "GraphDelayCalc.hh"
31 
32 namespace sta {
33 
34 class PinCapacitanceLimitSlackLess
35 {
36 public:
37   PinCapacitanceLimitSlackLess(const Corner *corner,
38 			       const MinMax *min_max,
39 			       CheckCapacitanceLimits *check_capacitance_limit,
40 			       const StaState *sta);
41   bool operator()(Pin *pin1,
42 		  Pin *pin2) const;
43 
44 private:
45   const Corner *corner_;
46   const MinMax *min_max_;
47   CheckCapacitanceLimits *check_capacitance_limit_;
48   const StaState *sta_;
49 
50 };
51 
PinCapacitanceLimitSlackLess(const Corner * corner,const MinMax * min_max,CheckCapacitanceLimits * check_capacitance_limit,const StaState * sta)52 PinCapacitanceLimitSlackLess::PinCapacitanceLimitSlackLess(const Corner *corner,
53 							   const MinMax *min_max,
54 							   CheckCapacitanceLimits *check_capacitance_limit,
55 							   const StaState *sta) :
56   corner_(corner),
57   min_max_(min_max),
58   check_capacitance_limit_(check_capacitance_limit),
59   sta_(sta)
60 {
61 }
62 
63 bool
operator ()(Pin * pin1,Pin * pin2) const64 PinCapacitanceLimitSlackLess::operator()(Pin *pin1,
65 					 Pin *pin2) const
66 {
67   const Corner *corner1, *corner2;
68   const RiseFall *rf1, *rf2;
69   float capacitance1, capacitance2;
70   float limit1, limit2, slack1, slack2;
71   check_capacitance_limit_->checkCapacitance(pin1, corner_, min_max_,
72 					     corner1, rf1, capacitance1,
73 					     limit1, slack1);
74   check_capacitance_limit_->checkCapacitance(pin2, corner_, min_max_,
75 					     corner2, rf2, capacitance2,
76 					     limit2, slack2);
77   return fuzzyLess(slack1, slack2)
78     || (fuzzyEqual(slack1, slack2)
79 	// Break ties for the sake of regression stability.
80 	&& sta_->network()->pinLess(pin1, pin2));
81 }
82 
83 ////////////////////////////////////////////////////////////////
84 
CheckCapacitanceLimits(const Sta * sta)85 CheckCapacitanceLimits::CheckCapacitanceLimits(const Sta *sta) :
86   sta_(sta)
87 {
88 }
89 
90 void
checkCapacitance(const Pin * pin,const Corner * corner,const MinMax * min_max,const Corner * & corner1,const RiseFall * & rf1,float & capacitance1,float & limit1,float & slack1) const91 CheckCapacitanceLimits::checkCapacitance(const Pin *pin,
92 					 const Corner *corner,
93 					 const MinMax *min_max,
94 					 // Return values.
95 					 const Corner *&corner1,
96 					 const RiseFall *&rf1,
97 					 float &capacitance1,
98 					 float &limit1,
99 					 float &slack1) const
100 {
101   corner1 = nullptr;
102   rf1 = nullptr;
103   capacitance1 = 0.0;
104   limit1 = 0.0;
105   slack1 = MinMax::min()->initValue();
106   if (corner)
107     checkCapacitance1(pin, corner, min_max,
108 		      corner1, rf1, capacitance1, limit1, slack1);
109   else {
110     for (auto corner : *sta_->corners()) {
111       checkCapacitance1(pin, corner, min_max,
112                         corner1, rf1, capacitance1, limit1, slack1);
113     }
114   }
115 }
116 
117 void
checkCapacitance1(const Pin * pin,const Corner * corner,const MinMax * min_max,const Corner * & corner1,const RiseFall * & rf1,float & capacitance1,float & limit1,float & slack1) const118 CheckCapacitanceLimits::checkCapacitance1(const Pin *pin,
119 					  const Corner *corner,
120 					  const MinMax *min_max,
121 					  // Return values.
122 					  const Corner *&corner1,
123 					  const RiseFall *&rf1,
124 					  float &capacitance1,
125 					  float &limit1,
126 					  float &slack1) const
127 {
128   float limit;
129   bool limit_exists;
130   findLimit(pin, corner, min_max, limit, limit_exists);
131   if (limit_exists) {
132     for (auto rf : RiseFall::range()) {
133       checkCapacitance(pin, corner, min_max, rf, limit,
134 		       corner1, rf1, capacitance1, slack1, limit1);
135     }
136   }
137 }
138 
139 // return the tightest limit.
140 void
findLimit(const Pin * pin,const Corner * corner,const MinMax * min_max,float & limit,bool & exists) const141 CheckCapacitanceLimits::findLimit(const Pin *pin,
142                                   const Corner *corner,
143 				  const MinMax *min_max,
144 				  // Return values.
145 				  float &limit,
146 				  bool &exists) const
147 {
148   const Network *network = sta_->network();
149   Sdc *sdc = sta_->sdc();
150 
151   // Default to top ("design") limit.
152   Cell *top_cell = network->cell(network->topInstance());
153   sdc->capacitanceLimit(top_cell, min_max,
154 			limit, exists);
155 
156   float limit1;
157   bool exists1;
158   if (network->isTopLevelPort(pin)) {
159     Port *port = network->port(pin);
160     sdc->capacitanceLimit(port, min_max, limit1, exists1);
161     if (exists1
162 	&& (!exists
163 	    || min_max->compare(limit, limit1))) {
164 	limit = limit1;
165 	exists = true;
166     }
167   }
168   else {
169     Cell *cell = network->cell(network->instance(pin));
170     sdc->capacitanceLimit(cell, min_max,
171 			  limit1, exists1);
172     if (exists1
173 	&& (!exists
174 	    || min_max->compare(limit, limit1))) {
175 	limit = limit1;
176 	exists = true;
177     }
178     LibertyPort *port = network->libertyPort(pin);
179     if (port) {
180       LibertyPort *corner_port = port->cornerPort(corner->libertyIndex(min_max));
181       corner_port->capacitanceLimit(min_max, limit1, exists1);
182       if (!exists1
183 	  && port->direction()->isAnyOutput())
184 	corner_port->libertyLibrary()->defaultMaxCapacitance(limit1, exists1);
185       if (exists1
186 	  && (!exists
187 	      || min_max->compare(limit, limit1))) {
188 	limit = limit1;
189 	exists = true;
190       }
191     }
192   }
193 }
194 
195 void
checkCapacitance(const Pin * pin,const Corner * corner,const MinMax * min_max,const RiseFall * rf,float limit,const Corner * & corner1,const RiseFall * & rf1,float & capacitance1,float & slack1,float & limit1) const196 CheckCapacitanceLimits::checkCapacitance(const Pin *pin,
197 					 const Corner *corner,
198 					 const MinMax *min_max,
199 					 const RiseFall *rf,
200 					 float limit,
201 					 // Return values.
202 					 const Corner *&corner1,
203 					 const RiseFall *&rf1,
204 					 float &capacitance1,
205 					 float &slack1,
206 					 float &limit1) const
207 {
208   const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(min_max);
209   GraphDelayCalc *dcalc = sta_->graphDelayCalc();
210   float cap = dcalc->loadCap(pin, dcalc_ap);
211 
212   float slack = (min_max == MinMax::max())
213     ? limit - cap : cap - limit;
214   if (slack < slack1
215       // Break ties for the sake of regression stability.
216       || (fuzzyEqual(slack, slack1)
217           && rf->index() < rf1->index())) {
218     corner1 = corner;
219     rf1 = rf;
220     capacitance1 = cap;
221     slack1 = slack;
222     limit1 = limit;
223   }
224 }
225 
226 ////////////////////////////////////////////////////////////////
227 
228 PinSeq *
checkCapacitanceLimits(Net * net,bool violators,const Corner * corner,const MinMax * min_max)229 CheckCapacitanceLimits::checkCapacitanceLimits(Net *net,
230                                                bool violators,
231                                                const Corner *corner,
232                                                const MinMax *min_max)
233 {
234   const Network *network = sta_->network();
235   PinSeq *cap_pins = new PinSeq;
236   float min_slack = MinMax::min()->initValue();
237   if (net) {
238     NetPinIterator *pin_iter = network->pinIterator(net);
239     while (pin_iter->hasNext()) {
240       Pin *pin = pin_iter->next();
241       checkCapLimits(pin, violators, corner, min_max, cap_pins, min_slack);
242     }
243     delete pin_iter;
244   }
245   else {
246     LeafInstanceIterator *inst_iter = network->leafInstanceIterator();
247     while (inst_iter->hasNext()) {
248       Instance *inst = inst_iter->next();
249       checkCapLimits(inst, violators, corner, min_max, cap_pins, min_slack);
250     }
251     delete inst_iter;
252     // Check top level ports.
253     checkCapLimits(network->topInstance(), violators, corner, min_max,
254                    cap_pins, min_slack);
255   }
256   sort(cap_pins, PinCapacitanceLimitSlackLess(corner, min_max, this, sta_));
257   // Keep the min slack pin unless all violators or net pins.
258   if (!cap_pins->empty() && !violators && net == nullptr)
259     cap_pins->resize(1);
260   return cap_pins;
261 }
262 
263 void
checkCapLimits(Instance * inst,bool violators,const Corner * corner,const MinMax * min_max,PinSeq * cap_pins,float & min_slack)264 CheckCapacitanceLimits::checkCapLimits(Instance *inst,
265                                        bool violators,
266                                        const Corner *corner,
267                                        const MinMax *min_max,
268                                        PinSeq *cap_pins,
269                                        float &min_slack)
270 {
271   const Network *network = sta_->network();
272   InstancePinIterator *pin_iter = network->pinIterator(inst);
273   while (pin_iter->hasNext()) {
274     Pin *pin = pin_iter->next();
275     checkCapLimits(pin, violators, corner, min_max, cap_pins, min_slack);
276   }
277   delete pin_iter;
278 }
279 
280 void
checkCapLimits(Pin * pin,bool violators,const Corner * corner,const MinMax * min_max,PinSeq * cap_pins,float & min_slack)281 CheckCapacitanceLimits::checkCapLimits(Pin *pin,
282                                        bool violators,
283                                        const Corner *corner,
284                                        const MinMax *min_max,
285                                        PinSeq *cap_pins,
286                                        float &min_slack)
287 {
288   if (checkPin(pin)) {
289     const Corner *corner1;
290     const RiseFall *rf;
291     float capacitance, limit, slack;
292     checkCapacitance(pin, corner, min_max, corner1, rf, capacitance, limit, slack);
293     if (!fuzzyInf(slack)) {
294       if (violators) {
295         if (slack < 0.0)
296           cap_pins->push_back(pin);
297       }
298       else {
299         if (cap_pins->empty()
300             || slack < min_slack) {
301           cap_pins->push_back(pin);
302           min_slack = slack;
303         }
304       }
305     }
306   }
307 }
308 
309 bool
checkPin(Pin * pin)310 CheckCapacitanceLimits::checkPin(Pin *pin)
311 {
312   const Network *network = sta_->network();
313   const Sim *sim = sta_->sim();
314   const Sdc *sdc = sta_->sdc();
315   const Graph *graph = sta_->graph();
316   Vertex *vertex = graph->pinLoadVertex(pin);
317   return network->direction(pin)->isAnyOutput()
318     && !sim->logicZeroOne(pin)
319     && !sdc->isDisabled(pin)
320     && !(vertex && sta_->isIdealClock(pin));
321 }
322 
323 } // namespace
324