Skip to content

dpl: support LEF58_CELLEDGESPACINGTABLE #6595

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/dpl/include/dpl/Opendp.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ struct Cell;
struct Group;
struct Master;
struct Pixel;
struct EdgeSpacingEntry;

class DplObserver;
class Grid;
Expand Down Expand Up @@ -208,6 +209,11 @@ class Opendp
void makeMaster(Master* master, dbMaster* db_master);

void initGrid();

void makeCellEdgeSpacingTable();
bool hasCellEdgeSpacingTable() const;
int getMaxSpacing(int edge_idx) const;

std::string printBgBox(const boost::geometry::model::box<bgPoint>& queryBox);
void detailedPlacement();
DbuPt nearestPt(const Cell* cell, const DbuRect& rect) const;
Expand Down Expand Up @@ -240,6 +246,10 @@ class Opendp
GridY y,
GridX x_end,
GridY y_end) const;
bool checkEdgeSpacing(const Cell* cell,
GridX x,
GridY y,
const odb::dbOrientType& orient) const;
void shiftMove(Cell* cell);
bool mapMove(Cell* cell);
bool mapMove(Cell* cell, const GridPt& grid_pt);
Expand Down Expand Up @@ -300,7 +310,8 @@ class Opendp
const vector<Cell*>& one_site_gap_failures,
const vector<Cell*>& site_align_failures,
const vector<Cell*>& region_placement_failures,
const vector<Cell*>& placement_failures);
const vector<Cell*>& placement_failures,
const vector<Cell*>& edge_spacing_failures);
void writeJsonReport(const string& filename);

