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(¯o - &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 = ¯o - &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 = ¯o - &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(¯o);
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 != ¯o) {
1158 MacroPair from_to = (pin_fanin > ¯o)
1159 ? MacroPair(pin_fanin, ¯o)
1160 : MacroPair(¯o, 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 - ¯os_[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