1 ///////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (c) 2019-2020, The Regents of the University of California
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
25 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 ///////////////////////////////////////////////////////////////////////////////
33 
34 #include "mpl/MacroPlacer.h"
35 
36 #include <string>
37 
38 #include "db_sta/dbNetwork.hh"
39 #include "db_sta/dbSta.hh"
40 #include "graphics.h"
41 #include "sta/Bfs.hh"
42 #include "sta/Corner.hh"
43 #include "sta/FuncExpr.hh"
44 #include "sta/Graph.hh"
45 #include "sta/Liberty.hh"
46 #include "sta/Network.hh"
47 #include "sta/PortDirection.hh"
48 #include "sta/Sdc.hh"
49 #include "sta/SearchPred.hh"
50 #include "sta/Sequential.hh"
51 #include "sta/Sta.hh"
52 #include "utl/Logger.h"
53 
54 namespace mpl {
55 
56 using std::max;
57 using std::min;
58 using std::round;
59 
60 using utl::MPL;
61 
62 using odb::dbBlock;
63 using odb::dbBPin;
64 using odb::dbBTerm;
65 using odb::dbInst;
66 using odb::dbITerm;
67 using odb::dbPlacementStatus;
68 using odb::dbRow;
69 using odb::dbSet;
70 using odb::dbSigType;
71 using odb::dbSite;
72 using odb::dbTech;
73 using odb::dbTechLayer;
74 using odb::Rect;
75 
76 typedef vector<pair<Partition, Partition>> TwoPartitions;
77 
78 static CoreEdge getCoreEdge(int cx,
79                             int cy,
80                             int dieLx,
81                             int dieLy,
82                             int dieUx,
83                             int dieUy);
84 
85 ////////////////////////////////////////////////////////////////
86 
MacroPlacer()87 MacroPlacer::MacroPlacer()
88     : db_(nullptr),
89       sta_(nullptr),
90       logger_(nullptr),
91       snap_layer_(nullptr),
92       connection_driven_(false),
93       lx_(0),
94       ly_(0),
95       ux_(0),
96       uy_(0),
97       verbose_(1),
98       solution_count_(0),
99       gui_debug_(false),
100       gui_debug_partitions_(false)
101 {
102 }
103 
init(odb::dbDatabase * db,sta::dbSta * sta,utl::Logger * log)104 void MacroPlacer::init(odb::dbDatabase* db, sta::dbSta* sta, utl::Logger* log)
105 {
106   db_ = db;
107   sta_ = sta;
108   logger_ = log;
109 }
110 
setDebug(bool partitions)111 void MacroPlacer::setDebug(bool partitions)
112 {
113   gui_debug_ = true;
114   gui_debug_partitions_ = partitions;
115 }
116 
setHalo(double halo_x,double halo_y)117 void MacroPlacer::setHalo(double halo_x, double halo_y)
118 {
119   default_macro_spacings_.setHalo(halo_x, halo_y);
120 }
121 
setChannel(double channel_x,double channel_y)122 void MacroPlacer::setChannel(double channel_x, double channel_y)
123 {
124   default_macro_spacings_.setChannel(channel_x, channel_y);
125 }
126 
setVerboseLevel(int verbose)127 void MacroPlacer::setVerboseLevel(int verbose)
128 {
129   verbose_ = verbose;
130 }
131 
setFenceRegion(double lx,double ly,double ux,double uy)132 void MacroPlacer::setFenceRegion(double lx, double ly, double ux, double uy)
133 {
134   lx_ = lx;
135   ly_ = ly;
136   ux_ = ux;
137   uy_ = uy;
138 }
139 
setSnapLayer(odb::dbTechLayer * snap_layer)140 void MacroPlacer::setSnapLayer(odb::dbTechLayer* snap_layer)
141 {
142   snap_layer_ = snap_layer;
143 }
144 
getSolutionCount()145 int MacroPlacer::getSolutionCount()
146 {
147   return solution_count_;
148 }
149 
init()150 void MacroPlacer::init()
151 {
152   findMacros();
153 
154   // Connection driven will be disabled if some instances are missing liberty
155   // cells.
156   connection_driven_ = !isMissingLiberty();
157 
158   if (connection_driven_) {
159     reportEdgePinCounts();
160     findAdjacencies();
161   } else {
162     logger_->warn(MPL,
163                   2,
164                   "Some instances do not have Liberty models. TritonMP will "
165                   "place macros without connection information.");
166   }
167 }
168 
isMissingLiberty()169 bool MacroPlacer::isMissingLiberty()
170 {
171   sta::Network* network = sta_->network();
172   sta::LeafInstanceIterator* instIter = network->leafInstanceIterator();
173   while (instIter->hasNext()) {
174     sta::Instance* inst = instIter->next();
175     if (network->libertyCell(inst) == nullptr) {
176       delete instIter;
177       return true;
178     }
179   }
180   delete instIter;
181   return false;
182 }
183 
reportEdgePinCounts()184 void MacroPlacer::reportEdgePinCounts()
185 {
186   int counts[core_edge_count] = {0};
187   for (dbBTerm* bterm : db_->getChip()->getBlock()->getBTerms()) {
188     CoreEdge edge = findNearestEdge(bterm);
189     counts[coreEdgeIndex(edge)]++;
190   }
191   for (int i = 0; i < core_edge_count; i++) {
192     CoreEdge edge = coreEdgeFromIndex(i);
193     logger_->info(MPL, 9, "{} pins {}", coreEdgeString(edge), counts[i]);
194   }
195 }
196 
197 // Use parquefp on all the macros in the lower left corner.
placeMacrosCornerMinWL()198 void MacroPlacer::placeMacrosCornerMinWL()
199 {
200   init();
201 
202   double wl = getWeightedWL();
203   logger_->info(MPL, 67, "Initial weighted wire length {:g}", wl);
204 
205   // All of this partitioning garbage is unnecessary but survives to support
206   // the multiple partition algorithm.
207 
208   Layout layout(lx_, ly_, ux_, uy_);
209   Partition partition(
210       PartClass::ALL, lx_, ly_, ux_ - lx_, uy_ - ly_, this, logger_);
211   partition.macros_ = macros_;
212 
213   MacroPartMap globalMacroPartMap;
214   updateMacroPartMap(partition, globalMacroPartMap);
215 
216   if (connection_driven_) {
217     partition.fillNetlistTable(globalMacroPartMap);
218   }
219 
220   // Annealing based on ParquetFP Engine
221   if (partition.anneal()) {
222     setDbInstLocations(partition);
223 
224     double curWwl = getWeightedWL();
225     logger_->info(MPL, 68, "Placed weighted wire length {:g}", curWwl);
226   } else
227     logger_->warn(MPL, 66, "Partitioning failed.");
228 }
229 
setDbInstLocations(Partition & partition)230 void MacroPlacer::setDbInstLocations(Partition& partition)
231 {
232   odb::dbTech* tech = db_->getTech();
233   const int dbu = tech->getDbUnitsPerMicron();
234   const float pitch_x = static_cast<float>(snap_layer_->getPitchX()) / dbu;
235   const float pitch_y = static_cast<float>(snap_layer_->getPitchY()) / dbu;
236 
237   int macro_idx = 0;
238   for (Macro& pmacro : partition.macros_) {
239     // partition macros are 1:1 with macros_.
240     Macro& macro = macros_[macro_idx];
241 
242     double x = pmacro.lx;
243     double y = pmacro.ly;
244 
245     // Snap to routing grid.
246     x = round(x / pitch_x) * pitch_x;
247     y = round(y / pitch_y) * pitch_y;
248 
249     // Snap macro location to grid.
250     macro.lx = x;
251     macro.ly = y;
252 
253     // Update db inst location.
254     dbInst* db_inst = macro.dbInstPtr;
255     db_inst->setLocation(round(x * dbu), round(y * dbu));
256     db_inst->setPlacementStatus(odb::dbPlacementStatus::LOCKED);
257     macro_idx++;
258   }
259 }
260 
261 ////////////////////////////////////////////////////////////////
262 
263 // Use some undocumented method with cut lines to break the design
264 // into regions and try all combinations of something or other.
265 // Pick the one that maximizes (yes, really)
266 // wire lengths of connections between the macros to force them to the corners.
placeMacrosCornerMaxWl()267 void MacroPlacer::placeMacrosCornerMaxWl()
268 {
269   init();
270 
271   double wl = getWeightedWL();
272   logger_->info(MPL, 69, "Initial weighted wire length {:g}", wl);
273 
274   Layout layout(lx_, ly_, ux_, uy_);
275   bool horizontal = true;
276   Partition top_partition(
277       PartClass::ALL, lx_, ly_, ux_ - lx_, uy_ - ly_, this, logger_);
278   top_partition.macros_ = macros_;
279 
280   logger_->report("Begin One Level Partition");
281 
282   TwoPartitions oneLevelPart = getPartitions(layout, top_partition, horizontal);
283 
284   logger_->report("End One Level Partition");
285   TwoPartitions east_partitions, west_partitions;
286 
287   vector<vector<Partition>> allSets;
288 
289   MacroPartMap globalMacroPartMap;
290   updateMacroPartMap(top_partition, globalMacroPartMap);
291 
292   if (connection_driven_) {
293     top_partition.fillNetlistTable(globalMacroPartMap);
294   }
295 
296   // push to the outer vector
297   vector<Partition> layoutSet;
298   layoutSet.push_back(top_partition);
299 
300   allSets.push_back(layoutSet);
301   for (auto& partition_set : oneLevelPart) {
302     if (horizontal) {
303       logger_->report("Begin Horizontal Partition");
304       Layout eastInfo(layout, partition_set.first);
305       Layout westInfo(layout, partition_set.second);
306 
307       logger_->report("Begin East Partition");
308       TwoPartitions east_partitions
309           = getPartitions(eastInfo, partition_set.first, !horizontal);
310       logger_->report("End East Partition");
311 
312       logger_->report("Begin West Partition");
313       TwoPartitions west_partitions
314           = getPartitions(westInfo, partition_set.second, !horizontal);
315       logger_->report("End West Partition");
316 
317       // Zero case handling when east_partitions = 0
318       if (east_partitions.empty() && !west_partitions.empty()) {
319         for (size_t i = 0; i < west_partitions.size(); i++) {
320           vector<Partition> partition_set;
321 
322           // one set is composed of two subblocks
323           partition_set.push_back(west_partitions[i].first);
324           partition_set.push_back(west_partitions[i].second);
325 
326           // Fill Macro Netlist
327           // update macroPartMap
328           MacroPartMap macroPartMap;
329           for (auto& partition_set : partition_set) {
330             updateMacroPartMap(partition_set, macroPartMap);
331           }
332 
333           if (connection_driven_) {
334             for (auto& partition_set : partition_set) {
335               partition_set.fillNetlistTable(macroPartMap);
336             }
337           }
338 
339           allSets.push_back(partition_set);
340         }
341       }
342       // Zero case handling when west_partitions = 0
343       else if (!east_partitions.empty() && west_partitions.empty()) {
344         for (size_t i = 0; i < east_partitions.size(); i++) {
345           vector<Partition> partition_set;
346 
347           // one set is composed of two subblocks
348           partition_set.push_back(east_partitions[i].first);
349           partition_set.push_back(east_partitions[i].second);
350 
351           // Fill Macro Netlist
352           // update macroPartMap
353           MacroPartMap macroPartMap;
354           for (auto& partition_set : partition_set) {
355             updateMacroPartMap(partition_set, macroPartMap);
356           }
357 
358           if (connection_driven_) {
359             for (auto& partition_set : partition_set) {
360               partition_set.fillNetlistTable(macroPartMap);
361             }
362           }
363 
364           allSets.push_back(partition_set);
365         }
366       } else {
367         // for all possible partition combinations
368         for (size_t i = 0; i < east_partitions.size(); i++) {
369           for (size_t j = 0; j < west_partitions.size(); j++) {
370             vector<Partition> partition_set;
371 
372             // one set is composed of four subblocks
373             partition_set.push_back(east_partitions[i].first);
374             partition_set.push_back(east_partitions[i].second);
375             partition_set.push_back(west_partitions[j].first);
376             partition_set.push_back(west_partitions[j].second);
377 
378             MacroPartMap macroPartMap;
379             for (auto& partition_set : partition_set) {
380               updateMacroPartMap(partition_set, macroPartMap);
381             }
382 
383             if (connection_driven_) {
384               for (auto& partition_set : partition_set) {
385                 partition_set.fillNetlistTable(macroPartMap);
386               }
387             }
388             allSets.push_back(partition_set);
389           }
390         }
391       }
392       logger_->report("End Horizontal Partition");
393     } else {
394       // Vertical partition support MIA
395     }
396   }
397   logger_->info(MPL, 70, "Using {} partition sets", allSets.size() - 1);
398 
399   std::unique_ptr<Graphics> graphics;
400   if (gui_debug_ && Graphics::guiActive()) {
401     graphics = std::make_unique<Graphics>(db_, logger_);
402   }
403 
404   solution_count_ = 0;
405   bool found_best = false;
406   int best_setIdx = 0;
407   double bestWwl = -DBL_MAX;
408   for (auto& partition_set : allSets) {
409     // skip for top partition
410     if (partition_set.size() == 1) {
411       continue;
412     }
413 
414     if (gui_debug_) {
415       graphics->status("Pre-anneal");
416       graphics->set_partitions(partition_set, true);
417     }
418 
419     // For each of the 4 partitions
420     bool isFailed = false;
421     for (auto& curPart : partition_set) {
422       // Annealing based on ParquetFP Engine
423       bool success = curPart.anneal();
424       if (!success) {
425         logger_->warn(
426             MPL,
427             61,
428             "Parquet area {:g} x {:g} exceeds the partition area {:g} x {:g}.",
429             curPart.solution_width,
430             curPart.solution_height,
431             curPart.width,
432             curPart.height);
433         isFailed = true;
434         break;
435       }
436       // Update mckt frequently
437       updateMacroLocations(curPart);
438     }
439 
440     if (isFailed) {
441       continue;
442     }
443 
444     double curWwl = getWeightedWL();
445     logger_->info(MPL,
446                   71,
447                   "Solution {} weighted wire length {:g}",
448                   solution_count_ + 1,
449                   curWwl);
450     bool is_best = false;
451     if (!found_best
452         // Note that this MAXIMIZES wirelength.
453         // That is they way mingyu wrote it.
454         // This is the only thing that keeps all the macros from ending
455         // up in one clump. -cherry
456         || curWwl > bestWwl) {
457       bestWwl = curWwl;
458       best_setIdx = &partition_set - &allSets[0];
459       found_best = true;
460       is_best = true;
461     }
462     solution_count_++;
463 
464     if (gui_debug_) {
465       auto msg("Post-anneal WL: " + std::to_string(curWwl));
466       if (is_best) {
467         msg += " [BEST]";
468       }
469       graphics->status(msg);
470       graphics->set_partitions(partition_set, false);
471     }
472   }
473 
474   if (found_best) {
475     logger_->info(MPL, 73, "Best weighted wire length {:g}", bestWwl);
476     std::vector<Partition> best_set = allSets[best_setIdx];
477     for (auto& best_partition : best_set) {
478       updateMacroLocations(best_partition);
479     }
480     updateDbInstLocations();
481   } else
482     logger_->warn(MPL, 72, "No partition solutions found.");
483 }
484 
weight(int idx1,int idx2)485 int MacroPlacer::weight(int idx1, int idx2)
486 {
487   return macro_weights_[idx1][idx2];
488 }
489 
490 // Update opendb instance locations from macros.
updateDbInstLocations()491 void MacroPlacer::updateDbInstLocations()
492 {
493   odb::dbTech* tech = db_->getTech();
494   const int dbu = tech->getDbUnitsPerMicron();
495 
496   for (auto& macro : macros_) {
497     macro.dbInstPtr->setLocation(round(macro.lx * dbu), round(macro.ly * dbu));
498     macro.dbInstPtr->setPlacementStatus(odb::dbPlacementStatus::LOCKED);
499   }
500 }
501 
cutRoundUp(const Layout & layout,double & cutLine,bool horizontal)502 void MacroPlacer::cutRoundUp(const Layout& layout,
503                              double& cutLine,
504                              bool horizontal)
505 {
506   dbBlock* block = db_->getChip()->getBlock();
507   dbSet<dbRow> rows = block->getRows();
508   const double dbu = db_->getTech()->getDbUnitsPerMicron();
509   dbSite* site = rows.begin()->getSite();
510   if (horizontal) {
511     double siteSizeX = site->getWidth() / dbu;
512     cutLine = round(cutLine / siteSizeX) * siteSizeX;
513     cutLine = min(cutLine, layout.ux());
514     cutLine = max(cutLine, layout.lx());
515   } else {
516     double siteSizeY = site->getHeight() / dbu;
517     cutLine = round(cutLine / siteSizeY) * siteSizeY;
518     cutLine = min(cutLine, layout.uy());
519     cutLine = max(cutLine, layout.ly());
520   }
521 }
522 
523 // using partition,
524 // fill in macroPartMap
525 //
526 // macroPartMap will contain
527 //
528 // first: macro partition class info
529 // second: macro candidates.
updateMacroPartMap(Partition & part,MacroPartMap & macroPartMap)530 void MacroPlacer::updateMacroPartMap(Partition& part,
531                                      MacroPartMap& macroPartMap)
532 {
533   // This does not look like it actually does anything -cherry
534   vector<int> macros = macroPartMap[part.partClass];
535   // convert macro Information into macroIdx
536   for (auto& macro : part.macros_) {
537     int macro_index = macro_inst_map_[macro.dbInstPtr];
538     macros.push_back(macro_index);
539   }
540   macroPartMap[part.partClass] = macros;
541 }
542 
543 // only considers lx or ly coordinates for sorting
segLxLyLess(const std::pair<int,double> & p1,const std::pair<int,double> & p2)544 static bool segLxLyLess(const std::pair<int, double>& p1,
545                         const std::pair<int, double>& p2)
546 {
547   return p1.second < p2.second;
548 }
549 
550 // Two partitioning functions:
551 // first : lower part
552 // second : upper part
553 //
554 // cutLine is sweeping from lower to upper coordinates in x / y
getPartitions(const Layout & layout,const Partition & partition,bool horizontal)555 vector<pair<Partition, Partition>> MacroPlacer::getPartitions(
556     const Layout& layout,
557     const Partition& partition,
558     bool horizontal)
559 {
560   logger_->info(MPL, 76, "Partition {} macros", partition.macros_.size());
561 
562   vector<pair<Partition, Partition>> partitions;
563 
564   double maxWidth = 0.0;
565   double maxHeight = 0.0;
566 
567   // segments
568   // In a sane implementation this would be a vector of Macro*
569   // and use a function to return the origin x/y. -cherry
570   vector<std::pair<int, double>> segments;
571 
572   // in parent partition, traverse macros
573   for (const Macro& macro : partition.macros_) {
574     segments.push_back(std::make_pair(&macro - &partition.macros_[0],
575                                       (horizontal) ? macro.lx : macro.ly));
576 
577     maxWidth = std::max(maxWidth, paddedWidth(macro));
578     maxHeight = std::max(maxHeight, paddedHeight(macro));
579   }
580 
581   double cutLineLimit = (horizontal) ? maxWidth * 0.25 : maxHeight * 0.25;
582   vector<double> cutlines;
583 
584   // less than 4
585   if (partition.macros_.size() <= 4) {
586     sort(segments.begin(), segments.end(), segLxLyLess);
587 
588     double prevPushLimit = -1e30;
589     bool isFirst = true;
590     // first : macros_ index
591     // second : macro lower coordinates
592     for (auto& segPair : segments) {
593       if (isFirst) {
594         cutlines.push_back(segPair.second);
595         prevPushLimit = segPair.second;
596         isFirst = false;
597       } else if (std::abs(segPair.second - prevPushLimit) > cutLineLimit) {
598         cutlines.push_back(segPair.second);
599         prevPushLimit = segPair.second;
600       }
601     }
602   }
603   // more than 4
604   else {
605     int hardLimit = round(std::sqrt(partition.macros_.size() / 3.0));
606     for (int i = 0; i <= hardLimit; i++) {
607       cutlines.push_back(
608           (horizontal)
609               ? layout.lx() + (layout.ux() - layout.lx()) / hardLimit * i
610               : layout.ly() + (layout.uy() - layout.ly()) / hardLimit * i);
611     }
612   }
613   logger_->info(MPL, 77, "Using {} cut lines", cutlines.size());
614 
615   // Macro checker array
616   // 0 for uninitialize
617   // 1 for lower
618   // 2 for upper
619   // 3 for both
620   vector<int> chkArr(partition.macros_.size());
621 
622   for (auto& cutLine : cutlines) {
623     cutRoundUp(layout, cutLine, horizontal);
624 
625     logger_->info(MPL, 79, "Cut line {:.2f}", cutLine);
626 
627     // chkArr initialize
628     for (size_t i = 0; i < partition.macros_.size(); i++) {
629       chkArr[i] = 0;
630     }
631 
632     bool isImpossible = false;
633     for (auto& macro : partition.macros_) {
634       int i = &macro - &partition.macros_[0];
635       if (horizontal) {
636         // lower is possible
637         if (paddedWidth(macro) <= cutLine) {
638           chkArr[i] += 1;
639         }
640         // upper is possible
641         if (paddedWidth(macro) <= partition.lx + partition.width - cutLine) {
642           chkArr[i] += 2;
643         }
644         // none of them
645         if (chkArr[i] == 0) {
646           isImpossible = true;
647           break;
648         }
649       } else {
650         // lower is possible
651         if (paddedHeight(macro) <= cutLine) {
652           chkArr[i] += 1;
653         }
654         // upper is possible
655         if (paddedHeight(macro) <= partition.ly + partition.height - cutLine) {
656           chkArr[i] += 2;
657         }
658         // none of
659         if (chkArr[i] == 0) {
660           isImpossible = true;
661           break;
662         }
663       }
664     }
665     // impossible cuts, then skip
666     if (isImpossible) {
667       continue;
668     }
669 
670     // Fill in the Partitioning information
671     PartClass lClass = None, uClass = None;
672     switch (partition.partClass) {
673       case PartClass::ALL:
674         lClass = (horizontal) ? W : S;
675         uClass = (horizontal) ? E : N;
676         break;
677       case PartClass::W:
678         lClass = SW;
679         uClass = NW;
680         break;
681       case PartClass::E:
682         lClass = SE;
683         uClass = NE;
684         break;
685       case PartClass::N:
686         lClass = NW;
687         uClass = NE;
688         break;
689       case PartClass::S:
690         lClass = SW;
691         uClass = SE;
692         break;
693       default:
694         logger_->error(MPL, 12, "unhandled partition class");
695         lClass = W;
696         uClass = E;
697         break;
698     }
699 
700     Partition lowerPart(
701         lClass,
702         partition.lx,
703         partition.ly,
704         (horizontal) ? cutLine - partition.lx : partition.width,
705         (horizontal) ? partition.height : cutLine - partition.ly,
706         this,
707         logger_);
708 
709     Partition upperPart(uClass,
710                         (horizontal) ? cutLine : partition.lx,
711                         (horizontal) ? partition.ly : cutLine,
712                         (horizontal) ? partition.lx + partition.width - cutLine
713                                      : partition.width,
714                         (horizontal)
715                             ? partition.height
716                             : partition.ly + partition.height - cutLine,
717                         this,
718                         logger_);
719 
720     // Fill in child partitons' macros_
721     for (const Macro& macro : partition.macros_) {
722       int i = &macro - &partition.macros_[0];
723       if (chkArr[i] == 1) {
724         lowerPart.macros_.push_back(macro);
725       } else if (chkArr[i] == 2) {
726         upperPart.macros_.push_back(
727             Macro((horizontal) ? macro.lx - cutLine : macro.lx,
728                   (horizontal) ? macro.ly : macro.ly - cutLine,
729                   macro));
730       } else if (chkArr[i] == 3) {
731         double centerPoint = (horizontal) ? macro.lx + macro.w / 2.0
732                                           : macro.ly + macro.h / 2.0;
733 
734         if (centerPoint < cutLine) {
735           lowerPart.macros_.push_back(macro);
736 
737         } else {
738           upperPart.macros_.push_back(
739               Macro((horizontal) ? macro.lx - cutLine : macro.lx,
740                     (horizontal) ? macro.ly : macro.ly - cutLine,
741                     macro));
742         }
743       }
744     }
745 
746     double lowerArea = lowerPart.width * lowerPart.height;
747     double upperArea = upperPart.width * upperPart.height;
748 
749     double upperMacroArea = 0.0f;
750     double lowerMacroArea = 0.0f;
751 
752     for (auto& macro : upperPart.macros_) {
753       upperMacroArea += macro.w * macro.h;
754     }
755     for (auto& macro : lowerPart.macros_) {
756       lowerMacroArea += macro.w * macro.h;
757     }
758 
759     // impossible partitioning
760     if (upperMacroArea > upperArea || lowerMacroArea > lowerArea) {
761       logger_->info(MPL, 80, "Impossible partition found.");
762       continue;
763     }
764 
765     pair<Partition, Partition> curPart(lowerPart, upperPart);
766     partitions.push_back(curPart);
767   }
768   return partitions;
769 }
770 
paddedWidth(const Macro & macro)771 double MacroPlacer::paddedWidth(const Macro& macro)
772 {
773   MacroSpacings& spacings = getSpacings(macro);
774   return macro.w + spacings.getSpacingX() * 2;
775 }
776 
paddedHeight(const Macro & macro)777 double MacroPlacer::paddedHeight(const Macro& macro)
778 {
779   MacroSpacings& spacings = getSpacings(macro);
780   return macro.h + spacings.getSpacingY() * 2;
781 }
782 
findMacros()783 void MacroPlacer::findMacros()
784 {
785   dbBlock* block = db_->getChip()->getBlock();
786   const int dbu = db_->getTech()->getDbUnitsPerMicron();
787   for (dbInst* inst : block->getInsts()) {
788     if (inst->getMaster()->getType().isBlock()) {
789       // for Macro cells
790       dbPlacementStatus dps = inst->getPlacementStatus();
791       if (dps == dbPlacementStatus::NONE
792           || dps == dbPlacementStatus::UNPLACED) {
793         logger_->error(MPL,
794                        3,
795                        "Macro {} is unplaced. Use global_placement to get an "
796                        "initial placement before macro placement.",
797                        inst->getConstName());
798       }
799 
800       int placeX, placeY;
801       inst->getLocation(placeX, placeY);
802 
803       macro_inst_map_[inst] = macros_.size();
804       Macro macro(1.0 * placeX / dbu,
805                   1.0 * placeY / dbu,
806                   1.0 * inst->getBBox()->getDX() / dbu,
807                   1.0 * inst->getBBox()->getDY() / dbu,
808                   inst);
809       macros_.push_back(macro);
810     }
811   }
812 
813   if (macros_.empty()) {
814     logger_->error(MPL, 4, "No macros found.");
815   }
816 
817   logger_->info(MPL, 5, "Found {} macros", macros_.size());
818 }
819 
isWithIn(int val,int min,int max)820 static bool isWithIn(int val, int min, int max)
821 {
822   return ((min <= val) && (val <= max));
823 }
824 
getRoundUpFloat(float x,float unit)825 static float getRoundUpFloat(float x, float unit)
826 {
827   return round(x / unit) * unit;
828 }
829 
updateMacroLocations(Partition & part)830 void MacroPlacer::updateMacroLocations(Partition& part)
831 {
832   dbTech* tech = db_->getTech();
833   const float pitchX = static_cast<float>(snap_layer_->getPitchX())
834                        / tech->getDbUnitsPerMicron();
835   const float pitchY = static_cast<float>(snap_layer_->getPitchY())
836                        / tech->getDbUnitsPerMicron();
837 
838   for (auto& macro : part.macros_) {
839     // snap location to routing layer grid
840     float macroX = getRoundUpFloat(macro.lx, pitchX);
841     float macroY = getRoundUpFloat(macro.ly, pitchY);
842     macro.lx = macroX;
843     macro.ly = macroY;
844     // Update Macro Location
845     int macroIdx = macro_inst_map_[macro.dbInstPtr];
846     macros_[macroIdx].lx = macroX;
847     macros_[macroIdx].ly = macroY;
848   }
849 }
850 
851 #define EAST_IDX (macros_.size() + coreEdgeIndex(CoreEdge::East))
852 #define WEST_IDX (macros_.size() + coreEdgeIndex(CoreEdge::West))
853 #define NORTH_IDX (macros_.size() + coreEdgeIndex(CoreEdge::North))
854 #define SOUTH_IDX (macros_.size() + coreEdgeIndex(CoreEdge::South))
855 
getWeightedWL()856 double MacroPlacer::getWeightedWL()
857 {
858   double wwl = 0.0f;
859 
860   double width = ux_ - lx_;
861   double height = uy_ - ly_;
862 
863   for (size_t i = 0; i < macros_.size() + core_edge_count; i++) {
864     for (size_t j = i + 1; j < macros_.size() + core_edge_count; j++) {
865       double pointX1 = 0, pointY1 = 0;
866       if (i == EAST_IDX) {
867         pointX1 = lx_ + width;
868         pointY1 = ly_ + height / 2.0;
869       } else if (i == WEST_IDX) {
870         pointX1 = lx_;
871         pointY1 = ly_ + height / 2.0;
872       } else if (i == NORTH_IDX) {
873         pointX1 = lx_ + width / 2.0;
874         pointY1 = ly_ + height;
875       } else if (i == SOUTH_IDX) {
876         pointX1 = lx_ + width / 2.0;
877         pointY1 = ly_;
878       } else {
879         pointX1 = macros_[i].lx + macros_[i].w / 2;
880         pointY1 = macros_[i].ly + macros_[i].h / 2;
881       }
882 
883       double pointX2 = 0, pointY2 = 0;
884       if (j == EAST_IDX) {
885         pointX2 = lx_ + width;
886         pointY2 = ly_ + height / 2.0;
887       } else if (j == WEST_IDX) {
888         pointX2 = lx_;
889         pointY2 = ly_ + height / 2.0;
890       } else if (j == NORTH_IDX) {
891         pointX2 = lx_ + width / 2.0;
892         pointY2 = ly_ + height;
893       } else if (j == SOUTH_IDX) {
894         pointX2 = lx_ + width / 2.0;
895         pointY2 = ly_;
896       } else {
897         pointX2 = macros_[j].lx + macros_[j].w / 2;
898         pointY2 = macros_[j].ly + macros_[j].h / 2;
899       }
900 
901       float edgeWeight = 0.0f;
902       if (connection_driven_) {
903         edgeWeight = macro_weights_[i][j];
904       } else {
905         edgeWeight = 1;
906       }
907       double wl = std::sqrt((pointX1 - pointX2) * (pointX1 - pointX2)
908                             + (pointY1 - pointY2) * (pointY1 - pointY2));
909       double weighted_wl = edgeWeight * wl;
910       if (edgeWeight > 0)
911         debugPrint(logger_,
912                    MPL,
913                    "weighted_wl",
914                    1,
915                    "{} -> {} wl {:.2f} * weight {:.2f} = {:.2f}",
916                    macroIndexName(i),
917                    macroIndexName(j),
918                    wl,
919                    edgeWeight,
920                    weighted_wl);
921       wwl += weighted_wl;
922     }
923   }
924 
925   return wwl;
926 }
927 
Layout()928 Layout::Layout() : lx_(0), ly_(0), ux_(0), uy_(0)
929 {
930 }
931 
Layout(double lx,double ly,double ux,double uy)932 Layout::Layout(double lx, double ly, double ux, double uy)
933     : lx_(lx), ly_(ly), ux_(ux), uy_(uy)
934 {
935 }
936 
Layout(Layout & orig,Partition & part)937 Layout::Layout(Layout& orig, Partition& part)
938     : lx_(part.lx),
939       ly_(part.ly),
940       ux_(part.lx + part.width),
941       uy_(part.ly + part.height)
942 {
943 }
944 
setLx(double lx)945 void Layout::setLx(double lx)
946 {
947   lx_ = lx;
948 }
949 
setLy(double ly)950 void Layout::setLy(double ly)
951 {
952   ly_ = ly;
953 }
954 
setUx(double ux)955 void Layout::setUx(double ux)
956 {
957   ux_ = ux;
958 }
959 
setUy(double uy)960 void Layout::setUy(double uy)
961 {
962   uy_ = uy;
963 }
964 
getCoreEdge(int cx,int cy,int dieLx,int dieLy,int dieUx,int dieUy)965 static CoreEdge getCoreEdge(int cx,
966                             int cy,
967                             int dieLx,
968                             int dieLy,
969                             int dieUx,
970                             int dieUy)
971 {
972   int lxDx = abs(cx - dieLx);
973   int uxDx = abs(cx - dieUx);
974 
975   int lyDy = abs(cy - dieLy);
976   int uyDy = abs(cy - dieUy);
977 
978   int minDiff = std::min(lxDx, std::min(uxDx, std::min(lyDy, uyDy)));
979   if (minDiff == lxDx) {
980     return CoreEdge::West;
981   } else if (minDiff == uxDx) {
982     return CoreEdge::East;
983   } else if (minDiff == lyDy) {
984     return CoreEdge::South;
985   } else if (minDiff == uyDy) {
986     return CoreEdge::North;
987   }
988   return CoreEdge::West;
989 }
990 
991 ////////////////////////////////////////////////////////////////
992 
993 // Use OpenSTA graph to find macro adjacencies.
994 // No delay calculation or arrival search is required,
995 // just gate connectivity in the levelized graph.
findAdjacencies()996 void MacroPlacer::findAdjacencies()
997 {
998   sta_->ensureLevelized();
999   sta_->ensureClkNetwork();
1000   VertexFaninMap vertex_fanins;
1001   sta::SearchPred2 srch_pred(sta_);
1002   sta::BfsFwdIterator bfs(sta::BfsIndex::other, &srch_pred, sta_);
1003 
1004   seedFaninBfs(bfs, vertex_fanins);
1005   findFanins(bfs, vertex_fanins);
1006 
1007   // Propagate fanins through 3 levels of register D->Q.
1008   for (int i = 0; i < reg_adjacency_depth_; i++) {
1009     copyFaninsAcrossRegisters(bfs, vertex_fanins);
1010     findFanins(bfs, vertex_fanins);
1011   }
1012 
1013   AdjWeightMap adj_map;
1014   findAdjWeights(vertex_fanins, adj_map);
1015 
1016   fillMacroWeights(adj_map);
1017 }
1018 
seedFaninBfs(sta::BfsFwdIterator & bfs,VertexFaninMap & vertex_fanins)1019 void MacroPlacer::seedFaninBfs(sta::BfsFwdIterator& bfs,
1020                                VertexFaninMap& vertex_fanins)
1021 {
1022   sta::dbNetwork* network = sta_->getDbNetwork();
1023   sta::Graph* graph = sta_->ensureGraph();
1024   // Seed the BFS with macro output pins.
1025   for (Macro& macro : macros_) {
1026     for (dbITerm* iterm : macro.dbInstPtr->getITerms()) {
1027       sta::Pin* pin = network->dbToSta(iterm);
1028       if (network->direction(pin)->isAnyOutput() && !sta_->isClock(pin)) {
1029         sta::Vertex* vertex = graph->pinDrvrVertex(pin);
1030         vertex_fanins[vertex].insert(&macro);
1031         bfs.enqueueAdjacentVertices(vertex);
1032       }
1033     }
1034   }
1035   // Seed top level ports input ports.
1036   for (dbBTerm* bterm : db_->getChip()->getBlock()->getBTerms()) {
1037     sta::Pin* pin = network->dbToSta(bterm);
1038     if (network->direction(pin)->isAnyInput() && !sta_->isClock(pin)) {
1039       sta::Vertex* vertex = graph->pinDrvrVertex(pin);
1040       CoreEdge edge = findNearestEdge(bterm);
1041       vertex_fanins[vertex].insert(reinterpret_cast<Macro*>(edge));
1042       bfs.enqueueAdjacentVertices(vertex);
1043     }
1044   }
1045 }
1046 
1047 // BFS search forward union-ing fanins.
1048 // BFS stops at register inputs because there are no timing arcs
1049 // from register D->Q.
findFanins(sta::BfsFwdIterator & bfs,VertexFaninMap & vertex_fanins)1050 void MacroPlacer::findFanins(sta::BfsFwdIterator& bfs,
1051                              VertexFaninMap& vertex_fanins)
1052 {
1053   sta::dbNetwork* network = sta_->getDbNetwork();
1054   sta::Graph* graph = sta_->ensureGraph();
1055   while (bfs.hasNext()) {
1056     sta::Vertex* vertex = bfs.next();
1057     MacroSet& fanins = vertex_fanins[vertex];
1058     sta::VertexInEdgeIterator fanin_iter(vertex, graph);
1059     while (fanin_iter.hasNext()) {
1060       sta::Edge* edge = fanin_iter.next();
1061       sta::Vertex* fanin = edge->from(graph);
1062       // Union fanins sets of fanin vertices.
1063       for (Macro* fanin : vertex_fanins[fanin]) {
1064         fanins.insert(fanin);
1065         debugPrint(logger_,
1066                    MPL,
1067                    "find_fanins",
1068                    1,
1069                    "{} + {}",
1070                    vertex->name(network),
1071                    faninName(fanin));
1072       }
1073     }
1074     bfs.enqueueAdjacentVertices(vertex);
1075   }
1076 }
1077 
copyFaninsAcrossRegisters(sta::BfsFwdIterator & bfs,VertexFaninMap & vertex_fanins)1078 void MacroPlacer::copyFaninsAcrossRegisters(sta::BfsFwdIterator& bfs,
1079                                             VertexFaninMap& vertex_fanins)
1080 {
1081   sta::dbNetwork* network = sta_->getDbNetwork();
1082   sta::Graph* graph = sta_->ensureGraph();
1083   sta::Instance* top_inst = network->topInstance();
1084   sta::LeafInstanceIterator* leaf_iter
1085       = network->leafInstanceIterator(top_inst);
1086   while (leaf_iter->hasNext()) {
1087     sta::Instance* inst = leaf_iter->next();
1088     sta::LibertyCell* lib_cell = network->libertyCell(inst);
1089     if (lib_cell->hasSequentials() && !lib_cell->isMacro()) {
1090       sta::LibertyCellSequentialIterator seq_iter(lib_cell);
1091       while (seq_iter.hasNext()) {
1092         sta::Sequential* seq = seq_iter.next();
1093         sta::FuncExpr* data_expr = seq->data();
1094         sta::FuncExprPortIterator data_port_iter(data_expr);
1095         while (data_port_iter.hasNext()) {
1096           sta::LibertyPort* data_port = data_port_iter.next();
1097           sta::Pin* data_pin = network->findPin(inst, data_port);
1098           sta::LibertyPort* out_port = seq->output();
1099           sta::Pin* out_pin = findSeqOutPin(inst, out_port);
1100           if (data_pin && out_pin) {
1101             sta::Vertex* data_vertex = graph->pinLoadVertex(data_pin);
1102             sta::Vertex* out_vertex = graph->pinDrvrVertex(out_pin);
1103             // Copy fanins from D to Q on register.
1104             vertex_fanins[out_vertex] = vertex_fanins[data_vertex];
1105             bfs.enqueueAdjacentVertices(out_vertex);
1106           }
1107         }
1108       }
1109     }
1110   }
1111   delete leaf_iter;
1112 }
1113 
1114 // Sequential outputs are generally to internal pins that are not physically
1115 // part of the instance. Find the output port with a function that uses
1116 // the internal port.
findSeqOutPin(sta::Instance * inst,sta::LibertyPort * out_port)1117 sta::Pin* MacroPlacer::findSeqOutPin(sta::Instance* inst,
1118                                      sta::LibertyPort* out_port)
1119 {
1120   sta::dbNetwork* network = sta_->getDbNetwork();
1121   if (out_port->direction()->isInternal()) {
1122     sta::InstancePinIterator* pin_iter = network->pinIterator(inst);
1123     while (pin_iter->hasNext()) {
1124       sta::Pin* pin = pin_iter->next();
1125       sta::LibertyPort* lib_port = network->libertyPort(pin);
1126       if (lib_port->direction()->isAnyOutput()) {
1127         sta::FuncExpr* func = lib_port->function();
1128         if (func->hasPort(out_port)) {
1129           sta::Pin* out_pin = network->findPin(inst, lib_port);
1130           if (out_pin) {
1131             delete pin_iter;
1132             return out_pin;
1133           }
1134         }
1135       }
1136     }
1137     delete pin_iter;
1138     return nullptr;
1139   } else
1140     return network->findPin(inst, out_port);
1141 }
1142 
findAdjWeights(VertexFaninMap & vertex_fanins,AdjWeightMap & adj_map)1143 void MacroPlacer::findAdjWeights(VertexFaninMap& vertex_fanins,
1144                                  AdjWeightMap& adj_map)
1145 {
1146   sta::dbNetwork* network = sta_->getDbNetwork();
1147   sta::Graph* graph = sta_->ensureGraph();
1148   // Find adjacencies from macro input pin fanins.
1149   for (Macro& macro : macros_) {
1150     for (dbITerm* iterm : macro.dbInstPtr->getITerms()) {
1151       sta::Pin* pin = network->dbToSta(iterm);
1152       if (network->direction(pin)->isAnyInput()) {
1153         sta::Vertex* vertex = graph->pinLoadVertex(pin);
1154         MacroSet& pin_fanins = vertex_fanins[vertex];
1155         for (Macro* pin_fanin : pin_fanins) {
1156           // Adjacencies are symmetric so only fill in one side.
1157           if (pin_fanin != &macro) {
1158             MacroPair from_to = (pin_fanin > &macro)
1159                                     ? MacroPair(pin_fanin, &macro)
1160                                     : MacroPair(&macro, pin_fanin);
1161             adj_map[from_to]++;
1162           }
1163         }
1164       }
1165     }
1166   }
1167   // Find adjacencies from output pin fanins.
1168   for (dbBTerm* bterm : db_->getChip()->getBlock()->getBTerms()) {
1169     sta::Pin* pin = network->dbToSta(bterm);
1170     if (network->direction(pin)->isAnyOutput() && !sta_->isClock(pin)) {
1171       sta::Vertex* vertex = graph->pinDrvrVertex(pin);
1172       CoreEdge edge = findNearestEdge(bterm);
1173       debugPrint(logger_,
1174                  MPL,
1175                  "pin_edge",
1176                  1,
1177                  "pin edge {} {}",
1178                  bterm->getConstName(),
1179                  coreEdgeString(edge));
1180       int edge_index = static_cast<int>(edge);
1181       Macro* macro = reinterpret_cast<Macro*>(edge_index);
1182       MacroSet& edge_fanins = vertex_fanins[vertex];
1183       for (Macro* edge_fanin : edge_fanins) {
1184         if (edge_fanin != macro) {
1185           // Adjacencies are symmetric so only fill in one side.
1186           MacroPair from_to = (edge_fanin > macro)
1187                                   ? MacroPair(edge_fanin, macro)
1188                                   : MacroPair(macro, edge_fanin);
1189           adj_map[from_to]++;
1190         }
1191       }
1192     }
1193   }
1194 }
1195 
1196 // Fill macro_weights_ array.
fillMacroWeights(AdjWeightMap & adj_map)1197 void MacroPlacer::fillMacroWeights(AdjWeightMap& adj_map)
1198 {
1199   size_t weight_size = macros_.size() + core_edge_count;
1200   macro_weights_.resize(weight_size);
1201   for (size_t i = 0; i < weight_size; i++) {
1202     macro_weights_[i].resize(weight_size);
1203     macro_weights_[i] = {0};
1204   }
1205 
1206   for (auto pair_weight : adj_map) {
1207     const MacroPair& from_to = pair_weight.first;
1208     Macro* from = from_to.first;
1209     Macro* to = from_to.second;
1210     float weight = pair_weight.second;
1211     if (!(macroIndexIsEdge(from) && macroIndexIsEdge(to))) {
1212       int idx1 = macroIndex(from);
1213       int idx2 = macroIndex(to);
1214       // Note macro_weights only has entries for idx1 < idx2.
1215       macro_weights_[min(idx1, idx2)][max(idx1, idx2)] = weight;
1216       if (weight > 0)
1217         debugPrint(logger_,
1218                    MPL,
1219                    "weights",
1220                    1,
1221                    "{} -> {} {}",
1222                    faninName(from),
1223                    faninName(to),
1224                    weight);
1225     }
1226   }
1227 }
1228 
faninName(Macro * macro)1229 std::string MacroPlacer::faninName(Macro* macro)
1230 {
1231   intptr_t edge_index = reinterpret_cast<intptr_t>(macro);
1232   if (edge_index < core_edge_count)
1233     return coreEdgeString(static_cast<CoreEdge>(edge_index));
1234   else
1235     return macro->name();
1236 }
1237 
1238 // This has to be consistent with the accessors in EAST_IDX
macroIndex(Macro * macro)1239 int MacroPlacer::macroIndex(Macro* macro)
1240 {
1241   intptr_t edge_index = reinterpret_cast<intptr_t>(macro);
1242   if (edge_index < core_edge_count)
1243     return macros_.size() + edge_index;
1244   else
1245     return macro - &macros_[0];
1246 }
1247 
macroIndexName(int index)1248 string MacroPlacer::macroIndexName(int index)
1249 {
1250   if (index < macros_.size())
1251     return macros_[index].name();
1252   else
1253     return coreEdgeString(static_cast<CoreEdge>(index - macros_.size()));
1254 }
1255 
macroIndex(dbInst * inst)1256 int MacroPlacer::macroIndex(dbInst* inst)
1257 {
1258   return macro_inst_map_[inst];
1259 }
1260 
macroIndexIsEdge(Macro * macro)1261 bool MacroPlacer::macroIndexIsEdge(Macro* macro)
1262 {
1263   intptr_t edge_index = reinterpret_cast<intptr_t>(macro);
1264   return edge_index < core_edge_count;
1265 }
1266 
1267 // This assumes the pins straddle the die/fence boundary.
1268 // It should look for the nearest edge to the pin center. -cherry
findNearestEdge(dbBTerm * bTerm)1269 CoreEdge MacroPlacer::findNearestEdge(dbBTerm* bTerm)
1270 {
1271   dbPlacementStatus status = bTerm->getFirstPinPlacementStatus();
1272   if (status == dbPlacementStatus::UNPLACED
1273       || status == dbPlacementStatus::NONE) {
1274     logger_->warn(
1275         MPL, 11, "pin {} is not placed. Using west.", bTerm->getConstName());
1276     return CoreEdge::West;
1277   } else {
1278     const double dbu = db_->getTech()->getDbUnitsPerMicron();
1279 
1280     int dbuCoreLx = round(lx_ * dbu);
1281     int dbuCoreLy = round(ly_ * dbu);
1282     int dbuCoreUx = round(ux_ * dbu);
1283     int dbuCoreUy = round(uy_ * dbu);
1284 
1285     int placeX = 0, placeY = 0;
1286     bool isAxisFound = false;
1287     bTerm->getFirstPinLocation(placeX, placeY);
1288     for (dbBPin* bPin : bTerm->getBPins()) {
1289       Rect pin_bbox = bPin->getBBox();
1290       int boxLx = pin_bbox.xMin();
1291       int boxLy = pin_bbox.yMin();
1292       int boxUx = pin_bbox.xMax();
1293       int boxUy = pin_bbox.yMax();
1294 
1295       if (isWithIn(dbuCoreLx, boxLx, boxUx)) {
1296         return CoreEdge::West;
1297       } else if (isWithIn(dbuCoreUx, boxLx, boxUx)) {
1298         return CoreEdge::East;
1299       } else if (isWithIn(dbuCoreLy, boxLy, boxUy)) {
1300         return CoreEdge::South;
1301       } else if (isWithIn(dbuCoreUy, boxLy, boxUy)) {
1302         return CoreEdge::North;
1303       }
1304     }
1305     if (!isAxisFound) {
1306       dbBPin* bPin = *(bTerm->getBPins().begin());
1307       Rect pin_bbox = bPin->getBBox();
1308       int boxLx = pin_bbox.xMin();
1309       int boxLy = pin_bbox.yMin();
1310       int boxUx = pin_bbox.xMax();
1311       int boxUy = pin_bbox.yMax();
1312       return getCoreEdge((boxLx + boxUx) / 2,
1313                          (boxLy + boxUy) / 2,
1314                          dbuCoreLx,
1315                          dbuCoreLy,
1316                          dbuCoreUx,
1317                          dbuCoreUy);
1318     }
1319   }
1320   return CoreEdge::West;
1321 }
1322 
1323 ////////////////////////////////////////////////////////////////
1324 
getSpacings(const Macro & macro)1325 MacroSpacings& MacroPlacer::getSpacings(const Macro& macro)
1326 {
1327   auto itr = macro_spacings_.find(macro.dbInstPtr);
1328   if (itr == macro_spacings_.end())
1329     return default_macro_spacings_;
1330   else
1331     return itr->second;
1332 }
1333 
1334 ////////////////////////////////////////////////////////////////
1335 
coreEdgeString(CoreEdge edge)1336 const char* coreEdgeString(CoreEdge edge)
1337 {
1338   switch (edge) {
1339     case CoreEdge::West:
1340       return "West";
1341     case CoreEdge::East:
1342       return "East";
1343     case CoreEdge::North:
1344       return "North";
1345     case CoreEdge::South:
1346       return "South";
1347     default:
1348       return "??";
1349   }
1350 }
1351 
coreEdgeIndex(CoreEdge edge)1352 int coreEdgeIndex(CoreEdge edge)
1353 {
1354   return static_cast<int>(edge);
1355 }
1356 
coreEdgeFromIndex(int edge_index)1357 CoreEdge coreEdgeFromIndex(int edge_index)
1358 {
1359   return static_cast<CoreEdge>(edge_index);
1360 }
1361 
1362 ////////////////////////////////////////////////////////////////
1363 
1364 // Most of what is in this class is the dbInst and should be functions
1365 // instead of class variables. -cherry
Macro(double _lx,double _ly,double _w,double _h,odb::dbInst * _dbInstPtr)1366 Macro::Macro(double _lx,
1367              double _ly,
1368              double _w,
1369              double _h,
1370              odb::dbInst* _dbInstPtr)
1371     : lx(_lx), ly(_ly), w(_w), h(_h), dbInstPtr(_dbInstPtr)
1372 {
1373 }
1374 
Macro(double _lx,double _ly,const Macro & copy_from)1375 Macro::Macro(double _lx, double _ly, const Macro& copy_from)
1376     : lx(_lx),
1377       ly(_ly),
1378       w(copy_from.w),
1379       h(copy_from.h),
1380       dbInstPtr(copy_from.dbInstPtr)
1381 {
1382 }
1383 
name()1384 std::string Macro::name()
1385 {
1386   return dbInstPtr->getName();
1387 }
1388 
MacroSpacings()1389 MacroSpacings::MacroSpacings()
1390     : halo_x_(0), halo_y_(0), channel_x_(0), channel_y_(0)
1391 {
1392 }
1393 
MacroSpacings(double halo_x,double halo_y,double channel_x,double channel_y)1394 MacroSpacings::MacroSpacings(double halo_x,
1395                              double halo_y,
1396                              double channel_x,
1397                              double channel_y)
1398     : halo_x_(halo_x),
1399       halo_y_(halo_y),
1400       channel_x_(channel_x),
1401       channel_y_(channel_y)
1402 {
1403 }
1404 
setHalo(double halo_x,double halo_y)1405 void MacroSpacings::setHalo(double halo_x, double halo_y)
1406 {
1407   halo_x_ = halo_x;
1408   halo_y_ = halo_y;
1409 }
1410 
setChannel(double channel_x,double channel_y)1411 void MacroSpacings::setChannel(double channel_x, double channel_y)
1412 {
1413   channel_x_ = channel_x;
1414   channel_y_ = channel_y;
1415 }
1416 
setChannelX(double channel_x)1417 void MacroSpacings::setChannelX(double channel_x)
1418 {
1419   channel_x_ = channel_x;
1420 }
1421 
setChannelY(double channel_y)1422 void MacroSpacings::setChannelY(double channel_y)
1423 {
1424   channel_y_ = channel_y;
1425 }
1426 
getSpacingX() const1427 double MacroSpacings::getSpacingX() const
1428 {
1429   return max(halo_x_, channel_x_ / 2);
1430 }
1431 
getSpacingY() const1432 double MacroSpacings::getSpacingY() const
1433 {
1434   return max(halo_y_, channel_y_ / 2);
1435 }
1436 
1437 }  // namespace mpl
1438