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 "defout_impl.h"
34
35 #include <stdio.h>
36
37 #include <limits>
38 #include <set>
39 #include <string>
40
41 #include "db.h"
42 #include "dbMap.h"
43 #include "dbWireCodec.h"
44 #include "utl/Logger.h"
45 namespace odb {
46
47 template <typename T>
sortedSet(dbSet<T> & to_sort)48 static std::vector<T*> sortedSet(dbSet<T>& to_sort)
49 {
50 std::vector<T*> sorted(to_sort.begin(), to_sort.end());
51 std::sort(sorted.begin(), sorted.end(), [](T* a, T* b) {
52 return a->getName() < b->getName();
53 });
54 return sorted;
55 }
56
defOrient(dbOrientType orient)57 static const char* defOrient(dbOrientType orient)
58 {
59 switch (orient.getValue()) {
60 case dbOrientType::R0:
61 return "N";
62
63 case dbOrientType::R90:
64 return "W";
65
66 case dbOrientType::R180:
67 return "S";
68
69 case dbOrientType::R270:
70 return "E";
71
72 case dbOrientType::MY:
73 return "FN";
74
75 case dbOrientType::MYR90:
76 return "FE";
77
78 case dbOrientType::MX:
79 return "FS";
80
81 case dbOrientType::MXR90:
82 return "FW";
83 }
84
85 return "N";
86 }
87
defSigType(dbSigType type)88 static const char* defSigType(dbSigType type)
89 {
90 return type.getString();
91 }
defIoType(dbIoType type)92 static const char* defIoType(dbIoType type)
93 {
94 return type.getString();
95 }
96
selectNet(dbNet * net)97 void defout_impl::selectNet(dbNet* net)
98 {
99 if (!net)
100 return;
101 _select_net_list.push_back(net);
102 }
103
selectInst(dbInst * inst)104 void defout_impl::selectInst(dbInst* inst)
105 {
106 if (!inst)
107 return;
108 _select_inst_list.push_back(inst);
109 }
110
writeBlock(dbBlock * block,const char * def_file)111 bool defout_impl::writeBlock(dbBlock* block, const char* def_file)
112 {
113 if (!_select_net_list.empty()) {
114 _select_net_map = new dbMap<dbNet, char>(block->getNets());
115 std::list<dbNet*>::iterator sitr;
116 for (sitr = _select_net_list.begin(); sitr != _select_net_list.end();
117 ++sitr) {
118 dbNet* net = *sitr;
119 (*_select_net_map)[net] = 1;
120 if (net->isSpecial() || net->isMark_1ed())
121 continue;
122 if (!_select_inst_map)
123 _select_inst_map = new dbMap<dbInst, char>(block->getInsts());
124 dbSet<dbITerm> iterms = net->getITerms();
125 dbSet<dbITerm>::iterator titr;
126 for (titr = iterms.begin(); titr != iterms.end(); ++titr) {
127 dbInst* inst = (*titr)->getInst();
128 (*_select_inst_map)[inst] = 1;
129 }
130 }
131 }
132 if (!_select_inst_list.empty()) {
133 if (!_select_inst_map)
134 _select_inst_map = new dbMap<dbInst, char>(block->getInsts());
135 std::list<dbInst*>::iterator xitr;
136 for (xitr = _select_inst_list.begin(); xitr != _select_inst_list.end();
137 ++xitr) {
138 dbInst* inst = *xitr;
139 (*_select_inst_map)[inst] = 1;
140 }
141 }
142
143 _dist_factor
144 = (double) block->getDefUnits() / (double) block->getDbUnitsPerMicron();
145 _out = fopen(def_file, "w");
146
147 if (_out == NULL) {
148 _logger->warn(
149 utl::ODB, 172, "Cannot open DEF file ({}) for writing", def_file);
150 return false;
151 }
152
153 if (_version == defout::DEF_5_3) {
154 fprintf(_out, "VERSION 5.3 ;\n");
155 } else if (_version == defout::DEF_5_4) {
156 fprintf(_out, "VERSION 5.4 ;\n");
157 } else if (_version == defout::DEF_5_5) {
158 fprintf(_out, "VERSION 5.5 ;\n");
159 } else if (_version == defout::DEF_5_6) {
160 fprintf(_out, "VERSION 5.6 ;\n");
161 } else if (_version == defout::DEF_5_8) {
162 fprintf(_out, "VERSION 5.8 ;\n");
163 }
164 if (_version < defout::DEF_5_6) {
165 fprintf(_out, "NAMESCASESENSITIVE ON ;\n");
166 }
167 char hd = block->getHierarchyDelimeter();
168
169 if (hd == 0)
170 hd = '|';
171
172 fprintf(_out, "DIVIDERCHAR \"%c\" ;\n", hd);
173
174 char left_bus, right_bus;
175 block->getBusDelimeters(left_bus, right_bus);
176
177 if ((left_bus == 0) || (right_bus == 0)) {
178 left_bus = '[';
179 right_bus = ']';
180 }
181
182 fprintf(_out, "BUSBITCHARS \"%c%c\" ;\n", left_bus, right_bus);
183
184 std::string bname = block->getName();
185 fprintf(_out, "DESIGN %s ;\n", bname.c_str());
186
187 fprintf(_out, "UNITS DISTANCE MICRONS %d ;\n", block->getDefUnits());
188
189 writePropertyDefinitions(block);
190
191 Rect r;
192 block->getDieArea(r);
193
194 int x1 = defdist(r.xMin());
195 int y1 = defdist(r.yMin());
196 int x2 = defdist(r.xMax());
197 int y2 = defdist(r.yMax());
198
199 if ((x1 != 0) || (y1 != 0) || (x2 != 0) || (y2 != 0))
200 fprintf(_out, "DIEAREA ( %d %d ) ( %d %d ) ;\n", x1, y1, x2, y2);
201
202 writeRows(block);
203 writeTracks(block);
204 writeGCells(block);
205 writeVias(block);
206 writeNonDefaultRules(block);
207 writeRegions(block);
208 writeInsts(block);
209 writeBTerms(block);
210 writePinProperties(block);
211 writeBlockages(block);
212 writeFills(block);
213 writeNets(block);
214 writeGroups(block);
215
216 fprintf(_out, "END DESIGN\n");
217 fclose(_out);
218 if (_select_net_map)
219 delete _select_net_map;
220 if (_select_inst_map)
221 delete _select_inst_map;
222 return true;
223 }
224
writeRows(dbBlock * block)225 void defout_impl::writeRows(dbBlock* block)
226 {
227 dbSet<dbRow> rows = block->getRows();
228 dbSet<dbRow>::iterator itr;
229
230 for (itr = rows.begin(); itr != rows.end(); ++itr) {
231 dbRow* row = *itr;
232 int x, y;
233 std::string n = row->getName();
234 row->getOrigin(x, y);
235 int s = row->getSpacing();
236 int c = row->getSiteCount();
237 dbSite* site = row->getSite();
238 std::string sn = site->getName();
239 const char* o = defOrient(row->getOrient());
240
241 fprintf(_out,
242 "ROW %s %s %d %d %s ",
243 n.c_str(),
244 sn.c_str(),
245 defdist(x),
246 defdist(y),
247 o);
248
249 if (row->getDirection() == dbRowDir::VERTICAL)
250 fprintf(_out, "DO 1 BY %d STEP 0 %d", c, defdist(s));
251 else
252 fprintf(_out, "DO %d BY 1 STEP %d 0", c, defdist(s));
253
254 if (hasProperties(row, ROW)) {
255 fprintf(_out, " + PROPERTY ");
256 writeProperties(row);
257 }
258
259 fprintf(_out, " ;\n");
260 }
261 }
262
writeTracks(dbBlock * block)263 void defout_impl::writeTracks(dbBlock* block)
264 {
265 dbSet<dbTrackGrid> grids = block->getTrackGrids();
266 dbSet<dbTrackGrid>::iterator itr;
267
268 for (itr = grids.begin(); itr != grids.end(); ++itr) {
269 dbTrackGrid* grid = *itr;
270 dbTechLayer* layer = grid->getTechLayer();
271
272 std::string lname;
273 if (_use_alias && layer->hasAlias())
274 lname = layer->getAlias();
275 else
276 lname = layer->getName();
277
278 for (int i = 0; i < grid->getNumGridPatternsX(); ++i) {
279 int orgX, count, step;
280 grid->getGridPatternX(i, orgX, count, step);
281 fprintf(_out,
282 "TRACKS X %d DO %d STEP %d LAYER %s ;\n",
283 defdist(orgX),
284 count,
285 defdist(step),
286 lname.c_str());
287 }
288
289 for (int i = 0; i < grid->getNumGridPatternsY(); ++i) {
290 int orgY, count, step;
291 grid->getGridPatternY(i, orgY, count, step);
292 fprintf(_out,
293 "TRACKS Y %d DO %d STEP %d LAYER %s ;\n",
294 defdist(orgY),
295 count,
296 defdist(step),
297 lname.c_str());
298 }
299 }
300 }
301
writeGCells(dbBlock * block)302 void defout_impl::writeGCells(dbBlock* block)
303 {
304 dbGCellGrid* grid = block->getGCellGrid();
305
306 if (grid == NULL)
307 return;
308
309 int i;
310
311 for (i = 0; i < grid->getNumGridPatternsX(); ++i) {
312 int orgX, count, step;
313 grid->getGridPatternX(i, orgX, count, step);
314 fprintf(_out,
315 "GCELLGRID X %d DO %d STEP %d ;\n",
316 defdist(orgX),
317 count,
318 defdist(step));
319 }
320
321 for (i = 0; i < grid->getNumGridPatternsY(); ++i) {
322 int orgY, count, step;
323 grid->getGridPatternY(i, orgY, count, step);
324 fprintf(_out,
325 "GCELLGRID Y %d DO %d STEP %d ;\n",
326 defdist(orgY),
327 count,
328 defdist(step));
329 }
330 }
331
writeVias(dbBlock * block)332 void defout_impl::writeVias(dbBlock* block)
333 {
334 dbSet<dbVia> vias = block->getVias();
335
336 if (vias.size() == 0)
337 return;
338
339 dbSet<dbVia>::iterator itr;
340 uint cnt = 0;
341
342 for (itr = vias.begin(); itr != vias.end(); ++itr) {
343 dbVia* via = *itr;
344
345 if ((_version >= defout::DEF_5_6) && via->isViaRotated())
346 continue;
347
348 ++cnt;
349 }
350
351 fprintf(_out, "VIAS %u ;\n", cnt);
352
353 for (itr = vias.begin(); itr != vias.end(); ++itr) {
354 dbVia* via = *itr;
355
356 if ((_version >= defout::DEF_5_6) && via->isViaRotated())
357 continue;
358
359 writeVia(via);
360 }
361
362 fprintf(_out, "END VIAS\n");
363 }
364
writeVia(dbVia * via)365 void defout_impl::writeVia(dbVia* via)
366 {
367 std::string vname = via->getName();
368 fprintf(_out, " - %s", vname.c_str());
369 dbTechViaGenerateRule* rule = via->getViaGenerateRule();
370
371 if ((_version >= defout::DEF_5_6) && via->hasParams() && (rule != NULL)) {
372 std::string rname = rule->getName();
373 fprintf(_out, " + VIARULE %s", rname.c_str());
374
375 dbViaParams P;
376 via->getViaParams(P);
377
378 fprintf(_out,
379 " + CUTSIZE %d %d ",
380 defdist(P.getXCutSize()),
381 defdist(P.getYCutSize()));
382 std::string top = P.getTopLayer()->getName();
383 std::string bot = P.getBottomLayer()->getName();
384 std::string cut = P.getCutLayer()->getName();
385 fprintf(_out, " + LAYERS %s %s %s ", bot.c_str(), cut.c_str(), top.c_str());
386 fprintf(_out,
387 " + CUTSPACING %d %d ",
388 defdist(P.getXCutSpacing()),
389 defdist(P.getYCutSpacing()));
390 fprintf(_out,
391 " + ENCLOSURE %d %d %d %d ",
392 defdist(P.getXBottomEnclosure()),
393 defdist(P.getYBottomEnclosure()),
394 defdist(P.getXTopEnclosure()),
395 defdist(P.getYTopEnclosure()));
396
397 if ((P.getNumCutRows() != 1) || (P.getNumCutCols() != 1))
398 fprintf(_out, " + ROWCOL %d %d ", P.getNumCutRows(), P.getNumCutCols());
399
400 if ((P.getXOrigin() != 0) || (P.getYOrigin() != 0))
401 fprintf(_out,
402 " + ORIGIN %d %d ",
403 defdist(P.getXOrigin()),
404 defdist(P.getYOrigin()));
405
406 if ((P.getXTopOffset() != 0) || (P.getYTopOffset() != 0)
407 || (P.getXBottomOffset() != 0) || (P.getYBottomOffset() != 0))
408 fprintf(_out,
409 " + OFFSET %d %d %d %d ",
410 defdist(P.getXBottomOffset()),
411 defdist(P.getYBottomOffset()),
412 defdist(P.getXTopOffset()),
413 defdist(P.getYTopOffset()));
414
415 std::string pname = via->getPattern();
416 if (strcmp(pname.c_str(), "") != 0)
417 fprintf(_out, " + PATTERNNAME %s", pname.c_str());
418 } else {
419 std::string pname = via->getPattern();
420 if (strcmp(pname.c_str(), "") != 0)
421 fprintf(_out, " + PATTERNNAME %s", pname.c_str());
422
423 int i = 0;
424 dbSet<dbBox> boxes = via->getBoxes();
425 dbSet<dbBox>::iterator bitr;
426
427 for (bitr = boxes.begin(); bitr != boxes.end(); ++bitr) {
428 dbBox* box = *bitr;
429 dbTechLayer* layer = box->getTechLayer();
430 std::string lname;
431 if (_use_alias && layer->hasAlias())
432 lname = layer->getAlias();
433 else
434 lname = layer->getName();
435 int x1 = defdist(box->xMin());
436 int y1 = defdist(box->yMin());
437 int x2 = defdist(box->xMax());
438 int y2 = defdist(box->yMax());
439
440 if ((++i & 7) == 0)
441 fprintf(_out, "\n ");
442
443 fprintf(_out,
444 " + RECT %s ( %d %d ) ( %d %d )",
445 lname.c_str(),
446 x1,
447 y1,
448 x2,
449 y2);
450 }
451 }
452
453 fprintf(_out, " ;\n");
454 }
455
writeInsts(dbBlock * block)456 void defout_impl::writeInsts(dbBlock* block)
457 {
458 dbSet<dbInst> insts = block->getInsts();
459
460 fprintf(_out, "COMPONENTS %u ;\n", insts.size());
461
462 // Sort the components for consistent output
463 for (dbInst* inst : sortedSet(insts)) {
464 if (_select_inst_map && !(*_select_inst_map)[inst])
465 continue;
466 writeInst(inst);
467 }
468
469 fprintf(_out, "END COMPONENTS\n");
470 }
471
writeNonDefaultRules(dbBlock * block)472 void defout_impl::writeNonDefaultRules(dbBlock* block)
473 {
474 dbSet<dbTechNonDefaultRule> rules = block->getNonDefaultRules();
475
476 if (rules.empty())
477 return;
478
479 fprintf(_out, "NONDEFAULTRULES %u ;\n", rules.size());
480
481 dbSet<dbTechNonDefaultRule>::iterator itr;
482
483 for (itr = rules.begin(); itr != rules.end(); ++itr) {
484 dbTechNonDefaultRule* rule = *itr;
485 writeNonDefaultRule(rule);
486 }
487
488 fprintf(_out, "END NONDEFAULTRULES\n");
489 }
490
writeNonDefaultRule(dbTechNonDefaultRule * rule)491 void defout_impl::writeNonDefaultRule(dbTechNonDefaultRule* rule)
492 {
493 std::string name = rule->getName();
494 fprintf(_out, " - %s\n", name.c_str());
495
496 if (rule->getHardSpacing())
497 fprintf(_out, " + HARDSPACING\n");
498
499 std::vector<dbTechLayerRule*> layer_rules;
500 rule->getLayerRules(layer_rules);
501
502 std::vector<dbTechLayerRule*>::iterator litr;
503 for (litr = layer_rules.begin(); litr != layer_rules.end(); ++litr)
504 writeLayerRule(*litr);
505
506 std::vector<dbTechVia*> use_vias;
507 rule->getUseVias(use_vias);
508
509 std::vector<dbTechVia*>::iterator uvitr;
510 for (uvitr = use_vias.begin(); uvitr != use_vias.end(); ++uvitr) {
511 dbTechVia* via = *uvitr;
512 std::string vname = via->getName();
513 fprintf(_out, " + VIA %s\n", vname.c_str());
514 }
515
516 std::vector<dbTechViaGenerateRule*> use_rules;
517 rule->getUseViaRules(use_rules);
518
519 std::vector<dbTechViaGenerateRule*>::iterator uvritr;
520 for (uvritr = use_rules.begin(); uvritr != use_rules.end(); ++uvritr) {
521 dbTechViaGenerateRule* rule = *uvritr;
522 std::string rname = rule->getName();
523 fprintf(_out, " + VIARULE %s\n", rname.c_str());
524 }
525
526 dbTech* tech = rule->getDb()->getTech();
527 dbSet<dbTechLayer> layers = tech->getLayers();
528 dbSet<dbTechLayer>::iterator layitr;
529
530 for (layitr = layers.begin(); layitr != layers.end(); ++layitr) {
531 dbTechLayer* layer = *layitr;
532 int count;
533
534 if (rule->getMinCuts(layer, count)) {
535 std::string lname = layer->getName();
536 fprintf(_out, " + MINCUTS %s %d\n", lname.c_str(), count);
537 }
538 }
539
540 if (hasProperties(rule, NONDEFAULTRULE)) {
541 fprintf(_out, " + PROPERTY ");
542 writeProperties(rule);
543 }
544
545 fprintf(_out, " ;\n");
546 }
547
writeLayerRule(dbTechLayerRule * rule)548 void defout_impl::writeLayerRule(dbTechLayerRule* rule)
549 {
550 dbTechLayer* layer = rule->getLayer();
551 std::string name = layer->getName();
552
553 fprintf(_out, " + LAYER %s", name.c_str());
554
555 fprintf(_out, " WIDTH %d", defdist(rule->getWidth()));
556
557 if (rule->getSpacing())
558 fprintf(_out, " SPACING %d", defdist(rule->getSpacing()));
559
560 if (rule->getWireExtension() != 0.0)
561 fprintf(_out, " WIREEXTENSION %d", defdist(rule->getWireExtension()));
562
563 fprintf(_out, "\n");
564 }
565
writeInst(dbInst * inst)566 void defout_impl::writeInst(dbInst* inst)
567 {
568 dbMaster* master = inst->getMaster();
569 std::string mname = master->getName();
570
571 if (_use_net_inst_ids) {
572 if (_use_master_ids)
573 fprintf(_out, " - I%u M%u", inst->getId(), master->getMasterId());
574 else
575 fprintf(_out, " - I%u %s", inst->getId(), mname.c_str());
576 } else {
577 std::string iname = inst->getName();
578 if (_use_master_ids)
579 fprintf(_out, " - %s M%u", iname.c_str(), master->getMasterId());
580 else
581 fprintf(_out, " - %s %s", iname.c_str(), mname.c_str());
582 }
583
584 dbSourceType source = inst->getSourceType();
585
586 switch (source.getValue()) {
587 case dbSourceType::NONE:
588 break;
589
590 case dbSourceType::NETLIST:
591 fprintf(_out, " + SOURCE NETLIST");
592 break;
593
594 case dbSourceType::DIST:
595 fprintf(_out, " + SOURCE DIST");
596 break;
597
598 case dbSourceType::USER:
599 fprintf(_out, " + SOURCE USER");
600 break;
601
602 case dbSourceType::TIMING:
603 fprintf(_out, " + SOURCE TIMING");
604 break;
605
606 case dbSourceType::TEST:
607 break;
608 }
609
610 int x, y;
611 inst->getLocation(x, y);
612 x = defdist(x);
613 y = defdist(y);
614
615 const char* orient = defOrient(inst->getOrient());
616 dbPlacementStatus status = inst->getPlacementStatus();
617
618 switch (status.getValue()) {
619 case dbPlacementStatus::NONE:
620 break;
621
622 case dbPlacementStatus::UNPLACED: {
623 fprintf(_out, " + UNPLACED");
624 break;
625 }
626
627 case dbPlacementStatus::SUGGESTED:
628 case dbPlacementStatus::PLACED: {
629 fprintf(_out, " + PLACED ( %d %d ) %s", x, y, orient);
630 break;
631 }
632
633 case dbPlacementStatus::LOCKED:
634 case dbPlacementStatus::FIRM: {
635 fprintf(_out, " + FIXED ( %d %d ) %s", x, y, orient);
636 break;
637 }
638
639 case dbPlacementStatus::COVER: {
640 fprintf(_out, " + COVER ( %d %d ) %s", x, y, orient);
641 break;
642 }
643 }
644
645 if (inst->getWeight() != 0)
646 fprintf(_out, " + WEIGHT %d", inst->getWeight());
647
648 dbRegion* region = inst->getRegion();
649
650 if (region) {
651 if (!region->getBoundaries().empty()) {
652 std::string rname = region->getName();
653 fprintf(_out, " + REGION %s", rname.c_str());
654 }
655 }
656
657 if (hasProperties(inst, COMPONENT)) {
658 fprintf(_out, " + PROPERTY ");
659 writeProperties(inst);
660 }
661
662 if (_version >= defout::DEF_5_6) {
663 dbBox* box = inst->getHalo();
664
665 if (box) {
666 int left = defdist(box->xMin());
667 int bottom = defdist(box->yMin());
668 int right = defdist(box->xMax());
669 int top = defdist(box->yMax());
670
671 fprintf(_out, " + HALO %d %d %d %d", left, bottom, right, top);
672 }
673 }
674
675 fprintf(_out, " ;\n");
676 }
677
writeBTerms(dbBlock * block)678 void defout_impl::writeBTerms(dbBlock* block)
679 {
680 dbSet<dbBTerm> bterms = block->getBTerms();
681
682 if (bterms.size() == 0)
683 return;
684
685 uint n = 0;
686
687 dbSet<dbBTerm>::iterator itr;
688
689 for (itr = bterms.begin(); itr != bterms.end(); ++itr) {
690 dbBTerm* bterm = *itr;
691 dbNet* net = bterm->getNet();
692
693 if (net && _select_net_map && !(*_select_net_map)[net])
694 continue;
695
696 dbSet<dbBPin> bpins = bterm->getBPins();
697 uint pcnt = bpins.size();
698
699 if (pcnt == 0)
700 n += 1;
701 else
702 n += pcnt;
703 }
704
705 fprintf(_out, "PINS %u ;\n", n);
706
707 for (dbBTerm* bterm : sortedSet(bterms)) {
708 dbNet* net = bterm->getNet();
709 if (net && _select_net_map && !(*_select_net_map)[net])
710 continue;
711 writeBTerm(bterm);
712 }
713
714 fprintf(_out, "END PINS\n");
715 }
716
writeRegions(dbBlock * block)717 void defout_impl::writeRegions(dbBlock* block)
718 {
719 dbSet<dbRegion> regions = block->getRegions();
720
721 uint cnt = 0;
722 dbSet<dbRegion>::iterator itr;
723
724 for (itr = regions.begin(); itr != regions.end(); ++itr) {
725 dbRegion* region = *itr;
726
727 dbSet<dbBox> boxes = region->getBoundaries();
728
729 if (!boxes.empty())
730 ++cnt;
731 }
732
733 if (cnt == 0)
734 return;
735
736 fprintf(_out, "REGIONS %u ;\n", cnt);
737
738 for (itr = regions.begin(); itr != regions.end(); ++itr) {
739 dbRegion* region = *itr;
740
741 dbSet<dbBox> boxes = region->getBoundaries();
742
743 if (boxes.empty())
744 continue;
745
746 std::string name = region->getName();
747 fprintf(_out, " - %s", name.c_str());
748
749 dbSet<dbBox>::iterator bitr;
750 int cnt = 0;
751
752 for (bitr = boxes.begin(); bitr != boxes.end(); ++bitr, ++cnt) {
753 dbBox* box = *bitr;
754
755 if ((cnt & 0x3) == 0x3)
756 fprintf(_out, "\n ");
757
758 fprintf(_out,
759 " ( %d %d ) ( %d %d )",
760 defdist(box->xMin()),
761 defdist(box->yMin()),
762 defdist(box->xMax()),
763 defdist(box->yMax()));
764 }
765
766 switch ((dbRegionType::Value) region->getRegionType()) {
767 case dbRegionType::INCLUSIVE:
768 break;
769
770 case dbRegionType::EXCLUSIVE:
771 fprintf(_out, " + TYPE FENCE");
772 break;
773
774 case dbRegionType::SUGGESTED:
775 fprintf(_out, " + TYPE GUIDE");
776 break;
777 }
778
779 if (hasProperties(region, REGION)) {
780 fprintf(_out, " + PROPERTY ");
781 writeProperties(region);
782 }
783
784 fprintf(_out, " ;\n");
785 }
786
787 fprintf(_out, "END REGIONS\n");
788 }
789
writeGroups(dbBlock * block)790 void defout_impl::writeGroups(dbBlock* block)
791 {
792 dbSet<dbRegion> regions = block->getRegions();
793
794 uint cnt = 0;
795 dbSet<dbRegion>::iterator itr;
796
797 for (itr = regions.begin(); itr != regions.end(); ++itr) {
798 dbRegion* region = *itr;
799
800 dbSet<dbBox> boxes = region->getBoundaries();
801
802 if (boxes.empty())
803 ++cnt;
804 }
805
806 if (cnt == 0)
807 return;
808
809 fprintf(_out, "GROUPS %u ;\n", cnt);
810
811 for (itr = regions.begin(); itr != regions.end(); ++itr) {
812 dbRegion* region = *itr;
813
814 dbSet<dbBox> boxes = region->getBoundaries();
815
816 if (!boxes.empty())
817 continue;
818
819 std::string name = region->getName();
820 fprintf(_out, " - %s", name.c_str());
821
822 dbSet<dbInst> insts = region->getRegionInsts();
823 dbSet<dbInst>::iterator iitr;
824 cnt = 0;
825
826 for (iitr = insts.begin(); iitr != insts.end(); ++iitr, ++cnt) {
827 dbInst* inst = *iitr;
828
829 if ((cnt & 0x3) == 0x3)
830 fprintf(_out, "\n ");
831
832 std::string name = inst->getName();
833
834 fprintf(_out, " %s", name.c_str());
835 }
836
837 dbRegion* parent = region->getParent();
838
839 // The semantic is: if the parent region has boundaries then it is a DEF
840 // region.
841 if (parent) {
842 dbSet<dbBox> rboxes = parent->getBoundaries();
843
844 if (!rboxes.empty()) {
845 std::string rname = parent->getName();
846 fprintf(_out, " + REGION %s", rname.c_str());
847 }
848 }
849
850 if (hasProperties(region, GROUP)) {
851 fprintf(_out, " + PROPERTY ");
852 writeProperties(region);
853 }
854
855 fprintf(_out, " ;\n");
856 }
857
858 fprintf(_out, "END GROUPS\n");
859 }
860
writeBTerm(dbBTerm * bterm)861 void defout_impl::writeBTerm(dbBTerm* bterm)
862 {
863 dbNet* net = bterm->getNet();
864 if (net) {
865 dbSet<dbBPin> bpins = bterm->getBPins();
866
867 if (bpins.size() != 0) {
868 int cnt = 0;
869
870 dbSet<dbBPin>::iterator itr;
871
872 for (itr = bpins.begin(); itr != bpins.end(); ++itr)
873 writeBPin(*itr, cnt++);
874
875 fprintf(_out, " ;\n");
876
877 return;
878 }
879
880 std::string bname = bterm->getName();
881
882 if (_use_net_inst_ids)
883 fprintf(_out, " - %s + NET N%u", bname.c_str(), net->getId());
884 else {
885 std::string nname = net->getName();
886 fprintf(_out, " - %s + NET %s", bname.c_str(), nname.c_str());
887 }
888
889 if (bterm->isSpecial())
890 fprintf(_out, " + SPECIAL");
891
892 fprintf(_out, " + DIRECTION %s", defIoType(bterm->getIoType()));
893
894 if (_version >= defout::DEF_5_6) {
895 dbBTerm* supply = bterm->getSupplyPin();
896
897 if (supply) {
898 std::string pname = supply->getName();
899 fprintf(_out, " + SUPPLYSENSITIVITY %s", pname.c_str());
900 }
901
902 dbBTerm* ground = bterm->getGroundPin();
903
904 if (ground) {
905 std::string pname = ground->getName();
906 fprintf(_out, " + GROUNDSENSITIVITY %s", pname.c_str());
907 }
908 }
909
910 const char* sig_type = defSigType(bterm->getSigType());
911 fprintf(_out, " + USE %s", sig_type);
912
913 fprintf(_out, " ;\n");
914 } else
915 _logger->warn(utl::ODB,
916 173,
917 "warning: pin {} skipped because it has no net",
918 bterm->getConstName());
919 }
920
writeBPin(dbBPin * bpin,int cnt)921 void defout_impl::writeBPin(dbBPin* bpin, int cnt)
922 {
923 dbBTerm* bterm = bpin->getBTerm();
924 dbNet* net = bterm->getNet();
925 std::string bname = bterm->getName();
926
927 if (cnt == 0 || _version <= defout::DEF_5_6) {
928 if (_use_net_inst_ids) {
929 if (cnt == 0)
930 fprintf(_out, " - %s + NET N%u", bname.c_str(), net->getId());
931 else
932 fprintf(_out,
933 " - %s.extra%d + NET N%u",
934 bname.c_str(),
935 cnt,
936 net->getId());
937 } else {
938 std::string nname = net->getName();
939 if (cnt == 0)
940 fprintf(_out, " - %s + NET %s", bname.c_str(), nname.c_str());
941 else
942 fprintf(_out,
943 " - %s.extra%d + NET %s",
944 bname.c_str(),
945 cnt,
946 nname.c_str());
947 }
948
949 if (bterm->isSpecial())
950 fprintf(_out, " + SPECIAL");
951
952 fprintf(_out, " + DIRECTION %s", defIoType(bterm->getIoType()));
953
954 if (_version >= defout::DEF_5_6) {
955 dbBTerm* supply = bterm->getSupplyPin();
956
957 if (supply) {
958 std::string pname = supply->getName();
959 fprintf(_out, " + SUPPLYSENSITIVITY %s", pname.c_str());
960 }
961
962 dbBTerm* ground = bterm->getGroundPin();
963
964 if (ground) {
965 std::string pname = ground->getName();
966 fprintf(_out, " + GROUNDSENSITIVITY %s", pname.c_str());
967 }
968 }
969
970 fprintf(_out, " + USE %s", defSigType(bterm->getSigType()));
971 }
972
973 fprintf(_out, "\n ");
974
975 if (_version > defout::DEF_5_6)
976 fprintf(_out, "+ PORT");
977
978 bool isFirst = 1;
979 int dw, dh, x = 0, y = 0;
980 int xMin, yMin, xMax, yMax;
981
982 for (dbBox* box : bpin->getBoxes()) {
983 dw = defdist(int(box->getDX() / 2));
984 dh = defdist(int(box->getDY() / 2));
985
986 if (isFirst) {
987 isFirst = 0;
988 x = defdist(box->xMin()) + dw;
989 y = defdist(box->yMin()) + dh;
990 }
991
992 xMin = defdist(box->xMin()) - x;
993 yMin = defdist(box->yMin()) - y;
994 xMax = defdist(box->xMax()) - x;
995 yMax = defdist(box->yMax()) - y;
996 dbTechLayer* layer = box->getTechLayer();
997 std::string lname;
998
999 if (_use_alias && layer->hasAlias())
1000 lname = layer->getAlias();
1001 else
1002 lname = layer->getName();
1003
1004 fprintf(_out, "\n ");
1005 if (_version == defout::DEF_5_5)
1006 fprintf(_out,
1007 " + LAYER %s ( %d %d ) ( %d %d )",
1008 lname.c_str(),
1009 xMin,
1010 yMin,
1011 xMax,
1012 yMax);
1013 else {
1014 if (bpin->hasEffectiveWidth()) {
1015 int w = defdist(bpin->getEffectiveWidth());
1016 fprintf(_out,
1017 " + LAYER %s DESIGNRULEWIDTH %d ( %d %d ) ( %d %d )",
1018 lname.c_str(),
1019 w,
1020 xMin,
1021 yMin,
1022 xMax,
1023 yMax);
1024 } else if (bpin->hasMinSpacing()) {
1025 int s = defdist(bpin->getMinSpacing());
1026 fprintf(_out,
1027 " + LAYER %s SPACING %d ( %d %d ) ( %d %d )",
1028 lname.c_str(),
1029 s,
1030 xMin,
1031 yMin,
1032 xMax,
1033 yMax);
1034 } else {
1035 fprintf(_out,
1036 " + LAYER %s ( %d %d ) ( %d %d )",
1037 lname.c_str(),
1038 xMin,
1039 yMin,
1040 xMax,
1041 yMax);
1042 }
1043 }
1044 }
1045
1046 dbPlacementStatus status = bpin->getPlacementStatus();
1047
1048 switch (status.getValue()) {
1049 case dbPlacementStatus::NONE:
1050 case dbPlacementStatus::UNPLACED:
1051 break;
1052
1053 case dbPlacementStatus::SUGGESTED:
1054 case dbPlacementStatus::PLACED: {
1055 fprintf(_out, "\n + PLACED ( %d %d ) N", x, y);
1056 break;
1057 }
1058
1059 case dbPlacementStatus::LOCKED:
1060 case dbPlacementStatus::FIRM: {
1061 fprintf(_out, "\n + FIXED ( %d %d ) N", x, y);
1062 break;
1063 }
1064
1065 case dbPlacementStatus::COVER: {
1066 fprintf(_out, "\n + COVER ( %d %d ) N", x, y);
1067 break;
1068 }
1069 }
1070 }
1071
writeBlockages(dbBlock * block)1072 void defout_impl::writeBlockages(dbBlock* block)
1073 {
1074 dbSet<dbObstruction> obstructions = block->getObstructions();
1075 dbSet<dbBlockage> blockages = block->getBlockages();
1076
1077 int bcnt = obstructions.size() + blockages.size();
1078
1079 if (bcnt == 0)
1080 return;
1081
1082 bool first = true;
1083
1084 dbSet<dbObstruction>::iterator obs_itr;
1085
1086 for (obs_itr = obstructions.begin(); obs_itr != obstructions.end();
1087 ++obs_itr) {
1088 dbObstruction* obs = *obs_itr;
1089 dbInst* inst = obs->getInstance();
1090 if (inst && _select_inst_map && !(*_select_inst_map)[inst])
1091 continue;
1092
1093 if (first) {
1094 first = false;
1095 fprintf(_out, "BLOCKAGES %d ;\n", bcnt);
1096 }
1097
1098 dbBox* bbox = obs->getBBox();
1099 dbTechLayer* layer = bbox->getTechLayer();
1100 std::string lname;
1101 if (_use_alias && layer->hasAlias())
1102 lname = layer->getAlias();
1103 else
1104 lname = layer->getName();
1105
1106 fprintf(_out, " - LAYER %s", lname.c_str());
1107
1108 if (inst) {
1109 if (_use_net_inst_ids)
1110 fprintf(_out, " + COMPONENT I%u", inst->getId());
1111 else {
1112 std::string iname = inst->getName();
1113 fprintf(_out, " + COMPONENT %s", iname.c_str());
1114 }
1115 }
1116
1117 if (obs->isSlotObstruction())
1118 fprintf(_out, " + SLOTS");
1119
1120 if (obs->isFillObstruction())
1121 fprintf(_out, " + FILLS");
1122
1123 if (obs->isPushedDown())
1124 fprintf(_out, " + PUSHDOWN");
1125
1126 if (_version >= defout::DEF_5_6) {
1127 if (obs->hasEffectiveWidth()) {
1128 int w = defdist(obs->getEffectiveWidth());
1129 fprintf(_out, " + DESIGNRULEWIDTH %d", w);
1130 } else if (obs->hasMinSpacing()) {
1131 int s = defdist(obs->getMinSpacing());
1132 fprintf(_out, " + SPACING %d", s);
1133 }
1134 }
1135
1136 int x1 = defdist(bbox->xMin());
1137 int y1 = defdist(bbox->yMin());
1138 int x2 = defdist(bbox->xMax());
1139 int y2 = defdist(bbox->yMax());
1140
1141 fprintf(_out, " RECT ( %d %d ) ( %d %d ) ;\n", x1, y1, x2, y2);
1142 }
1143
1144 dbSet<dbBlockage>::iterator blk_itr;
1145
1146 for (blk_itr = blockages.begin(); blk_itr != blockages.end(); ++blk_itr) {
1147 dbBlockage* blk = *blk_itr;
1148 dbInst* inst = blk->getInstance();
1149 if (inst && _select_inst_map && !(*_select_inst_map)[inst])
1150 continue;
1151
1152 if (first) {
1153 first = false;
1154 fprintf(_out, "BLOCKAGES %d ;\n", bcnt);
1155 }
1156
1157 fprintf(_out, " - PLACEMENT");
1158
1159 if (blk->isSoft())
1160 fprintf(_out, " + SOFT");
1161
1162 if (blk->getMaxDensity() > 0)
1163 fprintf(_out, " + PARTIAL %f", blk->getMaxDensity());
1164
1165 if (inst) {
1166 if (_use_net_inst_ids)
1167 fprintf(_out, " + COMPONENT I%u", inst->getId());
1168 else {
1169 std::string iname = inst->getName();
1170 fprintf(_out, " + COMPONENT %s", iname.c_str());
1171 }
1172 }
1173
1174 if (blk->isPushedDown())
1175 fprintf(_out, " + PUSHDOWN");
1176
1177 dbBox* bbox = blk->getBBox();
1178 int x1 = defdist(bbox->xMin());
1179 int y1 = defdist(bbox->yMin());
1180 int x2 = defdist(bbox->xMax());
1181 int y2 = defdist(bbox->yMax());
1182
1183 fprintf(_out, " RECT ( %d %d ) ( %d %d ) ;\n", x1, y1, x2, y2);
1184 }
1185
1186 if (!first)
1187 fprintf(_out, "END BLOCKAGES\n");
1188 }
1189
writeFills(dbBlock * block)1190 void defout_impl::writeFills(dbBlock* block)
1191 {
1192 dbSet<dbFill> fills = block->getFills();
1193 int num_fills = fills.size();
1194
1195 if (num_fills == 0)
1196 return;
1197
1198 fprintf(_out, "FILLS %d ;\n", num_fills);
1199
1200 for (dbFill* fill : fills) {
1201 fprintf(_out, " - LAYER %s", fill->getTechLayer()->getName().c_str());
1202
1203 uint mask = fill->maskNumber();
1204 if (mask != 0)
1205 fprintf(_out, " + MASK %u", mask);
1206
1207 if (fill->needsOPC())
1208 fprintf(_out, " + OPC");
1209
1210 Rect r;
1211 fill->getRect(r);
1212
1213 int x1 = defdist(r.xMin());
1214 int y1 = defdist(r.yMin());
1215 int x2 = defdist(r.xMax());
1216 int y2 = defdist(r.yMax());
1217
1218 fprintf(_out, " RECT ( %d %d ) ( %d %d ) ;\n", x1, y1, x2, y2);
1219 }
1220
1221 fprintf(_out, "END FILLS\n");
1222 }
1223
writeNets(dbBlock * block)1224 void defout_impl::writeNets(dbBlock* block)
1225 {
1226 dbSet<dbNet> nets = block->getNets();
1227
1228 int net_cnt = 0;
1229 int snet_cnt = 0;
1230
1231 dbSet<dbNet>::iterator itr;
1232 dbMap<dbNet, char> regular_net(nets);
1233
1234 auto sorted_nets = sortedSet(nets);
1235
1236 for (dbNet* net : sorted_nets) {
1237 if (_select_net_map) {
1238 if (!(*_select_net_map)[net])
1239 continue;
1240 }
1241
1242 if (!net->isSpecial()) {
1243 regular_net[net] = 1;
1244 net_cnt++;
1245 } else {
1246 regular_net[net] = 0;
1247 snet_cnt++;
1248
1249 // Check for non-special iterms.
1250 for (dbITerm* iterm : net->getITerms()) {
1251 if (!iterm->isSpecial()) {
1252 regular_net[net] = 1;
1253 net_cnt++;
1254 break;
1255 }
1256 }
1257 }
1258 }
1259
1260 if (snet_cnt > 0) {
1261 fprintf(_out, "SPECIALNETS %d ;\n", snet_cnt);
1262
1263 for (dbNet* net : sorted_nets) {
1264 if (_select_net_map && !(*_select_net_map)[net])
1265 continue;
1266 if (net->isSpecial())
1267 writeSNet(net);
1268 }
1269
1270 fprintf(_out, "END SPECIALNETS\n");
1271 }
1272
1273 fprintf(_out, "NETS %d ;\n", net_cnt);
1274
1275 for (dbNet* net : sorted_nets) {
1276 if (_select_net_map && !(*_select_net_map)[net])
1277 continue;
1278
1279 if (regular_net[net] == 1)
1280 writeNet(net);
1281 }
1282
1283 fprintf(_out, "END NETS\n");
1284 }
1285
writeSNet(dbNet * net)1286 void defout_impl::writeSNet(dbNet* net)
1287 {
1288 dbSet<dbITerm> iterms = net->getITerms();
1289
1290 if (_use_net_inst_ids)
1291 fprintf(_out, " - N%u", net->getId());
1292 else {
1293 std::string nname = net->getName();
1294 fprintf(_out, " - %s", nname.c_str());
1295 }
1296
1297 int i = 0;
1298
1299 for (dbBTerm* bterm : net->getBTerms()) {
1300 if ((++i & 7) == 0) {
1301 fprintf(_out, "\n ");
1302 }
1303 fprintf(_out, " ( PIN %s )", bterm->getName().c_str());
1304 }
1305
1306 char ttname[dbObject::max_name_length];
1307 dbSet<dbITerm>::iterator iterm_itr;
1308 std::set<std::string> wild_names;
1309 for (iterm_itr = iterms.begin(); iterm_itr != iterms.end(); ++iterm_itr) {
1310 dbITerm* iterm = *iterm_itr;
1311
1312 if (!iterm->isSpecial())
1313 continue;
1314
1315 dbInst* inst = iterm->getInst();
1316 dbMTerm* mterm = iterm->getMTerm();
1317 // std::string mtname = mterm->getName();
1318 char* mtname = mterm->getName(inst, &ttname[0]);
1319 if (net->isWildConnected()) {
1320 if (wild_names.find(mtname) == wild_names.end()) {
1321 fprintf(_out, " ( * %s )", mtname);
1322 ++i;
1323 wild_names.insert(mtname);
1324 }
1325 } else {
1326 if ((++i & 7) == 0) {
1327 if (_use_net_inst_ids)
1328 fprintf(_out, "\n ( I%u %s )", inst->getId(), mtname);
1329 else {
1330 std::string iname = inst->getName();
1331 fprintf(_out, "\n ( %s %s )", iname.c_str(), mtname);
1332 }
1333 } else {
1334 if (_use_net_inst_ids)
1335 fprintf(_out, " ( I%u %s )", inst->getId(), mtname);
1336 else {
1337 std::string iname = inst->getName();
1338 fprintf(_out, " ( %s %s )", iname.c_str(), mtname);
1339 }
1340 }
1341 }
1342 }
1343
1344 const char* sig_type = defSigType(net->getSigType());
1345 fprintf(_out, " + USE %s", sig_type);
1346
1347 _non_default_rule = NULL;
1348 dbSet<dbSWire> swires = net->getSWires();
1349 dbSet<dbSWire>::iterator itr;
1350
1351 for (itr = swires.begin(); itr != swires.end(); ++itr)
1352 writeSWire(*itr);
1353
1354 dbSourceType source = net->getSourceType();
1355
1356 switch (source.getValue()) {
1357 case dbSourceType::NONE:
1358 break;
1359
1360 case dbSourceType::NETLIST:
1361 fprintf(_out, " + SOURCE NETLIST");
1362 break;
1363
1364 case dbSourceType::DIST:
1365 fprintf(_out, " + SOURCE DIST");
1366 break;
1367
1368 case dbSourceType::USER:
1369 fprintf(_out, " + SOURCE USER");
1370 break;
1371
1372 case dbSourceType::TIMING:
1373 fprintf(_out, " + SOURCE TIMING");
1374 break;
1375
1376 case dbSourceType::TEST:
1377 break;
1378 }
1379
1380 if (net->hasFixedBump())
1381 fprintf(_out, " + FIXEDBUMP");
1382
1383 if (net->getWeight() != 1)
1384 fprintf(_out, " + WEIGHT %d", net->getWeight());
1385
1386 if (hasProperties(net, SPECIALNET)) {
1387 fprintf(_out, " + PROPERTY ");
1388 writeProperties(net);
1389 }
1390
1391 fprintf(_out, " ;\n");
1392 }
1393
writeWire(dbWire * wire)1394 void defout_impl::writeWire(dbWire* wire)
1395 {
1396 dbWireDecoder decode;
1397 dbTechLayer* layer;
1398 dbWireType prev_wire_type = dbWireType::NONE;
1399 int point_cnt = 0;
1400 int path_cnt = 0;
1401 int prev_x = std::numeric_limits<int>::max();
1402 int prev_y = std::numeric_limits<int>::max();
1403
1404 for (decode.begin(wire);;) {
1405 dbWireDecoder::OpCode opcode = decode.next();
1406
1407 switch (opcode) {
1408 case dbWireDecoder::PATH:
1409 case dbWireDecoder::SHORT:
1410 case dbWireDecoder::VWIRE:
1411 case dbWireDecoder::JUNCTION: {
1412 layer = decode.getLayer();
1413 std::string lname;
1414 if (_use_alias && layer->hasAlias())
1415 lname = layer->getAlias();
1416 else
1417 lname = layer->getName();
1418 dbWireType wire_type = decode.getWireType();
1419 if (wire->getNet()->getWireType() == dbWireType::FIXED)
1420 wire_type = dbWireType::FIXED;
1421
1422 if ((path_cnt == 0) || (wire_type != prev_wire_type)) {
1423 fprintf(
1424 _out, "\n + %s %s", wire_type.getString(), lname.c_str());
1425 } else {
1426 fprintf(_out, "\n NEW %s", lname.c_str());
1427 }
1428
1429 if (_non_default_rule && (decode.peek() != dbWireDecoder::RULE)) {
1430 fprintf(_out, " TAPER");
1431 }
1432
1433 prev_wire_type = wire_type;
1434 point_cnt = 0;
1435 ++path_cnt;
1436 break;
1437 }
1438
1439 case dbWireDecoder::POINT: {
1440 int x, y;
1441 decode.getPoint(x, y);
1442 x = defdist(x);
1443 y = defdist(y);
1444
1445 if ((++point_cnt & 7) == 0)
1446 fprintf(_out, "\n ");
1447
1448 if (point_cnt == 1) {
1449 fprintf(_out, " ( %d %d )", x, y);
1450 }
1451 /*
1452 else if ( (x == prev_x) && (y == prev_y) )
1453 {
1454 fprintf(_out, " ( * * )");
1455 }
1456 */
1457 else if (x == prev_x) {
1458 fprintf(_out, " ( * %d )", y);
1459 } else if (y == prev_y) {
1460 fprintf(_out, " ( %d * )", x);
1461 }
1462
1463 prev_x = x;
1464 prev_y = y;
1465 break;
1466 }
1467
1468 case dbWireDecoder::POINT_EXT: {
1469 int x, y, ext;
1470 decode.getPoint(x, y, ext);
1471 x = defdist(x);
1472 y = defdist(y);
1473 ext = defdist(ext);
1474
1475 if ((++point_cnt & 7) == 0)
1476 fprintf(_out, "\n ");
1477
1478 if (point_cnt == 1) {
1479 fprintf(_out, " ( %d %d %d )", x, y, ext);
1480 } else if ((x == prev_x) && (y == prev_y)) {
1481 fprintf(_out, " ( * * %d )", ext);
1482 } else if (x == prev_x) {
1483 fprintf(_out, " ( * %d %d )", y, ext);
1484 } else if (y == prev_y) {
1485 fprintf(_out, " ( %d * %d )", x, ext);
1486 }
1487
1488 prev_x = x;
1489 prev_y = y;
1490 break;
1491 }
1492
1493 case dbWireDecoder::VIA: {
1494 if ((++point_cnt & 7) == 0)
1495 fprintf(_out, "\n ");
1496
1497 dbVia* via = decode.getVia();
1498
1499 if ((_version >= defout::DEF_5_6) && via->isViaRotated()) {
1500 std::string vname;
1501
1502 if (via->getTechVia())
1503 vname = via->getTechVia()->getName();
1504 else
1505 vname = via->getBlockVia()->getName();
1506
1507 fprintf(_out, " %s %s", vname.c_str(), defOrient(via->getOrient()));
1508 } else {
1509 std::string vname = via->getName();
1510 fprintf(_out, " %s", vname.c_str());
1511 }
1512 break;
1513 }
1514
1515 case dbWireDecoder::TECH_VIA: {
1516 if ((++point_cnt & 7) == 0)
1517 fprintf(_out, "\n ");
1518
1519 dbTechVia* via = decode.getTechVia();
1520 std::string vname = via->getName();
1521 fprintf(_out, " %s", vname.c_str());
1522 break;
1523 }
1524
1525 case dbWireDecoder::ITERM:
1526 case dbWireDecoder::BTERM:
1527 break;
1528
1529 case dbWireDecoder::RULE: {
1530 if (point_cnt == 0) {
1531 dbTechLayerRule* rule = decode.getRule();
1532 dbTechNonDefaultRule* taper_rule = rule->getNonDefaultRule();
1533
1534 if (_non_default_rule == NULL) {
1535 std::string name = taper_rule->getName();
1536 fprintf(_out, " TAPERRULE %s ", name.c_str());
1537 } else if (_non_default_rule != taper_rule) {
1538 std::string name = taper_rule->getName();
1539 fprintf(_out, " TAPERRULE %s ", name.c_str());
1540 }
1541 }
1542 break;
1543 }
1544
1545 case dbWireDecoder::RECT: {
1546 if ((++point_cnt & 7) == 0)
1547 fprintf(_out, "\n ");
1548
1549 int deltaX1;
1550 int deltaY1;
1551 int deltaX2;
1552 int deltaY2;
1553 decode.getRect(deltaX1, deltaY1, deltaX2, deltaY2);
1554 deltaX1 = defdist(deltaX1);
1555 deltaY1 = defdist(deltaY1);
1556 deltaX2 = defdist(deltaX2);
1557 deltaY2 = defdist(deltaY2);
1558 fprintf(
1559 _out, " RECT ( %d %d %d %d ) ", deltaX1, deltaY1, deltaX2, deltaY2);
1560 break;
1561 }
1562
1563 case dbWireDecoder::END_DECODE:
1564 return;
1565 }
1566 }
1567 }
1568
writeSWire(dbSWire * wire)1569 void defout_impl::writeSWire(dbSWire* wire)
1570 {
1571 switch (wire->getWireType().getValue()) {
1572 case dbWireType::COVER:
1573 fprintf(_out, "\n + COVER");
1574 break;
1575
1576 case dbWireType::FIXED:
1577 fprintf(_out, "\n + FIXED");
1578 break;
1579
1580 case dbWireType::ROUTED:
1581 fprintf(_out, "\n + ROUTED");
1582 break;
1583
1584 case dbWireType::SHIELD: {
1585 dbNet* s = wire->getShield();
1586 if (s) {
1587 std::string n = s->getName();
1588 fprintf(_out, "\n + SHIELD %s", n.c_str());
1589 } else {
1590 _logger->warn(utl::ODB, 174, "warning: missing shield net");
1591 fprintf(_out, "\n + ROUTED");
1592 }
1593 break;
1594 }
1595
1596 default:
1597 fprintf(_out, "\n + ROUTED");
1598 break;
1599 }
1600
1601 int i = 0;
1602 dbSet<dbSBox> wires = wire->getWires();
1603 dbSet<dbSBox>::iterator itr;
1604
1605 for (itr = wires.begin(); itr != wires.end(); ++itr) {
1606 dbSBox* box = *itr;
1607
1608 if (i++ > 0)
1609 fprintf(_out, "\n NEW");
1610
1611 if (!box->isVia())
1612 writeSpecialPath(box);
1613
1614 else if (box->getTechVia()) {
1615 dbWireShapeType type = box->getWireShapeType();
1616 dbTechVia* v = box->getTechVia();
1617 std::string vn = v->getName();
1618 dbTechLayer* l = v->getBottomLayer();
1619 std::string ln;
1620 if (_use_alias && l->hasAlias())
1621 ln = l->getAlias();
1622 else
1623 ln = l->getName();
1624
1625 int x, y;
1626 box->getViaXY(x, y);
1627
1628 if (type.getValue() == dbWireShapeType::NONE)
1629 fprintf(_out,
1630 " %s 0 ( %d %d ) %s",
1631 ln.c_str(),
1632 defdist(x),
1633 defdist(y),
1634 vn.c_str());
1635 else
1636 fprintf(_out,
1637 " %s 0 + SHAPE %s ( %d %d ) %s",
1638 ln.c_str(),
1639 type.getString(),
1640 defdist(x),
1641 defdist(y),
1642 vn.c_str());
1643 } else if (box->getBlockVia()) {
1644 dbWireShapeType type = box->getWireShapeType();
1645 dbVia* v = box->getBlockVia();
1646 std::string vn = v->getName();
1647 dbTechLayer* l = v->getBottomLayer();
1648 std::string ln;
1649 if (_use_alias && l->hasAlias())
1650 ln = l->getAlias();
1651 else
1652 ln = l->getName();
1653
1654 int x, y;
1655 box->getViaXY(x, y);
1656
1657 if (type.getValue() == dbWireShapeType::NONE)
1658 fprintf(_out,
1659 " %s 0 ( %d %d ) %s",
1660 ln.c_str(),
1661 defdist(x),
1662 defdist(y),
1663 vn.c_str());
1664 else
1665 fprintf(_out,
1666 " %s 0 + SHAPE %s ( %d %d ) %s",
1667 ln.c_str(),
1668 type.getString(),
1669 defdist(x),
1670 defdist(y),
1671 vn.c_str());
1672 }
1673 }
1674 }
1675
writeSpecialPath(dbSBox * box)1676 void defout_impl::writeSpecialPath(dbSBox* box)
1677 {
1678 dbTechLayer* l = box->getTechLayer();
1679 std::string ln;
1680
1681 if (_use_alias && l->hasAlias())
1682 ln = l->getAlias();
1683 else
1684 ln = l->getName();
1685
1686 int x1 = box->xMin();
1687 int y1 = box->yMin();
1688 int x2 = box->xMax();
1689 int y2 = box->yMax();
1690 uint dx = x2 - x1;
1691 uint dy = y2 - y1;
1692 uint w;
1693
1694 switch (box->getDirection()) {
1695 case dbSBox::UNDEFINED: {
1696 bool dx_even = ((dx & 1) == 0);
1697 bool dy_even = ((dy & 1) == 0);
1698
1699 if (dx_even && dy_even) {
1700 if (dy < dx) {
1701 w = dy;
1702 uint dw = dy >> 1;
1703 y1 += dw;
1704 y2 -= dw;
1705 assert(y1 == y2);
1706 } else {
1707 w = dx;
1708 uint dw = dx >> 1;
1709 x1 += dw;
1710 x2 -= dw;
1711 assert(x1 == x2);
1712 }
1713 } else if (dx_even) {
1714 w = dx;
1715 uint dw = dx >> 1;
1716 x1 += dw;
1717 x2 -= dw;
1718 assert(x1 == x2);
1719 } else if (dy_even) {
1720 w = dy;
1721 uint dw = dy >> 1;
1722 y1 += dw;
1723 y2 -= dw;
1724 assert(y1 == y2);
1725 } else {
1726 throw ZException("odd dimension in both directions");
1727 }
1728
1729 break;
1730 }
1731
1732 case dbSBox::HORIZONTAL: {
1733 w = dy;
1734 uint dw = dy >> 1;
1735 y1 += dw;
1736 y2 -= dw;
1737 assert(y1 == y2);
1738 break;
1739 }
1740
1741 case dbSBox::VERTICAL: {
1742 w = dx;
1743 uint dw = dx >> 1;
1744 x1 += dw;
1745 x2 -= dw;
1746 assert(x1 == x2);
1747 break;
1748 }
1749 case dbSBox::OCTILINEAR: {
1750 Oct oct = box->getOct();
1751 x1 = oct.getCenterLow().getX();
1752 y1 = oct.getCenterLow().getY();
1753 x2 = oct.getCenterHigh().getX();
1754 y2 = oct.getCenterHigh().getY();
1755 w = oct.getWidth();
1756 break;
1757 }
1758 default:
1759 throw ZException("unknown direction");
1760 break;
1761 }
1762
1763 dbWireShapeType type = box->getWireShapeType();
1764
1765 if (type.getValue() == dbWireShapeType::NONE)
1766 fprintf(_out,
1767 " %s %d ( %d %d ) ( %d %d )",
1768 ln.c_str(),
1769 defdist(w),
1770 defdist(x1),
1771 defdist(y1),
1772 defdist(x2),
1773 defdist(y2));
1774 else
1775 fprintf(_out,
1776 " %s %d + SHAPE %s ( %d %d ) ( %d %d )",
1777 ln.c_str(),
1778 defdist(w),
1779 type.getString(),
1780 defdist(x1),
1781 defdist(y1),
1782 defdist(x2),
1783 defdist(y2));
1784 }
1785
writeNet(dbNet * net)1786 void defout_impl::writeNet(dbNet* net)
1787 {
1788 if (_use_net_inst_ids)
1789 fprintf(_out, " - N%u", net->getId());
1790 else {
1791 std::string nname = net->getName();
1792 fprintf(_out, " - %s", nname.c_str());
1793 }
1794
1795 char ttname[dbObject::max_name_length];
1796 int i = 0;
1797
1798 for (dbBTerm* bterm : net->getBTerms()) {
1799 const char* pin_name = bterm->getConstName();
1800 if ((++i & 7) == 0)
1801 fprintf(_out, "\n ");
1802 fprintf(_out, " ( PIN %s )", pin_name);
1803 }
1804
1805 for (dbITerm* iterm : net->getITerms()) {
1806 if (iterm->isSpecial())
1807 continue;
1808
1809 dbInst* inst = iterm->getInst();
1810 if (_select_inst_map && !(*_select_inst_map)[inst])
1811 continue; // for power nets in regular net section, tie-lo/hi
1812 dbMTerm* mterm = iterm->getMTerm();
1813 // std::string mtname = mterm->getName();
1814 char* mtname = mterm->getName(inst, &ttname[0]);
1815
1816 if ((++i & 7) == 0)
1817 fprintf(_out, "\n ");
1818
1819 if (_use_net_inst_ids)
1820 fprintf(_out, " ( I%u %s )", inst->getId(), mtname);
1821 else {
1822 std::string iname = inst->getName();
1823 fprintf(_out, " ( %s %s )", iname.c_str(), mtname);
1824 }
1825 }
1826
1827 if (net->getXTalkClass() != 0)
1828 fprintf(_out, " + XTALK %d", net->getXTalkClass());
1829
1830 const char* sig_type = defSigType(net->getSigType());
1831 fprintf(_out, " + USE %s", sig_type);
1832
1833 _non_default_rule = net->getNonDefaultRule();
1834
1835 if (_non_default_rule) {
1836 std::string n = _non_default_rule->getName();
1837 fprintf(_out, " + NONDEFAULTRULE %s", n.c_str());
1838 }
1839
1840 dbWire* wire = net->getWire();
1841
1842 if (wire)
1843 writeWire(wire);
1844
1845 dbSourceType source = net->getSourceType();
1846
1847 switch (source.getValue()) {
1848 case dbSourceType::NONE:
1849 break;
1850
1851 case dbSourceType::NETLIST:
1852 fprintf(_out, " + SOURCE NETLIST");
1853 break;
1854
1855 case dbSourceType::DIST:
1856 fprintf(_out, " + SOURCE DIST");
1857 break;
1858
1859 case dbSourceType::USER:
1860 fprintf(_out, " + SOURCE USER");
1861 break;
1862
1863 case dbSourceType::TIMING:
1864 fprintf(_out, " + SOURCE TIMING");
1865 break;
1866
1867 case dbSourceType::TEST:
1868 fprintf(_out, " + SOURCE TEST");
1869 break;
1870 }
1871
1872 if (net->hasFixedBump())
1873 fprintf(_out, " + FIXEDBUMP");
1874
1875 if (net->getWeight() != 1)
1876 fprintf(_out, " + WEIGHT %d", net->getWeight());
1877
1878 if (hasProperties(net, NET)) {
1879 fprintf(_out, " + PROPERTY ");
1880 writeProperties(net);
1881 }
1882
1883 fprintf(_out, " ;\n");
1884 }
1885
1886 //
1887 // See defin/definProDefs.h
1888 //
writePropertyDefinitions(dbBlock * block)1889 void defout_impl::writePropertyDefinitions(dbBlock* block)
1890 {
1891 dbProperty* defs
1892 = dbProperty::find(block, "__ADS_DEF_PROPERTY_DEFINITIONS__");
1893
1894 if (defs == NULL)
1895 return;
1896
1897 fprintf(_out, "PROPERTYDEFINITIONS\n");
1898
1899 dbSet<dbProperty> obj_types = dbProperty::getProperties(defs);
1900 dbSet<dbProperty>::iterator objitr;
1901
1902 for (objitr = obj_types.begin(); objitr != obj_types.end(); ++objitr) {
1903 dbProperty* obj = *objitr;
1904 std::string objType = obj->getName();
1905
1906 ObjType obj_type;
1907
1908 if (strcmp(objType.c_str(), "COMPONENT") == 0) {
1909 obj_type = COMPONENT;
1910 } else if (strcmp(objType.c_str(), "COMPONENTPIN") == 0) {
1911 obj_type = COMPONENTPIN;
1912 } else if (strcmp(objType.c_str(), "DESIGN") == 0) {
1913 obj_type = DESIGN;
1914 } else if (strcmp(objType.c_str(), "GROUP") == 0) {
1915 obj_type = GROUP;
1916 } else if (strcmp(objType.c_str(), "NET") == 0) {
1917 obj_type = NET;
1918 } else if (strcmp(objType.c_str(), "NONDEFAULTRULE") == 0) {
1919 obj_type = NONDEFAULTRULE;
1920 } else if (strcmp(objType.c_str(), "REGION") == 0) {
1921 obj_type = REGION;
1922 } else if (strcmp(objType.c_str(), "ROW") == 0) {
1923 obj_type = ROW;
1924 } else if (strcmp(objType.c_str(), "SPECIALNET") == 0) {
1925 obj_type = SPECIALNET;
1926 } else {
1927 continue;
1928 }
1929
1930 std::map<std::string, bool>& defs_map = _prop_defs[obj_type];
1931 dbSet<dbProperty> props = dbProperty::getProperties(obj);
1932 dbSet<dbProperty>::iterator pitr;
1933
1934 for (pitr = props.begin(); pitr != props.end(); ++pitr) {
1935 dbProperty* prop = *pitr;
1936 std::string name = prop->getName();
1937 defs_map[std::string(name.c_str())] = true;
1938 switch (prop->getType()) {
1939 case dbProperty::STRING_PROP:
1940 fprintf(_out, "%s %s STRING ", objType.c_str(), name.c_str());
1941 break;
1942
1943 case dbProperty::INT_PROP:
1944 fprintf(_out, "%s %s INTEGER ", objType.c_str(), name.c_str());
1945 break;
1946
1947 case dbProperty::DOUBLE_PROP:
1948 fprintf(_out, "%s %s REAL ", objType.c_str(), name.c_str());
1949 break;
1950
1951 default:
1952 continue;
1953 }
1954
1955 dbProperty* minV = dbProperty::find(prop, "MIN");
1956 dbProperty* maxV = dbProperty::find(prop, "MAX");
1957
1958 if (minV && maxV) {
1959 fprintf(_out, "RANGE ");
1960 writePropValue(minV);
1961 writePropValue(maxV);
1962 }
1963
1964 dbProperty* value = dbProperty::find(prop, "VALUE");
1965
1966 if (value)
1967 writePropValue(value);
1968
1969 fprintf(_out, ";\n");
1970 }
1971 }
1972
1973 fprintf(_out, "END PROPERTYDEFINITIONS\n");
1974 }
1975
writePropValue(dbProperty * prop)1976 void defout_impl::writePropValue(dbProperty* prop)
1977 {
1978 switch (prop->getType()) {
1979 case dbProperty::STRING_PROP: {
1980 dbStringProperty* p = (dbStringProperty*) prop;
1981 std::string v = p->getValue();
1982 fprintf(_out, "\"%s\" ", v.c_str());
1983 break;
1984 }
1985
1986 case dbProperty::INT_PROP: {
1987 dbIntProperty* p = (dbIntProperty*) prop;
1988 int v = p->getValue();
1989 fprintf(_out, "%d ", v);
1990 break;
1991 }
1992
1993 case dbProperty::DOUBLE_PROP: {
1994 dbDoubleProperty* p = (dbDoubleProperty*) prop;
1995 double v = p->getValue();
1996 fprintf(_out, "%G ", v);
1997 }
1998
1999 default:
2000 break;
2001 }
2002 }
2003
writeProperties(dbObject * object)2004 void defout_impl::writeProperties(dbObject* object)
2005 {
2006 dbSet<dbProperty> props = dbProperty::getProperties(object);
2007 dbSet<dbProperty>::iterator itr;
2008 int cnt = 0;
2009
2010 for (itr = props.begin(); itr != props.end(); ++itr) {
2011 if (cnt && ((cnt & 3) == 0))
2012 fprintf(_out, "\n ");
2013
2014 dbProperty* prop = *itr;
2015 std::string name = prop->getName();
2016 fprintf(_out, "%s ", name.c_str());
2017 writePropValue(prop);
2018 }
2019 }
2020
hasProperties(dbObject * object,ObjType type)2021 bool defout_impl::hasProperties(dbObject* object, ObjType type)
2022 {
2023 dbSet<dbProperty> props = dbProperty::getProperties(object);
2024 dbSet<dbProperty>::iterator itr;
2025
2026 for (itr = props.begin(); itr != props.end(); ++itr) {
2027 dbProperty* prop = *itr;
2028 std::string name = prop->getName();
2029
2030 if (_prop_defs[type].find(name.c_str()) != _prop_defs[type].end())
2031 return true;
2032 }
2033
2034 return false;
2035 }
2036
writePinProperties(dbBlock * block)2037 void defout_impl::writePinProperties(dbBlock* block)
2038 {
2039 uint cnt = 0;
2040
2041 dbSet<dbBTerm> bterms = block->getBTerms();
2042 dbSet<dbBTerm>::iterator bitr;
2043
2044 for (bitr = bterms.begin(); bitr != bterms.end(); ++bitr) {
2045 if (hasProperties(*bitr, COMPONENTPIN))
2046 ++cnt;
2047 }
2048
2049 dbSet<dbITerm> iterms = block->getITerms();
2050 dbSet<dbITerm>::iterator iitr;
2051
2052 for (iitr = iterms.begin(); iitr != iterms.end(); ++iitr) {
2053 if (hasProperties(*iitr, COMPONENTPIN))
2054 ++cnt;
2055 }
2056
2057 if (cnt == 0)
2058 return;
2059
2060 fprintf(_out, "PINPROPERTIES %u ;\n", cnt);
2061
2062 for (bitr = bterms.begin(); bitr != bterms.end(); ++bitr) {
2063 dbBTerm* bterm = *bitr;
2064
2065 if (hasProperties(bterm, COMPONENTPIN)) {
2066 std::string name = bterm->getName();
2067 fprintf(_out, " - PIN %s + PROPERTY ", name.c_str());
2068 writeProperties(bterm);
2069 fprintf(_out, " ;\n");
2070 }
2071 }
2072
2073 char ttname[dbObject::max_name_length];
2074 for (iitr = iterms.begin(); iitr != iterms.end(); ++iitr) {
2075 dbITerm* iterm = *iitr;
2076
2077 if (hasProperties(iterm, COMPONENTPIN)) {
2078 dbInst* inst = iterm->getInst();
2079 dbMTerm* mterm = iterm->getMTerm();
2080 std::string iname = inst->getName();
2081 // std::string mtname = mterm->getName();
2082 char* mtname = mterm->getName(inst, &ttname[0]);
2083 fprintf(_out, " - %s %s + PROPERTY ", iname.c_str(), mtname);
2084 writeProperties(iterm);
2085 fprintf(_out, " ;\n");
2086 }
2087 }
2088
2089 fprintf(_out, "END PINPROPERTIES\n");
2090 }
2091
2092 } // namespace odb
2093