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