1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (c) 2019, Nefelus Inc
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright notice, this
11 //   list of conditions and the following disclaimer.
12 //
13 // * Redistributions in binary form must reproduce the above copyright notice,
14 //   this list of conditions and the following disclaimer in the documentation
15 //   and/or other materials provided with the distribution.
16 //
17 // * Neither the name of the copyright holder nor the names of its
18 //   contributors may be used to endorse or promote products derived from
19 //   this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 
33 #include "rcx/extRCap.h"
34 
35 #include <wire.h>
36 
37 #ifdef _WIN32
38 #include "direct.h"
39 #endif
40 
41 #include <map>
42 #include <vector>
43 
44 #include "darr.h"
45 #include "utl/Logger.h"
46 
47 namespace rcx {
48 
49 using utl::RCX;
50 
read_total_cap_file(const char * file,double * ctotV,double * rtotV,int nmax,dbBlock * block,Logger * logger)51 static int read_total_cap_file(const char* file, double* ctotV, double* rtotV,
52                                int nmax, dbBlock* block, Logger* logger) {
53 #ifndef BILL_WAY
54   Ath__parser parser;
55   parser.openFile((char*)file);
56 
57   logger->info(RCX, 67, "Reading ref_file {} ... ... ", file);
58 
59   while (parser.parseNextLine() > 0) {
60     parser.printWords(stdout);
61 
62     uint netid = 0;
63     if (parser.isDigit(0, 0))
64       netid = parser.getInt(0);
65     else {
66       char* netName = parser.get(0);
67       if (block != NULL) {
68         dbNet* net = block->findNet(netName);
69         if (net == NULL)
70           logger->warn(RCX, 66, "Can't find net {} in db", netName);
71       }
72     }
73     double rtot = 0.0;
74     if (parser.getWordCnt() > 2)
75       rtot = parser.getDouble(2);
76 
77     double ctot = parser.getDouble(1);
78 
79     ctotV[netid] = ctot;
80     rtotV[netid] = rtot;
81   }
82 #else
83   FILE* fp = fopen(file, "r");
84   if (!fp) {
85     logger_->warn(RCX, 379, "Can't open {}", file);
86     return 0;
87   }
88 
89   char line[256];
90   int netid;
91   double ctot, rtot;
92   while (fgets(line, 256, fp)) {
93     if (3 == sscanf(line, "%d %lf %lf", &netid, &ctot, &rtot)) {
94       if (netid < 0 || netid >= nmax) {
95         logger_->warn(RCX, 186, "Net id {} out of range in {}", netid, file);
96         fclose(fp);
97         return 0;
98       }
99       ctotV[netid] = ctot;
100       rtotV[netid] = rtot;
101     }
102   }
103   fclose(fp);
104 #endif
105   return 1;
106 }
107 
108 typedef struct {
109   int netid;
110   double ctot;
111   double cref;
112   double cdif;
113   double rtot;
114   double rref;
115   double rdif;
116 } ext_rctot;
117 
ext_rctot_cmp_c(const void * a,const void * b)118 static int ext_rctot_cmp_c(const void* a, const void* b) {
119   ext_rctot* x = (ext_rctot*)a;
120   ext_rctot* y = (ext_rctot*)b;
121   if (x->cdif < y->cdif)
122     return 1;
123   if (x->cdif > y->cdif)
124     return -1;
125   return 0;
126 }
127 
initIncrementalSpef(const char * origp,const char * newp,const char * excludeC,bool noBackSlash)128 void extMain::initIncrementalSpef(const char* origp, const char* newp,
129                                   const char* excludeC, bool noBackSlash) {
130   if (_origSpefFilePrefix)
131     free(_origSpefFilePrefix);
132   _origSpefFilePrefix = NULL;
133   if (origp)
134     _origSpefFilePrefix = strdup((char*)origp);
135   if (_newSpefFilePrefix)
136     free(_newSpefFilePrefix);
137   _newSpefFilePrefix = NULL;
138   if (newp)
139     _newSpefFilePrefix = strdup((char*)newp);
140   if (_excludeCells)
141     free(_excludeCells);
142   _excludeCells = NULL;
143   if (excludeC)
144     _excludeCells = strdup((char*)excludeC);
145   if (!_origSpefFilePrefix && !_newSpefFilePrefix)
146     _bufSpefCnt = 0;
147   else
148     _bufSpefCnt = 1;
149   _incrNoBackSlash = noBackSlash;
150 }
151 #ifndef DEFAULT_BILL_WAY
reportTotalCap(const char * file,bool icap,bool ires,double ccmult,const char * ref,const char * rd_file)152 void extMain::reportTotalCap(const char* file, bool icap, bool ires,
153                              double ccmult, const char* ref,
154                              const char* rd_file) {
155   FILE* fp = stdout;
156   if (file != NULL)
157     fp = fopen(file, "w");
158   else
159     return;
160 
161   if (ref == NULL) {
162     dbSet<dbNet> nets = _block->getNets();
163     dbSet<dbNet>::iterator nitr;
164     for (nitr = nets.begin(); nitr != nets.end(); ++nitr) {
165       dbNet* net = *nitr;
166       float totCap = net->getTotalCapacitance(0, true);
167       float ccCap = net->getTotalCouplingCap(0);
168       fprintf(fp, "%13.6f %13.6f %s\n", totCap, ccCap, net->getConstName());
169     }
170   } else {
171     Ath__parser parser;
172     parser.openFile((char*)ref);
173     logger_->info(RCX, 184, "Reading ref_file {} ...", ref);
174     while (parser.parseNextLine() > 0) {
175       // parser.printWords(stdout);
176 
177       dbNet* net = NULL;
178       uint netid = 0;
179       if (parser.isDigit(0, 0))
180         netid = parser.getInt(0);
181       else {
182         char* netName = parser.get(0);
183         if (_block != NULL) {
184           net = _block->findNet(netName);
185           if (net == NULL) {
186             logger_->warn(RCX, 185, "Can't find net {} in db", netName);
187             continue;
188           }
189         }
190       }
191       if (net == NULL)
192         continue;
193 
194       if (parser.getWordCnt() < 2)
195         continue;
196 
197       float totCap = net->getTotalCapacitance(0, true);
198       float ccCap = net->getTotalCouplingCap(0);
199 
200       double ref_tot = parser.getDouble(1);
201 
202       double tot_diff = 100.0 * (ref_tot - totCap) / ref_tot;
203       if (parser.getWordCnt() < 3) {
204         fprintf(fp, "%5.1f %13.6f %13.6f %s\n", tot_diff, totCap, ref_tot,
205                 net->getConstName());
206         continue;
207       }
208 
209       double ref_cc = parser.getDouble(2);
210       double cc_diff = 100.0 * (ref_cc - ccCap) / ref_cc;
211 
212       fprintf(fp, "%5.1f %5.1f   %13.6f %13.6f   %13.6f %13.6f  %s\n", tot_diff,
213               cc_diff, totCap, ref_tot, ccCap, ref_cc, net->getConstName());
214     }
215   }
216   if (file != NULL)
217     fclose(fp);
218 }
219 #else
reportTotalCap(const char * file,bool icap,bool ires,double ccmult,const char * ref,const char * rd_file)220 void extMain::reportTotalCap(const char* file, bool icap, bool ires,
221                              double ccmult, const char* ref,
222                              const char* rd_file) {
223   bool cap = icap;
224   bool res = ires;
225   if (!res && !cap)
226     res = cap = true;
227   if (ccmult != 1.0)
228     logger_->info(RCX, 187, "Cc multiplier {}", ccmult);
229 
230   int j, nn = 2 + _block->getNets().size();
231   double* ctotV = (double*)malloc(nn * sizeof(double));
232   double* rtotV = (double*)malloc(nn * sizeof(double));
233   for (j = 0; j < nn; j++)
234     ctotV[j] = rtotV[j] = 0.0;
235 
236   dbSet<dbNet> nets = _block->getNets();
237   dbSet<dbNet>::iterator nitr;
238   dbNet* net;
239   dbCapNode* node;
240   if (rd_file && rd_file[0]) {
241     if (!read_total_cap_file(rd_file, ctotV, rtotV, nn, _block)) {
242       logger_->warn(RCX, 428, "Can't read {}", rd_file);
243       return;
244     }
245   } else
246     for (nitr = nets.begin(); nitr != nets.end(); ++nitr) {
247       net = *nitr;
248       dbSet<dbCapNode> nodeSet = net->getCapNodes();
249       dbSet<dbCapNode>::iterator c_itr;
250       bool has_foreign = false;
251       double ctot = 0.0;
252       for (c_itr = nodeSet.begin(); c_itr != nodeSet.end(); ++c_itr) {
253         node = *c_itr;
254         if (node->isForeign())
255           has_foreign = true;
256         ctot += node->getCapacitance(0);
257       }
258       double rtot = 0.0;
259       dbSet<dbRSeg> rSet = net->getRSegs();
260       dbSet<dbRSeg>::iterator r_itr;
261       for (r_itr = rSet.begin(); r_itr != rSet.end(); ++r_itr) {
262         dbRSeg* r = *r_itr;
263         rtot += r->getResistance(0);
264         if (!has_foreign)
265           ctot += r->getCapacitance(0);
266       }
267       double cctot = net->getTotalCouplingCap(0);
268 
269       ctot += ccmult * cctot;
270       ctot *= 1e-3;
271       rtotV[net->getId()] = rtot;
272       ctotV[net->getId()] = ctot;
273     }
274 
275   double* crefV = NULL;
276   double* rrefV = NULL;
277   if (ref && ref[0]) {
278     crefV = (double*)malloc(nn * sizeof(double));
279     rrefV = (double*)malloc(nn * sizeof(double));
280     for (j = 0; j < nn; j++)
281       crefV[j] = rrefV[j] = 0.0;
282     if (!read_total_cap_file(ref, crefV, rrefV, nn, _block)) {
283       logger_->warn(RCX, 429, "Can't read {}", ref);
284       free(crefV);
285       crefV = NULL;
286       free(rrefV);
287       rrefV = NULL;
288     }
289   }
290 
291   FILE* fp = NULL;
292   if (file && file[0])
293     fp = fopen(file, "w");
294   if (fp && !crefV) {
295     for (j = 0; j < nn; j++)
296       if (ctotV[j] > 0.0 || rtotV[j] > 0.0) {
297         if (cap && res)
298           fprintf(fp, "%d %g %.2f\n", j, ctotV[j], rtotV[j]);
299         else if (cap)
300           fprintf(fp, "%d %g\n", j, ctotV[j]);
301         else
302           fprintf(fp, "%d %.2f\n", j, rtotV[j]);
303       }
304   } else if (crefV) {
305     double max_abs_c = 0.0;
306     double max_abs_r = 0.0;
307     double abs_cthresh = 0.001;    // pf
308     double abs_cthresh2 = 0.0005;  // pf
309     double abs_rthresh = 1.0;      // ohms
310 
311     double rel_cfloor = 0.010;   // 10 ff
312     double rel_cfloor2 = 0.001;  // 1 ff
313     double max_rel_c = 0.0;
314     double max_rel_c2 = 0.0;
315     uint max_rel_c_id = 0;
316     uint max_rel_c_id2 = 0;
317     double rel_cthresh = 0.02;  // 2 percent
318     int rel_cn = 0;             // number over rel_cthresh
319     int rel_cn2 = 0;
320 
321     ext_rctot* rctotV = (ext_rctot*)malloc(nn * sizeof(ext_rctot));
322     int rctotN = 0;
323     ext_rctot* rctot;
324     double cdif, rdif, cdif_avg = 0.0, rdif_avg = 0.0;
325     double crel, cden;
326     int ncdif = 0, nrdif = 0, ncdif2 = 0;
327     int crel_cnt = 0, crel_cnt2 = 0;
328     for (j = 0; j < nn; j++) {
329       if (ctotV[j] == 0.0 && rtotV[j] == 0.0 && crefV[j] == 0.0 &&
330           rrefV[j] == 0.0)
331         continue;
332       cdif = ctotV[j] - crefV[j];
333       rdif = rtotV[j] - rrefV[j];
334       cdif_avg += cdif;
335       rdif_avg += rdif;
336       if (cdif >= abs_cthresh || cdif <= -abs_cthresh)
337         ncdif++;
338       if (cdif >= abs_cthresh2 || cdif <= -abs_cthresh2)
339         ncdif2++;
340       if (rdif >= abs_rthresh || rdif <= -abs_rthresh)
341         nrdif++;
342       rctot = rctotV + rctotN++;
343       rctot->netid = j;
344       rctot->ctot = ctotV[j];
345       rctot->cref = crefV[j];
346       rctot->cdif = cdif;
347       rctot->rtot = rtotV[j];
348       rctot->rref = rrefV[j];
349       rctot->rdif = rdif;
350 
351       if (cdif < 0.0)
352         cdif = -cdif;
353       if (cdif > max_abs_c) {
354         max_abs_c = cdif;
355       }
356       if (rdif < 0.0)
357         rdif = -rdif;
358       if (rdif > max_abs_r) {
359         max_abs_r = rdif;
360       }
361       cden = (crefV[j] >= ctotV[j] ? crefV[j] : ctotV[j]);
362       if (cden >= rel_cfloor) {
363         crel_cnt++;
364         crel = cdif / cden;
365         if (crel > max_rel_c) {
366           max_rel_c = crel;
367           max_rel_c_id = j;
368         }
369         if (crel >= rel_cthresh) {
370           rel_cn++;
371         }
372       }
373       if (cden >= rel_cfloor2) {
374         crel_cnt2++;
375         crel = cdif / cden;
376         if (crel > max_rel_c2) {
377           max_rel_c2 = crel;
378           max_rel_c_id2 = j;
379         }
380         if (crel >= rel_cthresh) {
381           rel_cn2++;
382         }
383       }
384     }
385     logger_->info(
386         RCX, 188,
387         "Comparing all {} signal nets worst abs ctot diff = {:.4f) pF "
388         "worst abs rtot diff = {:.2f) ohms",
389         rctotN, max_abs_c, max_abs_r);
390 
391     logger_->info(RCX, 426,
392                   "Comparing nets with c>={:.4f}, {} nets"
393                   " worst percent ctot diff = {:.1f} %% for c>={:.4f}",
394                   rel_cfloor, crel_cnt, 100.0 * max_rel_c, rel_cfloor);
395     if (max_rel_c_id) {
396       j = max_rel_c_id;
397       net = dbNet::getNet(_block, j);
398       logger_->info(
399           RCX, 423,
400           "\tNet {} {}  c_tot {:.4f} c_ref {:.4f} r_tot {:.2f} r_ref {:.2f}",
401           net->getId(), net->getName().c_str(), ctotV[j], crefV[j], rtotV[j],
402           rrefV[j]);
403     }
404     logger_->info(RCX, 422,
405                   "\t{} nets have ctot diff >= {:.1f} %% for c>={:.4f}", rel_cn,
406                   100.0 * rel_cthresh, rel_cfloor);
407 
408     logger_->info(RCX, 427,
409                   "Comparing nets with c>={:.4f}, {} nets"
410                   " worst percent ctot diff = {:.1f} %% for c>={:.4f}",
411                   rel_cfloor2, crel_cnt2, 100.0 * max_rel_c2, rel_cfloor2);
412 
413     if (max_rel_c_id2) {
414       j = max_rel_c_id2;
415       net = dbNet::getNet(_block, j);
416       logger_->info(
417           RCX, 424,
418           "\tNet {} {}  c_tot {:.4f} c_ref {:.4f} r_tot {:.2f} r_ref {:.2f}",
419           net->getId(), net->getName().c_str(), ctotV[j], crefV[j], rtotV[j],
420           rrefV[j]);
421     }
422 
423     logger_->info(RCX, 189,
424                   "Comparing nets with c>={:.4f}, {} nets"
425                   " worst percent ctot diff = {:.1f} %% for c>={:.4f}",
426                   rel_cfloor2, crel_cnt2, 100.0 * max_rel_c2, rel_cfloor2);
427 
428     if (rctotN > 0) {
429       cdif_avg /= rctotN;
430       rdif_avg /= rctotN;
431       qsort(rctotV, rctotN, sizeof(ext_rctot), ext_rctot_cmp_c);
432       rctot = rctotV;
433       if (rctot->cdif > 0.0) {
434         logger_->info(RCX, 191, "Max c_tot diff vs ref = {:.4f} pF",
435                       rctot->cdif);
436         net = dbNet::getNet(_block, rctot->netid);
437         logger_->info(
438             RCX, 425,
439             "\tNet {} {}  c_tot {:.4f} c_ref {:.4f} r_tot {:.2f} r_ref {:.2f}",
440             net->getId(), net->getName().c_str(), rctot->ctot, rctot->cref,
441             rctot->rtot, rctot->rref);
442       }
443       rctot = rctotV + rctotN - 1;
444       if (rctot->cdif < 0.0) {
445         logger_->info(RCX, 192, "Min c_tot diff vs ref = {:.4f} pF",
446                       rctot->cdif);
447         net = dbNet::getNet(_block, rctot->netid);
448         logger_->info(
449             RCX, 190,
450             "\tNet {} {}  c_tot {:.4f} c_ref {:.4f} r_tot {:.2f} r_ref {:.2f}",
451             net->getId(), net->getName().c_str(), rctot->ctot, rctot->cref,
452             rctot->rtot, rctot->rref);
453       }
454       logger_->info(RCX, 193,
455                     "Avg ctot diff vs ref = {:.4f} pf"
456                     "\nAvg rtot diff vs ref = {:.2f} ohms"
457                     "\n{} nets have absolute ctot diff >= {:.4f}",
458                     cdif_avg, rdif_avg, ncdif, abs_cthresh);
459       logger_->info(RCX, 194, "{} nets have absolute ctot diff >= {:.4f}",
460                     ncdif2, abs_cthresh2);
461       logger_->info(RCX, 195, "{} nets have absolute rtot diff >= :.2f}", nrdif,
462                     abs_rthresh);
463       if (fp && ncdif + nrdif) {
464         fprintf(fp, "# netid cdif ctot cref rdif rtot rref\n");
465         for (j = 0; j < rctotN; j++) {
466           rctot = rctotV + j;
467           if (rctot->cdif < abs_cthresh2 && rctot->cdif > -abs_cthresh2 &&
468               rctot->rdif < abs_rthresh && rctot->rdif > -abs_rthresh)
469             continue;
470           fprintf(fp, "%6d %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n", rctot->netid,
471                   rctot->cdif, rctot->ctot, rctot->cref, rctot->rdif,
472                   rctot->rtot, rctot->rref);
473         }
474       }
475     }
476     free(rctotV);
477   }
478   free(ctotV);
479   free(rtotV);
480   if (crefV)
481     free(crefV);
482   if (rrefV)
483     free(rrefV);
484   if (fp)
485     fclose(fp);
486 }
487 #endif
488 
489 /////////////////////////////////////////////////////
490 
491 typedef struct {
492   int netid0;
493   int netid1;
494   double cctot;
495   double ccref;
496   double ccdif;
497 } ext_cctot;
498 
read_total_cc_file(const char * file,Darr<ext_cctot> & V,Logger * logger)499 static bool read_total_cc_file(const char* file, Darr<ext_cctot>& V,
500                                Logger* logger) {
501   FILE* fp = fopen(file, "r");
502   if (!fp) {
503     logger->warn(RCX, 33, "Can't open {}", file);
504     return false;
505   }
506   char line[256];
507   ext_cctot x;
508   x.ccref = x.ccdif = 0.0;
509   while (fgets(line, 256, fp)) {
510     if (3 == sscanf(line, "%d %d %lf", &x.netid0, &x.netid1, &x.cctot)) {
511       V.insert(x);
512     }
513   }
514   fclose(fp);
515   return true;
516 }
517 
ext_cctot_cmp(const void * a,const void * b)518 static int ext_cctot_cmp(const void* a, const void* b) {
519   ext_cctot* x = (ext_cctot*)a;
520   ext_cctot* y = (ext_cctot*)b;
521   if (x->ccdif < y->ccdif)
522     return 1;
523   if (x->ccdif > y->ccdif)
524     return -1;
525   return 0;
526 }
527 
read_ref_cc_file(const char * file,int netn,Darr<ext_cctot> & V,Logger * logger)528 static bool read_ref_cc_file(const char* file, int netn, Darr<ext_cctot>& V,
529                              Logger* logger) {
530   FILE* fp = fopen(file, "r");
531   if (!fp) {
532     logger->warn(RCX, 34, "Can't open {}", file);
533     return false;
534   }
535   int* indV = (int*)malloc((2 + netn) * sizeof(int));
536   int nn = V.n();
537   char line[256];
538   ext_cctot x;
539   int j;
540   int netid0 = 0;
541   for (j = 0; j < nn; j++) {
542     x = V.get(j);
543     if (netid0 < x.netid0) {
544       while (++netid0 < x.netid0) {
545         indV[netid0] = j;
546       }
547       indV[netid0] = j;
548     }
549   }
550   indV[netid0 + 1] = j;
551 
552   int netid1;
553   double ccref;
554   while (fgets(line, 256, fp)) {
555     if (3 == sscanf(line, "%d %d %lf", &netid0, &netid1, &ccref)) {
556       int j0 = indV[netid0];
557       int j1 = indV[netid0 + 1];
558       if (j0 >= j1)
559         continue;
560       for (j = j0; j < j1; j++) {
561         x = V.get(j);
562         if (x.netid1 == netid1) {
563           x.ccref = ccref;
564           V.set(j, x);
565           break;
566         }
567       }
568       if (j < j1)
569         continue;
570       // not found
571       x.netid0 = netid0;
572       x.netid1 = netid1;
573       x.cctot = 0.0;
574       x.ccref = ccref;
575       x.ccdif = -ccref;
576       V.insert(x);
577     }
578   }
579 
580   free(indV);
581   return true;
582 }
583 
reportTotalCc(const char * file,const char * ref,const char * rd_file)584 void extMain::reportTotalCc(const char* file, const char* ref,
585                             const char* rd_file) {
586   Darr<ext_cctot> V;
587   dbSet<dbNet> nets = _block->getNets();
588   dbSet<dbNet>::iterator nitr;
589   dbNet* net0, *net1;
590   std::vector<dbNet*> netV;
591   std::vector<double> ccV;
592   //  dbSet<dbCCSeg> ccSet;
593   std::vector<dbCCSeg*>::iterator cc_itr;
594 
595   dbCCSeg* cc;
596   int j, nn, netN;
597   ext_cctot x;
598   x.ccref = 0.0;
599   x.ccdif = 0.0;
600   if (rd_file) {
601     if (!read_total_cc_file(rd_file, V, logger_) || V.n() < 1) {
602       logger_->warn(RCX, 35, "Can't read {}", rd_file);
603       return;
604     }
605   } else
606     for (nitr = nets.begin(); nitr != nets.end(); ++nitr) {
607       net0 = *nitr;
608       netN = 0;
609       netV.clear();
610       ccV.clear();
611 
612       std::vector<dbCCSeg*> ccSet1;
613       net0->getSrcCCSegs(ccSet1);
614       for (cc_itr = ccSet1.begin(); cc_itr != ccSet1.end(); ++cc_itr) {
615         cc = *cc_itr;
616         net1 = cc->getTargetNet();
617         if (net1->getId() > net0->getId())
618           continue;
619         for (j = 0; j < netN; j++)
620           if (net1 == netV[j])
621             break;
622         if (j == netN) {
623           netV.push_back(net1);
624           ccV.push_back(0.0);
625           netN++;
626         }
627         ccV[j] += cc->getCapacitance(0);
628       }
629       std::vector<dbCCSeg*> ccSet2;
630       net0->getTgtCCSegs(ccSet2);
631       for (cc_itr = ccSet2.begin(); cc_itr != ccSet2.end(); ++cc_itr) {
632         cc = *cc_itr;
633         net1 = cc->getSourceNet();
634         if (net1->getId() > net0->getId())
635           continue;
636         for (j = 0; j < netN; j++)
637           if (net1 == netV[j])
638             break;
639         if (j == netN) {
640           netV.push_back(net1);
641           ccV.push_back(0.0);
642           netN++;
643         }
644         ccV[j] += cc->getCapacitance(0);
645       }
646       for (j = 0; j < netN; j++) {
647         x.netid0 = net0->getId();
648         x.netid1 = netV[j]->getId();
649         x.cctot = 1e-3 * ccV[j];
650         V.insert(x);
651       }
652     }
653   if (ref) {
654     if (!read_ref_cc_file(ref, nets.size(), V, logger_)) {
655       logger_->warn(RCX, 37, "Can't read {}", ref);
656       return;
657     }
658   }
659   nn = V.n();
660   FILE* fp = NULL;
661   if (file)
662     fp = fopen(file, "w");
663   if (fp && !ref) {
664     for (j = 0; j < nn; j++) {
665       x = V.get(j);
666       fprintf(fp, "%d %d %g\n", x.netid0, x.netid1, x.cctot);
667     }
668   } else if (ref) {
669     double max_abs_cc = 0.0;
670     double abs_ccthresh = 5e-4;   // pf,  so 0.5 ff
671     double abs_ccthresh2 = 1e-4;  // 0.1 ff
672     int nccdif = 0;
673     int nccdif2 = 0;
674     for (j = 0; j < nn; j++) {
675       x = V.get(j);
676       x.ccdif = x.cctot - x.ccref;
677       V.set(j, x);
678       double difabs = (x.ccdif < 0 ? -x.ccdif : x.ccdif);
679       if (difabs >= abs_ccthresh)
680         nccdif++;
681       if (difabs >= abs_ccthresh2)
682         nccdif2++;
683       if (difabs > max_abs_cc) {
684         max_abs_cc = difabs;
685       }
686     }
687     logger_->info(RCX, 196, "Worst abs cctot(net0, net1) diff = {} pF",
688                   max_abs_cc);
689     logger_->info(RCX, 197, "{} net pairs have absolute cctot diff > {} pF",
690                   nccdif, abs_ccthresh);
691     logger_->info(RCX, 207, "{} net pairs have absolute cctot diff > {} pF",
692                   nccdif2, abs_ccthresh2);
693     V.dsort(ext_cctot_cmp);
694     dbNet* net0, *net1;
695     x = V.get(0);
696     if (x.ccdif > 0.0) {
697       logger_->info(RCX, 198, "Max cc_tot diff vs ref = {} pF", x.ccdif);
698       net0 = dbNet::getNet(_block, x.netid0);
699       net1 = dbNet::getNet(_block, x.netid1);
700       logger_->info(RCX, 199, "Net0 {} {}", net0->getId(),
701                     net0->getConstName());
702       logger_->info(RCX, 200, "Net1 {} {}", net1->getId(),
703                     net1->getConstName());
704       logger_->info(RCX, 201, "Cc_tot {} cc_ref {} cc_dif {}", x.cctot, x.ccref,
705                     x.ccdif);
706     }
707     x = V.get(nn - 1);
708     if (x.ccdif < 0.0) {
709       logger_->info(RCX, 202, "Min cc_tot diff vs ref = {} pF", x.ccdif);
710       net0 = dbNet::getNet(_block, x.netid0);
711       net1 = dbNet::getNet(_block, x.netid1);
712       logger_->info(RCX, 420, "Net0 {} {}", net0->getId(),
713                     net0->getConstName());
714       logger_->info(RCX, 419, "Net1 {} {}", net1->getId(),
715                     net1->getConstName());
716       logger_->info(RCX, 421, "Cc_tot {} cc_ref {} cc_dif {}", x.cctot, x.ccref,
717                     x.ccdif);
718     }
719     if (fp) {
720       fprintf(fp, "# netid0 netid1 cctot ccref ccdif\n");
721       for (j = 0; j < nn; j++) {
722         x = V.get(j);
723         if (x.ccdif < abs_ccthresh && x.ccdif > -abs_ccthresh)
724           continue;
725         fprintf(fp, "%6d %6d %8g %8g %8g\n", x.netid0, x.netid1, x.cctot,
726                 x.ccref, x.ccdif);
727       }
728     }
729   }
730   if (fp)
731     fclose(fp);
732 }
733 
734 /////////////////////////////////////////////////////
735 
extDump(char * file,bool openTreeFile,bool closeTreeFile,bool ccCapGeom,bool ccNetGeom,bool trackCnt,bool signal,bool power,uint layer)736 void extMain::extDump(char* file, bool openTreeFile, bool closeTreeFile,
737                       bool ccCapGeom, bool ccNetGeom, bool trackCnt,
738                       bool signal, bool power, uint layer) {
739   Ath__searchBox bb;
740   ZPtr<ISdb> targetSdb;
741   if (closeTreeFile) {
742     if (_ptFile)
743       fclose(_ptFile);
744     _ptFile = NULL;
745     _block->setPtFile(NULL);
746     return;
747   } else if (ccCapGeom)
748     targetSdb = _extCcapSDB;
749   else if (ccNetGeom || trackCnt)
750     targetSdb = _extNetSDB;
751   else if (!openTreeFile && !trackCnt)
752     return;
753   if (!file || !file[0]) {
754     logger_->warn(RCX, 203, "Filename is not defined (extDump)!");
755     return;
756   }
757   FILE* fp = fopen(file, "w");
758   if (!fp) {
759     logger_->warn(RCX, 38, "Can't open file {}", file);
760     return;
761   }
762   if (openTreeFile) {
763     _ptFile = fp;
764     _block->setPtFile(fp);
765     return;
766   }
767   if (trackCnt) {
768     targetSdb->dumpTrackCounts(fp);
769     fclose(fp);
770     return;
771   }
772   bool dumpSignalWire = true;
773   bool dumpPowerWire = true;
774   if (signal && !power)
775     dumpPowerWire = false;
776   if (!signal && power)
777     dumpSignalWire = false;
778   bool* etable = (bool*)malloc(100 * sizeof(bool));
779   bool init = layer == 0 ? false : true;
780   for (uint idx = 0; idx < 100; idx++)
781     etable[idx] = init;
782   etable[layer] = false;
783   targetSdb->resetMaxArea();
784   dbBox* tbox = _block->getBBox();
785   targetSdb->searchWireIds(tbox->xMin(), tbox->yMin(), tbox->xMax(),
786                            tbox->yMax(), false, etable);
787   targetSdb->startIterator();
788   uint wid, wflags;
789   while ((wid = targetSdb->getNextWireId())) {
790     if (ccNetGeom) {
791       wflags = targetSdb->getSearchPtr()->getWirePtr(wid)->getFlags();
792       if ((wflags == 1 && !dumpPowerWire) || (wflags == 2 && !dumpSignalWire))
793         continue;
794     }
795     targetSdb->getSearchPtr()->getCoords(&bb, wid);
796     fprintf(fp, "m%d %d %d  %d %d\n", bb.getLevel(), bb.loXY(0), bb.loXY(1),
797             bb.hiXY(0), bb.hiXY(1));
798   }
799   if (fp)
800     fclose(fp);
801 }
extCount(bool signalWireSeg,bool powerWireSeg)802 void extMain::extCount(bool signalWireSeg, bool powerWireSeg) {
803   if (!signalWireSeg && !powerWireSeg)
804     signalWireSeg = powerWireSeg = true;
805   uint signalViaCnt = 0;
806   uint signalWireCnt = 0;
807   uint powerViaCnt = 0;
808   uint powerWireCnt = 0;
809   dbSet<dbNet> bnets = _block->getNets();
810   dbSet<dbNet>::iterator net_itr;
811   dbNet* net;
812   for (net_itr = bnets.begin(); net_itr != bnets.end(); ++net_itr) {
813     net = *net_itr;
814     dbSigType type = net->getSigType();
815     if ((type == dbSigType::POWER) || (type == dbSigType::GROUND))
816       net->getPowerWireCount(powerWireCnt, powerViaCnt);
817     else
818       net->getSignalWireCount(signalWireCnt, signalViaCnt);
819   }
820   if (signalWireSeg)
821     logger_->info(RCX, 204, "{} signal seg ({} wire, {} via)",
822                   signalWireCnt + signalViaCnt, signalWireCnt, signalViaCnt);
823   if (powerWireSeg)
824     logger_->info(RCX, 205, "{} power seg ({} wire, {} via)",
825                   powerWireCnt + powerViaCnt, powerWireCnt, powerViaCnt);
826 }
827 /*
828 class extNetStats
829 {
830         double _tcap[2];
831         double _ccap[2];
832         double _cc2tcap[2];
833         double _cc[2];
834         uint _len[2];
835         uint _layerCnt[2];
836         uint _wCnt[2];
837         uint _vCnt[2];
838         uint _resCnt[2];
839         uint _ccCnt[2];
840         uint _gndCnt[2];
841         uint _id;
842         bool _layerFilter[20];
843         Rect _bbox;
844 };
845 */
outOfBounds_i(int limit[2],int v)846 bool extMain::outOfBounds_i(int limit[2], int v) {
847   if ((v < limit[0]) || (v > limit[1]))
848     return true;
849   else
850     return false;
851 }
outOfBounds_d(double limit[2],double v)852 bool extMain::outOfBounds_d(double limit[2], double v) {
853   if ((v < limit[0]) || (v > limit[1]))
854     return true;
855   else
856     return false;
857 }
printNetRC(char * buff,dbNet * net,extNetStats * st)858 bool extMain::printNetRC(char* buff, dbNet* net, extNetStats* st) {
859   double tCap = net->getTotalCapacitance(0, true);
860   if (tCap <= 0.0)
861     return false;
862 
863   if (outOfBounds_d(st->_tcap, tCap))
864     return false;
865 
866   double ccCap = net->getTotalCouplingCap();
867   if (outOfBounds_d(st->_ccap, ccCap))
868     return false;
869 
870   double cc2tcap = 0.0;
871   if (ccCap > 0.0) {
872     cc2tcap = ccCap / tCap;
873     if (outOfBounds_d(st->_cc2tcap, cc2tcap))
874       return false;
875   } else
876     return false;
877 
878   double res = net->getTotalResistance();
879   if (outOfBounds_d(st->_res, res))
880     return false;
881 
882   //	fprintf(fp, "C %8.3 CC %8.3f CCr %3.1f R %8.2f maxCC= %8.4f ",
883   //		tCap, ccCap, cc2tcap, res, maxCC);
884   sprintf(buff, "C %.3f CC %.3f CCr %2.1f R %.1f ", tCap, ccCap, cc2tcap, res);
885 
886   return true;
887 }
printNetDB(char * buff,dbNet * net,extNetStats * st)888 bool extMain::printNetDB(char* buff, dbNet* net, extNetStats* st) {
889   uint termCnt = net->getTermCount();
890   if (outOfBounds_i(st->_termCnt, termCnt))
891     return false;
892   uint btermCnt = net->getBTermCount();
893   if (outOfBounds_i(st->_btermCnt, btermCnt))
894     return false;
895 
896   uint wireCnt = 0;
897   uint viaCnt = 0;
898   uint len = 0;
899   uint layerCnt = 0;
900 
901   uint layerTable[12];
902   for (uint jj = 0; jj < 12; jj++)
903     layerTable[jj] = 0;
904 
905   net->getNetStats(wireCnt, viaCnt, len, layerCnt, layerTable);
906   uint ii = 1;
907   for (; ii < 12; ii++) {
908     if (layerTable[ii] == 0)
909       continue;
910 
911     layerCnt++;
912 
913     if (!st->_layerFilter[ii])
914       return false;
915   }
916 
917   if (outOfBounds_i(st->_vCnt, viaCnt))
918     return false;
919   if (outOfBounds_i(st->_wCnt, wireCnt))
920     return false;
921   if (outOfBounds_i(st->_len, len))
922     return false;
923   if (outOfBounds_i(st->_layerCnt, layerCnt))
924     return false;
925 
926   char buf1[256];
927 
928   sprintf(buf1, "%s", "\0");
929 
930   ii = 1;
931   for (; ii < 12; ii++) {
932     if (layerTable[ii] > 0) {
933       sprintf(buf1, "%s%d", buf1, ii);
934       break;
935     }
936   }
937   ii++;
938   for (; ii < 12; ii++) {
939     if (layerTable[ii] == 0)
940       continue;
941 
942     sprintf(buf1, "%s.%d", buf1, ii);
943   }
944   sprintf(buff, "V %d Wc %d  L %d  %dM%s T %d B %d", viaCnt, wireCnt,
945           len / 1000, layerCnt, buf1, termCnt, btermCnt);
946   return true;
947 }
948 
printNetStats(FILE * fp,dbBlock * block,extNetStats * bounds,bool skipRC,bool skipDb,bool skipPower,std::list<int> * list_of_nets)949 uint extMain::printNetStats(FILE* fp, dbBlock* block, extNetStats* bounds,
950                             bool skipRC, bool skipDb, bool skipPower,
951                             std::list<int>* list_of_nets) {
952   Rect bbox(bounds->_ll[0], bounds->_ll[1], bounds->_ur[0], bounds->_ur[1]);
953 
954   char buff1[256];
955   char buff2[256];
956   uint cnt = 0;
957   dbSet<dbNet> bnets = block->getNets();
958   dbSet<dbNet>::iterator net_itr;
959   for (net_itr = bnets.begin(); net_itr != bnets.end(); ++net_itr) {
960     dbNet* net = *net_itr;
961 
962     //		uint viaCnt = 0;
963     //		uint wireCnt = 0;
964 
965     dbSigType type = net->getSigType();
966     if ((type == dbSigType::POWER) || (type == dbSigType::GROUND)) {
967       if (skipPower)
968         continue;
969       // net->getPowerWireCount (powerWireCnt, powerViaCnt);
970       continue;
971     }
972     if (!net->isEnclosed(&bbox))
973       continue;
974     if (!skipRC) {
975       if (!printNetRC(buff1, net, bounds))
976         continue;
977     }
978     if (!skipDb) {
979       if (!printNetDB(buff2, net, bounds))
980         continue;
981     }
982     fprintf(fp, "%s %s ", buff1, buff2);
983     net->printNetName(fp, true, true);
984 
985     list_of_nets->push_back(net->getId());
986     cnt++;
987   }
988   return cnt;
989 }
reset()990 void extNetStats::reset() {
991   _tcap[0] = 0.0;
992   _tcap[1] = 1.0 * INT_MAX;
993   _ccap[0] = 0.0;
994   _ccap[1] = 1.0 * INT_MAX;
995   _cc2tcap[0] = 0.0;
996   _cc2tcap[1] = 1.0 * INT_MAX;
997   _cc[0] = 0.0;
998   _cc[1] = 1.0 * INT_MAX;
999   _res[0] = 0.0;
1000   _res[1] = 1.0 * INT_MAX;
1001 
1002   _len[0] = 0;
1003   _len[1] = INT_MAX;
1004   _layerCnt[0] = 0;
1005   _layerCnt[1] = INT_MAX;
1006   _wCnt[0] = 0;
1007   _wCnt[1] = INT_MAX;
1008   _vCnt[0] = 0;
1009   _vCnt[1] = INT_MAX;
1010   _resCnt[0] = 0;
1011   _resCnt[1] = INT_MAX;
1012   _ccCnt[0] = 0;
1013   _ccCnt[1] = INT_MAX;
1014   _gndCnt[0] = 0;
1015   _gndCnt[1] = INT_MAX;
1016   _termCnt[0] = 0;
1017   _termCnt[1] = INT_MAX;
1018   _btermCnt[0] = 0;
1019   _btermCnt[1] = INT_MAX;
1020   _id = 0;
1021   _ll[0] = INT_MIN;
1022   _ll[1] = INT_MIN;
1023   _ur[0] = INT_MAX;
1024   _ur[1] = INT_MAX;
1025 
1026   for (uint ii = 0; ii < 20; ii++)
1027     _layerFilter[ii] = true;
1028 }
update_double_limits(int n,double v1,double v2,double * val,double units)1029 void extNetStats::update_double_limits(int n, double v1, double v2, double* val,
1030                                        double units) {
1031   if (n == 0) {
1032     val[0] = v1 * units;
1033     val[1] = v2 * units;
1034   } else if (n == 1)
1035     val[0] = v1 * units;
1036   else if (n == 2)
1037     val[1] = v2 * units;
1038 }
update_double(Ath__parser * parser,const char * word,double * val,double units)1039 void extNetStats::update_double(Ath__parser* parser, const char* word,
1040                                 double* val, double units) {
1041   double v1, v2;
1042   int n = parser->get2Double(word, ":", v1, v2);
1043 
1044   if (n >= 0)
1045     update_double_limits(n, v1, v2, val, units);
1046 }
update_int_limits(int n,int v1,int v2,int * val,uint units)1047 void extNetStats::update_int_limits(int n, int v1, int v2, int* val,
1048                                     uint units) {
1049   if (n == 0) {
1050     val[0] = v1 * units;
1051     val[1] = v2 * units;
1052   } else if (n == 1)
1053     val[0] = v1 * units;
1054   else if (n == 2)
1055     val[1] = v2 * units;
1056 }
update_int(Ath__parser * parser,const char * word,int * val,uint units)1057 void extNetStats::update_int(Ath__parser* parser, const char* word, int* val,
1058                              uint units) {
1059   int v1, v2;
1060   int n = parser->get2Int(word, ":", v1, v2);
1061 
1062   if (n >= 0)
1063     update_int_limits(n, v1, v2, val, units);
1064 }
update_bbox(Ath__parser * parser,const char * bbox)1065 void extNetStats::update_bbox(Ath__parser* parser, const char* bbox) {
1066   int n = parser->mkWords(bbox, " ");
1067 
1068   if (n <= 3) {
1069     logger_->warn(RCX, 206, "Invalid bbox <{}>! Assuming entire block.", bbox);
1070     return;
1071   }
1072   _ll[0] = parser->getInt(0);
1073   _ll[1] = parser->getInt(1);
1074   _ur[0] = parser->getInt(2);
1075   _ur[1] = parser->getInt(3);
1076 }
1077 }  // namespace rcx
1078