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