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 "ReduceParasitics.hh"
18
19 #include "Error.hh"
20 #include "Debug.hh"
21 #include "MinMax.hh"
22 #include "Liberty.hh"
23 #include "Network.hh"
24 #include "Sdc.hh"
25 #include "Corner.hh"
26 #include "Parasitics.hh"
27
28 namespace sta {
29
30 using std::max;
31
32 typedef Map<ParasiticNode*, double> ParasiticNodeValueMap;
33 typedef Map<ParasiticDevice*, double> ParasiticDeviceValueMap;
34 typedef Set<ParasiticNode*> ParasiticNodeSet;
35 typedef Set<ParasiticDevice*> ParasiticDeviceSet;
36
37 class ReduceToPi : public StaState
38 {
39 public:
40 ReduceToPi(StaState *sta);
41 void reduceToPi(const Pin *drvr_pin,
42 ParasiticNode *drvr_node,
43 bool includes_pin_caps,
44 float coupling_cap_factor,
45 const RiseFall *rf,
46 const OperatingConditions *op_cond,
47 const Corner *corner,
48 const MinMax *cnst_min_max,
49 const ParasiticAnalysisPt *ap,
50 float &c2,
51 float &rpi,
52 float &c1);
pinCapsOneValue()53 bool pinCapsOneValue() { return pin_caps_one_value_; }
54
55 protected:
56 void reducePiDfs(const Pin *drvr_pin,
57 ParasiticNode *node,
58 ParasiticDevice *from_res,
59 const ParasiticAnalysisPt *ap,
60 double src_resistance,
61 double &y1,
62 double &y2,
63 double &y3,
64 double &dwn_cap,
65 double &max_resistance);
66 void visit(ParasiticNode *node);
67 bool isVisited(ParasiticNode *node);
68 void leave(ParasiticNode *node);
69 void setDownstreamCap(ParasiticNode *node,
70 float cap);
71 float downstreamCap(ParasiticNode *node);
72 float pinCapacitance(ParasiticNode *node);
73 bool isLoopResistor(ParasiticDevice *device);
74 void markLoopResistor(ParasiticDevice *device);
75
76 bool includes_pin_caps_;
77 float coupling_cap_multiplier_;
78 const RiseFall *rf_;
79 const OperatingConditions *op_cond_;
80 const Corner *corner_;
81 const MinMax *cnst_min_max_;
82 ParasiticNodeSet visited_nodes_;
83 ParasiticNodeValueMap node_values_;
84 ParasiticDeviceSet loop_resistors_;
85 bool pin_caps_one_value_;
86 };
87
ReduceToPi(StaState * sta)88 ReduceToPi::ReduceToPi(StaState *sta) :
89 StaState(sta),
90 coupling_cap_multiplier_(1.0),
91 rf_(nullptr),
92 op_cond_(nullptr),
93 corner_(nullptr),
94 cnst_min_max_(nullptr),
95 pin_caps_one_value_(true)
96 {
97 }
98
99 // "Modeling the Driving-Point Characteristic of Resistive
100 // Interconnect for Accurate Delay Estimation", Peter O'Brien and
101 // Thomas Savarino, Proceedings of the 1989 Design Automation
102 // Conference.
103 void
reduceToPi(const Pin * drvr_pin,ParasiticNode * drvr_node,bool includes_pin_caps,float coupling_cap_factor,const RiseFall * rf,const OperatingConditions * op_cond,const Corner * corner,const MinMax * cnst_min_max,const ParasiticAnalysisPt * ap,float & c2,float & rpi,float & c1)104 ReduceToPi::reduceToPi(const Pin *drvr_pin,
105 ParasiticNode *drvr_node,
106 bool includes_pin_caps,
107 float coupling_cap_factor,
108 const RiseFall *rf,
109 const OperatingConditions *op_cond,
110 const Corner *corner,
111 const MinMax *cnst_min_max,
112 const ParasiticAnalysisPt *ap,
113 float &c2,
114 float &rpi,
115 float &c1)
116 {
117 includes_pin_caps_ = includes_pin_caps;
118 coupling_cap_multiplier_ = coupling_cap_factor;
119 rf_ = rf;
120 op_cond_ = op_cond;
121 corner_ = corner;
122 cnst_min_max_ = cnst_min_max;
123
124 double y1, y2, y3, dcap;
125 double max_resistance = 0.0;
126 reducePiDfs(drvr_pin, drvr_node, nullptr, ap, 0.0,
127 y1, y2, y3, dcap, max_resistance);
128
129 if (y2 == 0.0 && y3 == 0.0) {
130 // Capacitive load.
131 c1 = y1;
132 c2 = 0.0;
133 rpi = 0.0;
134 }
135 else {
136 c1 = y2 * y2 / y3;
137 c2 = y1 - y2 * y2 / y3;
138 rpi = -y3 * y3 / (y2 * y2 * y2);
139 }
140 debugPrint(debug_, "parasitic_reduce", 2,
141 " Pi model c2=%.3g rpi=%.3g c1=%.3g max_r=%.3g",
142 c2, rpi, c1, max_resistance);
143 }
144
145 // Find admittance moments.
146 void
reducePiDfs(const Pin * drvr_pin,ParasiticNode * node,ParasiticDevice * from_res,const ParasiticAnalysisPt * ap,double src_resistance,double & y1,double & y2,double & y3,double & dwn_cap,double & max_resistance)147 ReduceToPi::reducePiDfs(const Pin *drvr_pin,
148 ParasiticNode *node,
149 ParasiticDevice *from_res,
150 const ParasiticAnalysisPt *ap,
151 double src_resistance,
152 double &y1,
153 double &y2,
154 double &y3,
155 double &dwn_cap,
156 double &max_resistance)
157 {
158 double coupling_cap = 0.0;
159 ParasiticDeviceIterator *device_iter1 = parasitics_->deviceIterator(node);
160 while (device_iter1->hasNext()) {
161 ParasiticDevice *device = device_iter1->next();
162 if (parasitics_->isCouplingCap(device))
163 coupling_cap += parasitics_->value(device, ap);
164 }
165 delete device_iter1;
166
167 y1 = dwn_cap = parasitics_->nodeGndCap(node, ap)
168 + coupling_cap * coupling_cap_multiplier_
169 + pinCapacitance(node);
170 y2 = y3 = 0.0;
171 max_resistance = max(max_resistance, src_resistance);
172
173 visit(node);
174 ParasiticDeviceIterator *device_iter2 = parasitics_->deviceIterator(node);
175 while (device_iter2->hasNext()) {
176 ParasiticDevice *device = device_iter2->next();
177 if (parasitics_->isResistor(device)
178 && !isLoopResistor(device)) {
179 ParasiticNode *onode = parasitics_->otherNode(device, node);
180 // One commercial extractor creates resistors with identical from/to nodes.
181 if (onode != node
182 && device != from_res) {
183 if (isVisited(onode)) {
184 // Resistor loop.
185 debugPrint(debug_, "parasitic_reduce", 2, " loop detected thru resistor %s",
186 parasitics_->name(device));
187 markLoopResistor(device);
188 }
189 else {
190 double r = parasitics_->value(device, ap);
191 double yd1, yd2, yd3, dcap;
192 reducePiDfs(drvr_pin, onode, device, ap, src_resistance + r,
193 yd1, yd2, yd3, dcap, max_resistance);
194 // Rule 3. Upstream traversal of a series resistor.
195 // Rule 4. Parallel admittances add.
196 y1 += yd1;
197 y2 += yd2 - r * yd1 * yd1;
198 y3 += yd3 - 2 * r * yd1 * yd2 + r * r * yd1 * yd1 * yd1;
199 dwn_cap += dcap;
200 }
201 }
202 }
203 }
204 delete device_iter2;
205
206 setDownstreamCap(node, dwn_cap);
207 leave(node);
208 debugPrint(debug_, "parasitic_reduce", 3,
209 " node %s y1=%.3g y2=%.3g y3=%.3g cap=%.3g",
210 parasitics_->name(node), y1, y2, y3, dwn_cap);
211 }
212
213 float
pinCapacitance(ParasiticNode * node)214 ReduceToPi::pinCapacitance(ParasiticNode *node)
215 {
216 const Pin *pin = parasitics_->connectionPin(node);
217 float pin_cap = 0.0;
218 if (pin) {
219 Port *port = network_->port(pin);
220 LibertyPort *lib_port = network_->libertyPort(port);
221 if (lib_port) {
222 if (!includes_pin_caps_) {
223 pin_cap = sdc_->pinCapacitance(pin, rf_, op_cond_, corner_,
224 cnst_min_max_);
225 pin_caps_one_value_ &= lib_port->capacitanceIsOneValue();
226 }
227 }
228 else if (network_->isTopLevelPort(pin))
229 pin_cap = sdc_->portExtCap(port, rf_, cnst_min_max_);
230 }
231 return pin_cap;
232 }
233
234 void
visit(ParasiticNode * node)235 ReduceToPi::visit(ParasiticNode *node)
236 {
237 visited_nodes_.insert(node);
238 }
239
240 bool
isVisited(ParasiticNode * node)241 ReduceToPi::isVisited(ParasiticNode *node)
242 {
243 return visited_nodes_.hasKey(node);
244 }
245
246 void
leave(ParasiticNode * node)247 ReduceToPi::leave(ParasiticNode *node)
248 {
249 visited_nodes_.erase(node);
250 }
251
252 bool
isLoopResistor(ParasiticDevice * device)253 ReduceToPi::isLoopResistor(ParasiticDevice *device)
254 {
255 return loop_resistors_.hasKey(device);
256 }
257
258 void
markLoopResistor(ParasiticDevice * device)259 ReduceToPi::markLoopResistor(ParasiticDevice *device)
260 {
261 loop_resistors_.insert(device);
262 }
263
264 void
setDownstreamCap(ParasiticNode * node,float cap)265 ReduceToPi::setDownstreamCap(ParasiticNode *node,
266 float cap)
267 {
268 node_values_[node] = cap;
269 }
270
271 float
downstreamCap(ParasiticNode * node)272 ReduceToPi::downstreamCap(ParasiticNode *node)
273 {
274 return node_values_[node];
275 }
276
277 ////////////////////////////////////////////////////////////////
278
279 class ReduceToPiElmore : public ReduceToPi
280 {
281 public:
282 ReduceToPiElmore(StaState *sta);
283 void makePiElmore(Parasitic *parasitic_network,
284 const Pin *drvr_pin,
285 ParasiticNode *drvr_node,
286 float coupling_cap_factor,
287 const RiseFall *rf,
288 const OperatingConditions *op_cond,
289 const Corner *corner,
290 const MinMax *cnst_min_max,
291 const ParasiticAnalysisPt *ap);
292 void reduceElmoreDfs(const Pin *drvr_pin,
293 ParasiticNode *node,
294 ParasiticDevice *from_res,
295 double elmore,
296 Parasitic *pi_elmore,
297 const ParasiticAnalysisPt *ap);
298 };
299
300 void
reduceToPiElmore(Parasitic * parasitic_network,const Pin * drvr_pin,float coupling_cap_factor,const OperatingConditions * op_cond,const Corner * corner,const MinMax * cnst_min_max,const ParasiticAnalysisPt * ap,StaState * sta)301 reduceToPiElmore(Parasitic *parasitic_network,
302 const Pin *drvr_pin,
303 float coupling_cap_factor,
304 const OperatingConditions *op_cond,
305 const Corner *corner,
306 const MinMax *cnst_min_max,
307 const ParasiticAnalysisPt *ap,
308 StaState *sta)
309 {
310 Parasitics *parasitics = sta->parasitics();
311 ParasiticNode *drvr_node = parasitics->findNode(parasitic_network,
312 drvr_pin);
313 if (drvr_node) {
314 debugPrint(sta->debug(), "parasitic_reduce", 1, "Reduce driver %s",
315 sta->network()->pathName(drvr_pin));
316 ReduceToPiElmore reducer(sta);
317 reducer.makePiElmore(parasitic_network, drvr_pin, drvr_node,
318 coupling_cap_factor, RiseFall::rise(),
319 op_cond, corner, cnst_min_max, ap);
320 if (!reducer.pinCapsOneValue())
321 reducer.makePiElmore(parasitic_network, drvr_pin, drvr_node,
322 coupling_cap_factor, RiseFall::fall(),
323 op_cond, corner, cnst_min_max, ap);
324 }
325 }
326
ReduceToPiElmore(StaState * sta)327 ReduceToPiElmore::ReduceToPiElmore(StaState *sta) :
328 ReduceToPi(sta)
329 {
330 }
331
332 void
makePiElmore(Parasitic * parasitic_network,const Pin * drvr_pin,ParasiticNode * drvr_node,float coupling_cap_factor,const RiseFall * rf,const OperatingConditions * op_cond,const Corner * corner,const MinMax * cnst_min_max,const ParasiticAnalysisPt * ap)333 ReduceToPiElmore::makePiElmore(Parasitic *parasitic_network,
334 const Pin *drvr_pin,
335 ParasiticNode *drvr_node,
336 float coupling_cap_factor,
337 const RiseFall *rf,
338 const OperatingConditions *op_cond,
339 const Corner *corner,
340 const MinMax *cnst_min_max,
341 const ParasiticAnalysisPt *ap)
342 {
343 float c2, rpi, c1;
344 reduceToPi(drvr_pin, drvr_node,
345 parasitics_->includesPinCaps(parasitic_network),
346 coupling_cap_factor,
347 rf, op_cond, corner, cnst_min_max, ap,
348 c2, rpi, c1);
349 Parasitic *pi_elmore = parasitics_->makePiElmore(drvr_pin, rf, ap,
350 c2, rpi, c1);
351 parasitics_->setIsReducedParasiticNetwork(pi_elmore, true);
352 reduceElmoreDfs(drvr_pin, drvr_node, 0, 0.0, pi_elmore, ap);
353 }
354
355 // Find elmore delays on 2nd DFS search using downstream capacitances
356 // set by reducePiDfs.
357 void
reduceElmoreDfs(const Pin * drvr_pin,ParasiticNode * node,ParasiticDevice * from_res,double elmore,Parasitic * pi_elmore,const ParasiticAnalysisPt * ap)358 ReduceToPiElmore::reduceElmoreDfs(const Pin *drvr_pin,
359 ParasiticNode *node,
360 ParasiticDevice *from_res,
361 double elmore,
362 Parasitic *pi_elmore,
363 const ParasiticAnalysisPt *ap)
364 {
365 const Pin *pin = parasitics_->connectionPin(node);
366 if (from_res && pin) {
367 if (network_->isLoad(pin)) {
368 debugPrint(debug_, "parasitic_reduce", 2, " Load %s elmore=%.3g",
369 network_->pathName(pin),
370 elmore);
371 parasitics_->setElmore(pi_elmore, pin, elmore);
372 }
373 }
374 visit(node);
375 ParasiticDeviceIterator *device_iter = parasitics_->deviceIterator(node);
376 while (device_iter->hasNext()) {
377 ParasiticDevice *device = device_iter->next();
378 if (parasitics_->isResistor(device)) {
379 ParasiticNode *onode = parasitics_->otherNode(device, node);
380 if (device != from_res
381 && !isVisited(onode)
382 && !isLoopResistor(device)) {
383 float r = parasitics_->value(device, ap);
384 double onode_elmore = elmore + r * downstreamCap(onode);
385 reduceElmoreDfs(drvr_pin, onode, device, onode_elmore,
386 pi_elmore, ap);
387 }
388 }
389 }
390 delete device_iter;
391 leave(node);
392 }
393
394 ////////////////////////////////////////////////////////////////
395
396 class ReduceToPiPoleResidue2 : public ReduceToPi
397 {
398 public:
399 ReduceToPiPoleResidue2(StaState *sta);
400 ~ReduceToPiPoleResidue2();
401 void findPolesResidues(Parasitic *parasitic_network,
402 Parasitic *pi_pole_residue,
403 const Pin *drvr_pin,
404 ParasiticNode *drvr_node,
405 const ParasiticAnalysisPt *ap);
406 void makePiPoleResidue2(Parasitic *parasitic_network,
407 const Pin *drvr_pin,
408 ParasiticNode *drvr_node,
409 float coupling_cap_factor,
410 const RiseFall *rf,
411 const OperatingConditions *op_cond,
412 const Corner *corner,
413 const MinMax *cnst_min_max,
414 const ParasiticAnalysisPt *ap);
415
416 private:
417 void findMoments(const Pin *drvr_pin,
418 ParasiticNode *drvr_node,
419 int moment_count,
420 const ParasiticAnalysisPt *ap);
421 void findMoments(const Pin *drvr_pin,
422 ParasiticNode *node,
423 double from_volt,
424 ParasiticDevice *from_res,
425 int moment_index,
426 const ParasiticAnalysisPt *ap);
427 double findBranchCurrents(const Pin *drvr_pin,
428 ParasiticNode *node,
429 ParasiticDevice *from_res,
430 int moment_index,
431 const ParasiticAnalysisPt *ap);
432 double moment(ParasiticNode *node,
433 int moment_index);
434 void setMoment(ParasiticNode *node,
435 double moment,
436 int moment_index);
437 double current(ParasiticDevice *res);
438 void setCurrent(ParasiticDevice *res,
439 double i);
440 void findPolesResidues(Parasitic *pi_pole_residue,
441 const Pin *drvr_pin,
442 const Pin *load_pin,
443 ParasiticNode *load_node);
444
445 // Resistor/capacitor currents.
446 ParasiticDeviceValueMap currents_;
447 ParasiticNodeValueMap *moments_;
448 };
449
ReduceToPiPoleResidue2(StaState * sta)450 ReduceToPiPoleResidue2::ReduceToPiPoleResidue2(StaState *sta) :
451 ReduceToPi(sta),
452 moments_(nullptr)
453 {
454 }
455
456 // The interconnect moments are found using RICE.
457 // "RICE: Rapid Interconnect Circuit Evaluation Using AWE",
458 // Curtis Ratzlaff and Lawrence Pillage, IEEE Transactions on
459 // Computer-Aided Design of Integrated Circuits and Systems,
460 // Vol 13, No 6, June 1994, pg 763-776.
461 //
462 // The poles and residues are found using these algorithms.
463 // "An Explicit RC-Circuit Delay Approximation Based on the First
464 // Three Moments of the Impulse Response", Proceedings of the 33rd
465 // Design Automation Conference, 1996, pg 611-616.
466 void
reduceToPiPoleResidue2(Parasitic * parasitic_network,const Pin * drvr_pin,float coupling_cap_factor,const OperatingConditions * op_cond,const Corner * corner,const MinMax * cnst_min_max,const ParasiticAnalysisPt * ap,StaState * sta)467 reduceToPiPoleResidue2(Parasitic *parasitic_network,
468 const Pin *drvr_pin,
469 float coupling_cap_factor,
470 const OperatingConditions *op_cond,
471 const Corner *corner,
472 const MinMax *cnst_min_max,
473 const ParasiticAnalysisPt *ap,
474 StaState *sta)
475 {
476 Parasitics *parasitics = sta->parasitics();
477 ParasiticNode *drvr_node = parasitics->findNode(parasitic_network, drvr_pin);
478 if (drvr_node) {
479 debugPrint(sta->debug(), "parasitic_reduce", 1, "Reduce driver %s",
480 sta->network()->pathName(drvr_pin));
481 ReduceToPiPoleResidue2 reducer(sta);
482 reducer.makePiPoleResidue2(parasitic_network, drvr_pin, drvr_node,
483 coupling_cap_factor, RiseFall::rise(),
484 op_cond, corner, cnst_min_max, ap);
485 if (!reducer.pinCapsOneValue())
486 reducer.makePiPoleResidue2(parasitic_network, drvr_pin, drvr_node,
487 coupling_cap_factor, RiseFall::fall(),
488 op_cond, corner, cnst_min_max, ap);
489 }
490 }
491
492 void
makePiPoleResidue2(Parasitic * parasitic_network,const Pin * drvr_pin,ParasiticNode * drvr_node,float coupling_cap_factor,const RiseFall * rf,const OperatingConditions * op_cond,const Corner * corner,const MinMax * cnst_min_max,const ParasiticAnalysisPt * ap)493 ReduceToPiPoleResidue2::makePiPoleResidue2(Parasitic *parasitic_network,
494 const Pin *drvr_pin,
495 ParasiticNode *drvr_node,
496 float coupling_cap_factor,
497 const RiseFall *rf,
498 const OperatingConditions *op_cond,
499 const Corner *corner,
500 const MinMax *cnst_min_max,
501 const ParasiticAnalysisPt *ap)
502 {
503 float c2, rpi, c1;
504 reduceToPi(drvr_pin, drvr_node,
505 parasitics_->includesPinCaps(parasitic_network),
506 coupling_cap_factor,
507 rf, op_cond, corner, cnst_min_max, ap,
508 c2, rpi, c1);
509 Parasitic *pi_pole_residue = parasitics_->makePiPoleResidue(drvr_pin,
510 rf, ap,
511 c2, rpi, c1);
512 parasitics_->setIsReducedParasiticNetwork(pi_pole_residue, true);
513 findPolesResidues(parasitic_network, pi_pole_residue,
514 drvr_pin, drvr_node, ap);
515 }
516
~ReduceToPiPoleResidue2()517 ReduceToPiPoleResidue2::~ReduceToPiPoleResidue2()
518 {
519 delete [] moments_;
520 }
521
522 void
findPolesResidues(Parasitic * parasitic_network,Parasitic * pi_pole_residue,const Pin * drvr_pin,ParasiticNode * drvr_node,const ParasiticAnalysisPt * ap)523 ReduceToPiPoleResidue2::findPolesResidues(Parasitic *parasitic_network,
524 Parasitic *pi_pole_residue,
525 const Pin *drvr_pin,
526 ParasiticNode *drvr_node,
527 const ParasiticAnalysisPt *ap)
528 {
529 moments_ = new ParasiticNodeValueMap[4];
530 findMoments(drvr_pin, drvr_node, 4, ap);
531
532 PinConnectedPinIterator *pin_iter = network_->connectedPinIterator(drvr_pin);
533 while (pin_iter->hasNext()) {
534 Pin *pin = pin_iter->next();
535 if (network_->isLoad(pin)) {
536 ParasiticNode *load_node = parasitics_->findNode(parasitic_network, pin);
537 if (load_node) {
538 findPolesResidues(pi_pole_residue, drvr_pin, pin, load_node);
539 }
540 }
541 }
542 delete pin_iter;
543 }
544
545 void
findMoments(const Pin * drvr_pin,ParasiticNode * drvr_node,int moment_count,const ParasiticAnalysisPt * ap)546 ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin,
547 ParasiticNode *drvr_node,
548 int moment_count,
549 const ParasiticAnalysisPt *ap)
550 {
551 // Driver model thevenin resistance.
552 double rd = 0.0;
553 // Zero'th moments are all 1 because Vin(0)=1 and there is no
554 // current thru the resistors. Thus, there is no point in doing a
555 // pass to find the zero'th moments.
556 for (int moment_index = 1; moment_index < moment_count; moment_index++) {
557 double rd_i = findBranchCurrents(drvr_pin, drvr_node, 0,
558 moment_index, ap);
559 double rd_volt = rd_i * rd;
560 setMoment(drvr_node, 0.0, moment_index);
561 findMoments(drvr_pin, drvr_node, -rd_volt, 0, moment_index, ap);
562 }
563 }
564
565 double
findBranchCurrents(const Pin * drvr_pin,ParasiticNode * node,ParasiticDevice * from_res,int moment_index,const ParasiticAnalysisPt * ap)566 ReduceToPiPoleResidue2::findBranchCurrents(const Pin *drvr_pin,
567 ParasiticNode *node,
568 ParasiticDevice *from_res,
569 int moment_index,
570 const ParasiticAnalysisPt *ap)
571 {
572 visit(node);
573 double branch_i = 0.0;
574 double coupling_cap = 0.0;
575 ParasiticDeviceIterator *device_iter = parasitics_->deviceIterator(node);
576 while (device_iter->hasNext()) {
577 ParasiticDevice *device = device_iter->next();
578 if (parasitics_->isResistor(device)) {
579 ParasiticNode *onode = parasitics_->otherNode(device, node);
580 // One commercial extractor creates resistors with identical from/to nodes.
581 if (onode != node
582 && device != from_res
583 && !isVisited(onode)
584 && !isLoopResistor(device)) {
585 branch_i += findBranchCurrents(drvr_pin, onode, device,
586 moment_index, ap);
587 }
588 }
589 else if (parasitics_->isCouplingCap(device))
590 coupling_cap += parasitics_->value(device, ap);
591 }
592 delete device_iter;
593 double cap = parasitics_->nodeGndCap(node, ap)
594 + coupling_cap * coupling_cap_multiplier_
595 + pinCapacitance(node);
596 branch_i += cap * moment(node, moment_index - 1);
597 leave(node);
598 if (from_res) {
599 setCurrent(from_res, branch_i);
600 debugPrint(debug_, "parasitic_reduce", 3, " res i=%.3g", branch_i);
601 }
602 return branch_i;
603 }
604
605 void
findMoments(const Pin * drvr_pin,ParasiticNode * node,double from_volt,ParasiticDevice * from_res,int moment_index,const ParasiticAnalysisPt * ap)606 ReduceToPiPoleResidue2::findMoments(const Pin *drvr_pin,
607 ParasiticNode *node,
608 double from_volt,
609 ParasiticDevice *from_res,
610 int moment_index,
611 const ParasiticAnalysisPt *ap)
612 {
613 visit(node);
614 ParasiticDeviceIterator *device_iter = parasitics_->deviceIterator(node);
615 while (device_iter->hasNext()) {
616 ParasiticDevice *device = device_iter->next();
617 if (parasitics_->isResistor(device)) {
618 ParasiticNode *onode = parasitics_->otherNode(device, node);
619 // One commercial extractor creates resistors with identical from/to nodes.
620 if (onode != node
621 && device != from_res
622 && !isVisited(onode)
623 && !isLoopResistor(device)) {
624 double r = parasitics_->value(device, ap);
625 double r_volt = r * current(device);
626 double onode_volt = from_volt - r_volt;
627 setMoment(onode, onode_volt, moment_index);
628 debugPrint(debug_, "parasitic_reduce", 3, " moment %s %d %.3g",
629 parasitics_->name(onode),
630 moment_index,
631 onode_volt);
632 findMoments(drvr_pin, onode, onode_volt, device, moment_index, ap);
633 }
634 }
635 }
636 delete device_iter;
637 leave(node);
638 }
639
640 double
moment(ParasiticNode * node,int moment_index)641 ReduceToPiPoleResidue2::moment(ParasiticNode *node,
642 int moment_index)
643 {
644 // Zero'th moments are all 1.
645 if (moment_index == 0)
646 return 1.0;
647 else {
648 ParasiticNodeValueMap &map = moments_[moment_index];
649 return map[node];
650 }
651 }
652
653 void
setMoment(ParasiticNode * node,double moment,int moment_index)654 ReduceToPiPoleResidue2::setMoment(ParasiticNode *node,
655 double moment,
656 int moment_index)
657 {
658 // Zero'th moments are all 1.
659 if (moment_index > 0) {
660 ParasiticNodeValueMap &map = moments_[moment_index];
661 map[node] = moment;
662 }
663 }
664
665 double
current(ParasiticDevice * res)666 ReduceToPiPoleResidue2::current(ParasiticDevice *res)
667 {
668 return currents_[res];
669 }
670
671 void
setCurrent(ParasiticDevice * res,double i)672 ReduceToPiPoleResidue2::setCurrent(ParasiticDevice *res,
673 double i)
674 {
675 currents_[res] = i;
676 }
677
678 void
findPolesResidues(Parasitic * pi_pole_residue,const Pin *,const Pin * load_pin,ParasiticNode * load_node)679 ReduceToPiPoleResidue2::findPolesResidues(Parasitic *pi_pole_residue,
680 const Pin *,
681 const Pin *load_pin,
682 ParasiticNode *load_node)
683 {
684 double m1 = moment(load_node, 1);
685 double m2 = moment(load_node, 2);
686 double m3 = moment(load_node, 3);
687 double p1 = -m2 / m3;
688 double p2 = p1 * (1.0 / m1 - m1 / m2) / (m1 / m2 - m2 / m3);
689 if (p1 <= 0.0
690 || p2 <= 0.0
691 // Coincident poles. Not handled by delay calculator.
692 || p1 == p2
693 || m1 / m2 == m2 / m3) {
694 double p1 = -1.0 / m1;
695 double k1 = 1.0;
696 debugPrint(debug_, "parasitic_reduce", 3, " load %s p1=%.3g k1=%.3g",
697 network_->pathName(load_pin), p1, k1);
698 ComplexFloatSeq *poles = new ComplexFloatSeq(1);
699 ComplexFloatSeq *residues = new ComplexFloatSeq(1);
700 (*poles)[0] = ComplexFloat(p1, 0.0);
701 (*residues)[0] = ComplexFloat(k1, 0.0);
702 parasitics_->setPoleResidue(pi_pole_residue, load_pin, poles, residues);
703 }
704 else {
705 double k1 = p1 * p1 * (1.0 + m1 * p2) / (p1 - p2);
706 double k2 = -p2 * p2 * (1.0 + m1 * p1) / (p1 - p2);
707 if (k1 < 0.0 && k2 > 0.0) {
708 // Swap p1 and p2.
709 double p = p2, k = k2;
710 p2 = p1;
711 k2 = k1;
712 p1 = p;
713 k1 = k;
714 }
715 debugPrint(debug_, "parasitic_reduce", 3,
716 " load %s p1=%.3g p2=%.3g k1=%.3g k2=%.3g",
717 network_->pathName(load_pin), p1, p2, k1, k2);
718
719 ComplexFloatSeq *poles = new ComplexFloatSeq(2);
720 ComplexFloatSeq *residues = new ComplexFloatSeq(2);
721 (*poles)[0] = ComplexFloat(p1, 0.0);
722 (*residues)[0] = ComplexFloat(k1, 0.0);
723 (*poles)[1] = ComplexFloat(p2, 0.0);
724 (*residues)[1] = ComplexFloat(k2, 0.0);
725 parasitics_->setPoleResidue(pi_pole_residue, load_pin, poles, residues);
726 }
727 }
728
729 } // namespace
730