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