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