void rectDist(const Cell* cell,
Expand Down Expand Up @@ -389,6 +400,10 @@ class Opendp
std::unique_ptr<DplObserver> debug_observer_;
std::unique_ptr<Cell> dummy_cell_;

// LEF58_EDGETYPE
std::map<std::string, int> edge_types_indices_;
std::vector<std::vector<EdgeSpacingEntry>> edge_spacing_table_;

// Magic numbers
static constexpr int bin_search_width_ = 10;
static constexpr double group_refine_percent_ = .05;
Expand Down
27 changes: 23 additions & 4 deletions src/dpl/src/CheckPlacement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ void Opendp::checkPlacement(const bool verbose,
vector<Cell*> one_site_gap_failures;
vector<Cell*> site_align_failures;
vector<Cell*> region_placement_failures;
vector<Cell*> edge_spacing_failures;

initGrid();
groupAssignCellRegions();
Expand Down Expand Up @@ -91,6 +92,13 @@ void Opendp::checkPlacement(const bool verbose,
if (checkOverlap(cell)) {
overlap_failures.push_back(&cell);
}
// EdgeSpacing check
if (!checkEdgeSpacing(&cell,
grid_->gridX(&cell),
grid_->gridSnapDownY(&cell),
cell.orient_)) {
edge_spacing_failures.emplace_back(&cell);
}
}
// This loop is separate because it needs to be done after the overlap check
// The overlap check assigns the overlap cell to its pixel
Expand All @@ -111,7 +119,8 @@ void Opendp::checkPlacement(const bool verbose,
one_site_gap_failures,
site_align_failures,
region_placement_failures,
{});
{},
edge_spacing_failures);
if (!report_file_name.empty()) {
writeJsonReport(report_file_name);
}
Expand All @@ -124,6 +133,8 @@ void Opendp::checkPlacement(const bool verbose,
reportFailures(site_align_failures, 6, "Site aligned", verbose);
reportFailures(one_site_gap_failures, 7, "One site gap", verbose);
reportFailures(region_placement_failures, 8, "Region placement", verbose);
reportFailures(
edge_spacing_failures, 9, "LEF58_CELLEDGESPACINGTABLE", verbose);

logger_->metric("design__violations",
placed_failures.size() + in_rows_failures.size()
Expand All @@ -132,7 +143,7 @@ void Opendp::checkPlacement(const bool verbose,
if (placed_failures.size() + in_rows_failures.size() + overlap_failures.size()
+ site_align_failures.size()
+ (disallow_one_site_gaps ? one_site_gap_failures.size() : 0)
+ region_placement_failures.size()
+ region_placement_failures.size() + edge_spacing_failures.size()
> 0) {
logger_->error(DPL, 33, "detailed placement checks failed.");
}
Expand Down Expand Up @@ -191,12 +202,13 @@ void Opendp::saveFailures(const vector<Cell*>& placed_failures,
const vector<Cell*>& one_site_gap_failures,
const vector<Cell*>& site_align_failures,
const vector<Cell*>& region_placement_failures,
const vector<Cell*>& placement_failures)
const vector<Cell*>& placement_failures,
const vector<Cell*>& edge_spacing_failures)
{
if (placed_failures.empty() && in_rows_failures.empty()
&& overlap_failures.empty() && one_site_gap_failures.empty()
&& site_align_failures.empty() && region_placement_failures.empty()
&& placement_failures.empty()) {
&& placement_failures.empty() && edge_spacing_failures.empty()) {
return;
}

Expand Down Expand Up @@ -247,6 +259,13 @@ void Opendp::saveFailures(const vector<Cell*>& placed_failures,
category->setDescription("Cells that DPL failed to place.");
saveViolations(placement_failures, category);
}
if (!edge_spacing_failures.empty()) {
auto category = odb::dbMarkerCategory::createOrReplace(
tool_category, "Cell_edge_spacing_failures");
category->setDescription(
"Cells that violate the LEF58_CELLEDGESPACINGTABLE.");
saveViolations(edge_spacing_failures, category);
}
}

void Opendp::writeJsonReport(const string& filename)
Expand Down
16 changes: 16 additions & 0 deletions src/dpl/src/Grid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,22 @@ GridX Grid::gridPaddedWidth(const Cell* cell) const
return GridX{divCeil(padding_->paddedWidth(cell).v, getSiteWidth().v)};
}

GridY Grid::gridHeight(odb::dbMaster* master) const
{
Rect bbox;
master->getPlacementBoundary(bbox);
if (uniform_row_height_) {
DbuY row_height = uniform_row_height_.value();
return GridY{max(1, divCeil(bbox.dy(), row_height.v))};
}
auto site = master->getSite();
if (!site->hasRowPattern()) {
return GridY{1};
}

return GridY{static_cast<int>(site->getRowPattern().size())};
}

GridY Grid::gridHeight(const Cell* cell) const
{
if (uniform_row_height_) {
Expand Down
1 change: 1 addition & 0 deletions src/dpl/src/Grid.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class Grid

GridX gridPaddedWidth(const Cell* cell) const;
GridY gridHeight(const Cell* cell) const;
GridY gridHeight(odb::dbMaster* master) const;
DbuY rowHeight(GridY index);
void setGridPaddedLoc(Cell* cell, GridX x, GridY y) const;

Expand Down
32 changes: 32 additions & 0 deletions src/dpl/src/Objects.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,41 @@ namespace dpl {
using odb::dbOrientType;
using odb::dbSite;

struct Edge
{
Edge(unsigned int type, const odb::Rect& box)
: edge_type_idx_(type), bbox_(box)
{
}
const unsigned int getEdgeType() const { return edge_type_idx_; }
const odb::Rect& getBBox() const { return bbox_; }

private:
unsigned int edge_type_idx_;
odb::Rect bbox_;
};

struct EdgeSpacingEntry
{
EdgeSpacingEntry(const int spc_in,
const bool is_exact_in,
const bool except_abutted_in)
: spc(spc_in), is_exact(is_exact_in), except_abutted(except_abutted_in)
{
}
const bool operator<(const EdgeSpacingEntry& rhs) const
{
return spc < rhs.spc;
}
int spc;
bool is_exact;
bool except_abutted;
};

struct Master
{
bool is_multi_row = false;
std::vector<Edge> edges_;
};

struct Cell
Expand Down
2 changes: 1 addition & 1 deletion src/dpl/src/Opendp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ void Opendp::detailedPlacement(const int max_displacement_x,
logger_->info(DPL, 35, " {}", cell->name());
}

saveFailures({}, {}, {}, {}, {}, {}, placement_failures_);
saveFailures({}, {}, {}, {}, {}, {}, placement_failures_, {});
if (!report_file_name.empty()) {
writeJsonReport(report_file_name);
}
Expand Down
96 changes: 94 additions & 2 deletions src/dpl/src/Place.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "Objects.h"
#include "Padding.h"
#include "dpl/Opendp.h"
#include "odb/dbTransform.h"
#include "utl/Logger.h"

// #define ODP_DEBUG
Expand Down Expand Up @@ -932,6 +933,96 @@ bool Opendp::checkRegionOverlap(const Cell* cell,
// be fully contained by the cell's bounding box.
return result.empty();
}
namespace cell_edges {
Rect transformEdgeRect(const Rect& edge_rect,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't you just apply the instance transform directly to the edge?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because x and y are the instance location (lower left corner point of the instance bounding box) not the origin point. applying the inst transform directly is not correct.

const Cell* cell,
const DbuX x,
const DbuY y,
const odb::dbOrientType& orient)
{
Rect bbox;
cell->db_inst_->getMaster()->getPlacementBoundary(bbox);
odb::dbTransform transform(orient);
transform.apply(bbox);
Point offset(x.v - bbox.xMin(), y.v - bbox.yMin());
transform.setOffset(offset);
Rect result(edge_rect);
transform.apply(result);
return result;
}
Rect getQueryRect(const Rect& edge_box, const int spc)
{
Rect query_rect(edge_box);
bool is_vertical_edge = edge_box.getDir() == 0;
if (is_vertical_edge) {
// vertical edge
query_rect = query_rect.bloat(spc, odb::Orientation2D::Horizontal);
} else {
// horizontal edge
query_rect = query_rect.bloat(spc, odb::Orientation2D::Vertical);
}
return query_rect;
}
}; // namespace cell_edges
bool Opendp::checkEdgeSpacing(const Cell* cell,
const GridX x,
const GridY y,
const odb::dbOrientType& orient) const
{
if (!hasCellEdgeSpacingTable()) {
return true;
}
const auto& master = db_master_map_.at(cell->db_inst_->getMaster());
DbuX x_real = gridToDbu(x, grid_->getSiteWidth());
DbuY y_real = grid_->gridYToDbu(y);
for (const auto& edge1 : master.edges_) {
int max_spc = getMaxSpacing(edge1.getEdgeType());
Rect edge1_box = cell_edges::transformEdgeRect(
edge1.getBBox(), cell, x_real, y_real, orient);
bool is_vertical_edge = edge1_box.getDir() == 0;
Rect query_rect = cell_edges::getQueryRect(edge1_box, max_spc);
GridX xMin = grid_->gridX(DbuX(query_rect.xMin()));
GridX xMax = grid_->gridEndX(DbuX(query_rect.xMax()));
GridY yMin = grid_->gridEndY(DbuY(query_rect.yMin())) - 1;
GridY yMax = grid_->gridEndY(DbuY(query_rect.yMax()));
for (GridY y1 = yMin; y1 <= yMax; y1++) {
for (GridX x1 = xMin; x1 <= xMax; x1++) {
const Pixel* pixel = grid_->gridPixel(x1, y1);
if (pixel == nullptr || pixel->cell == nullptr || pixel->cell == cell) {
continue;
}
auto cell2 = pixel->cell;
auto master2 = db_master_map_.at(cell2->db_inst_->getMaster());
for (const auto& edge2 : master2.edges_) {
auto spc_entry
= edge_spacing_table_[edge1.getEdgeType()][edge2.getEdgeType()];
int spc = spc_entry.spc;
Rect edge2_box = cell_edges::transformEdgeRect(edge2.getBBox(),
pixel->cell,
pixel->cell->x_,
pixel->cell->y_,
pixel->cell->orient_);
if (edge1_box.getDir() != edge2_box.getDir()) {
continue;
}
if (!query_rect.overlaps(edge2_box)) {
continue;
}
Rect test_rect(edge1_box);
test_rect.merge(edge2_box);
int dist = is_vertical_edge ? test_rect.dx() : test_rect.dy();
if (spc_entry.is_exact && dist == spc) {
return false;
}
if (!spc_entry.is_exact && dist < spc) {
return false;
}
}
}
}
}
return true;
}

// Check all pixels are empty.
bool Opendp::checkPixels(const Cell* cell,
Expand Down Expand Up @@ -991,8 +1082,9 @@ bool Opendp::checkPixels(const Cell* cell,
}
}
}

return true;
const auto& orient = grid_->gridPixel(x, y)->sites.at(
cell->db_inst_->getMaster()->getSite());
return checkEdgeSpacing(cell, x, y, orient);
}

////////////////////////////////////////////////////////////////
Expand Down
Loading