diff --git a/src/mpl/src/SimulatedAnnealingCore.cpp b/src/mpl/src/SimulatedAnnealingCore.cpp index 26c4c0fe273..1e7fad9cf9f 100644 --- a/src/mpl/src/SimulatedAnnealingCore.cpp +++ b/src/mpl/src/SimulatedAnnealingCore.cpp @@ -87,9 +87,18 @@ SimulatedAnnealingCore::SimulatedAnnealingCore(PhysicalHierarchy* tree, logger_ = logger; macros_ = macros; + setDieArea(tree->die_area); setBlockedBoundariesForIOs(); } +template +void SimulatedAnnealingCore::setDieArea(const Rect& die_area) +{ + die_area_ = die_area; + die_area_.moveHor(-outline_.xMin()); + die_area_.moveVer(-outline_.yMin()); +} + template void SimulatedAnnealingCore::setBlockedBoundariesForIOs() { @@ -327,42 +336,42 @@ void SimulatedAnnealingCore::calWirelength() template void SimulatedAnnealingCore::addBoundaryDistToWirelength( const T& macro, - const T& io, + const T& unplaced_ios, const float net_weight) { - Cluster* io_cluster = io.getCluster(); - const Rect die = io_cluster->getBBox(); - const float die_hpwl = die.getWidth() + die.getHeight(); + // To generate maximum cost. + const float max_dist = die_area_.getPerimeter() / 2; if (isOutsideTheOutline(macro)) { - wirelength_ += net_weight * die_hpwl; + wirelength_ += net_weight * max_dist; return; } const float x1 = macro.getPinX(); const float y1 = macro.getPinY(); - Boundary constraint_boundary = io_cluster->getConstraintBoundary(); + Boundary constraint_boundary + = unplaced_ios.getCluster()->getConstraintBoundary(); if (constraint_boundary == NONE) { - float dist_to_left = die_hpwl; + float dist_to_left = max_dist; if (!left_is_blocked_) { - dist_to_left = std::abs(x1 - die.xMin()); + dist_to_left = std::abs(x1 - die_area_.xMin()); } - float dist_to_right = die_hpwl; + float dist_to_right = max_dist; if (!right_is_blocked_) { - dist_to_right = std::abs(x1 - die.xMax()); + dist_to_right = std::abs(x1 - die_area_.xMax()); } - float dist_to_bottom = die_hpwl; + float dist_to_bottom = max_dist; if (!bottom_is_blocked_) { - dist_to_right = std::abs(y1 - die.yMin()); + dist_to_right = std::abs(y1 - die_area_.yMin()); } - float dist_to_top = die_hpwl; + float dist_to_top = max_dist; if (!top_is_blocked_) { - dist_to_top = std::abs(y1 - die.yMax()); + dist_to_top = std::abs(y1 - die_area_.yMax()); } wirelength_ @@ -371,11 +380,11 @@ void SimulatedAnnealingCore::addBoundaryDistToWirelength( {dist_to_left, dist_to_right, dist_to_bottom, dist_to_top}); } else if (constraint_boundary == Boundary::L || constraint_boundary == Boundary::R) { - const float x2 = io.getPinX(); + const float x2 = unplaced_ios.getPinX(); wirelength_ += net_weight * std::abs(x2 - x1); } else if (constraint_boundary == Boundary::T || constraint_boundary == Boundary::B) { - const float y2 = io.getPinY(); + const float y2 = unplaced_ios.getPinY(); wirelength_ += net_weight * std::abs(y2 - y1); } } diff --git a/src/mpl/src/SimulatedAnnealingCore.h b/src/mpl/src/SimulatedAnnealingCore.h index 7fe8104df43..bb46315a13c 100644 --- a/src/mpl/src/SimulatedAnnealingCore.h +++ b/src/mpl/src/SimulatedAnnealingCore.h @@ -127,6 +127,7 @@ class SimulatedAnnealingCore void fastSA(); void initSequencePair(); + void setDieArea(const Rect& die_area); void setBlockedBoundariesForIOs(); void updateBestValidResult(); void useBestValidResult(); @@ -136,7 +137,7 @@ class SimulatedAnnealingCore void calOutlinePenalty(); void calWirelength(); void addBoundaryDistToWirelength(const T& macro, - const T& io, + const T& unplaced_ios, float net_weight); bool isOutsideTheOutline(const T& macro) const; void calGuidancePenalty(); @@ -163,11 +164,8 @@ class SimulatedAnnealingCore void reportLocations() const; void report(const PenaltyData& penalty) const; - ///////////////////////////////////////////// - // private member variables - ///////////////////////////////////////////// - // boundary constraints Rect outline_; + Rect die_area_; // Offset to the current outline. // Boundaries blocked for IO pins std::set blocked_boundaries_; diff --git a/src/mpl/src/clusterEngine.cpp b/src/mpl/src/clusterEngine.cpp index ae73902f84e..7e87fd07d71 100644 --- a/src/mpl/src/clusterEngine.cpp +++ b/src/mpl/src/clusterEngine.cpp @@ -111,6 +111,7 @@ void ClusteringEngine::init() return; } + setDieArea(); setFloorplanShape(); searchForFixedInstsInsideFloorplanShape(); @@ -130,6 +131,19 @@ void ClusteringEngine::init() reportDesignData(); } +// Note: The die area's dimensions will be used inside +// SA Core when computing the wirelength in a situation in which +// the target cluster is a cluster of unplaced IOs. +void ClusteringEngine::setDieArea() +{ + const odb::Rect& die = block_->getDieArea(); + + tree_->die_area = Rect(block_->dbuToMicrons(die.xMin()), + block_->dbuToMicrons(die.yMin()), + block_->dbuToMicrons(die.xMax()), + block_->dbuToMicrons(die.yMax())); +} + float ClusteringEngine::computeMacroWithHaloArea( const std::vector& unfixed_macros) { diff --git a/src/mpl/src/clusterEngine.h b/src/mpl/src/clusterEngine.h index b2ade123650..b90dcedacd9 100644 --- a/src/mpl/src/clusterEngine.h +++ b/src/mpl/src/clusterEngine.h @@ -123,6 +123,7 @@ struct PhysicalHierarchy float macro_with_halo_area{0.0f}; Rect global_fence; Rect floorplan_shape; + Rect die_area; bool has_io_clusters{true}; bool has_only_macros{false}; @@ -182,6 +183,7 @@ class ClusteringEngine void init(); Metrics* computeModuleMetrics(odb::dbModule* module); std::vector getUnfixedMacros(); + void setDieArea(); void setFloorplanShape(); void searchForFixedInstsInsideFloorplanShape(); float computeMacroWithHaloArea( diff --git a/src/mpl/src/graphics.cpp b/src/mpl/src/graphics.cpp index deee9a31b6c..afba226edd6 100644 --- a/src/mpl/src/graphics.cpp +++ b/src/mpl/src/graphics.cpp @@ -638,14 +638,12 @@ void Graphics::drawDistToIoConstraintBoundary(gui::Painter& painter, return; } - Cluster* io_cluster = io.getCluster(); - const int x1 = block_->micronsToDbu(macro.getPinX()); const int y1 = block_->micronsToDbu(macro.getPinY()); odb::Point from(x1, y1); odb::Point to; - Boundary constraint_boundary = io_cluster->getConstraintBoundary(); + Boundary constraint_boundary = io.getCluster()->getConstraintBoundary(); if (constraint_boundary == Boundary::L || constraint_boundary == Boundary::R) { @@ -660,12 +658,14 @@ void Graphics::drawDistToIoConstraintBoundary(gui::Painter& painter, to.setX(x2); to.setY(y2); } else { - // For NONE, the shape of the io cluster is the die area. - const Rect die = io_cluster->getBBox(); + // We need to use the bbox of the SoftMacro to get the necessary + // offset compensation (the cluster bbox is the bbox w.r.t. to the + // actual die area). + const Rect offset_die = io.getBBox(); Boundary closest_unblocked_boundary - = getClosestUnblockedBoundary(macro, die); + = getClosestUnblockedBoundary(macro, offset_die); - to = getClosestBoundaryPoint(macro, die, closest_unblocked_boundary); + to = getClosestBoundaryPoint(macro, offset_die, closest_unblocked_boundary); } addOutlineOffsetToLine(from, to); @@ -696,19 +696,15 @@ odb::Point Graphics::getClosestBoundaryPoint(const T& macro, if (closest_boundary == Boundary::L) { to.setX(block_->micronsToDbu(die.xMin())); to.setY(block_->micronsToDbu(macro.getPinY())); - to.addX(-outline_.xMin()); } else if (closest_boundary == Boundary::R) { to.setX(block_->micronsToDbu(die.xMax())); to.setY(block_->micronsToDbu(macro.getPinY())); - to.addX(-outline_.xMin()); } else if (closest_boundary == Boundary::B) { to.setX(block_->micronsToDbu(macro.getPinX())); to.setY(block_->micronsToDbu(die.yMin())); - to.addY(-outline_.yMin()); } else { // Top to.setX(block_->micronsToDbu(macro.getPinX())); to.setY(block_->micronsToDbu(die.yMax())); - to.addY(-outline_.yMin()); } return to; diff --git a/src/mpl/src/hier_rtlmp.cpp b/src/mpl/src/hier_rtlmp.cpp index 0173bd4b41e..2a684fba1f8 100644 --- a/src/mpl/src/hier_rtlmp.cpp +++ b/src/mpl/src/hier_rtlmp.cpp @@ -1949,41 +1949,53 @@ void HierRTLMP::createFixedTerminals( parents.push(parent); while (!parents.empty()) { - auto frontwave = parents.front(); + Cluster* frontwave = parents.front(); parents.pop(); Cluster* grandparent = frontwave->getParent(); for (auto& cluster : grandparent->getChildren()) { if (cluster->getId() != frontwave->getId()) { - soft_macro_id_map[cluster->getName()] - = static_cast(soft_macros.size()); - - const float center_x = cluster->getX() + cluster->getWidth() / 2.0; - const float center_y = cluster->getY() + cluster->getHeight() / 2.0; - Point location = {center_x - outline.xMin(), center_y - outline.yMin()}; - - // The information of whether or not a cluster is a group of - // unplaced IO pins is needed inside the SA Core, so if a fixed - // terminal corresponds to a cluster of unplaced IO pins it needs - // to contain that cluster data. - Cluster* fixed_terminal_cluster - = cluster->isClusterOfUnplacedIOPins() ? cluster.get() : nullptr; - - // Note that a fixed terminal is just a point. - soft_macros.emplace_back(location, - cluster->getName(), - 0.0f /* width */, - 0.0f /* height */, - fixed_terminal_cluster); + const int id = static_cast(soft_macros.size()); + soft_macro_id_map[cluster->getName()] = id; + createFixedTerminal(cluster.get(), outline, soft_macros); } } - if (frontwave->getParent()->getParent() != nullptr) { + if (frontwave->getParent()->getParent()) { parents.push(frontwave->getParent()); } } } +template +void HierRTLMP::createFixedTerminal(Cluster* cluster, + const Rect& outline, + std::vector& macros) +{ + // A conventional fixed terminal is just a point without + // the cluster data. + Point location = cluster->getCenter(); + float width = 0.0f; + float height = 0.0f; + Cluster* terminal_cluster = nullptr; + + if (cluster->isClusterOfUnplacedIOPins()) { + // Clusters of unplaced IOs are not treated as conventional + // fixed terminals. As they correspond to regions, we need + // both their actual shape and their cluster data inside SA. + location = {cluster->getX(), cluster->getY()}; + width = cluster->getWidth(); + height = cluster->getHeight(); + terminal_cluster = cluster; + } + + location.first -= outline.xMin(); + location.second -= outline.yMin(); + + macros.emplace_back( + location, cluster->getName(), width, height, terminal_cluster); +} + // Determine the shape of each cluster based on target utilization // and target dead space. In constrast to all previous works, we // use two parameters: target utilization, target_dead_space. @@ -2429,6 +2441,7 @@ void HierRTLMP::computeFencesAndGuides( } } +// Create terminals for macro placement (Hard) annealing. void HierRTLMP::createFixedTerminals(const Rect& outline, const UniqueClusterVector& macro_clusters, std::map& cluster_to_macro, @@ -2446,22 +2459,12 @@ void HierRTLMP::createFixedTerminals(const Rect& outline, if (cluster_to_macro.find(cluster_id) != cluster_to_macro.end()) { continue; } - auto& temp_cluster = tree_->maps.id_to_cluster[cluster_id]; - - // model other cluster as a fixed macro with zero size - cluster_to_macro[cluster_id] = sa_macros.size(); - sa_macros.emplace_back( - std::pair( - temp_cluster->getX() + temp_cluster->getWidth() / 2.0 - - outline.xMin(), - temp_cluster->getY() + temp_cluster->getHeight() / 2.0 - - outline.yMin()), - temp_cluster->getName(), - // The information of whether or not a cluster is a group of - // unplaced IO pins is needed inside the SA Core, so if a fixed - // terminal corresponds to a cluster of unplaced IO pins it needs - // to contain that cluster data. - temp_cluster->isClusterOfUnplacedIOPins() ? temp_cluster : nullptr); + + Cluster* temp_cluster = tree_->maps.id_to_cluster[cluster_id]; + const int terminal_id = static_cast(sa_macros.size()); + + cluster_to_macro[cluster_id] = terminal_id; + createFixedTerminal(temp_cluster, outline, sa_macros); } } diff --git a/src/mpl/src/hier_rtlmp.h b/src/mpl/src/hier_rtlmp.h index de398e93ba9..eec916a7b82 100644 --- a/src/mpl/src/hier_rtlmp.h +++ b/src/mpl/src/hier_rtlmp.h @@ -245,6 +245,11 @@ class HierRTLMP odb::Rect micronsToDbu(const Rect& micron_rect); Rect dbuToMicrons(const odb::Rect& dbu_rect); + template + void createFixedTerminal(Cluster* cluster, + const Rect& outline, + std::vector& macros); + // For debugging template void printPlacementResult(Cluster* parent, diff --git a/src/mpl/src/object.cpp b/src/mpl/src/object.cpp index 8d1a77f675e..9e3e6b2f659 100644 --- a/src/mpl/src/object.cpp +++ b/src/mpl/src/object.cpp @@ -493,6 +493,11 @@ Rect Cluster::getBBox() const return soft_macro_->getBBox(); } +Point Cluster::getCenter() const +{ + return {getX() + getWidth() / 2.0, getY() + getHeight() / 2.0}; +} + // Hierarchy Support void Cluster::setParent(Cluster* parent) { @@ -755,17 +760,19 @@ void Cluster::addVirtualConnection(int src, int target) /////////////////////////////////////////////////////////////////////// // HardMacro -HardMacro::HardMacro(std::pair loc, +HardMacro::HardMacro(std::pair location, const std::string& name, + float width, + float height, Cluster* cluster) { - width_ = 0.0; - height_ = 0.0; + width_ = width; + height_ = height; name_ = name; pin_x_ = 0.0; pin_y_ = 0.0; - x_ = loc.first; - y_ = loc.second; + x_ = location.first; + y_ = location.second; cluster_ = cluster; } @@ -840,6 +847,11 @@ bool HardMacro::isClusterOfUnplacedIOPins() const return cluster_->isClusterOfUnplacedIOPins(); } +Rect HardMacro::getBBox() const +{ + return Rect(x_, y_, x_ + width_, y_ + height_); +} + // Get Physical Information // Note that the default X and Y include halo_width void HardMacro::setLocation(const std::pair& location) @@ -978,19 +990,25 @@ SoftMacro::SoftMacro(float width, float height, const std::string& name) cluster_ = nullptr; } -// Create a SoftMacro representing the IO cluster or fixed terminals -SoftMacro::SoftMacro(const std::pair& pos, +// Create a SoftMacro representing a cluster of unplaced IOs or fixed terminals +SoftMacro::SoftMacro(const std::pair& location, const std::string& name, float width, float height, Cluster* cluster) { name_ = name; - x_ = pos.first; - y_ = pos.second; + x_ = location.first; + y_ = location.second; width_ = width; height_ = height; - area_ = 0.0; // width_ * height_ = 0.0 for this case + + // Even though clusters of unplaced IOs have shapes, i.e., are not + // just points, their area should be zero, because we use the area + // to check whether or not a SoftMacro if a fixed terminal or cluster + // of unplaced IOs inside SA. Ideally we should check the fixed flag. + area_ = 0.0f; + cluster_ = cluster; fixed_ = true; } diff --git a/src/mpl/src/object.h b/src/mpl/src/object.h index 4155d9a452d..0cc8717a34b 100644 --- a/src/mpl/src/object.h +++ b/src/mpl/src/object.h @@ -244,6 +244,7 @@ class Cluster void setY(float y); std::pair getLocation() const; Rect getBBox() const; + Point getCenter() const; // Hierarchy Support void setParent(Cluster* parent); @@ -353,9 +354,11 @@ class HardMacro public: // Create a macro with specified size // Model fixed terminals - HardMacro(std::pair loc, + HardMacro(std::pair location, const std::string& name, - Cluster* cluster = nullptr); + float width, + float height, + Cluster* cluster); // In this case, we model the pin position at the center of the macro HardMacro(float width, float height, const std::string& name); @@ -371,6 +374,7 @@ class HardMacro void setCluster(Cluster* cluster) { cluster_ = cluster; } Cluster* getCluster() const { return cluster_; } bool isClusterOfUnplacedIOPins() const; + Rect getBBox() const; // Get Physical Information // Note that the default X and Y include halo_width @@ -494,12 +498,11 @@ class SoftMacro // Create a SoftMacro representing the blockage SoftMacro(float width, float height, const std::string& name); - // Create a SoftMacro representing the IO cluster - SoftMacro(const std::pair& pos, + SoftMacro(const std::pair& location, const std::string& name, - float width = 0.0, - float height = 0.0, - Cluster* cluster = nullptr); + float width, + float height, + Cluster* cluster); // create a SoftMacro from a cluster SoftMacro(Cluster* cluster);