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