diff --git a/src/dpl/CMakeLists.txt b/src/dpl/CMakeLists.txt index 671cac7b4ca..64703d3cdf9 100644 --- a/src/dpl/CMakeLists.txt +++ b/src/dpl/CMakeLists.txt @@ -45,6 +45,8 @@ add_library(dpl_lib src/dbToOpendp.cpp src/Grid.cpp src/CheckPlacement.cpp + src/Objects.cpp + src/Padding.cpp src/Place.cpp src/FillerPlacement.cpp src/OptMirror.cpp diff --git a/src/dpl/include/dpl/Opendp.h b/src/dpl/include/dpl/Opendp.h index d721e895262..022e6cf3dd2 100644 --- a/src/dpl/include/dpl/Opendp.h +++ b/src/dpl/include/dpl/Opendp.h @@ -65,7 +65,6 @@ using std::map; using std::pair; using std::set; using std::string; -using std::unordered_map; using std::vector; using utl::Logger; @@ -73,192 +72,27 @@ using utl::Logger; using odb::dbBlock; using odb::dbDatabase; using odb::dbInst; -using odb::dbLib; using odb::dbMaster; using odb::dbMasterType; -using odb::dbMPin; -using odb::dbMTerm; -using odb::dbNet; -using odb::dbOrientType; -using odb::dbRow; -using odb::dbSite; using odb::dbTechLayer; using odb::Point; using odb::Rect; -struct Pixel; +struct Cell; struct Group; +struct Master; +struct Pixel; + class DplObserver; +class Grid; +class GridInfo; +class Padding; +class PixelPt; -using bgPoint - = boost::geometry::model::d2::point_xy; -using bgBox = boost::geometry::model::box; - -using RtreeBox - = boost::geometry::index::rtree>; -// The "Grid" is now an array of 2D grids. The new dimension is to support -// multi-height cells. Each unique row height creates a new grid that is used in -// legalization. The first index is the grid index (corresponding to row -// height), second index is the row index, and third index is the site index. -using Grid = std::vector>>; using dbMasterSeq = vector; -// gap -> sequence of masters to fill the gap -using GapFillers = vector; - -using InstPaddingMap = map>; -using MasterPaddingMap = map>; - -struct Master -{ - bool is_multi_row = false; -}; - -struct GridMapKey -{ - int grid_index; - bool operator<(const GridMapKey& other) const - { - return grid_index < other.grid_index; - } - bool operator==(const GridMapKey& other) const - { - return grid_index == other.grid_index; - } -}; - -class HybridSiteInfo -{ - public: - HybridSiteInfo(int index, dbSite* site) : index_(index), site_(site) {} - int getIndex() const { return index_; } - const dbSite* getSite() const { return site_; } - - private: - const int index_; - const dbSite* site_; -}; - -struct Cell -{ - const char* name() const; - bool inGroup() const { return group_ != nullptr; } - int64_t area() const; - - dbInst* db_inst_ = nullptr; - int x_ = 0; // lower left wrt core DBU - int y_ = 0; - dbOrientType orient_; - int width_ = 0; // DBU - int height_ = 0; - bool is_placed_ = false; - bool hold_ = false; - Group* group_ = nullptr; - Rect* region_ = nullptr; // group rect - - bool isHybrid() const - { - dbSite* site = getSite(); - return site ? site->isHybrid() : false; - } - - bool isHybridParent() const - { - dbSite* site = getSite(); - return site ? site->hasRowPattern() : false; - } - - dbSite* getSite() const - { - if (!db_inst_ || !db_inst_->getMaster()) { - return nullptr; - } - return db_inst_->getMaster()->getSite(); - } -}; - -struct Group -{ - string name; - vector regions; - vector cells_; - Rect boundary; - double util = 0.0; -}; - -struct Pixel -{ - Cell* cell; - Group* group_; - double util; - dbOrientType orient_; - bool is_valid; // false for dummy cells - bool is_hopeless; // too far from sites for diamond search - dbSite* site; // site that this pixel is -}; - -class GridInfo -{ - public: - GridInfo(const int row_count, - const int site_count, - const int grid_index, - const dbSite::RowPattern& sites) - : row_count_(row_count), - site_count_(site_count), - grid_index_(grid_index), - sites_(sites) - { - } - - int getRowCount() const { return row_count_; } - - int getSiteCount() const { return site_count_; } - - int getGridIndex() const { return grid_index_; } - - int getOffset() const { return offset_; } - - void setOffset(int offset) { offset_ = offset; } - - const dbSite::RowPattern& getSites() const { return sites_; } - - bool isHybrid() const - { - return sites_.size() > 1 || sites_[0].site->hasRowPattern(); - } - int getSitesTotalHeight() const - { - return std::accumulate(sites_.begin(), - sites_.end(), - 0, - [](int sum, const dbSite::OrientedSite& entry) { - return sum + entry.site->getHeight(); - }); - } - - private: - const int row_count_; - const int site_count_; - const int grid_index_; - int offset_ = 0; - // will have one site only for non-hybrid and hybrid parent cells. - // For hybrid children, this will have all the sites - const dbSite::RowPattern sites_; -}; //////////////////////////////////////////////////////////////// -// Return value for grid searches. -class PixelPt -{ - public: - PixelPt() = default; - PixelPt(Pixel* pixel, int grid_x, int grid_y); - Pixel* pixel = nullptr; - Point pt; // grid locataion -}; - class Opendp { public: @@ -289,11 +123,11 @@ class Opendp void setDebug(std::unique_ptr& observer); // Global padding. - int padGlobalLeft() const { return pad_left_; } - int padGlobalRight() const { return pad_right_; } + int padGlobalLeft() const; + int padGlobalRight() const; // Find instance/master/global padding value for an instance. - int padRight(dbInst* inst) const; int padLeft(dbInst* inst) const; + int padRight(dbInst* inst) const; void checkPlacement(bool verbose, bool disallow_one_site_gaps = false, @@ -311,6 +145,18 @@ class Opendp void optimizeMirroring(); private: + using bgPoint + = boost::geometry::model::d2::point_xy; + using bgBox = boost::geometry::model::box; + + using RtreeBox + = boost::geometry::index::rtree>; + + // gap -> sequence of masters to fill the gap + using GapFillers = vector; + using MasterByImplant = std::map; friend class OpendpTest_IsPlaced_Test; friend class Graphics; @@ -318,12 +164,9 @@ class Opendp Point pointOffMacro(const Cell& cell); void convertDbToCell(dbInst* db_inst, Cell& cell); const vector& getCells() const { return cells_; } - Rect getCore() const { return core_; } - int getRowHeight() const { return row_height_; } - int getRowHeight(const Cell* cell) const; - int getSiteWidth() const { return site_width_; } - int getRowCount() const { return row_count_; } - int getRowSiteCount() const { return row_site_count_; } + Rect getCore() const; + int getRowHeight() const; + int getSiteWidth() const; // Return error count. void processViolationsPtree(boost::property_tree::ptree& entry, const std::vector& failures, @@ -332,22 +175,17 @@ class Opendp void importClear(); Rect getBbox(dbInst* inst); void makeMacros(); - void examineRows(); void makeCells(); static bool isPlacedType(dbMasterType type); void makeGroups(); double dbuToMicrons(int64_t dbu) const; double dbuAreaToMicrons(int64_t dbu_area) const; - bool isFixed(const Cell* cell) const; // fixed cell or not bool isMultiRow(const Cell* cell) const; void updateDbInstLocations(); - GridMapKey getGridMapKey(const Cell* cell) const; - GridMapKey getGridMapKey(const dbSite* site) const; void makeMaster(Master* master, dbMaster* db_master); void initGrid(); - void initGridLayersMap(); std::string printBgBox(const boost::geometry::model::box& queryBox); void detailedPlacement(); Point nearestPt(const Cell* cell, const Rect* rect) const; @@ -385,8 +223,6 @@ class Opendp int distChange(const Cell* cell, int x, int y) const; bool swapCells(Cell* cell1, Cell* cell2); bool refineMove(Cell* cell); - int getHybridSiteIndex(dbSite* site); - int calculateHybridSitesRowCount(dbSite* parent_hybrid_site) const; Point legalPt(const Cell* cell, const Point& pt, int row_height = -1) const; Point legalGridPt(const Cell* cell, @@ -411,27 +247,11 @@ class Opendp int anneal(Group* group); int anneal(); int refine(); - bool cellFitsInCore(Cell* cell); void setFixedGridCells(); - void visitCellPixels(Cell& cell, - bool padded, - const std::function& visitor) const; - void visitCellBoundaryPixels( - Cell& cell, - bool padded, - const std::function< - void(Pixel* pixel, odb::Direction2D edge, int x, int y)>& visitor) - const; void setGridCell(Cell& cell, Pixel* pixel); void groupAssignCellRegions(); void groupInitPixels(); void groupInitPixels2(); - void erasePixel(Cell* cell); - void paintPixel(Cell* cell, int grid_x, int grid_y); - int map_ycoordinates(int source_grid_coordinate, - const GridMapKey& source_grid_key, - const GridMapKey& target_grid_key, - const bool start) const; // checkPlacement static bool isPlaced(const Cell* cell); @@ -461,44 +281,19 @@ class Opendp int* x, int* y) const; int rectDist(const Cell* cell, const Rect* rect) const; - bool havePadding() const; void checkOneSiteDbMaster(); void deleteGrid(); - Pixel* gridPixel(int grid_idx, int x, int y) const; // Cell initial location wrt core origin. int getRowCount(const Cell* cell) const; - int getRowCount(int row_height) const; - int gridPaddedWidth(const Cell* cell) const; int64_t paddedArea(const Cell* cell) const; - int coordinateToHeight(int y_coordinate, GridMapKey gmk) const; int gridNearestHeight(const Cell* cell) const; int gridNearestHeight(const Cell* cell, int row_height) const; int gridNearestWidth(const Cell* cell) const; - int gridHeight(const Cell* cell) const; - GridInfo getGridInfo(const Cell* cell) const; - int gridX(int x) const; - int gridX(const Cell* cell) const; - int gridPaddedX(const Cell* cell) const; - int gridY(int y, const Cell* cell) const; - int gridY(const Cell* cell) const; - pair gridY(int y, const dbSite::RowPattern& grid_sites) const; - pair gridEndY(int y, const dbSite::RowPattern& grid_sites) const; - int gridPaddedEndX(const Cell* cell) const; - int gridEndX(int x) const; - int gridEndX(const Cell* cell) const; - int gridEndY(int y, const Cell* cell) const; - int gridEndY(const Cell* cell) const; - void setGridPaddedLoc(Cell* cell, int x, int y) const; std::pair getRowInfo(const Cell* cell) const; // Lower left corner in core coordinates. Point initialLocation(const Cell* cell, bool padded) const; - bool isStdCell(const Cell* cell) const; static bool isBlock(const Cell* cell); - int paddedWidth(const Cell* cell) const; - bool isPaddedType(dbInst* inst) const; - int padLeft(const Cell* cell) const; - int padRight(const Cell* cell) const; int disp(const Cell* cell) const; // Place fillers MasterByImplant splitByImplant(dbMasterSeq* filler_masters); @@ -521,31 +316,14 @@ class Opendp Logger* logger_ = nullptr; dbDatabase* db_ = nullptr; dbBlock* block_ = nullptr; - int pad_left_ = 0; - int pad_right_ = 0; - InstPaddingMap inst_padding_map_; - MasterPaddingMap master_padding_map_; + std::unique_ptr padding_; vector cells_; vector groups_; map db_master_map_; - map grid_info_map_; - // This map is used to map each unqie site to a grid. The key is always - // unique, but the value is not unique in the case of hybrid sites - // (alternating rows) - map site_to_grid_key_; - GridMapKey smallest_non_hybrid_grid_key_; - std::vector grid_info_vector_; - std::unordered_map _hybrid_parent; map db_inst_map_; - bool has_hybrid_rows_ = false; - Rect core_; - int row_height_ = 0; // dbu - int site_width_ = 0; // dbu - int row_count_ = 0; - int row_site_count_ = 0; int have_multi_row_cells_ = 0; int max_displacement_x_ = 0; // sites int max_displacement_y_ = 0; // sites @@ -553,8 +331,7 @@ class Opendp vector placement_failures_; // 3D pixel grid - Grid grid_; - Cell dummy_cell_; + std::unique_ptr grid_; RtreeBox regions_rtree; // Filler placement. diff --git a/src/dpl/src/CheckPlacement.cpp b/src/dpl/src/CheckPlacement.cpp index 5f310355bb8..226db65c9e3 100644 --- a/src/dpl/src/CheckPlacement.cpp +++ b/src/dpl/src/CheckPlacement.cpp @@ -38,6 +38,9 @@ #include #include +#include "Grid.h" +#include "Objects.h" +#include "Padding.h" #include "dpl/Opendp.h" #include "utl/Logger.h" namespace dpl { @@ -63,21 +66,23 @@ void Opendp::checkPlacement(bool verbose, initGrid(); groupAssignCellRegions(); for (Cell& cell : cells_) { - if (isStdCell(&cell)) { + if (cell.isStdCell()) { // Site alignment check if (!cell.isHybrid()) { - if (cell.x_ % site_width_ != 0 || cell.y_ % row_height_ != 0) { + if (cell.x_ % grid_->getSiteWidth() != 0 + || cell.y_ % grid_->getRowHeight() != 0) { site_align_failures.push_back(&cell); } } else { // here, the cell is hybrid, if it is a parent, then the check is // quite simple - if (cell.x_ % site_width_ != 0) { + if (cell.x_ % grid_->getSiteWidth() != 0) { site_align_failures.push_back(&cell); continue; } - auto grid_info = getGridInfo(&cell); - auto [cell_index, cell_height] = gridY(cell.y_, grid_info.getSites()); + auto grid_info = grid_->getGridInfo(&cell); + auto [cell_index, cell_height] + = grid_->gridY(cell.y_, grid_info.getSites()); if (cell.y_ != cell_height && cell_height % cell.y_ != 0) { site_align_failures.push_back(&cell); } @@ -330,10 +335,10 @@ bool Opendp::isPlaced(const Cell* cell) bool Opendp::checkInRows(const Cell& cell) const { auto grid_info = getRowInfo(&cell); - int x_ll = gridX(&cell); - int x_ur = gridEndX(&cell); - int y_ll = gridY(&cell); - int y_ur = gridEndY(&cell); + int x_ll = grid_->gridX(&cell); + int x_ur = grid_->gridEndX(&cell); + int y_ll = grid_->gridY(&cell); + int y_ur = grid_->gridEndY(&cell); debugPrint(logger_, DPL, "hybrid", @@ -348,7 +353,7 @@ bool Opendp::checkInRows(const Cell& cell) const for (int y = y_ll; y < y_ur; y++) { for (int x = x_ll; x < x_ur; x++) { - Pixel* pixel = gridPixel(grid_info.second.getGridIndex(), x, y); + Pixel* pixel = grid_->gridPixel(grid_info.second.getGridIndex(), x, y); if (pixel == nullptr // outside core || !pixel->is_valid) { return false; @@ -386,7 +391,7 @@ Cell* Opendp::checkOverlap(Cell& cell) const debugPrint( logger_, DPL, "grid", 2, "checking overlap for cell {}", cell.name()); Cell* overlap_cell = nullptr; - visitCellPixels(cell, true, [&](Pixel* pixel) { + grid_->visitCellPixels(cell, true, [&](Pixel* pixel) { Cell* pixel_cell = pixel->cell; if (pixel_cell) { if (pixel_cell != &cell && overlap(&cell, pixel_cell)) { @@ -406,13 +411,15 @@ bool Opendp::overlap(const Cell* cell1, const Cell* cell2) const return false; } - bool padded = havePadding() && isOverlapPadded(cell1, cell2); + bool padded = padding_->havePadding() && isOverlapPadded(cell1, cell2); Point ll1 = initialLocation(cell1, padded); Point ll2 = initialLocation(cell2, padded); Point ur1, ur2; if (padded) { - ur1 = Point(ll1.getX() + paddedWidth(cell1), ll1.getY() + cell1->height_); - ur2 = Point(ll2.getX() + paddedWidth(cell2), ll2.getY() + cell2->height_); + ur1 = Point(ll1.getX() + padding_->paddedWidth(cell1), + ll1.getY() + cell1->height_); + ur2 = Point(ll2.getX() + padding_->paddedWidth(cell2), + ll2.getY() + cell2->height_); } else { ur1 = Point(ll1.getX() + cell1->width_, ll1.getY() + cell1->height_); ur2 = Point(ll2.getX() + cell2->width_, ll2.getY() + cell2->height_); @@ -426,7 +433,7 @@ Cell* Opendp::checkOneSiteGaps(Cell& cell) const Cell* gap_cell = nullptr; auto row_info = getRowInfo(&cell); int index_in_grid = row_info.second.getGridIndex(); - visitCellBoundaryPixels( + grid_->visitCellBoundaryPixels( cell, true, [&](Pixel* pixel, const Direction2D& edge, int x, int y) { Cell* pixel_cell = pixel->cell; @@ -442,13 +449,14 @@ Cell* Opendp::checkOneSiteGaps(Cell& cell) const } if (0 != abut_x) { // check the abutting pixel - Pixel* abut_pixel = gridPixel(index_in_grid, x + abut_x, y); + Pixel* abut_pixel = grid_->gridPixel(index_in_grid, x + abut_x, y); bool abuttment_exists = ((abut_pixel != nullptr) && abut_pixel->cell != pixel_cell && abut_pixel->cell != nullptr); if (!abuttment_exists) { // check the 1 site gap pixel - Pixel* gap_pixel = gridPixel(index_in_grid, x + 2 * abut_x, y); + Pixel* gap_pixel + = grid_->gridPixel(index_in_grid, x + 2 * abut_x, y); if (gap_pixel && gap_pixel->cell != pixel_cell) { gap_cell = gap_pixel->cell; } @@ -466,11 +474,12 @@ bool Opendp::checkRegionPlacement(const Cell* cell) const int y_end = y_begin + cell->height_; if (cell->region_) { + const int site_width = grid_->getSiteWidth(); return cell->region_->contains(odb::Rect(x_begin, y_begin, x_end, y_end)) && checkRegionOverlap(cell, - x_begin / site_width_, + x_begin / site_width, y_begin / cell->height_, - x_end / site_width_, + x_end / site_width, y_end / cell->height_); } return true; diff --git a/src/dpl/src/FillerPlacement.cpp b/src/dpl/src/FillerPlacement.cpp index 82a2a30f5e7..df611559d0f 100644 --- a/src/dpl/src/FillerPlacement.cpp +++ b/src/dpl/src/FillerPlacement.cpp @@ -34,6 +34,8 @@ #include +#include "Grid.h" +#include "Objects.h" #include "dpl/Opendp.h" #include "utl/Logger.h" @@ -92,19 +94,19 @@ void Opendp::fillerPlacement(dbMasterSeq* filler_masters, const char* prefix) initGrid(); setGridCells(); - if (!grid_info_map_.empty()) { + if (!grid_->infoMapEmpty()) { int min_height = std::numeric_limits::max(); GridMapKey chosen_grid_key = {0}; // we will first try to find the grid with min height that is non hybrid, if // that doesn't exist, we will pick the first hybrid grid. - for (auto [grid_idx, itr_grid_info] : grid_info_map_) { + for (auto [grid_idx, itr_grid_info] : grid_->getInfoMap()) { int site_height = itr_grid_info.getSites()[0].site->getHeight(); if (!itr_grid_info.isHybrid() && site_height < min_height) { min_height = site_height; chosen_grid_key = grid_idx; } } - auto chosen_grid_info = grid_info_map_.at(chosen_grid_key); + auto chosen_grid_info = grid_->getInfoMap().at(chosen_grid_key); int chosen_row_count = chosen_grid_info.getRowCount(); if (!chosen_grid_info.isHybrid()) { int site_height = min_height; @@ -135,7 +137,7 @@ void Opendp::fillerPlacement(dbMasterSeq* filler_masters, const char* prefix) void Opendp::setGridCells() { for (Cell& cell : cells_) { - visitCellPixels( + grid_->visitCellPixels( cell, false, [&](Pixel* pixel) { setGridCell(cell, pixel); }); } } @@ -148,26 +150,28 @@ void Opendp::placeRowFillers(int row, { int j = 0; - int row_site_count = divFloor(core_.dx(), site_width_); + const int site_width = grid_->getSiteWidth(); + int row_site_count = divFloor(grid_->getCore().dx(), site_width); while (j < row_site_count) { - Pixel* pixel = gridPixel(grid_info.getGridIndex(), j, row); + Pixel* pixel = grid_->gridPixel(grid_info.getGridIndex(), j, row); const dbOrientType orient = pixel->orient_; if (pixel->cell == nullptr && pixel->is_valid) { int k = j; while (k < row_site_count - && gridPixel(grid_info.getGridIndex(), k, row)->cell == nullptr - && gridPixel(grid_info.getGridIndex(), k, row)->is_valid) { + && grid_->gridPixel(grid_info.getGridIndex(), k, row)->cell + == nullptr + && grid_->gridPixel(grid_info.getGridIndex(), k, row)->is_valid) { k++; } dbTechLayer* implant = nullptr; if (j > 0) { - auto pixel = gridPixel(grid_info.getGridIndex(), j - 1, row); + auto pixel = grid_->gridPixel(grid_info.getGridIndex(), j - 1, row); if (pixel->cell && pixel->cell->db_inst_) { implant = getImplant(pixel->cell->db_inst_->getMaster()); } } else if (k < row_site_count) { - auto pixel = gridPixel(grid_info.getGridIndex(), k, row); + auto pixel = grid_->gridPixel(grid_info.getGridIndex(), k, row); if (pixel->cell && pixel->cell->db_inst_) { implant = getImplant(pixel->cell->db_inst_->getMaster()); } @@ -178,9 +182,10 @@ void Opendp::placeRowFillers(int row, int gap = k - j; dbMasterSeq& fillers = gapFillers(implant, gap, filler_masters_by_implant); + const Rect core = grid_->getCore(); if (fillers.empty()) { - int x = core_.xMin() + j * site_width_; - int y = core_.yMin() + row * row_height; + int x = core.xMin() + j * site_width; + int y = core.yMin() + row * row_height; logger_->error( DPL, 2, @@ -197,20 +202,18 @@ void Opendp::placeRowFillers(int row, for (dbMaster* master : fillers) { string inst_name = prefix + to_string(grid_info.getGridIndex()) + "_" + to_string(row) + "_" + to_string(k); - // printf(" filler %s %d\n", inst_name.c_str(), master->getWidth() / - // site_width_); dbInst* inst = dbInst::create(block_, master, inst_name.c_str(), /* physical_only */ true); - int x = core_.xMin() + k * site_width_; - int y = core_.yMin() + row * row_height; + int x = core.xMin() + k * site_width; + int y = core.yMin() + row * row_height; inst->setOrient(orient); inst->setLocation(x, y); inst->setPlacementStatus(dbPlacementStatus::PLACED); inst->setSourceType(odb::dbSourceType::DIST); filler_count_++; - k += master->getWidth() / site_width_; + k += master->getWidth() / site_width; } j += gap; } @@ -232,7 +235,7 @@ const char* Opendp::gridInstName(int row, return "core_right"; } - const Cell* cell = gridPixel(grid_info.getGridIndex(), col, row)->cell; + const Cell* cell = grid_->gridPixel(grid_info.getGridIndex(), col, row)->cell; if (cell) { return cell->db_inst_->getConstName(); } @@ -259,9 +262,10 @@ dbMasterSeq& Opendp::gapFillers( if (fillers.empty()) { int width = 0; dbMaster* smallest_filler = filler_masters[filler_masters.size() - 1]; - bool have_filler1 = smallest_filler->getWidth() == site_width_; + const int site_width = grid_->getSiteWidth(); + bool have_filler1 = smallest_filler->getWidth() == site_width; for (dbMaster* filler_master : filler_masters) { - int filler_width = filler_master->getWidth() / site_width_; + int filler_width = filler_master->getWidth() / site_width; while ((width + filler_width) <= gap && (have_filler1 || (width + filler_width) != gap - 1)) { fillers.push_back(filler_master); @@ -299,7 +303,7 @@ bool Opendp::isFiller(odb::dbInst* db_inst) bool Opendp::isOneSiteCell(odb::dbMaster* db_master) const { return db_master->getType() == odb::dbMasterType::CORE_SPACER - && db_master->getWidth() == site_width_; + && db_master->getWidth() == grid_->getSiteWidth(); } } // namespace dpl diff --git a/src/dpl/src/Graphics.cpp b/src/dpl/src/Graphics.cpp index 8212395803f..e63983a2f56 100644 --- a/src/dpl/src/Graphics.cpp +++ b/src/dpl/src/Graphics.cpp @@ -33,6 +33,8 @@ #include "Graphics.h" +#include "Grid.h" +#include "Objects.h" #include "dpl/Opendp.h" namespace dpl { @@ -76,9 +78,9 @@ void Graphics::binSearch(const Cell* cell, int xl, int yl, int xh, int yh) } Rect core = dp_->getCore(); int xl_dbu = core.xMin() + xl * dp_->getSiteWidth(); - int yl_dbu = core.yMin() + yl * dp_->getRowHeight(cell); + int yl_dbu = core.yMin() + yl * dp_->grid_->getRowHeight(cell); int xh_dbu = core.xMin() + xh * dp_->getSiteWidth(); - int yh_dbu = core.yMin() + yh * dp_->getRowHeight(cell); + int yh_dbu = core.yMin() + yh * dp_->grid_->getRowHeight(cell); searched_.emplace_back(xl_dbu, yl_dbu, xh_dbu, yh_dbu); } @@ -102,7 +104,7 @@ void Graphics::drawObjects(gui::Painter& painter) continue; } // Compare the squared distances to save calling sqrt - float min_length = min_displacement_ * dp_->getRowHeight(&cell); + float min_length = min_displacement_ * dp_->grid_->getRowHeight(&cell); min_length *= min_length; int lx = core.xMin() + cell.x_; int ly = core.yMin() + cell.y_; diff --git a/src/dpl/src/Grid.cpp b/src/dpl/src/Grid.cpp index 2520c9f2de6..d1e7ebee04a 100644 --- a/src/dpl/src/Grid.cpp +++ b/src/dpl/src/Grid.cpp @@ -37,10 +37,13 @@ // POSSIBILITY OF SUCH DAMAGE. /////////////////////////////////////////////////////////////////////////////// +#include "Grid.h" + #include #include #include +#include "Objects.h" #include "dpl/Opendp.h" #include "odb/dbTransform.h" #include "utl/Logger.h" @@ -55,7 +58,7 @@ using utl::DPL; using odb::dbBox; using odb::dbTransform; -int Opendp::calculateHybridSitesRowCount(dbSite* parent_hybrid_site) const +int Grid::calculateHybridSitesRowCount(dbSite* parent_hybrid_site) const { auto row_pattern = parent_hybrid_site->getRowPattern(); int rows_count = getRowCount(parent_hybrid_site->getHeight()); @@ -76,15 +79,15 @@ int Opendp::calculateHybridSitesRowCount(dbSite* parent_hybrid_site) const return rows_count; } -void Opendp::initGridLayersMap() +void Grid::initGridLayersMap(dbDatabase* db, dbBlock* block) { - _hybrid_parent.clear(); - for (auto lib : db_->getLibs()) { + clearHybridParent(); + for (auto lib : db->getLibs()) { for (auto site : lib->getSites()) { if (site->hasRowPattern()) { for (const auto& [child_site, orient] : site->getRowPattern()) { - if (_hybrid_parent.count(child_site) == 0) { - _hybrid_parent[child_site] = site; + if (getHybridParent().count(child_site) == 0) { + addHybridParent(child_site, site); } } } @@ -92,11 +95,11 @@ void Opendp::initGridLayersMap() } int grid_index = 0; - grid_info_map_.clear(); - grid_info_vector_.clear(); + clearInfoMap(); + clearInfo(); int min_site_height = std::numeric_limits::max(); int min_row_y_coordinate = std::numeric_limits::max(); - for (auto db_row : block_->getRows()) { + for (auto db_row : block->getRows()) { auto site = db_row->getSite(); if (site->getClass() == odb::dbSiteClass::PAD) { continue; @@ -104,7 +107,7 @@ void Opendp::initGridLayersMap() odb::Point row_base = db_row->getOrigin(); min_row_y_coordinate = min(min_row_y_coordinate, row_base.y()); - if (site_to_grid_key_.find(site) != site_to_grid_key_.end()) { + if (getSiteToGrid().find(site) != getSiteToGrid().end()) { continue; } @@ -116,11 +119,11 @@ void Opendp::initGridLayersMap() "Mapping {} to grid_index: {}", site->getName(), grid_index); - site_to_grid_key_[site] = GridMapKey{grid_index++}; + addSiteToGrid(site, GridMapKey{grid_index++}); auto rp = site->getRowPattern(); bool updated = false; for (auto& [child_site, child_site_orientation] : rp) { - if (site_to_grid_key_.find(child_site) == site_to_grid_key_.end()) { + if (getSiteToGrid().find(child_site) == getSiteToGrid().end()) { // FIXME(mina1460): this might need more work in the future if we // want to allow the same hybrid cell to be part of multiple grids // (For example, A in AB and AC). This is good enough for now. @@ -131,7 +134,7 @@ void Opendp::initGridLayersMap() "Mapping child site {} to grid_index: {}", child_site->getName(), grid_index); - site_to_grid_key_[child_site] = GridMapKey{grid_index}; + addSiteToGrid(child_site, GridMapKey{grid_index}); updated = true; } } @@ -146,18 +149,18 @@ void Opendp::initGridLayersMap() "Mapping non-hybrid {} to grid_index: {}", site->getName(), grid_index); - site_to_grid_key_[site] = GridMapKey{grid_index++}; + addSiteToGrid(site, GridMapKey{grid_index++}); } if (!site->isHybrid()) { if (site->getHeight() < min_site_height) { min_site_height = site->getHeight(); - smallest_non_hybrid_grid_key_ = site_to_grid_key_[site]; + setSmallestNonHybridGridKey(getSiteToGrid().at(site)); } } } - for (auto db_row : block_->getRows()) { + for (auto db_row : block->getRows()) { if (db_row->getSite()->getClass() == odb::dbSiteClass::PAD) { continue; } @@ -166,39 +169,40 @@ void Opendp::initGridLayersMap() if (row_base.y() == min_row_y_coordinate) { if (working_site->hasRowPattern()) { for (const auto& [child_site, orient] : working_site->getRowPattern()) { - if (_hybrid_parent[child_site] != working_site) { + if (getHybridParent().at(child_site) != working_site) { debugPrint(logger_, DPL, "hybrid", 1, "Overriding the parent of site {} from {} to {}", child_site->getName(), - _hybrid_parent[child_site]->getName(), + getHybridParent().at(child_site)->getName(), working_site->getName()); - _hybrid_parent[child_site] = working_site; + addHybridParent(child_site, working_site); } } } } } - if (!has_hybrid_rows_ && min_site_height == std::numeric_limits::max()) { + if (!getHasHybridRows() + && min_site_height == std::numeric_limits::max()) { logger_->error( DPL, 128, "Cannot find a non-hybrid grid to use for placement."); } - for (auto db_row : block_->getRows()) { + for (auto db_row : block->getRows()) { if (db_row->getSite()->getClass() == odb::dbSiteClass::PAD) { continue; } dbSite* working_site = db_row->getSite(); int row_height = working_site->getHeight(); - GridMapKey gmk = getGridMapKey(working_site); - if (grid_info_map_.find(gmk) == grid_info_map_.end()) { + GridMapKey gmk = site_to_grid_key_.at(working_site); + if (getInfoMap().find(gmk) == getInfoMap().end()) { if (working_site->hasRowPattern() || !working_site->isHybrid()) { GridInfo newGridInfo = { getRowCount(row_height), divFloor(core_.dx(), db_row->getSite()->getWidth()), - site_to_grid_key_.at(working_site).grid_index, + getSiteToGrid().at(working_site).grid_index, dbSite::RowPattern{{working_site, db_row->getOrient()}}, }; if (working_site->isHybrid()) { @@ -212,13 +216,13 @@ void Opendp::initGridLayersMap() working_site->getName(), row_offset); } - grid_info_map_.emplace(gmk, newGridInfo); + addInfoMap(gmk, newGridInfo); } else { - dbSite* parent_site = _hybrid_parent.at(working_site); + dbSite* parent_site = getHybridParent().at(working_site); GridInfo newGridInfo = { calculateHybridSitesRowCount(parent_site), divFloor(core_.dx(), db_row->getSite()->getWidth()), - site_to_grid_key_.at(working_site).grid_index, + getSiteToGrid().at(working_site).grid_index, parent_site->getRowPattern(), // FIXME(mina1460): this is wrong! in // the case of HybridAB, and // HybridBA. each of A and B maps to @@ -237,57 +241,69 @@ void Opendp::initGridLayersMap() newGridInfo.getGridIndex(), newGridInfo.getOffset()); } - grid_info_map_.emplace(gmk, newGridInfo); + addInfoMap(gmk, newGridInfo); } } else { int row_offset = db_row->getBBox().ll().getY() - min_row_y_coordinate; - auto grid_info = grid_info_map_.at(gmk); + auto grid_info = getInfoMap().at(gmk); if (grid_info.isHybrid()) { grid_info.setOffset(min(grid_info.getOffset(), row_offset)); - grid_info_map_.insert(std::make_pair(gmk, grid_info)); + addInfoMap(gmk, grid_info); } } } - grid_info_vector_.resize(grid_info_map_.size()); + resizeInfo(getInfoMap().size()); int min_height(std::numeric_limits::max()); - for (auto& [gmk, grid_info] : grid_info_map_) { + for (auto& [gmk, grid_info] : getInfoMap()) { assert(gmk.grid_index == grid_info.getGridIndex()); - grid_info_vector_[grid_info.getGridIndex()] = &grid_info; + setInfo(grid_info.getGridIndex(), &grid_info); if (grid_info.getSitesTotalHeight() < min_height) { min_height = grid_info.getSitesTotalHeight(); - if (has_hybrid_rows_) { - smallest_non_hybrid_grid_key_ = gmk; + if (getHasHybridRows()) { + setSmallestNonHybridGridKey(gmk); } } } debugPrint(logger_, DPL, "grid", 1, "grid layers map initialized"); -} // namespace dpl +} void Opendp::initGrid() { + grid_->initGrid( + db_, block_, padding_.get(), max_displacement_x_, max_displacement_y_); +} + +void Grid::initGrid(dbDatabase* db, + dbBlock* block, + Padding* padding, + int max_displacement_x, + int max_displacement_y) +{ + padding_ = padding; + // the number of layers in the grid is the number of unique row heights // the map key is the row height, the value is a pair of row count and site // count - if (grid_info_map_.empty()) { - initGridLayersMap(); + if (infoMapEmpty()) { + initGridLayersMap(db, block); } // Make pixel grid - if (grid_.empty()) { - grid_.resize(grid_info_map_.size()); - for (auto& [gmk, grid_info] : grid_info_map_) { - grid_[grid_info.getGridIndex()].resize(grid_info.getRowCount()); + if (empty()) { + resize(getInfoMap().size()); + for (auto& [gmk, grid_info] : getInfoMap()) { + resize(grid_info.getGridIndex(), grid_info.getRowCount()); } } - for (auto& [gmk, grid_info] : grid_info_map_) { + for (auto& [gmk, grid_info] : getInfoMap()) { const int layer_row_count = grid_info.getRowCount(); const int layer_row_site_count = grid_info.getSiteCount(); const int index = grid_info.getGridIndex(); - grid_[index].resize(layer_row_count); + resize(index, layer_row_count); for (int j = 0; j < layer_row_count; j++) { - grid_[index][j].resize(layer_row_site_count); + resize(index, j, layer_row_site_count); const auto& grid_sites = grid_info.getSites(); dbSite* row_site = nullptr; if (!grid_sites.empty()) { @@ -295,7 +311,7 @@ void Opendp::initGrid() } for (int k = 0; k < layer_row_site_count; k++) { - Pixel& pixel = grid_[index][j][k]; + Pixel& pixel = pixels_[index][j][k]; pixel.cell = nullptr; pixel.group_ = nullptr; pixel.util = 0.0; @@ -311,27 +327,28 @@ void Opendp::initGrid() using namespace gtl::operators; std::vector> hopeless; - hopeless.resize(grid_info_map_.size()); - for (const auto& [row_height, grid_info] : grid_info_map_) { + hopeless.resize(getInfoMap().size()); + for (const auto& [row_height, grid_info] : getInfoMap()) { hopeless[grid_info.getGridIndex()] += gtl::rectangle_data{ 0, 0, grid_info.getSiteCount(), grid_info.getRowCount()}; } // Fragmented row support; mark valid sites. - for (auto db_row : block_->getRows()) { + for (auto db_row : block->getRows()) { const auto db_row_site = db_row->getSite(); if (db_row_site->getClass() == odb::dbSiteClass::PAD) { continue; } int current_row_site_count = db_row->getSiteCount(); auto gmk = getGridMapKey(db_row_site); - auto entry = grid_info_map_.at(gmk); + auto entry = getInfoMap().at(gmk); int current_row_count = entry.getRowCount(); int current_row_grid_index = entry.getGridIndex(); const odb::Point orig = db_row->getOrigin(); - const int x_start = (orig.x() - core_.xMin()) / db_row_site->getWidth(); + const Rect core = getCore(); + const int x_start = (orig.x() - core.xMin()) / db_row_site->getWidth(); const int x_end = x_start + current_row_site_count; - const int y_row = gridY(orig.y() - core_.yMin(), entry.getSites()).first; + const int y_row = gridY(orig.y() - core.yMin(), entry.getSites()).first; for (int x = x_start; x < x_end; x++) { Pixel* pixel = gridPixel(current_row_grid_index, x, y_row); if (pixel == nullptr) { @@ -344,28 +361,28 @@ void Opendp::initGrid() // The safety margin is to avoid having only a very few sites // within the diamond search that may still lead to failures. const int safety = 20; - int max_row_site_count = divFloor(core_.dx(), db_row_site->getWidth()); + int max_row_site_count = divFloor(core.dx(), db_row_site->getWidth()); - const int xl = std::max(0, x_start - max_displacement_x_ + safety); + const int xl = std::max(0, x_start - max_displacement_x + safety); const int xh - = std::min(max_row_site_count, x_end + max_displacement_x_ - safety); + = std::min(max_row_site_count, x_end + max_displacement_x - safety); - const int yl = std::max(0, y_row - max_displacement_y_ + safety); + const int yl = std::max(0, y_row - max_displacement_y + safety); const int yh - = std::min(current_row_count, y_row + max_displacement_y_ - safety); + = std::min(current_row_count, y_row + max_displacement_y - safety); hopeless[current_row_grid_index] -= gtl::rectangle_data{xl, yl, xh, yh}; } std::vector> rects; - for (auto& grid_layer : grid_info_map_) { + for (auto& grid_layer : getInfoMap()) { rects.clear(); int h_index = grid_layer.second.getGridIndex(); hopeless[h_index].get_rectangles(rects); for (const auto& rect : rects) { for (int y = gtl::yl(rect); y < gtl::yh(rect); y++) { for (int x = gtl::xl(rect); x < gtl::xh(rect); x++) { - Pixel& pixel = grid_[h_index][y][x]; + Pixel& pixel = pixels_[h_index][y][x]; pixel.is_hopeless = true; } } @@ -375,18 +392,18 @@ void Opendp::initGrid() void Opendp::deleteGrid() { - grid_.clear(); + grid_->clear(); } -Pixel* Opendp::gridPixel(int grid_idx, int grid_x, int grid_y) const +Pixel* Grid::gridPixel(int grid_idx, int grid_x, int grid_y) const { if (grid_idx < 0 || grid_idx >= grid_info_vector_.size()) { return nullptr; } - GridInfo* grid_info = grid_info_vector_[grid_idx]; + const GridInfo* grid_info = grid_info_vector_[grid_idx]; if (grid_x >= 0 && grid_x < grid_info->getSiteCount() && grid_y >= 0 && grid_y < grid_info->getRowCount()) { - return const_cast(&grid_[grid_idx][grid_y][grid_x]); + return const_cast(&pixels_[grid_idx][grid_y][grid_x]); } return nullptr; } @@ -402,7 +419,7 @@ void Opendp::findOverlapInRtree(bgBox& queryBox, vector& overlaps) const //////////////////////////////////////////////////////////////// -void Opendp::visitCellPixels( +void Grid::visitCellPixels( Cell& cell, bool padded, const std::function& visitor) const @@ -410,6 +427,7 @@ void Opendp::visitCellPixels( dbInst* inst = cell.db_inst_; auto obstructions = inst->getMaster()->getObstructions(); bool have_obstructions = false; + const Rect core = getCore(); for (dbBox* obs : obstructions) { if (obs->getTechLayer()->getType() @@ -418,19 +436,20 @@ void Opendp::visitCellPixels( Rect rect = obs->getBox(); inst->getTransform().apply(rect); - int x_start = gridX(rect.xMin() - core_.xMin()); - int x_end = gridEndX(rect.xMax() - core_.xMin()); - int y_start = gridY(rect.yMin() - core_.yMin(), &cell); - int y_end = gridEndY(rect.yMax() - core_.yMin(), &cell); + int x_start = gridX(rect.xMin() - core.xMin()); + int x_end = gridEndX(rect.xMax() - core.xMin()); + int y_start = gridY(rect.yMin() - core.yMin(), &cell); + int y_end = gridEndY(rect.yMax() - core.yMin(), &cell); // Since there is an obstruction, we need to visit all the pixels at all // layers (for all row heights) int grid_idx = 0; - for (const auto& [target_GridMapKey, target_grid_info] : grid_info_map_) { + for (const auto& [target_GridMapKey, target_grid_info] : getInfoMap()) { + const auto smallest_non_hybrid_grid_key = getSmallestNonHybridGridKey(); int layer_y_start = map_ycoordinates( - y_start, smallest_non_hybrid_grid_key_, target_GridMapKey, true); + y_start, smallest_non_hybrid_grid_key, target_GridMapKey, true); int layer_y_end = map_ycoordinates( - y_end, smallest_non_hybrid_grid_key_, target_GridMapKey, false); + y_end, smallest_non_hybrid_grid_key, target_GridMapKey, false); if (layer_y_end == layer_y_start) { ++layer_y_end; } @@ -452,7 +471,7 @@ void Opendp::visitCellPixels( int y_start = gridY(&cell); int y_end = gridEndY(&cell); auto src_gmk = getGridMapKey(&cell); - for (const auto& layer_it : grid_info_map_) { + for (const auto& layer_it : getInfoMap()) { int layer_x_start = x_start; int layer_x_end = x_end; int layer_y_start @@ -477,7 +496,7 @@ void Opendp::visitCellPixels( } } -void Opendp::visitCellBoundaryPixels( +void Grid::visitCellBoundaryPixels( Cell& cell, bool padded, const std::function< @@ -485,12 +504,13 @@ void Opendp::visitCellBoundaryPixels( { dbInst* inst = cell.db_inst_; const GridMapKey& gmk = getGridMapKey(&cell); - GridInfo grid_info = grid_info_map_.at(gmk); + GridInfo grid_info = getInfoMap().at(gmk); const int index_in_grid = grid_info.getGridIndex(); const auto& grid_sites = grid_info.getSites(); dbMaster* master = inst->getMaster(); auto obstructions = master->getObstructions(); bool have_obstructions = false; + const Rect core = getCore(); for (dbBox* obs : obstructions) { if (obs->getTechLayer()->getType() == odb::dbTechLayerType::Value::OVERLAP) { @@ -499,10 +519,10 @@ void Opendp::visitCellBoundaryPixels( Rect rect = obs->getBox(); inst->getTransform().apply(rect); - int x_start = gridX(rect.xMin() - core_.xMin()); - int x_end = gridEndX(rect.xMax() - core_.xMin()); - int y_start = gridY(rect.yMin() - core_.yMin(), grid_sites).first; - int y_end = gridEndY(rect.yMax() - core_.yMin(), grid_sites).first; + int x_start = gridX(rect.xMin() - core.xMin()); + int x_end = gridEndX(rect.xMax() - core.xMin()); + int y_start = gridY(rect.yMin() - core.yMin(), grid_sites).first; + int y_end = gridEndY(rect.yMax() - core.yMin(), grid_sites).first; for (int x = x_start; x < x_end; x++) { Pixel* pixel = gridPixel(index_in_grid, x, y_start); if (pixel) { @@ -572,8 +592,8 @@ void Opendp::visitCellBoundaryPixels( void Opendp::setFixedGridCells() { for (Cell& cell : cells_) { - if (isFixed(&cell)) { - visitCellPixels( + if (cell.isFixed()) { + grid_->visitCellPixels( cell, true, [&](Pixel* pixel) { setGridCell(cell, pixel); }); } } @@ -593,25 +613,27 @@ void Opendp::groupAssignCellRegions() { for (Group& group : groups_) { int64_t site_count = 0; - int row_height = row_height_; + int row_height = grid_->getRowHeight(); + const int site_width = grid_->getSiteWidth(); if (!group.cells_.empty()) { auto group_cell = group.cells_.at(0); - int max_row_site_count = divFloor(core_.dx(), site_width_); - row_height = getRowHeight(group_cell); - int row_count = divFloor(core_.dy(), row_height); - auto gmk = getGridMapKey(group_cell); - auto grid_info = grid_info_map_.at(gmk); + const Rect core = grid_->getCore(); + int max_row_site_count = divFloor(core.dx(), site_width); + row_height = grid_->getRowHeight(group_cell); + int row_count = divFloor(core.dy(), row_height); + auto gmk = grid_->getGridMapKey(group_cell); + auto grid_info = grid_->getInfoMap().at(gmk); for (int x = 0; x < max_row_site_count; x++) { for (int y = 0; y < row_count; y++) { - Pixel* pixel = gridPixel(grid_info.getGridIndex(), x, y); + Pixel* pixel = grid_->gridPixel(grid_info.getGridIndex(), x, y); if (pixel->is_valid && pixel->group_ == &group) { site_count++; } } } } - int64_t site_area = site_count * site_width_ * row_height; + int64_t site_area = site_count * site_width * row_height; int64_t cell_area = 0; for (Cell* cell : group.cells_) { @@ -632,8 +654,8 @@ void Opendp::groupAssignCellRegions() void Opendp::groupInitPixels2() { - for (auto& layer : grid_info_map_) { - GridInfo& grid_info = layer.second; + for (auto& layer : grid_->getInfoMap()) { + const GridInfo& grid_info = layer.second; int row_count = layer.second.getRowCount(); int row_site_count = layer.second.getSiteCount(); auto grid_sites = layer.second.getSites(); @@ -643,16 +665,17 @@ void Opendp::groupInitPixels2() Rect sub; // TODO: Site width here is wrong if multiple site widths are // supported! - sub.init(x * site_width_, + const int site_width = grid_->getSiteWidth(); + sub.init(x * site_width, y * row_height, - (x + 1) * site_width_, + (x + 1) * site_width, (y + 1) * row_height); - Pixel* pixel = gridPixel(grid_info.getGridIndex(), x, y); + Pixel* pixel = grid_->gridPixel(grid_info.getGridIndex(), x, y); for (Group& group : groups_) { for (Rect& rect : group.regions) { if (!isInside(sub, rect) && checkOverlap(sub, rect)) { pixel->util = 0.0; - pixel->cell = &dummy_cell_; + pixel->cell = &Cell::dummy_cell; pixel->is_valid = false; } } @@ -677,11 +700,11 @@ bool Opendp::checkOverlap(const Rect& cell, const Rect& box) void Opendp::groupInitPixels() { - for (const auto& layer : grid_info_map_) { + for (const auto& layer : grid_->getInfoMap()) { const GridInfo& grid_info = layer.second; for (int x = 0; x < grid_info.getSiteCount(); x++) { for (int y = 0; y < grid_info.getRowCount(); y++) { - Pixel* pixel = gridPixel(grid_info.getGridIndex(), x, y); + Pixel* pixel = grid_->gridPixel(grid_info.getGridIndex(), x, y); pixel->util = 0.0; } } @@ -692,9 +715,10 @@ void Opendp::groupInitPixels() continue; } int row_height = group.cells_[0]->height_; - GridMapKey gmk = getGridMapKey(group.cells_[0]); - GridInfo& grid_info = grid_info_map_.at(gmk); + GridMapKey gmk = grid_->getGridMapKey(group.cells_[0]); + const GridInfo& grid_info = grid_->getInfoMap().at(gmk); int grid_index = grid_info.getGridIndex(); + const int site_width = grid_->getSiteWidth(); for (Rect& rect : group.regions) { debugPrint(logger_, DPL, @@ -710,22 +734,22 @@ void Opendp::groupInitPixels() int row_end = divFloor(rect.yMax(), row_height); for (int k = row_start; k < row_end; k++) { - int col_start = divCeil(rect.xMin(), site_width_); - int col_end = divFloor(rect.xMax(), site_width_); + int col_start = divCeil(rect.xMin(), site_width); + int col_end = divFloor(rect.xMax(), site_width); for (int l = col_start; l < col_end; l++) { - Pixel* pixel = gridPixel(grid_index, l, k); + Pixel* pixel = grid_->gridPixel(grid_index, l, k); pixel->util += 1.0; } - if (rect.xMin() % site_width_ != 0) { - Pixel* pixel = gridPixel(grid_index, col_start, k); + if (rect.xMin() % site_width != 0) { + Pixel* pixel = grid_->gridPixel(grid_index, col_start, k); pixel->util - -= (rect.xMin() % site_width_) / static_cast(site_width_); + -= (rect.xMin() % site_width) / static_cast(site_width); } - if (rect.xMax() % site_width_ != 0) { - Pixel* pixel = gridPixel(grid_index, col_end - 1, k); - pixel->util -= ((site_width_ - rect.xMax()) % site_width_) - / static_cast(site_width_); + if (rect.xMax() % site_width != 0) { + Pixel* pixel = grid_->gridPixel(grid_index, col_end - 1, k); + pixel->util -= ((site_width - rect.xMax()) % site_width) + / static_cast(site_width); } } } @@ -734,18 +758,18 @@ void Opendp::groupInitPixels() int row_end = divFloor(rect.yMax(), row_height); for (int k = row_start; k < row_end; k++) { - int col_start = divCeil(rect.xMin(), site_width_); - int col_end = divFloor(rect.xMax(), site_width_); + int col_start = divCeil(rect.xMin(), site_width); + int col_end = divFloor(rect.xMax(), site_width); // Assign group to each pixel. for (int l = col_start; l < col_end; l++) { - Pixel* pixel = gridPixel(grid_index, l, k); + Pixel* pixel = grid_->gridPixel(grid_index, l, k); if (pixel->util == 1.0) { pixel->group_ = &group; pixel->is_valid = true; pixel->util = 1.0; } else if (pixel->util > 0.0 && pixel->util < 1.0) { - pixel->cell = &dummy_cell_; + pixel->cell = &Cell::dummy_cell; pixel->util = 0.0; pixel->is_valid = false; } @@ -755,9 +779,9 @@ void Opendp::groupInitPixels() } } -void Opendp::erasePixel(Cell* cell) +void Grid::erasePixel(Cell* cell) { - if (!(isFixed(cell) || !cell->is_placed_)) { + if (!(cell->isFixed() || !cell->is_placed_)) { auto gmk = getGridMapKey(cell); int x_end = gridPaddedEndX(cell); int y_end = gridEndY(cell); @@ -778,7 +802,7 @@ void Opendp::erasePixel(Cell* cell) y_start, y_end); - for (const auto& [target_GridMapKey, target_grid_info] : grid_info_map_) { + for (const auto& [target_GridMapKey, target_grid_info] : getInfoMap()) { int layer_y_start = map_ycoordinates(y_start, gmk, target_GridMapKey, true); int layer_y_end = map_ycoordinates(y_end, gmk, target_GridMapKey, false); @@ -803,16 +827,16 @@ void Opendp::erasePixel(Cell* cell) } } -int Opendp::map_ycoordinates(int source_grid_coordinate, - const GridMapKey& source_grid_key, - const GridMapKey& target_grid_key, - const bool start) const +int Grid::map_ycoordinates(int source_grid_coordinate, + const GridMapKey& source_grid_key, + const GridMapKey& target_grid_key, + const bool start) const { if (source_grid_key == target_grid_key) { return source_grid_coordinate; } - auto src_grid_info = grid_info_map_.at(source_grid_key); - auto target_grid_info = grid_info_map_.at(target_grid_key); + auto src_grid_info = getInfoMap().at(source_grid_key); + auto target_grid_info = getInfoMap().at(target_grid_key); if (!src_grid_info.isHybrid()) { if (!target_grid_info.isHybrid()) { int original_step = src_grid_info.getSites()[0].site->getHeight(); @@ -847,14 +871,14 @@ int Opendp::map_ycoordinates(int source_grid_coordinate, return divCeil(src_height, target_step); } -void Opendp::paintPixel(Cell* cell, int grid_x, int grid_y) +void Grid::paintPixel(Cell* cell, int grid_x, int grid_y) { assert(!cell->is_placed_); int x_end = grid_x + gridPaddedWidth(cell); int grid_height = gridHeight(cell); int y_end = grid_y + grid_height; GridMapKey gmk = getGridMapKey(cell); - GridInfo grid_info = grid_info_map_.at(gmk); + GridInfo grid_info = getInfoMap().at(gmk); const int index_in_grid = gmk.grid_index; setGridPaddedLoc(cell, grid_x, grid_y); cell->is_placed_ = true; @@ -871,7 +895,7 @@ void Opendp::paintPixel(Cell* cell, int grid_x, int grid_y) } } - for (const auto& layer : grid_info_map_) { + for (const auto& layer : getInfoMap()) { if (layer.first == gmk) { continue; } diff --git a/src/dpl/src/Grid.h b/src/dpl/src/Grid.h new file mode 100644 index 00000000000..975b4cd1c40 --- /dev/null +++ b/src/dpl/src/Grid.h @@ -0,0 +1,282 @@ +///////////////////////////////////////////////////////////////////////////// +// Original authors: SangGi Do(sanggido@unist.ac.kr), Mingyu +// Woo(mwoo@eng.ucsd.edu) +// (respective Ph.D. advisors: Seokhyeong Kang, Andrew B. Kahng) +// Rewrite by James Cherry, Parallax Software, Inc. +// +// Copyright (c) 2019, The Regents of the University of California +// Copyright (c) 2018, SangGi Do and Mingyu Woo +// All rights reserved. +// +// BSD 3-Clause License +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "dpl/Opendp.h" + +namespace dpl { + +using odb::dbOrientType; +using odb::dbSite; + +struct Pixel +{ + Cell* cell; + Group* group_; + double util; + dbOrientType orient_; + bool is_valid; // false for dummy cells + bool is_hopeless; // too far from sites for diamond search + dbSite* site; // site that this pixel is +}; + +// Return value for grid searches. +class PixelPt +{ + public: + PixelPt() = default; + PixelPt(Pixel* pixel, int grid_x, int grid_y); + Pixel* pixel = nullptr; + Point pt; // grid locataion +}; + +class GridInfo +{ + public: + GridInfo(const int row_count, + const int site_count, + const int grid_index, + const dbSite::RowPattern& sites) + : row_count_(row_count), + site_count_(site_count), + grid_index_(grid_index), + sites_(sites) + { + } + + int getRowCount() const { return row_count_; } + int getSiteCount() const { return site_count_; } + int getGridIndex() const { return grid_index_; } + int getOffset() const { return offset_; } + + void setOffset(int offset) { offset_ = offset; } + + const dbSite::RowPattern& getSites() const { return sites_; } + + bool isHybrid() const + { + return sites_.size() > 1 || sites_[0].site->hasRowPattern(); + } + int getSitesTotalHeight() const + { + return std::accumulate(sites_.begin(), + sites_.end(), + 0, + [](int sum, const dbSite::OrientedSite& entry) { + return sum + entry.site->getHeight(); + }); + } + + private: + const int row_count_; + const int site_count_; + const int grid_index_; + int offset_ = 0; + // will have one site only for non-hybrid and hybrid parent cells. + // For hybrid children, this will have all the sites + const dbSite::RowPattern sites_; +}; + +struct GridMapKey +{ + int grid_index; + bool operator<(const GridMapKey& other) const + { + return grid_index < other.grid_index; + } + bool operator==(const GridMapKey& other) const + { + return grid_index == other.grid_index; + } +}; + +// The "Grid" is now an array of 2D grids. The new dimension is to support +// multi-height cells. Each unique row height creates a new grid that is used in +// legalization. The first index is the grid index (corresponding to row +// height), second index is the row index, and third index is the site index. +class Grid +{ + public: + void init(Logger* logger) { logger_ = logger; } + void initBlock(dbBlock* block) { core_ = block->getCoreArea(); } + void initGrid(dbDatabase* db, + dbBlock* block, + Padding* padding, + int max_displacement_x, + int max_displacement_y); + void examineRows(dbBlock* block); + + GridMapKey getGridMapKey(const dbSite* site) const; + GridMapKey getGridMapKey(const Cell* cell) const; + int gridX(int x) const; + int gridX(const Cell* cell) const; + int gridEndX(int x) const; + int gridEndX(const Cell* cell) const; + int gridPaddedX(const Cell* cell) const; + int gridPaddedEndX(const Cell* cell) const; + int gridY(int y, const Cell* cell) const; + int gridY(const Cell* cell) const; + int gridEndY(int y, const Cell* cell) const; + int gridEndY(const Cell* cell) const; + pair gridY(int y, const dbSite::RowPattern& grid_sites) const; + pair gridEndY(int y, const dbSite::RowPattern& grid_sites) const; + GridInfo getGridInfo(const Cell* cell) const; + int gridPaddedWidth(const Cell* cell) const; + int gridHeight(const Cell* cell) const; + void setGridPaddedLoc(Cell* cell, int x, int y) const; + int coordinateToHeight(int y_coordinate, GridMapKey gmk) const; + + void paintPixel(Cell* cell, int grid_x, int grid_y); + void erasePixel(Cell* cell); + void visitCellPixels(Cell& cell, + bool padded, + const std::function& visitor) const; + void visitCellBoundaryPixels( + Cell& cell, + bool padded, + const std::function< + void(Pixel* pixel, odb::Direction2D edge, int x, int y)>& visitor) + const; + + int getRowCount() const { return row_count_; } + int getRowSiteCount() const { return row_site_count_; } + int getRowHeight() const { return row_height_; } + int getRowHeight(const Cell* cell) const; + int getSiteWidth() const { return site_width_; } + void setRowHeight(int height) { row_height_ = height; } + void setSiteWidth(int width) { site_width_ = width; } + int map_ycoordinates(int source_grid_coordinate, + const GridMapKey& source_grid_key, + const GridMapKey& target_grid_key, + bool start) const; + + Pixel* gridPixel(int grid_idx, int x, int y) const; + Pixel& pixel(int g, int y, int x) { return pixels_[g][y][x]; } + const Pixel& pixel(int g, int y, int x) const { return pixels_[g][y][x]; } + + bool empty() const { return pixels_.empty(); } + void resize(int size) { pixels_.resize(size); } + void resize(int g, int size) { pixels_[g].resize(size); } + void resize(int g, int y, int size) { pixels_[g][y].resize(size); } + void clear() { pixels_.clear(); } + + void clearInfo() { grid_info_vector_.clear(); } + void resizeInfo(int size) { grid_info_vector_.resize(size); } + void setInfo(int idx, const GridInfo* info) { grid_info_vector_[idx] = info; } + + GridInfo& infoMap(const GridMapKey& key) { return grid_info_map_.at(key); } + const GridInfo& infoMap(const GridMapKey& key) const + { + return grid_info_map_.at(key); + } + bool infoMapEmpty() const { return grid_info_map_.empty(); } + const map& getInfoMap() const { return grid_info_map_; } + void addInfoMap(const GridMapKey& key, const GridInfo& info) + { + grid_info_map_.emplace(key, info); + } + void clearInfoMap() { grid_info_map_.clear(); } + + void clearHybridParent() { hybrid_parent_.clear(); } + const std::unordered_map& getHybridParent() const + { + return hybrid_parent_; + } + + void addHybridParent(dbSite* child, dbSite* parent) + { + hybrid_parent_[child] = parent; + } + + const map& getSiteToGrid() const + { + return site_to_grid_key_; + } + + void addSiteToGrid(dbSite* site, const GridMapKey& key) + { + site_to_grid_key_[site] = key; + } + + GridMapKey getSmallestNonHybridGridKey() const + { + return smallest_non_hybrid_grid_key_; + } + + void setSmallestNonHybridGridKey(const GridMapKey& key) + { + smallest_non_hybrid_grid_key_ = key; + } + + bool getHasHybridRows() const { return has_hybrid_rows_; } + void setHasHybridRows(bool has) { has_hybrid_rows_ = has; } + + int getRowCount(int row_height) const; + + Rect getCore() const { return core_; } + bool cellFitsInCore(Cell* cell) const; + + private: + int calculateHybridSitesRowCount(dbSite* parent_hybrid_site) const; + void initGridLayersMap(dbDatabase* db, dbBlock* block); + + Logger* logger_ = nullptr; + Padding* padding_ = nullptr; + std::vector>> pixels_; + std::vector grid_info_vector_; + map grid_info_map_; + std::unordered_map hybrid_parent_; // child -> parent + + // This map is used to map each unique site to a grid. The key is always + // unique, but the value is not unique in the case of hybrid sites + // (alternating rows) + map site_to_grid_key_; + GridMapKey smallest_non_hybrid_grid_key_; + bool has_hybrid_rows_ = false; + Rect core_; + + int row_height_ = 0; // dbu + int site_width_ = 0; // dbu + + int row_count_ = 0; + int row_site_count_ = 0; +}; + +} // namespace dpl diff --git a/src/dpl/src/Objects.cpp b/src/dpl/src/Objects.cpp new file mode 100644 index 00000000000..d7f2fd4a3bf --- /dev/null +++ b/src/dpl/src/Objects.cpp @@ -0,0 +1,123 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2024, Precision Innovations Inc. +// All rights reserved. +// +// BSD 3-Clause License +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// + +#include "Objects.h" + +namespace dpl { + +Cell Cell::dummy_cell; + +const char* Cell::name() const +{ + return db_inst_->getConstName(); +} + +int64_t Cell::area() const +{ + dbMaster* master = db_inst_->getMaster(); + return int64_t(master->getWidth()) * master->getHeight(); +} + +int Cell::siteWidth() const +{ + if (db_inst_) { + auto site = db_inst_->getMaster()->getSite(); + if (site) { + return db_inst_->getMaster()->getSite()->getWidth(); + } + } + return 0; +} + +bool Cell::isFixed() const +{ + return !db_inst_ || db_inst_->isFixed(); +} + +bool Cell::isStdCell() const +{ + if (db_inst_ == nullptr) { + return false; + } + dbMasterType type = db_inst_->getMaster()->getType(); + // Use switch so if new types are added we get a compiler warning. + switch (type) { + case dbMasterType::CORE: + case dbMasterType::CORE_ANTENNACELL: + case dbMasterType::CORE_FEEDTHRU: + case dbMasterType::CORE_TIEHIGH: + case dbMasterType::CORE_TIELOW: + case dbMasterType::CORE_SPACER: + case dbMasterType::CORE_WELLTAP: + case dbMasterType::ENDCAP: + case dbMasterType::ENDCAP_PRE: + case dbMasterType::ENDCAP_POST: + case dbMasterType::ENDCAP_TOPLEFT: + case dbMasterType::ENDCAP_TOPRIGHT: + case dbMasterType::ENDCAP_BOTTOMLEFT: + case dbMasterType::ENDCAP_BOTTOMRIGHT: + case dbMasterType::ENDCAP_LEF58_BOTTOMEDGE: + case dbMasterType::ENDCAP_LEF58_TOPEDGE: + case dbMasterType::ENDCAP_LEF58_RIGHTEDGE: + case dbMasterType::ENDCAP_LEF58_LEFTEDGE: + case dbMasterType::ENDCAP_LEF58_RIGHTBOTTOMEDGE: + case dbMasterType::ENDCAP_LEF58_LEFTBOTTOMEDGE: + case dbMasterType::ENDCAP_LEF58_RIGHTTOPEDGE: + case dbMasterType::ENDCAP_LEF58_LEFTTOPEDGE: + case dbMasterType::ENDCAP_LEF58_RIGHTBOTTOMCORNER: + case dbMasterType::ENDCAP_LEF58_LEFTBOTTOMCORNER: + case dbMasterType::ENDCAP_LEF58_RIGHTTOPCORNER: + case dbMasterType::ENDCAP_LEF58_LEFTTOPCORNER: + return true; + case dbMasterType::BLOCK: + case dbMasterType::BLOCK_BLACKBOX: + case dbMasterType::BLOCK_SOFT: + // These classes are completely ignored by the placer. + case dbMasterType::COVER: + case dbMasterType::COVER_BUMP: + case dbMasterType::RING: + case dbMasterType::PAD: + case dbMasterType::PAD_AREAIO: + case dbMasterType::PAD_INPUT: + case dbMasterType::PAD_OUTPUT: + case dbMasterType::PAD_INOUT: + case dbMasterType::PAD_POWER: + case dbMasterType::PAD_SPACER: + case dbMasterType::NONE: + return false; + } + // gcc warniing + return false; +} + +} // namespace dpl diff --git a/src/dpl/src/Objects.h b/src/dpl/src/Objects.h new file mode 100644 index 00000000000..f019d23fd0a --- /dev/null +++ b/src/dpl/src/Objects.h @@ -0,0 +1,100 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2024, Precision Innovations Inc. +// All rights reserved. +// +// BSD 3-Clause License +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "dpl/Opendp.h" + +namespace dpl { + +using odb::dbOrientType; +using odb::dbSite; + +struct Master +{ + bool is_multi_row = false; +}; + +struct Cell +{ + const char* name() const; + bool inGroup() const { return group_ != nullptr; } + int64_t area() const; + bool isStdCell() const; + int siteWidth() const; + bool isFixed() const; + + dbInst* db_inst_ = nullptr; + int x_ = 0; // lower left wrt core DBU + int y_ = 0; + dbOrientType orient_; + int width_ = 0; // DBU + int height_ = 0; + bool is_placed_ = false; + bool hold_ = false; + Group* group_ = nullptr; + Rect* region_ = nullptr; // group rect + + bool isHybrid() const + { + dbSite* site = getSite(); + return site ? site->isHybrid() : false; + } + + bool isHybridParent() const + { + dbSite* site = getSite(); + return site ? site->hasRowPattern() : false; + } + + dbSite* getSite() const + { + if (!db_inst_ || !db_inst_->getMaster()) { + return nullptr; + } + return db_inst_->getMaster()->getSite(); + } + + static Cell dummy_cell; +}; + +struct Group +{ + string name; + vector regions; + vector cells_; + Rect boundary; + double util = 0.0; +}; + +} // namespace dpl diff --git a/src/dpl/src/Opendp.cpp b/src/dpl/src/Opendp.cpp index d2fe596eab8..8bce2ac6bce 100644 --- a/src/dpl/src/Opendp.cpp +++ b/src/dpl/src/Opendp.cpp @@ -48,6 +48,9 @@ #include #include "DplObserver.h" +#include "Grid.h" +#include "Objects.h" +#include "Padding.h" #include "dpl/OptMirror.h" #include "odb/util.h" #include "utl/Logger.h" @@ -63,24 +66,8 @@ using odb::dbMasterType; using odb::dbNet; using odb::Rect; -const char* Cell::name() const -{ - return db_inst_->getConstName(); -} - -int64_t Cell::area() const -{ - dbMaster* master = db_inst_->getMaster(); - return int64_t(master->getWidth()) * master->getHeight(); -} - //////////////////////////////////////////////////////////////// -bool Opendp::isFixed(const Cell* cell) const -{ - return cell == &dummy_cell_ || cell->db_inst_->isFixed(); -} - bool Opendp::isMultiRow(const Cell* cell) const { auto iter = db_master_map_.find(cell->db_inst_->getMaster()); @@ -92,7 +79,7 @@ bool Opendp::isMultiRow(const Cell* cell) const Opendp::Opendp() { - dummy_cell_.is_placed_ = true; + Cell::dummy_cell.is_placed_ = true; } Opendp::~Opendp() = default; @@ -101,34 +88,30 @@ void Opendp::init(dbDatabase* db, Logger* logger) { db_ = db; logger_ = logger; + padding_ = std::make_unique(); + grid_ = std::make_unique(); + grid_->init(logger); } void Opendp::initBlock() { block_ = db_->getChip()->getBlock(); - core_ = block_->getCoreArea(); + grid_->initBlock(block_); } void Opendp::setPaddingGlobal(int left, int right) { - pad_left_ = left; - pad_right_ = right; + padding_->setPaddingGlobal(left, right); } void Opendp::setPadding(dbInst* inst, int left, int right) { - inst_padding_map_[inst] = std::make_pair(left, right); + padding_->setPadding(inst, left, right); } void Opendp::setPadding(dbMaster* master, int left, int right) { - master_padding_map_[master] = std::make_pair(left, right); -} - -bool Opendp::havePadding() const -{ - return pad_left_ > 0 || pad_right_ > 0 || !master_padding_map_.empty() - || !inst_padding_map_.empty(); + padding_->setPadding(master, left, right); } void Opendp::setDebug(std::unique_ptr& observer) @@ -192,14 +175,14 @@ void Opendp::detailedPlacement(int max_displacement_x, void Opendp::updateDbInstLocations() { for (Cell& cell : cells_) { - if (!isFixed(&cell) && isStdCell(&cell)) { + if (!cell.isFixed() && cell.isStdCell()) { dbInst* db_inst_ = cell.db_inst_; // Only move the instance if necessary to avoid triggering callbacks. if (db_inst_->getOrient() != cell.orient_) { db_inst_->setOrient(cell.orient_); } - int x = core_.xMin() + cell.x_; - int y = core_.yMin() + cell.y_; + int x = grid_->getCore().xMin() + cell.x_; + int y = grid_->getCore().yMin() + cell.y_; int inst_x, inst_y; db_inst_->getLocation(inst_x, inst_y); if (x != inst_x || y != inst_y) { @@ -273,11 +256,11 @@ Point Opendp::initialLocation(const Cell* cell, bool padded) const { int loc_x, loc_y; cell->db_inst_->getLocation(loc_x, loc_y); - loc_x -= core_.xMin(); + loc_x -= grid_->getCore().xMin(); if (padded) { - loc_x -= padLeft(cell) * site_width_; + loc_x -= padding_->padLeft(cell) * grid_->getSiteWidth(); } - loc_y -= core_.yMin(); + loc_y -= grid_->getCore().yMin(); return Point(loc_x, loc_y); } @@ -287,115 +270,6 @@ int Opendp::disp(const Cell* cell) const return abs(init.getX() - cell->x_) + abs(init.getY() - cell->y_); } -bool Opendp::isPaddedType(dbInst* inst) const -{ - dbMasterType type = inst->getMaster()->getType(); - // Use switch so if new types are added we get a compiler warning. - switch (type) { - case dbMasterType::CORE: - case dbMasterType::CORE_ANTENNACELL: - case dbMasterType::CORE_FEEDTHRU: - case dbMasterType::CORE_TIEHIGH: - case dbMasterType::CORE_TIELOW: - case dbMasterType::CORE_WELLTAP: - case dbMasterType::ENDCAP: - case dbMasterType::ENDCAP_PRE: - case dbMasterType::ENDCAP_POST: - case dbMasterType::ENDCAP_LEF58_RIGHTEDGE: - case dbMasterType::ENDCAP_LEF58_LEFTEDGE: - return true; - case dbMasterType::CORE_SPACER: - case dbMasterType::BLOCK: - case dbMasterType::BLOCK_BLACKBOX: - case dbMasterType::BLOCK_SOFT: - case dbMasterType::ENDCAP_TOPLEFT: - case dbMasterType::ENDCAP_TOPRIGHT: - case dbMasterType::ENDCAP_BOTTOMLEFT: - case dbMasterType::ENDCAP_BOTTOMRIGHT: - case dbMasterType::ENDCAP_LEF58_BOTTOMEDGE: - case dbMasterType::ENDCAP_LEF58_TOPEDGE: - case dbMasterType::ENDCAP_LEF58_RIGHTBOTTOMEDGE: - case dbMasterType::ENDCAP_LEF58_LEFTBOTTOMEDGE: - case dbMasterType::ENDCAP_LEF58_RIGHTTOPEDGE: - case dbMasterType::ENDCAP_LEF58_LEFTTOPEDGE: - case dbMasterType::ENDCAP_LEF58_RIGHTBOTTOMCORNER: - case dbMasterType::ENDCAP_LEF58_LEFTBOTTOMCORNER: - case dbMasterType::ENDCAP_LEF58_RIGHTTOPCORNER: - case dbMasterType::ENDCAP_LEF58_LEFTTOPCORNER: - // These classes are completely ignored by the placer. - case dbMasterType::COVER: - case dbMasterType::COVER_BUMP: - case dbMasterType::RING: - case dbMasterType::PAD: - case dbMasterType::PAD_AREAIO: - case dbMasterType::PAD_INPUT: - case dbMasterType::PAD_OUTPUT: - case dbMasterType::PAD_INOUT: - case dbMasterType::PAD_POWER: - case dbMasterType::PAD_SPACER: - case dbMasterType::NONE: - return false; - } - // gcc warniing - return false; -} - -bool Opendp::isStdCell(const Cell* cell) const -{ - if (cell->db_inst_ == nullptr) { - return false; - } - dbMasterType type = cell->db_inst_->getMaster()->getType(); - // Use switch so if new types are added we get a compiler warning. - switch (type) { - case dbMasterType::CORE: - case dbMasterType::CORE_ANTENNACELL: - case dbMasterType::CORE_FEEDTHRU: - case dbMasterType::CORE_TIEHIGH: - case dbMasterType::CORE_TIELOW: - case dbMasterType::CORE_SPACER: - case dbMasterType::CORE_WELLTAP: - case dbMasterType::ENDCAP: - case dbMasterType::ENDCAP_PRE: - case dbMasterType::ENDCAP_POST: - case dbMasterType::ENDCAP_TOPLEFT: - case dbMasterType::ENDCAP_TOPRIGHT: - case dbMasterType::ENDCAP_BOTTOMLEFT: - case dbMasterType::ENDCAP_BOTTOMRIGHT: - case dbMasterType::ENDCAP_LEF58_BOTTOMEDGE: - case dbMasterType::ENDCAP_LEF58_TOPEDGE: - case dbMasterType::ENDCAP_LEF58_RIGHTEDGE: - case dbMasterType::ENDCAP_LEF58_LEFTEDGE: - case dbMasterType::ENDCAP_LEF58_RIGHTBOTTOMEDGE: - case dbMasterType::ENDCAP_LEF58_LEFTBOTTOMEDGE: - case dbMasterType::ENDCAP_LEF58_RIGHTTOPEDGE: - case dbMasterType::ENDCAP_LEF58_LEFTTOPEDGE: - case dbMasterType::ENDCAP_LEF58_RIGHTBOTTOMCORNER: - case dbMasterType::ENDCAP_LEF58_LEFTBOTTOMCORNER: - case dbMasterType::ENDCAP_LEF58_RIGHTTOPCORNER: - case dbMasterType::ENDCAP_LEF58_LEFTTOPCORNER: - return true; - case dbMasterType::BLOCK: - case dbMasterType::BLOCK_BLACKBOX: - case dbMasterType::BLOCK_SOFT: - // These classes are completely ignored by the placer. - case dbMasterType::COVER: - case dbMasterType::COVER_BUMP: - case dbMasterType::RING: - case dbMasterType::PAD: - case dbMasterType::PAD_AREAIO: - case dbMasterType::PAD_INPUT: - case dbMasterType::PAD_OUTPUT: - case dbMasterType::PAD_INOUT: - case dbMasterType::PAD_POWER: - case dbMasterType::PAD_SPACER: - case dbMasterType::NONE: - return false; - } - // gcc warniing - return false; -} - /* static */ bool Opendp::isBlock(const Cell* cell) { @@ -403,63 +277,16 @@ bool Opendp::isBlock(const Cell* cell) return type == dbMasterType::BLOCK; } -int Opendp::padLeft(const Cell* cell) const -{ - return padLeft(cell->db_inst_); -} - -int Opendp::padLeft(dbInst* inst) const -{ - if (isPaddedType(inst)) { - auto itr1 = inst_padding_map_.find(inst); - if (itr1 != inst_padding_map_.end()) { - return itr1->second.first; - } - auto itr2 = master_padding_map_.find(inst->getMaster()); - if (itr2 != master_padding_map_.end()) { - return itr2->second.first; - } - return pad_left_; - } - return 0; -} - -int Opendp::padRight(const Cell* cell) const -{ - return padRight(cell->db_inst_); -} - -int Opendp::padRight(dbInst* inst) const +int Grid::gridPaddedWidth(const Cell* cell) const { - if (isPaddedType(inst)) { - auto itr1 = inst_padding_map_.find(inst); - if (itr1 != inst_padding_map_.end()) { - return itr1->second.second; - } - auto itr2 = master_padding_map_.find(inst->getMaster()); - if (itr2 != master_padding_map_.end()) { - return itr2->second.second; - } - return pad_right_; - } - return 0; + return divCeil(padding_->paddedWidth(cell), getSiteWidth()); } -int Opendp::paddedWidth(const Cell* cell) const -{ - return cell->width_ + (padLeft(cell) + padRight(cell)) * site_width_; -} - -int Opendp::gridPaddedWidth(const Cell* cell) const -{ - return divCeil(paddedWidth(cell), site_width_); -} - -int Opendp::coordinateToHeight(int y_coordinate, GridMapKey gmk) const +int Grid::coordinateToHeight(int y_coordinate, GridMapKey gmk) const { // gets a coordinate and its grid, and returns the height of the coordinate. // This is useful for hybrid sites - auto grid_info = grid_info_map_.at(gmk); + auto grid_info = infoMap(gmk); if (grid_info.isHybrid()) { auto& grid_sites = grid_info.getSites(); const int total_height = grid_info.getSitesTotalHeight(); @@ -478,7 +305,7 @@ int Opendp::coordinateToHeight(int y_coordinate, GridMapKey gmk) const return y_coordinate * grid_info.getSitesTotalHeight(); } -int Opendp::gridHeight(const Cell* cell) const +int Grid::gridHeight(const Cell* cell) const { int row_height = getRowHeight(cell); return std::max(1, divCeil(cell->height_, row_height)); @@ -486,12 +313,12 @@ int Opendp::gridHeight(const Cell* cell) const int64_t Opendp::paddedArea(const Cell* cell) const { - return int64_t(paddedWidth(cell)) * cell->height_; + return int64_t(padding_->paddedWidth(cell)) * cell->height_; } int Opendp::gridNearestWidth(const Cell* cell) const { - return divRound(paddedWidth(cell), site_width_); + return divRound(padding_->paddedWidth(cell), grid_->getSiteWidth()); } // Callers should probably be using gridHeight. @@ -502,44 +329,44 @@ int Opendp::gridNearestHeight(const Cell* cell, int row_height) const int Opendp::gridNearestHeight(const Cell* cell) const { - int row_height = getRowHeight(cell); + int row_height = grid_->getRowHeight(cell); return divRound(cell->height_, row_height); } -int Opendp::gridEndX(int x) const +int Grid::gridEndX(int x) const { - return divCeil(x, site_width_); + return divCeil(x, getSiteWidth()); } -int Opendp::gridX(int x) const +int Grid::gridX(int x) const { - return x / site_width_; + return x / getSiteWidth(); } -int Opendp::gridX(const Cell* cell) const +int Grid::gridX(const Cell* cell) const { return gridX(cell->x_); } -int Opendp::gridPaddedX(const Cell* cell) const +int Grid::gridPaddedX(const Cell* cell) const { - return gridX(cell->x_ - padLeft(cell) * site_width_); + return gridX(cell->x_ - padding_->padLeft(cell) * getSiteWidth()); } int Opendp::getRowCount(const Cell* cell) const { - return getRowCount(getRowHeight(cell)); + return grid_->getRowCount(grid_->getRowHeight(cell)); } -int Opendp::getRowCount(int row_height) const +int Grid::getRowCount(int row_height) const { return divFloor(core_.dy(), row_height); } -int Opendp::getRowHeight(const Cell* cell) const +int Grid::getRowHeight(const Cell* cell) const { - int row_height = row_height_; - if (isStdCell(cell) || cell->isHybrid()) { + int row_height = getRowHeight(); + if (cell->isStdCell() || cell->isHybrid()) { row_height = cell->height_; } return row_height; @@ -547,12 +374,12 @@ int Opendp::getRowHeight(const Cell* cell) const pair Opendp::getRowInfo(const Cell* cell) const { - if (grid_info_map_.empty()) { + if (grid_->infoMapEmpty()) { logger_->error(DPL, 43, "No grid layers mapped."); } - GridMapKey key = getGridMapKey(cell); - auto layer = grid_info_map_.find(key); - if (layer == grid_info_map_.end()) { + GridMapKey key = grid_->getGridMapKey(cell); + auto layer = grid_->getInfoMap().find(key); + if (layer == grid_->getInfoMap().end()) { // this means the cell is taller than any layer logger_->error(DPL, 44, @@ -563,25 +390,20 @@ pair Opendp::getRowInfo(const Cell* cell) const return std::make_pair(cell->height_, layer->second); } -GridMapKey Opendp::getGridMapKey(const dbSite* site) const +GridMapKey Grid::getGridMapKey(const dbSite* site) const { - auto grid_itr = site_to_grid_key_.find(site); - if (grid_itr == site_to_grid_key_.end()) { - logger_->error( - DPL, 46, "Site {} is not mapped to a grid.", site->getName()); - } - return grid_itr->second; + return getSiteToGrid().at(site); } -GridMapKey Opendp::getGridMapKey(const Cell* cell) const +GridMapKey Grid::getGridMapKey(const Cell* cell) const { if (cell == nullptr) { logger_->error(DPL, 5211, "getGridMapKey cell is null"); } auto site = cell->getSite(); - if (!isStdCell(cell)) { + if (!cell->isStdCell()) { // non std cells can go to the first grid. - return smallest_non_hybrid_grid_key_; + return getSmallestNonHybridGridKey(); } if (site == nullptr) { logger_->error(DPL, 4219, "Cell {} has no site.", cell->name()); @@ -589,12 +411,12 @@ GridMapKey Opendp::getGridMapKey(const Cell* cell) const return getGridMapKey(site); } -GridInfo Opendp::getGridInfo(const Cell* cell) const +GridInfo Grid::getGridInfo(const Cell* cell) const { - return grid_info_map_.at(getGridMapKey(cell)); + return getInfoMap().at(getGridMapKey(cell)); } -pair Opendp::gridY(int y, const dbSite::RowPattern& grid_sites) const +pair Grid::gridY(int y, const dbSite::RowPattern& grid_sites) const { int sum_heights = std::accumulate(grid_sites.begin(), @@ -619,8 +441,7 @@ pair Opendp::gridY(int y, const dbSite::RowPattern& grid_sites) const return {base_height_index + index, cur_height}; } -pair Opendp::gridEndY(int y, - const dbSite::RowPattern& grid_sites) const +pair Grid::gridEndY(int y, const dbSite::RowPattern& grid_sites) const { int sum_heights = std::accumulate(grid_sites.begin(), @@ -642,12 +463,12 @@ pair Opendp::gridEndY(int y, return {base_height_index + index, cur_height}; } -int Opendp::gridY(const Cell* cell) const +int Grid::gridY(const Cell* cell) const { return gridY(cell->y_, cell); } -int Opendp::gridY(const int y, const Cell* cell) const +int Grid::gridY(const int y, const Cell* cell) const { if (cell->isHybrid()) { auto grid_info = getGridInfo(cell); @@ -657,11 +478,11 @@ int Opendp::gridY(const int y, const Cell* cell) const return y / getRowHeight(cell); } -void Opendp::setGridPaddedLoc(Cell* cell, int x, int y) const +void Grid::setGridPaddedLoc(Cell* cell, int x, int y) const { - cell->x_ = (x + padLeft(cell)) * site_width_; + cell->x_ = (x + padding_->padLeft(cell)) * getSiteWidth(); if (cell->isHybrid()) { - auto grid_info = grid_info_map_.at(getGridMapKey(cell)); + auto grid_info = getInfoMap().at(getGridMapKey(cell)); int total_sites_height = grid_info.getSitesTotalHeight(); const auto& sites = grid_info.getSites(); const int sites_size = sites.size(); @@ -688,23 +509,25 @@ void Opendp::setGridPaddedLoc(Cell* cell, int x, int y) const cell->y_ = y * getRowHeight(cell); } -int Opendp::gridPaddedEndX(const Cell* cell) const +int Grid::gridPaddedEndX(const Cell* cell) const { - return divCeil(cell->x_ + cell->width_ + padRight(cell) * site_width_, - site_width_); + const int site_width = getSiteWidth(); + return divCeil( + cell->x_ + cell->width_ + padding_->padRight(cell) * site_width, + site_width); } -int Opendp::gridEndX(const Cell* cell) const +int Grid::gridEndX(const Cell* cell) const { - return divCeil(cell->x_ + cell->width_, site_width_); + return divCeil(cell->x_ + cell->width_, getSiteWidth()); } -int Opendp::gridEndY(const Cell* cell) const +int Grid::gridEndY(const Cell* cell) const { return gridEndY(cell->y_ + cell->height_, cell); } -int Opendp::gridEndY(int y, const Cell* cell) const +int Grid::gridEndY(int y, const Cell* cell) const { if (cell->isHybrid()) { auto grid_info = getGridInfo(cell); @@ -727,6 +550,40 @@ double Opendp::dbuAreaToMicrons(int64_t dbu_area) const return dbu_area / (dbu_micron * dbu_micron); } +Rect Opendp::getCore() const +{ + return grid_->getCore(); +} + +int Opendp::getRowHeight() const +{ + return grid_->getRowHeight(); +} + +int Opendp::getSiteWidth() const +{ + return grid_->getSiteWidth(); +} +int Opendp::padGlobalLeft() const +{ + return padding_->padGlobalLeft(); +} + +int Opendp::padGlobalRight() const +{ + return padding_->padGlobalRight(); +} + +int Opendp::padLeft(dbInst* inst) const +{ + return padding_->padLeft(inst); +} + +int Opendp::padRight(dbInst* inst) const +{ + return padding_->padRight(inst); +} + int divRound(int dividend, int divisor) { return round(static_cast(dividend) / divisor); diff --git a/src/dpl/src/Padding.cpp b/src/dpl/src/Padding.cpp new file mode 100644 index 00000000000..68b857808bf --- /dev/null +++ b/src/dpl/src/Padding.cpp @@ -0,0 +1,162 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2024, Precision Innovations Inc. +// All rights reserved. +// +// BSD 3-Clause License +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// + +#include "Padding.h" + +#include "Objects.h" + +namespace dpl { + +void Padding::setPaddingGlobal(int left, int right) +{ + pad_left_ = left; + pad_right_ = right; +} + +void Padding::setPadding(dbInst* inst, int left, int right) +{ + inst_padding_map_[inst] = {left, right}; +} + +void Padding::setPadding(dbMaster* master, int left, int right) +{ + master_padding_map_[master] = {left, right}; +} + +bool Padding::havePadding() const +{ + return pad_left_ > 0 || pad_right_ > 0 || !master_padding_map_.empty() + || !inst_padding_map_.empty(); +} + +bool Padding::isPaddedType(dbInst* inst) const +{ + dbMasterType type = inst->getMaster()->getType(); + // Use switch so if new types are added we get a compiler warning. + switch (type) { + case dbMasterType::CORE: + case dbMasterType::CORE_ANTENNACELL: + case dbMasterType::CORE_FEEDTHRU: + case dbMasterType::CORE_TIEHIGH: + case dbMasterType::CORE_TIELOW: + case dbMasterType::CORE_WELLTAP: + case dbMasterType::ENDCAP: + case dbMasterType::ENDCAP_PRE: + case dbMasterType::ENDCAP_POST: + case dbMasterType::ENDCAP_LEF58_RIGHTEDGE: + case dbMasterType::ENDCAP_LEF58_LEFTEDGE: + return true; + case dbMasterType::CORE_SPACER: + case dbMasterType::BLOCK: + case dbMasterType::BLOCK_BLACKBOX: + case dbMasterType::BLOCK_SOFT: + case dbMasterType::ENDCAP_TOPLEFT: + case dbMasterType::ENDCAP_TOPRIGHT: + case dbMasterType::ENDCAP_BOTTOMLEFT: + case dbMasterType::ENDCAP_BOTTOMRIGHT: + case dbMasterType::ENDCAP_LEF58_BOTTOMEDGE: + case dbMasterType::ENDCAP_LEF58_TOPEDGE: + case dbMasterType::ENDCAP_LEF58_RIGHTBOTTOMEDGE: + case dbMasterType::ENDCAP_LEF58_LEFTBOTTOMEDGE: + case dbMasterType::ENDCAP_LEF58_RIGHTTOPEDGE: + case dbMasterType::ENDCAP_LEF58_LEFTTOPEDGE: + case dbMasterType::ENDCAP_LEF58_RIGHTBOTTOMCORNER: + case dbMasterType::ENDCAP_LEF58_LEFTBOTTOMCORNER: + case dbMasterType::ENDCAP_LEF58_RIGHTTOPCORNER: + case dbMasterType::ENDCAP_LEF58_LEFTTOPCORNER: + // These classes are completely ignored by the placer. + case dbMasterType::COVER: + case dbMasterType::COVER_BUMP: + case dbMasterType::RING: + case dbMasterType::PAD: + case dbMasterType::PAD_AREAIO: + case dbMasterType::PAD_INPUT: + case dbMasterType::PAD_OUTPUT: + case dbMasterType::PAD_INOUT: + case dbMasterType::PAD_POWER: + case dbMasterType::PAD_SPACER: + case dbMasterType::NONE: + return false; + } + // gcc warniing + return false; +} + +int Padding::padLeft(const Cell* cell) const +{ + return padLeft(cell->db_inst_); +} + +int Padding::padLeft(dbInst* inst) const +{ + if (isPaddedType(inst)) { + auto itr1 = inst_padding_map_.find(inst); + if (itr1 != inst_padding_map_.end()) { + return itr1->second.first; + } + auto itr2 = master_padding_map_.find(inst->getMaster()); + if (itr2 != master_padding_map_.end()) { + return itr2->second.first; + } + return pad_left_; + } + return 0; +} + +int Padding::padRight(const Cell* cell) const +{ + return padRight(cell->db_inst_); +} + +int Padding::padRight(dbInst* inst) const +{ + if (isPaddedType(inst)) { + auto itr1 = inst_padding_map_.find(inst); + if (itr1 != inst_padding_map_.end()) { + return itr1->second.second; + } + auto itr2 = master_padding_map_.find(inst->getMaster()); + if (itr2 != master_padding_map_.end()) { + return itr2->second.second; + } + return pad_right_; + } + return 0; +} + +int Padding::paddedWidth(const Cell* cell) const +{ + return cell->width_ + (padLeft(cell) + padRight(cell)) * cell->siteWidth(); +} + +} // namespace dpl diff --git a/src/dpl/src/Padding.h b/src/dpl/src/Padding.h new file mode 100644 index 00000000000..e845a28cfbf --- /dev/null +++ b/src/dpl/src/Padding.h @@ -0,0 +1,69 @@ +///////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2024, Precision Innovations Inc. +// All rights reserved. +// +// BSD 3-Clause License +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "dpl/Opendp.h" + +namespace dpl { + +class Padding +{ + public: + int padGlobalLeft() const { return pad_left_; } + int padGlobalRight() const { return pad_right_; } + + void setPaddingGlobal(int left, int right); + void setPadding(dbInst* inst, int left, int right); + void setPadding(dbMaster* master, int left, int right); + bool havePadding() const; + + // Find instance/master/global padding value for an instance. + int padLeft(dbInst* inst) const; + int padLeft(const Cell* cell) const; + int padRight(dbInst* inst) const; + int padRight(const Cell* cell) const; + bool isPaddedType(dbInst* inst) const; + int paddedWidth(const Cell* cell) const; + + private: + using InstPaddingMap = map>; + using MasterPaddingMap = map>; + + int pad_left_ = 0; + int pad_right_ = 0; + InstPaddingMap inst_padding_map_; + MasterPaddingMap master_padding_map_; +}; + +} // namespace dpl diff --git a/src/dpl/src/Place.cpp b/src/dpl/src/Place.cpp index 584b820a2ca..c627ab3afda 100644 --- a/src/dpl/src/Place.cpp +++ b/src/dpl/src/Place.cpp @@ -44,6 +44,8 @@ #include #include "DplObserver.h" +#include "Grid.h" +#include "Objects.h" #include "dpl/Opendp.h" #include "utl/Logger.h" @@ -202,7 +204,7 @@ void Opendp::prePlaceGroups() { for (Group& group : groups_) { for (Cell* cell : group.cells_) { - if (!isFixed(cell) && !cell->is_placed_) { + if (!cell->isFixed() && !cell->is_placed_) { int dist = numeric_limits::max(); bool in_group = false; Rect* nearest_rect = nullptr; @@ -308,9 +310,9 @@ void Opendp::place() sorted_cells.reserve(cells_.size()); for (Cell& cell : cells_) { - if (!(isFixed(&cell) || cell.inGroup() || cell.is_placed_)) { + if (!(cell.isFixed() || cell.inGroup() || cell.is_placed_)) { sorted_cells.push_back(&cell); - if (!cellFitsInCore(&cell)) { + if (!grid_->cellFitsInCore(&cell)) { logger_->error(DPL, 15, "instance {} does not fit inside the ROW core area.", @@ -323,7 +325,7 @@ void Opendp::place() // Place multi-row instances first. if (have_multi_row_cells_) { for (Cell* cell : sorted_cells) { - if (isMultiRow(cell) && cellFitsInCore(cell)) { + if (isMultiRow(cell) && grid_->cellFitsInCore(cell)) { debugPrint(logger_, DPL, "place", @@ -337,7 +339,7 @@ void Opendp::place() } } for (Cell* cell : sorted_cells) { - if (!isMultiRow(cell) && cellFitsInCore(cell)) { + if (!isMultiRow(cell) && grid_->cellFitsInCore(cell)) { if (!mapMove(cell)) { shiftMove(cell); } @@ -347,10 +349,10 @@ void Opendp::place() // anneal(); } -bool Opendp::cellFitsInCore(Cell* cell) +bool Grid::cellFitsInCore(Cell* cell) const { - return gridPaddedWidth(cell) <= row_site_count_ - && gridHeight(cell) <= row_count_; + return gridPaddedWidth(cell) <= getRowSiteCount() + && gridHeight(cell) <= getRowCount(); } void Opendp::placeGroups2() @@ -359,7 +361,7 @@ void Opendp::placeGroups2() vector group_cells; group_cells.reserve(cells_.size()); for (Cell* cell : group.cells_) { - if (!isFixed(cell) && !cell->is_placed_) { + if (!cell->isFixed() && !cell->is_placed_) { group_cells.push_back(cell); } } @@ -368,7 +370,7 @@ void Opendp::placeGroups2() // Place multi-row cells in each group region. bool multi_pass = true; for (Cell* cell : group_cells) { - if (!isFixed(cell) && !cell->is_placed_) { + if (!cell->isFixed() && !cell->is_placed_) { assert(cell->inGroup()); if (isMultiRow(cell)) { multi_pass = mapMove(cell); @@ -382,7 +384,7 @@ void Opendp::placeGroups2() if (multi_pass) { // Place single-row cells in each group region. for (Cell* cell : group_cells) { - if (!isFixed(cell) && !cell->is_placed_) { + if (!cell->isFixed() && !cell->is_placed_) { assert(cell->inGroup()); if (!isMultiRow(cell)) { single_pass = mapMove(cell); @@ -397,7 +399,7 @@ void Opendp::placeGroups2() if (!single_pass || !multi_pass) { // Erase group cells for (Cell* cell : group.cells_) { - erasePixel(cell); + grid_->erasePixel(cell); } // Determine brick placement by utilization. @@ -549,7 +551,7 @@ int Opendp::refine() sorted.reserve(cells_.size()); for (Cell& cell : cells_) { - if (!(isFixed(&cell) || cell.hold_ || cell.inGroup())) { + if (!(cell.isFixed() || cell.hold_ || cell.inGroup())) { sorted.push_back(&cell); } } @@ -604,7 +606,7 @@ bool Opendp::mapMove(Cell* cell, const Point& grid_pt) pixel_pt.pt.getY(), pixel_pt.pixel->site->getName()); if (pixel_pt.pixel) { - paintPixel(cell, pixel_pt.pt.getX(), pixel_pt.pt.getY()); + grid_->paintPixel(cell, pixel_pt.pt.getX(), pixel_pt.pt.getY()); if (debug_observer_) { debug_observer_->placeInstance(cell->db_inst_); } @@ -618,24 +620,19 @@ void Opendp::shiftMove(Cell* cell) Point grid_pt = legalGridPt(cell, true); int grid_x = grid_pt.getX(); int grid_y = grid_pt.getY(); - int row_height = getRowHeight(cell); - GridMapKey grid_key = getGridMapKey(cell); - auto grid_mapped_entry = grid_info_map_.find(grid_key); - if (grid_mapped_entry == grid_info_map_.end()) { - logger_->error( - DPL, 18, "Cannot find grid info for row height {}.", row_height); - } - int grid_index = grid_mapped_entry->second.getGridIndex(); + GridMapKey grid_key = grid_->getGridMapKey(cell); + auto grid_info = grid_->infoMap(grid_key); + int grid_index = grid_info.getGridIndex(); // magic number alert int boundary_margin = 3; - int margin_width = gridPaddedWidth(cell) * boundary_margin; + int margin_width = grid_->gridPaddedWidth(cell) * boundary_margin; std::set region_cells; for (int x = grid_x - margin_width; x < grid_x + margin_width; x++) { for (int y = grid_y - boundary_margin; y < grid_y + boundary_margin; y++) { - Pixel* pixel = gridPixel(grid_index, x, y); + Pixel* pixel = grid_->gridPixel(grid_index, x, y); if (pixel) { Cell* cell = pixel->cell; - if (cell && !isFixed(cell)) { + if (cell && !cell->isFixed()) { region_cells.insert(cell); } } @@ -645,7 +642,7 @@ void Opendp::shiftMove(Cell* cell) // erase region cells for (Cell* around_cell : region_cells) { if (cell->inGroup() == around_cell->inGroup()) { - erasePixel(around_cell); + grid_->erasePixel(around_cell); } } @@ -666,20 +663,20 @@ bool Opendp::swapCells(Cell* cell1, Cell* cell2) { if (cell1 != cell2 && !cell1->hold_ && !cell2->hold_ && cell1->width_ == cell2->width_ && cell1->height_ == cell2->height_ - && !isFixed(cell1) && !isFixed(cell2)) { + && !cell1->isFixed() && !cell2->isFixed()) { int dist_change = distChange(cell1, cell2->x_, cell2->y_) + distChange(cell2, cell1->x_, cell1->y_); if (dist_change < 0) { - int grid_x1 = gridPaddedX(cell2); - int grid_y1 = gridY(cell2); - int grid_x2 = gridPaddedX(cell1); - int grid_y2 = gridY(cell1); - - erasePixel(cell1); - erasePixel(cell2); - paintPixel(cell1, grid_x1, grid_y1); - paintPixel(cell2, grid_x2, grid_y2); + int grid_x1 = grid_->gridPaddedX(cell2); + int grid_y1 = grid_->gridY(cell2); + int grid_x2 = grid_->gridPaddedX(cell1); + int grid_y2 = grid_->gridY(cell1); + + grid_->erasePixel(cell1); + grid_->erasePixel(cell2); + grid_->paintPixel(cell1, grid_x1, grid_y1); + grid_->paintPixel(cell2, grid_x2, grid_y2); return true; } } @@ -688,7 +685,7 @@ bool Opendp::swapCells(Cell* cell1, Cell* cell2) bool Opendp::refineMove(Cell* cell) { - int row_height = getRowHeight(cell); + int row_height = grid_->getRowHeight(cell); Point grid_pt = legalGridPt(cell, true, row_height); int grid_x = grid_pt.getX(); int grid_y = grid_pt.getY(); @@ -696,22 +693,22 @@ bool Opendp::refineMove(Cell* cell) if (pixel_pt.pixel) { int scaled_max_displacement_y_ - = map_ycoordinates(max_displacement_y_, - smallest_non_hybrid_grid_key_, - getGridMapKey(cell), - true); + = grid_->map_ycoordinates(max_displacement_y_, + grid_->getSmallestNonHybridGridKey(), + grid_->getGridMapKey(cell), + true); if (abs(grid_x - pixel_pt.pt.getX()) > max_displacement_x_ || abs(grid_y - pixel_pt.pt.getY()) > scaled_max_displacement_y_) { return false; } int dist_change = distChange(cell, - pixel_pt.pt.getX() * site_width_, + pixel_pt.pt.getX() * grid_->getSiteWidth(), pixel_pt.pt.getY() * row_height); if (dist_change < 0) { - erasePixel(cell); - paintPixel(cell, pixel_pt.pt.getX(), pixel_pt.pt.getY()); + grid_->erasePixel(cell); + grid_->paintPixel(cell, pixel_pt.pt.getX(), pixel_pt.pt.getY()); return true; } } @@ -744,10 +741,10 @@ PixelPt Opendp::diamondSearch(const Cell* cell, // max_displacement_y_ is in microns, and this doesn't translate directly to // x and y on the grid. int scaled_max_displacement_y_ - = map_ycoordinates(max_displacement_y_, - smallest_non_hybrid_grid_key_, - getGridMapKey(cell), - true); + = grid_->map_ycoordinates(max_displacement_y_, + grid_->getSmallestNonHybridGridKey(), + grid_->getGridMapKey(cell), + true); int y_min = y - scaled_max_displacement_y_; int y_max = y + scaled_max_displacement_y_; @@ -757,9 +754,10 @@ PixelPt Opendp::diamondSearch(const Cell* cell, Group* group = cell->group_; if (group) { // Map boundary to grid staying inside. - Rect grid_boundary(divCeil(group->boundary.xMin(), site_width_), + const int site_width = grid_->getSiteWidth(); + Rect grid_boundary(divCeil(group->boundary.xMin(), site_width), divCeil(group->boundary.yMin(), row_height), - group->boundary.xMax() / site_width_, + group->boundary.xMax() / site_width, group->boundary.yMax() / row_height); Point min = grid_boundary.closestPtInside(Point(x_min, y_min)); Point max = grid_boundary.closestPtInside(Point(x_max, y_max)); @@ -868,12 +866,12 @@ void Opendp::diamondSearchSide(const Cell* cell, if (avail_pt.pixel) { int y_dist = 0; if (cell->isHybrid() && !cell->isHybridParent()) { - auto gmk = getGridMapKey(cell); + auto gmk = grid_->getGridMapKey(cell); - y_dist = abs(coordinateToHeight(y, gmk) - - coordinateToHeight(avail_pt.pt.getY(), gmk)); + y_dist = abs(grid_->coordinateToHeight(y, gmk) + - grid_->coordinateToHeight(avail_pt.pt.getY(), gmk)); } else { - y_dist = abs(y - avail_pt.pt.getY()) * getRowHeight(cell); + y_dist = abs(y - avail_pt.pt.getY()) * grid_->getRowHeight(cell); } int avail_dist = abs(x - avail_pt.pt.getX()) * getSiteWidth() + y_dist; if (best_pt.pixel == nullptr || avail_dist < best_dist) { @@ -895,19 +893,14 @@ PixelPt Opendp::binSearch(int x, const Cell* cell, int bin_x, int bin_y) const x > bin_x ? "-" : "+", x > bin_x ? bin_x : bin_x + bin_search_width_ - 1, bin_y); - int x_end = bin_x + gridPaddedWidth(cell); - int row_height = getRowHeight(cell); - auto grid_mapped_entry = grid_info_map_.find(getGridMapKey(cell)); - if (grid_mapped_entry == grid_info_map_.end()) { - logger_->error( - DPL, 14, "Cannot find grid info for row height {}.", row_height); - } - auto grid_info = grid_mapped_entry->second; + int x_end = bin_x + grid_->gridPaddedWidth(cell); + int row_height = grid_->getRowHeight(cell); + auto grid_info = grid_->infoMap(grid_->getGridMapKey(cell)); if (bin_y >= grid_info.getRowCount()) { return PixelPt(); } - int height = gridHeight(cell); + int height = grid_->gridHeight(cell); int y_end = bin_y + height; if (debug_observer_) { @@ -920,7 +913,7 @@ PixelPt Opendp::binSearch(int x, const Cell* cell, int bin_x, int bin_y) const if (x > bin_x) { for (int i = bin_search_width_ - 1; i >= 0; i--) { - Point p((bin_x + i) * site_width_, bin_y * row_height); + Point p((bin_x + i) * grid_->getSiteWidth(), bin_y * row_height); if (cell->region_ && !cell->region_->intersects(p)) { continue; } @@ -928,13 +921,13 @@ PixelPt Opendp::binSearch(int x, const Cell* cell, int bin_x, int bin_y) const // rtree in checkPixels if (checkPixels(cell, bin_x + i, bin_y, x_end + i, y_end)) { Pixel* valid_grid_pixel - = gridPixel(grid_info.getGridIndex(), bin_x + i, bin_y); + = grid_->gridPixel(grid_info.getGridIndex(), bin_x + i, bin_y); return PixelPt(valid_grid_pixel, bin_x + i, bin_y); } } } else { for (int i = 0; i < bin_search_width_; i++) { - Point p((bin_x + i) * site_width_, bin_y * row_height); + Point p((bin_x + i) * grid_->getSiteWidth(), bin_y * row_height); if (cell->region_) { if (!cell->region_->intersects(p)) { continue; @@ -942,7 +935,7 @@ PixelPt Opendp::binSearch(int x, const Cell* cell, int bin_x, int bin_y) const } if (checkPixels(cell, bin_x + i, bin_y, x_end + i, y_end)) { Pixel* valid_grid_pixel - = gridPixel(grid_info.getGridIndex(), bin_x + i, bin_y); + = grid_->gridPixel(grid_info.getGridIndex(), bin_x + i, bin_y); return PixelPt(valid_grid_pixel, bin_x + i, bin_y); } } @@ -970,16 +963,20 @@ bool Opendp::checkRegionOverlap(const Cell* cell, y, y_end); auto row_info = getRowInfo(cell); - auto gmk = getGridMapKey(cell); - int min_row_height = row_height_; - bgBox queryBox( - bgPoint(x * site_width_, - map_ycoordinates(y, gmk, smallest_non_hybrid_grid_key_, true) - * min_row_height), - bgPoint(x_end * site_width_ - 1, - map_ycoordinates(y_end, gmk, smallest_non_hybrid_grid_key_, false) - * min_row_height - - 1)); + auto gmk = grid_->getGridMapKey(cell); + int min_row_height = grid_->getRowHeight(); + const auto smallest_non_hybrid_grid_key + = grid_->getSmallestNonHybridGridKey(); + const int site_width = grid_->getSiteWidth(); + bgBox queryBox(bgPoint(x * site_width, + grid_->map_ycoordinates( + y, gmk, smallest_non_hybrid_grid_key, true) + * min_row_height), + bgPoint(x_end * site_width - 1, + grid_->map_ycoordinates( + y_end, gmk, smallest_non_hybrid_grid_key, false) + * min_row_height + - 1)); std::vector result; findOverlapInRtree(queryBox, result); @@ -1006,7 +1003,7 @@ bool Opendp::checkPixels(const Cell* cell, int x_end, int y_end) const { - auto gmk = getGridMapKey(cell); + auto gmk = grid_->getGridMapKey(cell); auto row_info = getRowInfo(cell); if (x_end > row_info.second.getSiteCount()) { return false; @@ -1018,7 +1015,7 @@ bool Opendp::checkPixels(const Cell* cell, int layer = row_info.second.getGridIndex(); for (int y1 = y; y1 < y_end; y1++) { for (int x1 = x; x1 < x_end; x1++) { - Pixel* pixel = gridPixel(layer, x1, y1); + Pixel* pixel = grid_->gridPixel(layer, x1, y1); if (pixel == nullptr || pixel->cell || !pixel->is_valid || (cell->inGroup() && pixel->group_ != cell->group_) || (!cell->inGroup() && pixel->group_) @@ -1041,12 +1038,12 @@ bool Opendp::checkPixels(const Cell* cell, int y_finish = min(y_end, row_info.second.getRowCount() - 1); auto isAbutted = [this](int layer, int x, int y) { - Pixel* pixel = gridPixel(layer, x, y); + Pixel* pixel = grid_->gridPixel(layer, x, y); return (pixel == nullptr || pixel->cell); }; auto cellAtSite = [this](int layer, int x, int y) { - Pixel* pixel = gridPixel(layer, x, y); + Pixel* pixel = grid_->gridPixel(layer, x, y); return (pixel != nullptr && pixel->cell); }; // upper left corner @@ -1070,14 +1067,14 @@ bool Opendp::checkPixels(const Cell* cell, return false; } - int min_row_height = row_height_; + const int min_row_height = grid_->getRowHeight(); int steps = row_info.first / min_row_height; // This is needed for the scenario where we are placing a triple height // cell and we are not sure if there is a single height cell direcly in // the middle that would be missed by the 4 corners check above. // So, we loop with steps of min_row_height and check the left and right - int y_begin_mapped - = map_ycoordinates(y_begin, gmk, smallest_non_hybrid_grid_key_, true); + int y_begin_mapped = grid_->map_ycoordinates( + y_begin, gmk, grid_->getSmallestNonHybridGridKey(), true); int offset = 0; for (int step = 0; step < steps; step++) { @@ -1109,19 +1106,15 @@ Point Opendp::legalPt(const Cell* cell, const Point& pt, int row_height) const { // Move inside core. if (row_height == -1) { - row_height = getRowHeight(cell); - } - auto grid_mapped_entry = grid_info_map_.find(getGridMapKey(cell)); - if (grid_mapped_entry == grid_info_map_.end()) { - logger_->error( - DPL, 19, "Cannot find grid info for row height {}.", row_height); + row_height = grid_->getRowHeight(cell); } - auto grid_info = grid_mapped_entry->second; + auto grid_info = grid_->infoMap(grid_->getGridMapKey(cell)); + const int site_width = grid_->getSiteWidth(); int core_x = min(max(0, pt.getX()), - grid_info.getSiteCount() * site_width_ - cell->width_); + grid_info.getSiteCount() * site_width - cell->width_); // Align with row site. - int grid_x = divRound(core_x, site_width_); - int legal_x = grid_x * site_width_; + int grid_x = divRound(core_x, site_width); + int legal_x = grid_x * site_width; int legal_y = 0; if (cell->isHybrid()) { int index(0), height(0); @@ -1129,11 +1122,11 @@ Point Opendp::legalPt(const Cell* cell, const Point& pt, int row_height) const if (cell->isHybridParent()) { last_row_height = grid_info.getRowCount() * row_height - cell->height_; } else { - auto parent = _hybrid_parent.at(cell->getSite()); + auto parent = grid_->getHybridParent().at(cell->getSite()); last_row_height = (grid_info.getRowCount() - 1) * parent->getHeight(); } - std::tie(index, height) - = gridY(min(max(0, pt.getY()), last_row_height), grid_info.getSites()); + std::tie(index, height) = grid_->gridY( + min(max(0, pt.getY()), last_row_height), grid_info.getSites()); legal_y = height; } else { int core_y = min(max(0, pt.getY()), @@ -1150,10 +1143,10 @@ Point Opendp::legalGridPt(const Cell* cell, int row_height) const { if (row_height == -1) { - row_height = getRowHeight(cell); + row_height = grid_->getRowHeight(cell); } Point legal = legalPt(cell, pt, row_height); - return Point(gridX(legal.getX()), gridY(legal.getY(), cell)); + return Point(grid_->gridX(legal.getX()), grid_->gridY(legal.getY(), cell)); } Point Opendp::nearestBlockEdge(const Cell* cell, @@ -1162,7 +1155,7 @@ Point Opendp::nearestBlockEdge(const Cell* cell, { const int legal_x = legal_pt.getX(); const int legal_y = legal_pt.getY(); - const int row_height = getRowHeight(cell); + const int row_height = grid_->getRowHeight(cell); const int x_min_dist = abs(legal_x - block_bbox.xMin()); const int x_max_dist = abs(block_bbox.xMax() - (legal_x + cell->width_)); const int y_min_dist = abs(legal_y - block_bbox.yMin()); @@ -1208,21 +1201,22 @@ bool Opendp::moveHopeless(const Cell* cell, int& grid_x, int& grid_y) const int grid_index = grid_info.getGridIndex(); int layer_site_count = grid_info.getSiteCount(); int layer_row_count = grid_info.getRowCount(); + const int site_width = grid_->getSiteWidth(); // since the site doesn't have to be empty, we don't need to check all layers. // They will be checked in the checkPixels in the diamondSearch method after // this initialization for (int x = grid_x - 1; x >= 0; --x) { // left - if (grid_[grid_index][grid_y][x].is_valid) { - best_dist = (grid_x - x - 1) * site_width_; + if (grid_->pixel(grid_index, grid_y, x).is_valid) { + best_dist = (grid_x - x - 1) * site_width; best_x = x; best_y = grid_y; break; } } for (int x = grid_x + 1; x < layer_site_count; ++x) { // right - if (grid_[grid_index][grid_y][x].is_valid) { - const int dist = (x - grid_x) * site_width_ - cell->width_; + if (grid_->pixel(grid_index, grid_y, x).is_valid) { + const int dist = (x - grid_x) * site_width - cell->width_; if (dist < best_dist) { best_dist = dist; best_x = x; @@ -1232,7 +1226,7 @@ bool Opendp::moveHopeless(const Cell* cell, int& grid_x, int& grid_y) const } } for (int y = grid_y - 1; y >= 0; --y) { // below - if (grid_[grid_index][y][grid_x].is_valid) { + if (grid_->pixel(grid_index, y, grid_x).is_valid) { const int dist = (grid_y - y - 1) * row_height; // FIXME(mina1460): this is wrong for hybrid sites @@ -1245,7 +1239,7 @@ bool Opendp::moveHopeless(const Cell* cell, int& grid_x, int& grid_y) const } } for (int y = grid_y + 1; y < layer_row_count; ++y) { // above - if (grid_[grid_index][y][grid_x].is_valid) { + if (grid_->pixel(grid_index, y, grid_x).is_valid) { const int dist = (y - grid_y) * row_height - cell->height_; if (dist < best_dist) { best_dist = dist; @@ -1288,18 +1282,19 @@ Point Opendp::pointOffMacro(const Cell& cell) int init_x = init.getX(); int init_y = init.getY(); - auto grid_info = getGridInfo(&cell); - Pixel* pixel1 = gridPixel( - grid_info.getGridIndex(), gridX(init_x), gridY(init_y, &cell)); - Pixel* pixel2 = gridPixel(grid_info.getGridIndex(), - gridX(init_x + cell.width_), - gridY(init_y, &cell)); - Pixel* pixel3 = gridPixel(grid_info.getGridIndex(), - gridX(init_x), - gridY(init_y + cell.height_, &cell)); - Pixel* pixel4 = gridPixel(grid_info.getGridIndex(), - gridX(init_x + cell.width_), - gridY(init_y + cell.height_, &cell)); + auto grid_info = grid_->getGridInfo(&cell); + Pixel* pixel1 = grid_->gridPixel(grid_info.getGridIndex(), + grid_->gridX(init_x), + grid_->gridY(init_y, &cell)); + Pixel* pixel2 = grid_->gridPixel(grid_info.getGridIndex(), + grid_->gridX(init_x + cell.width_), + grid_->gridY(init_y, &cell)); + Pixel* pixel3 = grid_->gridPixel(grid_info.getGridIndex(), + grid_->gridX(init_x), + grid_->gridY(init_y + cell.height_, &cell)); + Pixel* pixel4 = grid_->gridPixel(grid_info.getGridIndex(), + grid_->gridX(init_x + cell.width_), + grid_->gridY(init_y + cell.height_, &cell)); Cell* block = nullptr; if (pixel1 && pixel1->cell && isBlock(pixel1->cell)) { @@ -1343,12 +1338,13 @@ void Opendp::legalCellPos(dbInst* db_inst) } // transform to grid Pos for align - const Point legal_grid_pt - = Point(gridX(new_pos.getX()), gridY(new_pos.getY(), &cell)); + const Point legal_grid_pt = Point(grid_->gridX(new_pos.getX()), + grid_->gridY(new_pos.getY(), &cell)); // Transform position on real position - setGridPaddedLoc(&cell, legal_grid_pt.getX(), legal_grid_pt.getY()); + grid_->setGridPaddedLoc(&cell, legal_grid_pt.getX(), legal_grid_pt.getY()); // Set position of cell on db - db_inst->setLocation(core_.xMin() + cell.x_, core_.yMin() + cell.y_); + const Rect core = grid_->getCore(); + db_inst->setLocation(core.xMin() + cell.x_, core.yMin() + cell.y_); } // Legalize pt origin for cell @@ -1358,27 +1354,27 @@ void Opendp::legalCellPos(dbInst* db_inst) // not in a hopeless site Point Opendp::legalPt(const Cell* cell, bool padded, int row_height) const { - if (isFixed(cell)) { + if (cell->isFixed()) { logger_->critical(DPL, 26, "legalPt called on fixed cell."); } if (row_height == -1) { - row_height = getRowHeight(cell); + row_height = grid_->getRowHeight(cell); } Point init = initialLocation(cell, padded); Point legal_pt = legalPt(cell, init, row_height); - auto grid_info = getGridInfo(cell); - int grid_x = gridX(legal_pt.getX()); + auto grid_info = grid_->getGridInfo(cell); + int grid_x = grid_->gridX(legal_pt.getX()); int grid_y, height; int y = legal_pt.getY() + grid_info.getOffset(); - std::tie(grid_y, height) = gridY(y, grid_info.getSites()); - Pixel* pixel = gridPixel(grid_info.getGridIndex(), grid_x, grid_y); + std::tie(grid_y, height) = grid_->gridY(y, grid_info.getSites()); + Pixel* pixel = grid_->gridPixel(grid_info.getGridIndex(), grid_x, grid_y); if (pixel) { // Move std cells off of macros. First try the is_hopeless strategy if (pixel->is_hopeless && moveHopeless(cell, grid_x, grid_y)) { - legal_pt = Point(grid_x * site_width_, grid_y * row_height); - pixel = gridPixel(grid_info.getGridIndex(), grid_x, grid_y); + legal_pt = Point(grid_x * grid_->getSiteWidth(), grid_y * row_height); + pixel = grid_->gridPixel(grid_info.getGridIndex(), grid_x, grid_y); } const Cell* block = pixel->cell; @@ -1408,10 +1404,10 @@ Point Opendp::legalPt(const Cell* cell, bool padded, int row_height) const Point Opendp::legalGridPt(const Cell* cell, bool padded, int row_height) const { if (row_height == -1) { - row_height = getRowHeight(cell); + row_height = grid_->getRowHeight(cell); } Point pt = legalPt(cell, padded, row_height); - return Point(gridX(pt.getX()), gridY(pt.getY(), cell)); + return Point(grid_->gridX(pt.getX()), grid_->gridY(pt.getY(), cell)); } //////////////////////////////////////////////////////////////// diff --git a/src/dpl/src/dbToOpendp.cpp b/src/dpl/src/dbToOpendp.cpp index 55b33b38903..994520a72c8 100644 --- a/src/dpl/src/dbToOpendp.cpp +++ b/src/dpl/src/dbToOpendp.cpp @@ -38,6 +38,8 @@ #include #include +#include "Grid.h" +#include "Objects.h" #include "dpl/Opendp.h" #include "utl/Logger.h" @@ -52,6 +54,7 @@ using odb::dbBox; using odb::dbMaster; using odb::dbOrientType; using odb::dbRegion; +using odb::dbRow; using odb::Rect; static bool swapWidthHeight(const dbOrientType& orient); @@ -59,12 +62,12 @@ static bool swapWidthHeight(const dbOrientType& orient); void Opendp::importDb() { block_ = db_->getChip()->getBlock(); - core_ = block_->getCoreArea(); + grid_->initBlock(block_); have_fillers_ = false; have_one_site_cells_ = false; importClear(); - examineRows(); + grid_->examineRows(block_); checkOneSiteDbMaster(); makeMacros(); makeCells(); @@ -112,17 +115,18 @@ void Opendp::makeMacros() void Opendp::makeMaster(Master* master, dbMaster* db_master) { const int master_height = db_master->getHeight(); + const int row_height = grid_->getRowHeight(); master->is_multi_row - = (master_height != row_height_ && master_height % row_height_ == 0); + = (master_height != row_height && master_height % row_height == 0); } -void Opendp::examineRows() +void Grid::examineRows(dbBlock* block) { std::vector rows; - auto block_rows = block_->getRows(); + auto block_rows = block->getRows(); rows.reserve(block_rows.size()); - has_hybrid_rows_ = false; + setHasHybridRows(false); bool has_non_hybrid_rows = false; for (auto* row : block_rows) { @@ -131,7 +135,7 @@ void Opendp::examineRows() continue; } if (site->isHybrid()) { - has_hybrid_rows_ = true; + setHasHybridRows(true); } else { has_non_hybrid_rows = true; } @@ -140,7 +144,7 @@ void Opendp::examineRows() if (rows.empty()) { logger_->error(DPL, 12, "no rows found."); } - if (has_hybrid_rows_ && has_non_hybrid_rows) { + if (getHasHybridRows() && has_non_hybrid_rows) { logger_->error( DPL, 49, "Mixing hybrid and non-hybrid rows is unsupported."); } @@ -154,10 +158,10 @@ void Opendp::examineRows() min_row_height_ = std::min(min_row_height_, static_cast(site->getHeight())); } - row_height_ = min_row_height_; - site_width_ = min_site_width_; - row_site_count_ = divFloor(core_.dx(), site_width_); - row_count_ = divFloor(core_.dy(), row_height_); + setRowHeight(min_row_height_); + setSiteWidth(min_site_width_); + row_site_count_ = divFloor(getCore().dx(), getSiteWidth()); + row_count_ = divFloor(getCore().dy(), getRowHeight()); } void Opendp::makeCells() @@ -179,7 +183,7 @@ void Opendp::makeCells() cell.y_ = bbox.yMin(); cell.orient_ = db_inst->getOrient(); // Cell is already placed if it is FIXED. - cell.is_placed_ = isFixed(&cell); + cell.is_placed_ = cell.isFixed(); Master& master = db_master_map_[db_master]; // We only want to set this if we have multi-row cells to @@ -201,8 +205,8 @@ Rect Opendp::getBbox(dbInst* inst) int loc_x, loc_y; inst->getLocation(loc_x, loc_y); // Shift by core lower left. - loc_x -= core_.xMin(); - loc_y -= core_.yMin(); + loc_x -= grid_->getCore().xMin(); + loc_y -= grid_->getCore().yMin(); int width = master->getWidth(); int height = master->getHeight(); @@ -272,9 +276,10 @@ void Opendp::makeGroups() for (dbBox* boundary : boundaries) { Rect box = boundary->getBox(); - box = box.intersect(core_); + const Rect core = grid_->getCore(); + box = box.intersect(core); // offset region to core origin - box.moveDelta(-core_.xMin(), -core_.yMin()); + box.moveDelta(-core.xMin(), -core.yMin()); if (height == *(unique_heights.begin())) { bgBox bbox( bgPoint(box.xMin(), box.yMin()), diff --git a/src/dpl/test/dpl_test.cc b/src/dpl/test/dpl_test.cc index 5cdfb5aedb6..4ec34ce9355 100644 --- a/src/dpl/test/dpl_test.cc +++ b/src/dpl/test/dpl_test.cc @@ -43,20 +43,4 @@ class OpendpTest : public ::testing::Test OdbUniquePtr block_{nullptr, &odb::dbBlock::destroy}; }; -TEST_F(OpendpTest, IsPlaced) -{ - odb::dbMaster* and_gate = lib_->findMaster("sky130_fd_sc_hd__and2_1"); - auto and_placed = OdbUniquePtr( - odb::dbInst::create(block_.get(), and_gate, "and_1"), - &odb::dbInst::destroy); - - and_placed->setPlacementStatus(odb::dbPlacementStatus::PLACED); - - Cell placed; - placed.db_inst_ = and_placed.get(); - - // Act & Assert - ASSERT_TRUE(Opendp::isPlaced(&placed)); -} - } // namespace dpl diff --git a/src/drt/src/dr/FlexDR.h b/src/drt/src/dr/FlexDR.h index aa114ec5f18..ef79d3c6df4 100644 --- a/src/drt/src/dr/FlexDR.h +++ b/src/drt/src/dr/FlexDR.h @@ -827,7 +827,7 @@ class FlexDRWorker void mazeNetInit(drNet* net); void mazeNetEnd(drNet* net); - bool routeNet(drNet* net); + bool routeNet(drNet* net, std::vector& paths); void routeNet_prep(drNet* net, std::set& unConnPins, std::map>& diff --git a/src/drt/src/dr/FlexDR_maze.cpp b/src/drt/src/dr/FlexDR_maze.cpp index 31185781b5e..0de3f70fbe0 100644 --- a/src/drt/src/dr/FlexDR_maze.cpp +++ b/src/drt/src/dr/FlexDR_maze.cpp @@ -1799,7 +1799,8 @@ void FlexDRWorker::route_queue_main(std::queue& rerouteQueue) } // route mazeNetInit(net); - bool isRouted = routeNet(net); + std::vector paths; + bool isRouted = routeNet(net, paths); if (isRouted == false) { if (OUT_MAZE_FILE == std::string("")) { if (VERBOSE > 0) { @@ -1847,9 +1848,25 @@ void FlexDRWorker::route_queue_main(std::queue& rerouteQueue) auto tmpPWire = std::make_unique(); tmpPWire->setLayerNum(pwire->getLayerNum()); Point origin = pwire->getOrigin(); - tmpPWire->setOrigin(origin); Rect box = pwire->getOffsetBox(); - tmpPWire->setOffsetBox(box); + // Find closest path point + Point closest; + frCoord closestDist = INT_MAX; + for (auto p : paths) { + Point pp; + gridGraph_.getPoint(pp, p.x(), p.y()); + frCoord pathLength = Point::squaredDistance(origin, pp); + if (pathLength < closestDist) { + closestDist = pathLength; + closest = pp; + } + } + tmpPWire->setOrigin(closest); + tmpPWire->setOffsetBox( + Rect(origin.getX() - closest.getX() + box.xMin(), + origin.getY() - closest.getY() + box.yMin(), + origin.getX() - closest.getX() + box.xMax(), + origin.getY() - closest.getY() + box.yMax())); tmpPWire->addToNet(net); pwire->addToNet(net); @@ -2995,7 +3012,7 @@ void FlexDRWorker::routeNet_prepAreaMap(drNet* net, } } -bool FlexDRWorker::routeNet(drNet* net) +bool FlexDRWorker::routeNet(drNet* net, std::vector& paths) { // ProfileTask profile("DR:routeNet"); @@ -3058,6 +3075,8 @@ bool FlexDRWorker::routeNet(drNet* net) routeNet_postAstarPatchMinAreaVio(net, path, areaMap); routeNet_AddCutSpcCost(path); isFirstConn = false; + // Add current pin path point to drNet paths + paths.insert(paths.end(), path.begin(), path.end()); } else { searchSuccess = false; logger_->report("Failed to find a path between pin " + nextPin->getName() diff --git a/src/drt/src/gc/FlexGC_main.cpp b/src/drt/src/gc/FlexGC_main.cpp index af571cab401..c7718e0d200 100644 --- a/src/drt/src/gc/FlexGC_main.cpp +++ b/src/drt/src/gc/FlexGC_main.cpp @@ -2158,25 +2158,25 @@ void FlexGCWorker::Impl::checkMetalShape_addPatch(gcPin* pin, int min_area) if (prefDirIsVert) { patchBx.set_xlo(-chosenEdg->length() / 2); patchBx.set_xhi(chosenEdg->length() / 2); - patchBx.set_yhi(length); offset.setX((chosenEdg->low().x() + chosenEdg->high().x()) / 2); + offset.setY(chosenEdg->low().y()); if (chosenEdg->getOuterDir() == frDirEnum::N) { - offset.setY(chosenEdg->low().y()); + patchBx.set_yhi(length); } else if (chosenEdg->getOuterDir() == frDirEnum::S) { - offset.setY(chosenEdg->low().y() - length); + patchBx.set_ylo(-length); } else { logger_->error( DRT, 4500, "Edge outer dir should be either North or South"); } } else { - patchBx.set_xhi(length); patchBx.set_ylo(-chosenEdg->length() / 2); patchBx.set_yhi(chosenEdg->length() / 2); + offset.setX(chosenEdg->low().x()); offset.setY((chosenEdg->low().y() + chosenEdg->high().y()) / 2); if (chosenEdg->getOuterDir() == frDirEnum::E) { - offset.setX(chosenEdg->low().x()); + patchBx.set_xhi(length); } else if (chosenEdg->getOuterDir() == frDirEnum::W) { - offset.setX(chosenEdg->low().x() - length); + patchBx.set_xlo(-length); } else { logger_->error(DRT, 4501, "Edge outer dir should be either East or West"); } @@ -2208,8 +2208,6 @@ void FlexGCWorker::Impl::checkMetalShape_addPatch(gcPin* pin, int min_area) return; } - Rect shiftedPatch = patchBx; - shiftedPatch.moveTo(offset.x(), offset.y()); pwires_.push_back(std::move(patch)); } diff --git a/src/grt/include/grt/GlobalRouter.h b/src/grt/include/grt/GlobalRouter.h index 0d9069a2317..40606b1350c 100644 --- a/src/grt/include/grt/GlobalRouter.h +++ b/src/grt/include/grt/GlobalRouter.h @@ -215,6 +215,7 @@ class GlobalRouter : public ant::GlobalRouteSource std::set getDirtyNets() { return dirty_nets_; } // check_antennas bool haveRoutes() override; + bool haveDetailedRoutes(); void makeNetWires() override; void destroyNetWires() override; @@ -387,6 +388,10 @@ class GlobalRouter : public ant::GlobalRouteSource void updateDirtyRoutes(bool save_guides = false); void mergeResults(NetRouteMap& routes); void updateDirtyNets(std::vector& dirty_nets); + void destroyNetWire(Net* net); + void removeWireUsage(odb::dbWire* wire); + void removeRectUsage(const odb::Rect& rect, odb::dbTechLayer* tech_layer); + bool isDetailedRouted(odb::dbNet* db_net); void updateDbCongestion(); // db functions diff --git a/src/grt/src/GlobalRouter.cpp b/src/grt/src/GlobalRouter.cpp index 5845d6979b1..7b427f14ddd 100644 --- a/src/grt/src/GlobalRouter.cpp +++ b/src/grt/src/GlobalRouter.cpp @@ -236,6 +236,16 @@ bool GlobalRouter::haveRoutes() return !routes_.empty(); } +bool GlobalRouter::haveDetailedRoutes() +{ + for (odb::dbNet* db_net : block_->getNets()) { + if (isDetailedRouted(db_net)) { + return true; + } + } + return false; +} + void GlobalRouter::globalRoute(bool save_guides, bool start_incremental, bool end_incremental) @@ -300,6 +310,11 @@ void GlobalRouter::repairAntennas(odb::dbMTerm* diode_mterm, int iterations, float ratio_margin) { + if (!initialized_) { + int min_layer, max_layer; + getMinMaxLayer(min_layer, max_layer); + initFastRoute(min_layer, max_layer); + } if (repair_antennas_ == nullptr) { repair_antennas_ = new RepairAntennas(this, antenna_checker_, opendp_, db_, logger_); @@ -540,6 +555,7 @@ void GlobalRouter::updateDirtyNets(std::vector& dirty_nets) makeItermPins(net, db_net, grid_->getGridArea()); makeBtermPins(net, db_net, grid_->getGridArea()); findPins(net); + destroyNetWire(net); // compare new positions with last positions & add on vector if (pinPositionsChanged(net, last_pos)) { dirty_nets.push_back(db_net_map_[db_net]); @@ -548,6 +564,80 @@ void GlobalRouter::updateDirtyNets(std::vector& dirty_nets) dirty_nets_.clear(); } +void GlobalRouter::destroyNetWire(Net* net) +{ + odb::dbWire* wire = net->getDbNet()->getWire(); + if (wire != nullptr) { + removeWireUsage(wire); + odb::dbWire::destroy(wire); + } + net->setHasWires(false); +} + +void GlobalRouter::removeWireUsage(odb::dbWire* wire) +{ + std::vector via_boxes; + + odb::dbWirePath path; + odb::dbWirePathShape pshape; + odb::dbWirePathItr pitr; + for (pitr.begin(wire); pitr.getNextPath(path);) { + while (pitr.getNextShape(pshape)) { + const odb::dbShape& shape = pshape.shape; + if (shape.isVia()) { + odb::dbShape::getViaBoxes(shape, via_boxes); + for (const odb::dbShape& box : via_boxes) { + odb::dbTechLayer* tech_layer = box.getTechLayer(); + if (tech_layer->getRoutingLevel() == 0) { + continue; + } + odb::Rect via_rect = box.getBox(); + removeRectUsage(via_rect, tech_layer); + } + } else { + odb::Rect wire_rect = shape.getBox(); + odb::dbTechLayer* tech_layer = shape.getTechLayer(); + removeRectUsage(wire_rect, tech_layer); + } + } + } +} + +void GlobalRouter::removeRectUsage(const odb::Rect& rect, + odb::dbTechLayer* tech_layer) +{ + bool vertical = tech_layer->getDirection() == odb::dbTechLayerDir::VERTICAL; + int layer_idx = tech_layer->getRoutingLevel(); + odb::Rect first_tile_box, last_tile_box; + odb::Point first_tile, last_tile; + + grid_->getBlockedTiles( + rect, first_tile_box, last_tile_box, first_tile, last_tile); + + if (vertical) { + for (int x = first_tile.getX(); x <= last_tile.getX(); x++) { + for (int y = first_tile.getY(); y < last_tile.getY(); y++) { + int cap = fastroute_->getEdgeCapacity(x, y, x, y + 1, layer_idx); + fastroute_->addAdjustment(x, y, x, y + 1, layer_idx, cap + 1, false); + } + } + } else { + for (int x = first_tile.getX(); x < last_tile.getX(); x++) { + for (int y = first_tile.getY(); y <= last_tile.getY(); y++) { + int cap = fastroute_->getEdgeCapacity(x, y, x, y + 1, layer_idx); + fastroute_->addAdjustment(x, y, x + 1, y, layer_idx, cap + 1, false); + } + } + } +} + +bool GlobalRouter::isDetailedRouted(odb::dbNet* db_net) +{ + return (!db_net->isSpecial() + && db_net->getWireType() == odb::dbWireType::ROUTED + && db_net->getWire()); +} + Rudy* GlobalRouter::getRudy() { if (rudy_ == nullptr) { @@ -1753,7 +1843,11 @@ void GlobalRouter::updateVias() void GlobalRouter::updateEdgesUsage() { - for (const auto& [net, groute] : routes_) { + for (const auto& [db_net, groute] : routes_) { + if (isDetailedRouted(db_net)) { + continue; + } + for (const GSegment& seg : groute) { int x0 = (seg.init_x - grid_->getXMin()) / grid_->getTileSize(); int y0 = (seg.init_y - grid_->getYMin()) / grid_->getTileSize(); diff --git a/src/grt/src/GlobalRouter.i b/src/grt/src/GlobalRouter.i index feda7fb9289..16b28f0bbfd 100644 --- a/src/grt/src/GlobalRouter.i +++ b/src/grt/src/GlobalRouter.i @@ -71,6 +71,12 @@ have_routes() return getGlobalRouter()->haveRoutes(); } +bool +have_detailed_routes() +{ + return getGlobalRouter()->haveDetailedRoutes(); +} + void set_capacity_adjustment(float adjustment) { diff --git a/src/grt/src/GlobalRouter.tcl b/src/grt/src/GlobalRouter.tcl index 6c1a7667abf..29d0d0689c4 100644 --- a/src/grt/src/GlobalRouter.tcl +++ b/src/grt/src/GlobalRouter.tcl @@ -308,7 +308,7 @@ sta::define_cmd_args "repair_antennas" { diode_cell \ proc repair_antennas { args } { sta::parse_key_args "repair_antennas" args \ keys {-iterations -ratio_margin} flags {} - if { [grt::have_routes] } { + if { [grt::have_routes] || [grt::have_detailed_routes] } { if { [llength $args] == 0 } { # repairAntennas locates diode set diode_mterm "NULL" diff --git a/src/grt/src/Net.h b/src/grt/src/Net.h index 1cecbca3607..b0ae8d45d9f 100644 --- a/src/grt/src/Net.h +++ b/src/grt/src/Net.h @@ -59,6 +59,7 @@ class Net bool isLocal(); void destroyPins(); bool hasWires() const { return has_wires_; } + void setHasWires(bool has_wires) { has_wires_ = has_wires; } bool hasStackedVias(odb::dbTechLayer* max_routing_layer); private: diff --git a/src/grt/src/RepairAntennas.cpp b/src/grt/src/RepairAntennas.cpp index d6d907e7407..9c94a994f93 100644 --- a/src/grt/src/RepairAntennas.cpp +++ b/src/grt/src/RepairAntennas.cpp @@ -65,6 +65,10 @@ RepairAntennas::RepairAntennas(GlobalRouter* grouter, illegal_diode_placement_count_(0) { block_ = db_->getChip()->getBlock(); + while (block_->findInst( + fmt::format("ANTENNA_{}", unique_diode_index_).c_str())) { + unique_diode_index_++; + } } bool RepairAntennas::checkAntennaViolations(NetRouteMap& routing, @@ -72,38 +76,77 @@ bool RepairAntennas::checkAntennaViolations(NetRouteMap& routing, odb::dbMTerm* diode_mterm, float ratio_margin) { + // safe copy net wires before orderWires calls + // TODO: remove this copy when antenna checker update is done + std::map, std::vector>> + copy_wires; + for (odb::dbNet* db_net : block_->getNets()) { + if (db_net->getWire() == nullptr) { + continue; + } + std::vector data; + std::vector op_codes; + db_net->getWire()->getRawWireData(data, op_codes); + copy_wires[db_net] = {data, op_codes}; + } + makeNetWires(routing, max_routing_layer); arc_->initAntennaRules(); - for (auto& [db_net, route] : routing) { - if (db_net->getWire()) { - std::vector net_violations - = arc_->getAntennaViolations(db_net, diode_mterm, ratio_margin); - if (!net_violations.empty()) { - antenna_violations_[db_net] = std::move(net_violations); - debugPrint(logger_, - GRT, - "repair_antennas", - 1, - "antenna violations {}", - db_net->getConstName()); - } + if (grouter_->haveDetailedRoutes()) { + for (odb::dbNet* db_net : block_->getNets()) { + checkNetViolations(db_net, diode_mterm, ratio_margin); + } + } else { + for (auto& [db_net, route] : routing) { + checkNetViolations(db_net, diode_mterm, ratio_margin); } } destroyNetWires(); + for (auto [net, val] : copy_wires) { + auto wire = odb::dbWire::create(net); + wire->setRawWireData(val.first, val.second); + } logger_->info( GRT, 12, "Found {} antenna violations.", antenna_violations_.size()); return !antenna_violations_.empty(); } +void RepairAntennas::checkNetViolations(odb::dbNet* db_net, + odb::dbMTerm* diode_mterm, + float ratio_margin) +{ + if (!db_net->isSpecial() && db_net->getWire()) { + std::vector net_violations + = arc_->getAntennaViolations(db_net, diode_mterm, ratio_margin); + if (!net_violations.empty()) { + antenna_violations_[db_net] = std::move(net_violations); + debugPrint(logger_, + GRT, + "repair_antennas", + 1, + "antenna violations {}", + db_net->getConstName()); + } + } +} + void RepairAntennas::makeNetWires(NetRouteMap& routing, int max_routing_layer) { std::map default_vias = grouter_->getDefaultVias(max_routing_layer); - for (auto& [db_net, route] : routing) { - if (!grouter_->getNet(db_net)->isLocal()) { - makeNetWire(db_net, route, default_vias); + if (grouter_->haveDetailedRoutes()) { + for (odb::dbNet* db_net : block_->getNets()) { + if (grouter_->isDetailedRouted(db_net)) { + odb::orderWires(logger_, db_net); + } + } + } else { + for (auto& [db_net, route] : routing) { + if (!grouter_->getNet(db_net)->isLocal()) { + makeNetWire(db_net, route, default_vias); + } } } } diff --git a/src/grt/src/RepairAntennas.h b/src/grt/src/RepairAntennas.h index d0670a08e35..b53d4d85eaf 100644 --- a/src/grt/src/RepairAntennas.h +++ b/src/grt/src/RepairAntennas.h @@ -95,6 +95,9 @@ class RepairAntennas int max_routing_layer, odb::dbMTerm* diode_mterm, float ratio_margin); + void checkNetViolations(odb::dbNet* db_net, + odb::dbMTerm* diode_mterm, + float ratio_margin); void repairAntennas(odb::dbMTerm* diode_mterm); int illegalDiodePlacementCount() const { diff --git a/src/gui/src/staGui.cpp b/src/gui/src/staGui.cpp index 9efabaf7e79..85f45c93d42 100644 --- a/src/gui/src/staGui.cpp +++ b/src/gui/src/staGui.cpp @@ -110,7 +110,7 @@ int TimingPathsModel::rowCount(const QModelIndex& parent) const int TimingPathsModel::columnCount(const QModelIndex& parent) const { - return 6; + return getColumnNames().size(); } QVariant TimingPathsModel::data(const QModelIndex& index, int role) const @@ -157,22 +157,7 @@ QVariant TimingPathsModel::headerData(int section, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { - switch (static_cast(section)) { - case Clock: - return "Capture Clock"; - case Required: - return "Required"; - case Arrival: - return "Arrival"; - case Slack: - return "Slack"; - case Skew: - return "Skew"; - case Start: - return "Start"; - case End: - return "End"; - } + return getColumnNames().at(static_cast(section)); } return QVariant(); } @@ -292,7 +277,7 @@ int TimingPathDetailModel::rowCount(const QModelIndex& parent) const int TimingPathDetailModel::columnCount(const QModelIndex& parent) const { - return 7; + return TimingPathsModel::getColumnNames().size(); } const TimingPathNode* TimingPathDetailModel::getNodeAt( diff --git a/src/gui/src/staGui.h b/src/gui/src/staGui.h index cfba06e252b..19937a843cf 100644 --- a/src/gui/src/staGui.h +++ b/src/gui/src/staGui.h @@ -70,7 +70,32 @@ class TimingPathsModel : public QAbstractTableModel { Q_OBJECT + private: + enum Column + { + Clock, + Required, + Arrival, + Slack, + Skew, + Start, + End + }; + public: + static const std::map& getColumnNames() + { + static const std::map columnNames + = {{Clock, "Capture Clock"}, + {Required, "Required"}, + {Arrival, "Arrival"}, + {Slack, "Slack"}, + {Skew, "Skew"}, + {Start, "Start"}, + {End, "End"}}; + return columnNames; + } + TimingPathsModel(bool is_setup, STAGuiInterface* sta, QObject* parent = nullptr); @@ -103,17 +128,6 @@ class TimingPathsModel : public QAbstractTableModel STAGuiInterface* sta_; bool is_setup_; std::vector> timing_paths_; - - enum Column - { - Clock, - Required, - Arrival, - Slack, - Skew, - Start, - End - }; }; class TimingPathDetailModel : public QAbstractTableModel diff --git a/src/odb/include/odb/db.h b/src/odb/include/odb/db.h index 32065892e0a..9d65001216e 100644 --- a/src/odb/include/odb/db.h +++ b/src/odb/include/odb/db.h @@ -3842,6 +3842,18 @@ class dbWire : public dbObject /// static void destroy(dbWire* wire); + /// + /// get raw data of _dbWire + /// + void getRawWireData(std::vector& data, + std::vector& op_codes); + + //// + /// set raw data of _dbWire + /// + void setRawWireData(const std::vector& data, + const std::vector& op_codes); + private: void addOneSeg(unsigned char op, int value, diff --git a/src/odb/src/db/dbWire.cpp b/src/odb/src/db/dbWire.cpp index 1454094ad00..f39880aebaa 100644 --- a/src/odb/src/db/dbWire.cpp +++ b/src/odb/src/db/dbWire.cpp @@ -1850,4 +1850,20 @@ void dbWire::destroy(dbWire* wire_) block->_wire_tbl->destroy(wire); } +void dbWire::getRawWireData(std::vector& data, + std::vector& op_codes) +{ + _dbWire* wire = (_dbWire*) this; + data = wire->_data; + op_codes = wire->_opcodes; +} + +void dbWire::setRawWireData(const std::vector& data, + const std::vector& op_codes) +{ + _dbWire* wire = (_dbWire*) this; + wire->_data = data; + wire->_opcodes = op_codes; +} + } // namespace odb