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 #include "rcx/ext.h"
33 
34 #include <errno.h>
35 
36 #include "opendb/wOrder.h"
37 #include "sta/StaMain.hh"
38 #include "utl/Logger.h"
39 #include "opendb/wOrder.h"
40 
41 namespace sta {
42 // Tcl files encoded into strings.
43 extern const char* rcx_tcl_inits[];
44 }  // namespace sta
45 
46 namespace rcx {
47 
48 using utl::Logger;
49 using utl::RCX;
50 
51 extern "C" { extern int Rcx_Init(Tcl_Interp* interp); }
52 
Ext()53 Ext::Ext() : odb::ZInterface() {
54   _ext = new extMain(5);
55   _tree = NULL;
56   logger_ = nullptr;
57 }
58 
~Ext()59 Ext::~Ext() { delete _ext; }
60 
init(Tcl_Interp * tcl_interp,odb::dbDatabase * db,Logger * logger)61 void Ext::init(Tcl_Interp* tcl_interp, odb::dbDatabase* db, Logger* logger) {
62   _db = db;
63   logger_ = logger;
64   _ext->init(db, logger);
65 
66   // Define swig TCL commands.
67   Rcx_Init(tcl_interp);
68   sta::evalTclInit(tcl_interp, sta::rcx_tcl_inits);
69 }
70 
setLogger(Logger * logger)71 void Ext::setLogger(Logger* logger) {
72   if (!logger_)
73     logger_ = logger;
74 }
75 
load_model(const std::string & name,bool lef_rc,const std::string & file,int setMin,int setTyp,int setMax)76 bool Ext::load_model(const std::string& name, bool lef_rc,
77                      const std::string& file, int setMin, int setTyp,
78                      int setMax) {
79   if (lef_rc) {
80     if (!_ext->checkLayerResistance())
81       return TCL_ERROR;
82     _ext->addExtModel();  // fprintf(stdout, "Using LEF RC values to
83                           // extract!\n");
84     logger_->info(RCX, 9, "Using LEF RC values to extract!");
85   } else if (!file.empty()) {
86     _ext->readExtRules(name.c_str(), file.c_str(), setMin, setTyp, setMax);
87     int numOfNet, numOfRSeg, numOfCapNode, numOfCCSeg;
88     _ext->getBlock()->getExtCount(numOfNet, numOfRSeg, numOfCapNode,
89                                   numOfCCSeg);
90 
91     _ext->setupMapping(3 * numOfNet);
92   } else {
93     // fprintf(stdout, "\nHave to specify options:\n\t-lef_rc to read resistance
94     // and capacitance values from LEF or \n\t-file to read high accuracy RC
95     // models\n");
96     logger_->info(
97         RCX, 151,
98         "Have to specify options:"
99         "\n\t-lef_rc to read resistance and "
100         "capacitance values from LEF or \n\t-file to read high accuracy RC "
101         "models");
102   }
103 
104   return 0;
105 }
106 
read_process(const std::string & name,const std::string & file)107 bool Ext::read_process(const std::string& name, const std::string& file) {
108   _ext->readProcess(name.c_str(), file.c_str());
109 
110   return TCL_OK;
111 }
112 
rules_gen(const std::string & name,const std::string & dir,const std::string & file,bool write_to_solver,bool read_from_solver,bool run_solver,int pattern,bool keep_file)113 bool Ext::rules_gen(const std::string& name, const std::string& dir,
114                     const std::string& file, bool write_to_solver,
115                     bool read_from_solver, bool run_solver, int pattern,
116                     bool keep_file) {
117   _ext->rulesGen(name.c_str(), dir.c_str(), file.c_str(), pattern,
118                  write_to_solver, read_from_solver, run_solver, keep_file);
119 
120   return TCL_OK;
121 }
122 
metal_rules_gen(const std::string & name,const std::string & dir,const std::string & file,bool write_to_solver,bool read_from_solver,bool run_solver,int pattern,bool keep_file,int metal)123 bool Ext::metal_rules_gen(const std::string& name, const std::string& dir,
124                           const std::string& file, bool write_to_solver,
125                           bool read_from_solver, bool run_solver, int pattern,
126                           bool keep_file, int metal) {
127   _ext->metRulesGen(name.c_str(), dir.c_str(), file.c_str(), pattern,
128                     write_to_solver, read_from_solver, run_solver, keep_file,
129                     metal);
130   return TCL_OK;
131 }
132 
write_rules(const std::string & name,const std::string & dir,const std::string & file,int pattern,bool read_from_db,bool read_from_solver)133 bool Ext::write_rules(const std::string& name, const std::string& dir,
134                       const std::string& file, int pattern, bool read_from_db,
135                       bool read_from_solver) {
136   _ext->setBlockFromChip();
137   _ext->writeRules(name.c_str(), dir.c_str(), file.c_str(), pattern,
138                    read_from_db, read_from_solver);
139   return TCL_OK;
140 }
141 
get_ext_metal_count(int & metal_count)142 bool Ext::get_ext_metal_count(int& metal_count) {
143   extRCModel* m = _ext->getRCModel();
144   metal_count = m->getLayerCnt();
145   return TCL_OK;
146 }
147 
bench_net(const std::string & dir,int net,bool write_to_solver,bool read_from_solver,bool run_solver,int max_track_count)148 bool Ext::bench_net(const std::string& dir, int net, bool write_to_solver,
149                     bool read_from_solver, bool run_solver,
150                     int max_track_count) {
151   extMainOptions opt;
152 
153   opt._write_to_solver = write_to_solver;
154   opt._read_from_solver = read_from_solver;
155   opt._run_solver = run_solver;
156 
157   int netId = net;
158   int trackCnt = max_track_count;
159   opt._topDir = dir.c_str();
160 
161   if (netId == 0) {
162     logger_->info(RCX, 144, "Net (={}), should be a positive number", netId);
163     return TCL_OK;
164   }
165   logger_->info(RCX, 145, "Benchmarking using 3d field solver net {}...",
166                 netId);
167 #ifdef ZUI
168   ZPtr<ISdb> dbNetSdb = _ext->getBlock()->getNetSdb(_context, _ext->getTech());
169 
170   _ext->benchNets(&opt, netId, trackCnt, dbNetSdb);
171 #endif
172   logger_->info(RCX, 146, "Finished 3D field solver benchmarking.");
173 
174   return TCL_OK;
175 }
176 
run_solver(const std::string & dir,int net,int shape)177 bool Ext::run_solver(const std::string& dir, int net, int shape) {
178   extMainOptions opt;
179   opt._topDir = dir.c_str();
180   uint netId = net;
181   int shapeId = shape;
182   _ext->runSolver(&opt, netId, shapeId);
183   return TCL_OK;
184 }
185 
bench_wires(const BenchWiresOptions & bwo)186 bool Ext::bench_wires(const BenchWiresOptions& bwo) {
187   extMainOptions opt;
188 
189   opt._topDir = bwo.dir;
190   opt._met_cnt = bwo.met_cnt;
191   opt._met = bwo.met;
192   opt._overDist = bwo.over_dist;
193   opt._underDist = bwo.under_dist;
194   opt._overMet = bwo.over_met;
195   opt._over = bwo.Over;
196   opt._underMet = bwo.under_met;
197   opt._overUnder = bwo.over_under;
198   opt._len = 1000 * bwo.len;
199   opt._wireCnt = bwo.cnt;
200   opt._name = bwo.block;
201 
202   opt._default_lef_rules = bwo.default_lef_rules;
203   opt._nondefault_lef_rules = bwo.nondefault_lef_rules;
204 
205   opt._3dFlag = bwo.ddd;
206   opt._multiple_widths = bwo.multiple_widths;
207 
208   opt._write_to_solver = bwo.write_to_solver;
209   opt._read_from_solver = bwo.read_from_solver;
210   opt._run_solver = bwo.run_solver;
211   opt._diag = bwo.diag;
212   opt._db_only = bwo.db_only;
213   opt._gen_def_patterns = bwo.gen_def_patterns;
214 
215   opt._res_patterns = bwo.resPatterns;
216 
217   if (opt._gen_def_patterns) {
218     opt._diag = true;
219     opt._overUnder = true;
220     opt._db_only = true;
221     opt._over = true;
222     opt._underMet = 0;
223   }
224 
225   Ath__parser parser;
226 
227   std::string th_list(bwo.th_list);
228   std::string w_list(bwo.w_list);
229   std::string s_list(bwo.s_list);
230   std::string th(bwo.th);
231   std::string w(bwo.w);
232   std::string s(bwo.s);
233   std::string d(bwo.d);
234   std::string grid_list(bwo.grid_list);
235 
236   if (!th.empty()) {
237     parser.mkWords(bwo.th_list);
238     parser.getDoubleArray(&opt._thicknessTable, 0);
239     opt._thListFlag = true;
240   } else {
241     parser.mkWords(bwo.th);
242     parser.getDoubleArray(&opt._thicknessTable, 0);
243     opt._thListFlag = false;
244   }
245   opt._listsFlag = false;
246   opt._wsListFlag = false;
247   if (opt._default_lef_rules) {  // minWidth, minSpacing, minThickness, pitch
248                                  // multiplied by grid_list
249     // user sets default_flag and grid_list multipliers
250     if (grid_list.empty()) {
251       opt._gridTable.add(1.0);
252     } else {
253       parser.mkWords(grid_list.c_str());
254       parser.getDoubleArray(&opt._gridTable, 0);
255     }
256     opt._listsFlag = true;
257   } else if (opt._nondefault_lef_rules) {
258     opt._listsFlag = true;
259   } else if (!w_list.empty() && !s_list.empty()) {
260     opt._listsFlag = true;
261     opt._wsListFlag = true;
262     parser.mkWords(w_list.c_str());
263     parser.getDoubleArray(&opt._widthTable, 0);
264     parser.mkWords(s_list.c_str());
265     parser.getDoubleArray(&opt._spaceTable, 0);
266   } else {
267     parser.mkWords(w.c_str());
268     parser.getDoubleArray(&opt._widthTable, 0);
269     parser.mkWords(s.c_str());
270     parser.getDoubleArray(&opt._spaceTable, 0);
271     parser.mkWords(th.c_str());
272     parser.getDoubleArray(&opt._thicknessTable, 0);
273     parser.mkWords(d.c_str());
274     parser.getDoubleArray(&opt._densityTable, 0);
275   }
276   _ext->benchWires(&opt);
277 
278   return TCL_OK;
279 }
280 
bench_verilog(const std::string & file)281 bool Ext::bench_verilog(const std::string& file) {
282   _ext->setBlockFromChip();
283   char* filename = (char*)file.c_str();
284   if (!filename || !filename[0]) {
285     logger_->error(RCX, 147, "bench_verilog: file is not defined!");
286   }
287   FILE* fp = fopen(filename, "w");
288   if (fp == NULL) {
289     logger_->error(RCX, 378, "Can't open file {}", filename);
290   }
291   _ext->benchVerilog(fp);
292 
293   return TCL_OK;
294 }
295 
clean(bool all_models,bool ext_only)296 bool Ext::clean(bool all_models, bool ext_only) { return TCL_OK; }
297 
define_process_corner(int ext_model_index,const std::string & name)298 bool Ext::define_process_corner(int ext_model_index, const std::string& name) {
299   _ext->setBlockFromChip();
300   char* cornerName = _ext->addRCCorner(name.c_str(), ext_model_index);
301 
302   if (cornerName != NULL) {
303     logger_->info(RCX, 29, "Defined extraction corner {}", cornerName);
304     return TCL_OK;
305   } else {
306     return TCL_ERROR;
307   }
308 }
309 
define_derived_corner(const std::string & name,const std::string & process_corner_name,float res_factor,float cc_factor,float gndc_factor)310 bool Ext::define_derived_corner(const std::string& name,
311                                 const std::string& process_corner_name,
312                                 float res_factor, float cc_factor,
313                                 float gndc_factor) {
314   if (process_corner_name.empty()) {
315     logger_->warn(RCX, 30, "The original process corner name is required");
316     return TCL_ERROR;
317   }
318 
319   int model = _ext->getDbCornerModel(process_corner_name.c_str());
320 
321   char* cornerName = _ext->addRCCornerScaled(name.c_str(), model, res_factor,
322                                              cc_factor, gndc_factor);
323 
324   if (cornerName != NULL) {
325     logger_->info(RCX, 31, "Defined Derived extraction corner {}", cornerName);
326     return TCL_OK;
327   } else {
328     return TCL_ERROR;
329   }
330 }
331 
delete_corners()332 bool Ext::delete_corners() {
333   _ext->deleteCorners();
334   return TCL_OK;
335 }
336 
get_corners(std::list<std::string> & corner_list)337 bool Ext::get_corners(std::list<std::string>& corner_list) {
338   _ext->getCorners(corner_list);
339   return TCL_OK;
340 }
341 
read_qcap(const std::string & file_name,const std::string & cap_file,bool skip_bterms,bool no_qcap,const std::string & design)342 bool Ext::read_qcap(const std::string& file_name, const std::string& cap_file,
343                     bool skip_bterms, bool no_qcap, const std::string& design) {
344   if (file_name.empty()) {
345     logger_->warn(RCX, 32, "-file flag is required on the command!");
346     return TCL_OK;
347   }
348 
349   extMeasure m;
350   if (!no_qcap)
351     m.readQcap(_ext, file_name.c_str(), design.c_str(), cap_file.c_str(),
352                skip_bterms, _db);
353   else
354     m.readAB(_ext, file_name.c_str(), design.c_str(), cap_file.c_str(),
355              skip_bterms, _db);
356 
357   return TCL_OK;
358 }
359 
get_ext_db_corner(int & index,const std::string & name)360 bool Ext::get_ext_db_corner(int& index, const std::string& name) {
361   index = _ext->getDbCornerIndex(name.c_str());
362 
363   if (index < 0)
364     logger_->warn(RCX, 148, "Extraction corner {} not found!", name.c_str());
365 
366   return TCL_OK;
367 }
368 
assembly(odb::dbBlock * block,odb::dbBlock * main_block)369 bool Ext::assembly(odb::dbBlock* block, odb::dbBlock* main_block) {
370   if (main_block == NULL) {
371     logger_->info(RCX, 149, "Add parasitics of block {} onto nets/wires ...{}",
372                   block->getConstName());
373   } else {
374     logger_->info(RCX, 150, "Add parasitics of block {} onto block {}...",
375                   block->getConstName(), main_block->getConstName());
376   }
377 
378   extMain::assemblyExt(main_block, block, logger_);
379 
380   return TCL_OK;
381 }
382 
flatten(odb::dbBlock * block,bool spef)383 bool Ext::flatten(odb::dbBlock* block, bool spef) {
384   if (block == NULL) {
385     logger_->error(RCX, 486, "No block for flatten command");
386   }
387   _ext->addRCtoTop(block, spef);
388   return TCL_OK;
389 }
390 
extract(ExtractOptions opts)391 bool Ext::extract(ExtractOptions opts) {
392   _ext->setBlockFromChip();
393   odb::dbBlock* block = _ext->getBlock();
394   logger_->info(RCX, 8, "extracting parasitics of {} ...",
395                 block->getConstName());
396 
397   odb::orderWires(block, nullptr /* net_name_or_id*/, false /* force */,
398                   false /* verbose */, true /* quiet */);
399   if (opts.lef_rc) {
400     if (!_ext->checkLayerResistance())
401       return TCL_ERROR;
402     _ext->addExtModel();
403     logger_->info(RCX, 375, "Using LEF RC values to extract!");
404   }
405 
406   bool extract_power_grid_only = opts.power_grid;
407 #ifdef ZUI
408   if (extract_power_grid_only) {
409     dbBlock* block = _ext->getBlock();
410     if (block != NULL) {
411       bool skipCutVias = true;
412       block->initSearchBlock(_db->getTech(), true, true, _context, skipCutVias);
413     } else {
414       logger_->error(RCX, 10, "There is no block to extract!");
415       return TCL_ERROR;
416     }
417     _ext->setPowerExtOptions(skip_power_stubs, exclude_cells.c_str(),
418                              in_args->skip_m1_caps(),
419                              in_args->power_source_coords());
420   }
421 #endif
422 
423   const char* extRules = opts.ext_model_file;
424   const char* cmpFile = opts.cmp_file;
425   bool density_model = opts.wire_density;
426 
427   uint ccUp = opts.cc_up;
428   uint ccFlag = opts.cc_model;
429   // uint ccFlag= 25;
430   int ccBandTracks = opts.cc_band_tracks;
431   uint use_signal_table = opts.signal_table;
432   bool merge_via_res = opts.no_merge_via_res ? false : true;
433   uint extdbg = opts.test;
434   const char* nets = opts.net;
435   const char* debug_nets = opts.debug_net;
436   bool gs = opts.no_gs ? false : true;
437   double ccThres = opts.coupling_threshold;
438   int ccContextDepth = opts.context_depth;
439   bool overCell = opts.over_cell;
440   bool btermThresholdFlag = opts.tile;
441 
442   _ext->set_debug_nets(debug_nets);
443   _ext->skip_via_wires(opts.skip_via_wires);
444   _ext->skip_via_wires(true);
445   _ext->_lef_res = opts.lef_res;
446 
447   uint tilingDegree = opts.tiling;
448 
449   odb::ZPtr<odb::ISdb> dbNetSdb = NULL;
450   bool extSdb = false;
451 
452   // ccBandTracks = 0;  // tttt no band CC for now
453   if (extdbg == 100 || extdbg == 102)  // 101: activate reuse metal fill
454                                        // 102: no bandTrack
455     ccBandTracks = 0;
456   if (ccBandTracks)
457     opts.eco = false;  // tbd
458   else {
459 #ifdef ZUI
460     dbNetSdb = _ext->getBlock()->getNetSdb();
461 
462     if (dbNetSdb == NULL) {
463       extSdb = true;
464       if (rlog)
465         AthResourceLog("before get sdb", 0);
466 
467       dbNetSdb = _ext->getBlock()->getNetSdb(_context, _ext->getTech());
468 
469       if (rlog)
470         AthResourceLog("after get sdb", 0);
471     }
472 #endif
473   }
474 
475   if (tilingDegree == 1)
476     extdbg = 501;
477   else if (tilingDegree == 10)
478     extdbg = 603;
479   else if (tilingDegree == 7)
480     extdbg = 703;
481   else if (tilingDegree == 77) {
482     extdbg = 773;
483     //_ext->rcGen(NULL, max_res, merge_via_res, 77, true, this);
484   }
485   /*
486     else if (tilingDegree==77) {
487     extdbg= 703;
488     _ext->rcGen(NULL, max_res, merge_via_res, 77, true, this);
489     }
490   */
491   else if (tilingDegree == 8)
492     extdbg = 803;
493   else if (tilingDegree == 9)
494     extdbg = 603;
495   else if (tilingDegree == 777) {
496     extdbg = 777;
497 
498     uint cnt = 0;
499     odb::dbSet<odb::dbNet> bnets = _ext->getBlock()->getNets();
500     odb::dbSet<odb::dbNet>::iterator net_itr;
501     for (net_itr = bnets.begin(); net_itr != bnets.end(); ++net_itr) {
502       odb::dbNet* net = *net_itr;
503 
504       cnt += _ext->rcNetGen(net);
505     }
506     logger_->info(RCX, 14, "777: Final rc segments = {}", cnt);
507   }
508   if (_ext->makeBlockRCsegs(
509           btermThresholdFlag, cmpFile, density_model, opts.litho, nets,
510           opts.bbox, opts.ibox, ccUp, ccFlag, ccBandTracks, use_signal_table,
511           opts.max_res, merge_via_res, extdbg, opts.preserve_geom, opts.re_run,
512           opts.eco, gs, opts.rlog, dbNetSdb, ccThres, ccContextDepth, overCell,
513           extRules, this) == 0)
514     return TCL_ERROR;
515 
516   odb::dbBlock* topBlock = _ext->getBlock();
517   if (tilingDegree == 1) {
518     odb::dbSet<odb::dbBlock> children = topBlock->getChildren();
519     odb::dbSet<odb::dbBlock>::iterator itr;
520 
521     // Extraction
522 
523     logger_->info(RCX, 6, "List of extraction tile blocks:");
524     for (itr = children.begin(); itr != children.end(); ++itr) {
525       odb::dbBlock* blk = *itr;
526       logger_->info(RCX, 377, "{}", blk->getConstName());
527     }
528   } else if (extdbg == 501) {
529     odb::dbSet<odb::dbBlock> children = topBlock->getChildren();
530     odb::dbSet<odb::dbBlock>::iterator itr;
531 
532     // Extraction
533     for (itr = children.begin(); itr != children.end(); ++itr) {
534       odb::dbBlock* blk = *itr;
535       logger_->info(RCX, 12, "Extacting block {}...", blk->getConstName());
536       extMain* ext = new extMain(5);
537 
538       ext->setBlock(blk);
539 
540       if (ext->makeBlockRCsegs(btermThresholdFlag, cmpFile, density_model,
541                                opts.litho, nets, opts.bbox, opts.ibox, ccUp,
542                                ccFlag, ccBandTracks, use_signal_table,
543                                opts.max_res, merge_via_res, 0,
544                                opts.preserve_geom, opts.re_run, opts.eco, gs,
545                                opts.rlog, dbNetSdb, ccThres, ccContextDepth,
546                                overCell, extRules, this) == 0) {
547         logger_->warn(RCX, 13, "Failed to Extract block {}...",
548                       blk->getConstName());
549         return TCL_ERROR;
550       }
551     }
552 
553     for (itr = children.begin(); itr != children.end(); ++itr) {
554       odb::dbBlock* blk = *itr;
555       logger_->info(RCX, 46, "Assembly of block {}...", blk->getConstName());
556 
557       extMain::assemblyExt(topBlock, blk, logger_);
558     }
559     //_ext= new extMain(5);
560     //_ext->setDB(_db);
561     //_ext->setBlock(topBlock);
562   }
563 
564   // report total net cap
565 
566   if (opts.write_total_caps) {
567     char netcapfile[500];
568     sprintf(netcapfile, "%s.totCap", _ext->getBlock()->getConstName());
569     _ext->reportTotalCap(netcapfile, true, false, 1.0, NULL, NULL);
570   }
571 
572   if (!ccBandTracks) {
573     if (extSdb && extdbg != 99) {
574       if (opts.rlog)
575         odb::AthResourceLog("before remove sdb", 0);
576       dbNetSdb->cleanSdb();
577 #ifdef ZUI
578       _ext->getBlock()->resetNetSdb();
579       if (rlog)
580         AthResourceLog("after remove sdb", 0);
581 #endif
582     }
583   }
584 
585   //    fprintf(stdout, "Finished extracting %s.\n",
586   //    _ext->getBlock()->getName().c_str());
587   logger_->info(RCX, 15, "Finished extracting {}.",
588                 _ext->getBlock()->getName().c_str());
589   return 0;
590 }
591 
adjust_rc(float res_factor,float cc_factor,float gndc_factor)592 bool Ext::adjust_rc(float res_factor, float cc_factor, float gndc_factor) {
593   _ext->adjustRC(res_factor, cc_factor, gndc_factor);
594   return 0;
595 }
596 
init_incremental_spef(const std::string & origp,const std::string & newp,bool no_backslash,const std::string & exclude_cells)597 bool Ext::init_incremental_spef(const std::string& origp,
598                                 const std::string& newp, bool no_backslash,
599                                 const std::string& exclude_cells) {
600   _ext->initIncrementalSpef(origp.c_str(), newp.c_str(), exclude_cells.c_str(),
601                             no_backslash);
602   return 0;
603 }
604 
export_sdb(odb::ZPtr<odb::ISdb> & net_sdb,odb::ZPtr<odb::ISdb> & cc_sdb)605 bool Ext::export_sdb(odb::ZPtr<odb::ISdb>& net_sdb,
606                      odb::ZPtr<odb::ISdb>& cc_sdb) {
607   cc_sdb = _ext->getCcSdb();
608   net_sdb = _ext->getNetSdb();
609 
610   return 0;
611 }
612 
write_spef_nets(odb::dbObject * block,bool flatten,bool parallel,int corner)613 bool Ext::write_spef_nets(odb::dbObject* block, bool flatten, bool parallel,
614                           int corner) {
615   _ext->setBlockFromChip();
616   _ext->write_spef_nets(flatten, parallel);
617 
618   return 0;
619 }
620 
write_spef(const SpefOptions & opts)621 bool Ext::write_spef(const SpefOptions& opts) {
622   _ext->setBlockFromChip();
623   if (opts.end) {
624     _ext->writeSPEF(true);
625     return 0;
626   }
627   const char* name = opts.ext_corner_name;
628 
629   uint netId = opts.net_id;
630   if (netId > 0) {
631     _ext->writeSPEF(netId, opts.single_pi, opts.debug, opts.corner, name);
632     return 0;
633   }
634   bool useIds = opts.use_ids;
635   bool stop = opts.stop_after_map;
636   bool initOnly = opts.init;
637   if (!initOnly)
638     logger_->info(RCX, 16, "Writing SPEF ...");
639   initOnly = opts.parallel && opts.flatten;
640   _ext->writeSPEF((char*)opts.file, (char*)opts.nets, useIds, opts.no_name_map,
641                   (char*)opts.N, opts.term_junction_xy, opts.exclude_cells,
642                   opts.cap_units, opts.res_units, opts.gz, stop, opts.w_clock,
643                   opts.w_conn, opts.w_cap, opts.w_cc_cap, opts.w_res,
644                   opts.no_c_num, initOnly, opts.single_pi, opts.no_backslash,
645                   opts.corner, name, opts.flatten, opts.parallel);
646 
647   logger_->info(RCX, 17, "Finished writing SPEF ...");
648   return 0;
649 }
650 
independent_spef_corner()651 bool Ext::independent_spef_corner() {
652   _ext->setUniqueExttreeCorner();
653   return 0;
654 }
655 
read_spef(ReadSpefOpts & opt)656 bool Ext::read_spef(ReadSpefOpts& opt) {
657   _ext->setBlockFromChip();
658   logger_->info(RCX, 1, "Reading SPEF file: {}", opt.file);
659 
660   odb::ZPtr<odb::ISdb> netSdb = NULL;
661   bool stampWire = opt.stamp_wire;
662 #ifdef ZUI
663   if (stampWire)
664     netSdb = _ext->getBlock()->getSignalNetSdb(_context, _db->getTech());
665 #endif
666   bool useIds = opt.use_ids;
667   uint testParsing = opt.test_parsing;
668 
669   Ath__parser parser;
670   char* filename = (char*)opt.file;
671   if (!filename || !filename[0]) {
672     logger_->error(RCX, 2, "Filename is not defined!");
673   }
674   parser.mkWords(filename);
675 
676   _ext->readSPEF(
677       parser.get(0), (char*)opt.net, opt.force, useIds, opt.r_conn,
678       (char*)opt.N, opt.r_cap, opt.r_cc_cap, opt.r_res, opt.cc_threshold,
679       opt.cc_ground_factor, opt.length_unit, opt.m_map, opt.no_cap_num_collapse,
680       (char*)opt.cap_node_map_file, opt.log, opt.corner, 0.0, 0.0, NULL, NULL,
681       NULL, opt.db_corner_name, opt.calibrate_base_corner, opt.spef_corner,
682       opt.fix_loop, opt.keep_loaded_corner, stampWire, netSdb, testParsing,
683       opt.more_to_read, false /*diff*/, false /*calibrate*/,
684       opt.app_print_limit);
685 
686   for (int ii = 1; ii < parser.getWordCnt(); ii++)
687     _ext->readSPEFincr(parser.get(ii));
688 
689   return 0;
690 }
691 
diff_spef(const DiffOptions & opt)692 bool Ext::diff_spef(const DiffOptions& opt) {
693   _ext->setBlockFromChip();
694   std::string filename(opt.file);
695   if (filename.empty()) {
696     logger_->error(RCX, 380,
697                    "Filename is not defined to run diff_spef command!");
698   }
699   logger_->info(RCX, 19, "diffing spef {}", opt.file);
700 
701   Ath__parser parser;
702   parser.mkWords(opt.file);
703 
704   // char* excludeSubWord = (char*) opt.exclude_net_subword.c_str();
705   // char* subWord        = (char*) opt.net_subword.c_str();
706   // char* statsFile      = (char*) opt.rc_stats_file.c_str();
707 
708   _ext->readSPEF(parser.get(0), (char*)opt.net, false /*force*/, opt.use_ids,
709                  opt.r_conn, NULL /*N*/, opt.r_cap, opt.r_cc_cap, opt.r_res,
710                  -1.0, 0.0 /*cc_ground_factor*/, 1.0 /*length_unit*/, opt.m_map,
711                  false /*noCapNumCollapse*/, NULL /*capNodeMapFile*/, opt.log,
712                  opt.ext_corner, opt.low_guard, opt.upper_guard,
713                  (char*)opt.exclude_net_subword, (char*)opt.net_subword,
714                  (char*)opt.rc_stats_file, (char*)opt.db_corner_name, NULL,
715                  opt.spef_corner, 0 /*fix_loop*/, false /*keepLoadedCorner*/,
716                  false /*stampWire*/, NULL /*netSdb*/, opt.test_parsing,
717                  false /*moreToRead*/, true /*diff*/, false /*calibrate*/, 0);
718 
719   // for (uint ii=1; ii<parser.getWordCnt(); ii++)
720   //	_ext->readSPEFincr(parser.get(ii));
721 
722   return 0;
723 }
724 
calibrate(const std::string & spef_file,const std::string & db_corner_name,int corner,int spef_corner,bool m_map,float upper_limit,float lower_limit)725 bool Ext::calibrate(const std::string& spef_file,
726                     const std::string& db_corner_name, int corner,
727                     int spef_corner, bool m_map, float upper_limit,
728                     float lower_limit) {
729   if (spef_file.empty())
730     logger_->error(RCX, 381,
731                    "Filename for calibration is not defined. Define the "
732                    "filename using -spef_file");
733 
734   logger_->info(RCX, 21, "calibrate on spef file  {}", spef_file.c_str());
735   Ath__parser parser;
736   parser.mkWords((char*)spef_file.c_str());
737   _ext->calibrate(parser.get(0), m_map, upper_limit, lower_limit,
738                   db_corner_name.c_str(), corner, spef_corner);
739   return 0;
740 }
741 
match(const std::string & spef_file,const std::string & db_corner_name,int corner,int spef_corner,bool m_map)742 bool Ext::match(const std::string& spef_file, const std::string& db_corner_name,
743                 int corner, int spef_corner, bool m_map) {
744   if (spef_file.empty()) {
745     logger_->info(RCX, 20,
746                   "Filename for calibration is not defined. Define the "
747                   "filename using -spef_file");
748   }
749   logger_->info(RCX, 18, "match on spef file  {}", spef_file.c_str());
750   Ath__parser parser;
751   parser.mkWords((char*)spef_file.c_str());
752   _ext->match(parser.get(0), m_map, db_corner_name.c_str(), corner,
753               spef_corner);
754   return 0;
755 }
756 
757 #if 0
758 TCL_METHOD ( Ext::setRules )
759 {
760     ZIn_Ext_setRules * in_args = (ZIn_Ext_setRules *) in;
761 	_extModel= (ExtModel *) in_args->model();
762 	xm->getFringeCap(....)
763 }
764 #endif
765 
set_block(const std::string & block_name,odb::dbBlock * block,const std::string & inst_name,odb::dbInst * inst)766 bool Ext::set_block(const std::string& block_name, odb::dbBlock* block,
767                     const std::string& inst_name, odb::dbInst* inst) {
768   if (!inst_name.empty()) {
769     odb::dbChip* chip = _db->getChip();
770     odb::dbInst* ii = chip->getBlock()->findInst(inst_name.c_str());
771     odb::dbMaster* m = ii->getMaster();
772     logger_->info(RCX, 24, "Inst={} ==> {} {} of Master {} {}",
773                   inst_name.c_str(), ii->getId(), ii->getConstName(),
774                   m->getId(), m->getConstName());
775   }
776   if (block == NULL) {
777     if (block_name.empty()) {
778       logger_->warn(RCX, 22, "command requires either dbblock or block name{}");
779       return TCL_ERROR;
780     }
781     odb::dbChip* chip = _db->getChip();
782     odb::dbBlock* child = chip->getBlock()->findChild(block_name.c_str());
783     if (child == NULL) {
784       logger_->warn(RCX, 430, "Cannot find block with master name {}",
785                     block_name.c_str());
786       return TCL_ERROR;
787     }
788     block = child;
789   }
790 
791   delete _ext;
792   _ext = new extMain(5);
793   _ext->init(_db, logger_);
794 
795   _ext->setBlock(block);
796   return 0;
797 }
798 
report_total_cap(const std::string & file,bool res_only,bool cap_only,float ccmult,const std::string & ref,const std::string & read)799 bool Ext::report_total_cap(const std::string& file, bool res_only,
800                            bool cap_only, float ccmult, const std::string& ref,
801                            const std::string& read) {
802   _ext->reportTotalCap(file.c_str(), cap_only, res_only, ccmult, ref.c_str(),
803                        read.c_str());
804   /*
805           dbChip *chip= _db->getChip();
806           dbBlock * child = chip->getBlock()->findChild(block_name);
807   if (child==NULL) {
808   logger_->warn(RCX, 23, "Cannot find block with master name {}",
809   block_name);
810   return TCL_ERROR;
811   }
812   block= child;
813   */
814   return 0;
815 }
816 
report_total_cc(const std::string & file,const std::string & ref,const std::string & read)817 bool Ext::report_total_cc(const std::string& file, const std::string& ref,
818                           const std::string& read) {
819   _ext->reportTotalCc(file.c_str(), ref.c_str(), read.c_str());
820   return 0;
821 }
822 
dump(bool open_tree_file,bool close_tree_file,bool cc_cap_geom,bool cc_net_geom,bool track_cnt,bool signal,bool power,int layer,const std::string & file)823 bool Ext::dump(bool open_tree_file, bool close_tree_file, bool cc_cap_geom,
824                bool cc_net_geom, bool track_cnt, bool signal, bool power,
825                int layer, const std::string& file) {
826   logger_->info(RCX, 25, "Printing file {}", file.c_str());
827 
828   _ext->extDump((char*)file.c_str(), open_tree_file, close_tree_file,
829                 cc_cap_geom, cc_net_geom, track_cnt, signal, power, layer);
830 
831   return 0;
832 }
833 
count(bool signal_wire_seg,bool power_wire_seg)834 bool Ext::count(bool signal_wire_seg, bool power_wire_seg) {
835   _ext->extCount(signal_wire_seg, power_wire_seg);
836 
837   return 0;
838 }
839 
rc_tree(float max_cap,uint test,int net,const std::string & print_tag)840 bool Ext::rc_tree(float max_cap, uint test, int net,
841                   const std::string& print_tag) {
842   int netId = net;
843   char* printTag = (char*)print_tag.c_str();
844 
845   odb::dbBlock* block = _ext->getBlock();
846 
847   if (_tree == NULL)
848     _tree = new extRcTree(block, logger_);
849 
850   uint cnt;
851   if (netId > 0)
852     _tree->makeTree((uint)netId, max_cap, test, true, true, cnt, 1.0 /*mcf*/,
853                     printTag, false /*for_buffering*/);
854   else
855     _tree->makeTree(max_cap, test);
856 
857   return TCL_OK;
858 }
net_stats(std::list<int> & net_ids,const std::string & tcap,const std::string & ccap,const std::string & ratio_cap,const std::string & res,const std::string & len,const std::string & met_cnt,const std::string & wire_cnt,const std::string & via_cnt,const std::string & seg_cnt,const std::string & term_cnt,const std::string & bterm_cnt,const std::string & file,const std::string & bbox,const std::string & branch_len)859 bool Ext::net_stats(std::list<int>& net_ids, const std::string& tcap,
860                     const std::string& ccap, const std::string& ratio_cap,
861                     const std::string& res, const std::string& len,
862                     const std::string& met_cnt, const std::string& wire_cnt,
863                     const std::string& via_cnt, const std::string& seg_cnt,
864                     const std::string& term_cnt, const std::string& bterm_cnt,
865                     const std::string& file, const std::string& bbox,
866                     const std::string& branch_len) {
867   Ath__parser parser;
868   extNetStats limits;
869   limits.reset();
870 
871   limits.update_double(&parser, tcap.c_str(), limits._tcap);
872   limits.update_double(&parser, ccap.c_str(), limits._ccap);
873   limits.update_double(&parser, ratio_cap.c_str(), limits._cc2tcap);
874   limits.update_double(&parser, res.c_str(), limits._res);
875 
876   limits.update_int(&parser, len.c_str(), limits._len, 1000);
877   limits.update_int(&parser, met_cnt.c_str(), limits._layerCnt);
878   limits.update_int(&parser, wire_cnt.c_str(), limits._wCnt);
879   limits.update_int(&parser, via_cnt.c_str(), limits._vCnt);
880   limits.update_int(&parser, term_cnt.c_str(), limits._termCnt);
881   limits.update_int(&parser, bterm_cnt.c_str(), limits._btermCnt);
882   limits.update_bbox(&parser, bbox.c_str());
883 
884   FILE* fp = stdout;
885   const char* filename = file.c_str();
886   if (filename != NULL) {
887     fp = fopen(filename, "w");
888     if (fp == NULL) {
889       logger_->warn(RCX, 11, "Can't open file {}", filename);
890       return TCL_OK;
891     }
892   }
893   bool skipDb = false;
894   bool skipRC = false;
895   bool skipPower = true;
896 
897   odb::dbBlock* block = _ext->getBlock();
898   if (block == NULL) {
899     logger_->warn(RCX, 28, "There is no extracted block");
900     skipRC = true;
901     return TCL_OK;
902   }
903   std::list<int> list_of_nets;
904   int n = _ext->printNetStats(fp, block, &limits, skipRC, skipDb, skipPower,
905                               &list_of_nets);
906   logger_->info(RCX, 26, "{} nets found", n);
907 
908   net_ids = list_of_nets;
909 
910   return TCL_OK;
911 }
912 
913 }  // namespace rcx
914