Skip to content

Commit a8452f3

Browse files
authored
Merge pull request #8795 from gadfort/pad-check-better
pad: expand place instance checks and add ability to shift cells during automatic placement
2 parents c8c1a2e + c9fe2ba commit a8452f3

12 files changed

+2966
-88
lines changed

src/pad/include/pad/ICeWall.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <cstdint>
77
#include <map>
88
#include <memory>
9+
#include <optional>
910
#include <set>
1011
#include <string>
1112
#include <utility>
@@ -110,7 +111,8 @@ class ICeWall
110111
int index,
111112
odb::dbInst* inst,
112113
const odb::dbOrientType& base_orient,
113-
bool allow_overlap = false) const;
114+
bool allow_overlap = false,
115+
bool allow_shift = false) const;
114116

115117
void makeBTerm(odb::dbNet* net,
116118
odb::dbTechLayer* layer,
@@ -160,6 +162,9 @@ class ICeWall
160162
odb::dbInst* inst,
161163
const std::map<odb::dbInst*, std::set<odb::dbITerm*>>&
162164
iterm_connections) const;
165+
std::optional<std::pair<odb::dbInst*, odb::Rect>> checkInstancePlacement(
166+
odb::dbInst* inst,
167+
odb::dbRow* row) const;
163168

164169
// Data members
165170
odb::dbDatabase* db_ = nullptr;

src/pad/src/ICeWall.cpp

Lines changed: 161 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <limits>
1212
#include <map>
1313
#include <memory>
14+
#include <optional>
1415
#include <set>
1516
#include <utility>
1617
#include <vector>
@@ -520,7 +521,6 @@ void ICeWall::placeCorner(odb::dbMaster* master, int ring_index)
520521

521522
// Check for instances overlapping the corner site
522523
bool place_inst = true;
523-
std::set<odb::dbInst*> covers;
524524
for (auto* check_inst : block->getInsts()) {
525525
if (check_inst == inst) {
526526
continue;
@@ -529,7 +529,6 @@ void ICeWall::placeCorner(odb::dbMaster* master, int ring_index)
529529
continue;
530530
}
531531
if (check_inst->getMaster()->isCover()) {
532-
covers.insert(check_inst);
533532
continue;
534533
}
535534
const odb::Rect check_rect = check_inst->getBBox()->getBox();
@@ -556,58 +555,7 @@ void ICeWall::placeCorner(odb::dbMaster* master, int ring_index)
556555
inst->setLocation(row_bbox.xMin(), row_bbox.yMin());
557556
inst->setPlacementStatus(odb::dbPlacementStatus::FIRM);
558557

559-
// Check if inst overlaps with bumps
560-
std::map<odb::dbTechLayer*, std::set<odb::Rect>> check_shapes;
561-
if (!covers.empty()) {
562-
// populate map as needed
563-
const auto xform = inst->getTransform();
564-
for (auto* obs : inst->getMaster()->getObstructions()) {
565-
odb::Rect obs_rect = obs->getBox();
566-
xform.apply(obs_rect);
567-
check_shapes[obs->getTechLayer()].insert(obs_rect);
568-
}
569-
for (auto* iterm : inst->getITerms()) {
570-
for (const auto& [layer, box] : iterm->getGeometries()) {
571-
check_shapes[layer].insert(box);
572-
}
573-
}
574-
}
575-
576-
bool remove = false;
577-
for (auto* check_inst : covers) {
578-
const auto xform = check_inst->getTransform();
579-
for (auto* obs : check_inst->getMaster()->getObstructions()) {
580-
odb::Rect obs_rect = obs->getBox();
581-
xform.apply(obs_rect);
582-
for (const auto& inst_rect : check_shapes[obs->getTechLayer()]) {
583-
if (inst_rect.intersects(obs_rect)) {
584-
remove = true;
585-
break;
586-
}
587-
}
588-
}
589-
if (remove) {
590-
break;
591-
}
592-
for (auto* iterm : check_inst->getITerms()) {
593-
for (const auto& [layer, box] : iterm->getGeometries()) {
594-
for (const auto& inst_rect : check_shapes[layer]) {
595-
if (inst_rect.intersects(box)) {
596-
remove = true;
597-
break;
598-
}
599-
}
600-
}
601-
if (remove) {
602-
break;
603-
}
604-
}
605-
if (remove) {
606-
break;
607-
}
608-
}
609-
610-
if (remove) {
558+
if (checkInstancePlacement(inst, row)) {
611559
if (create_inst) {
612560
logger_->warn(utl::PAD,
613561
45,
@@ -1034,7 +982,9 @@ void ICeWall::placePadsBumpAligned(
1034982
offset += placeInstance(row,
1035983
snapToRowSite(row, select_pos),
1036984
ginst,
1037-
odb::dbOrientType::R0)
985+
odb::dbOrientType::R0,
986+
/* allow_overlap */ false,
987+
/* allow_shift */ true)
1038988
* row->getSpacing();
1039989

1040990
performPadFlip(row, ginst, iterm_connections);
@@ -1064,7 +1014,12 @@ void ICeWall::placePadsUniform(const std::vector<odb::dbInst*>& insts,
10641014
inst->getName(),
10651015
offset / dbus);
10661016

1067-
placeInstance(row, snapToRowSite(row, offset), inst, odb::dbOrientType::R0);
1017+
placeInstance(row,
1018+
snapToRowSite(row, offset),
1019+
inst,
1020+
odb::dbOrientType::R0,
1021+
/* allow_overlap */ false,
1022+
/* allow_shift */ true);
10681023
offset += inst_widths.at(inst);
10691024
offset += target_spacing;
10701025
}
@@ -1124,7 +1079,8 @@ int ICeWall::placeInstance(odb::dbRow* row,
11241079
int index,
11251080
odb::dbInst* inst,
11261081
const odb::dbOrientType& base_orient,
1127-
bool allow_overlap) const
1082+
bool allow_overlap,
1083+
bool allow_shift) const
11281084
{
11291085
const int origin_offset = index * row->getSpacing();
11301086

@@ -1202,38 +1158,65 @@ int ICeWall::placeInstance(odb::dbRow* row,
12021158
row_bbox.yMax() / dbus);
12031159
}
12041160

1205-
// check for overlaps with other instances
1206-
for (auto* check_inst : block->getInsts()) {
1207-
if (check_inst == inst) {
1208-
continue;
1209-
}
1210-
if (!check_inst->isFixed()) {
1211-
continue;
1212-
}
1213-
if (check_inst->getMaster()->isCover()) {
1214-
continue;
1161+
const auto check_obs = checkInstancePlacement(inst, row);
1162+
if (allow_shift && check_obs) {
1163+
const auto& [check_inst, check_rect] = *check_obs;
1164+
1165+
int obs_index = index;
1166+
switch (row_edge) {
1167+
case odb::Direction2D::North:
1168+
case odb::Direction2D::South:
1169+
obs_index = snapToRowSite(row, check_rect.xMin());
1170+
break;
1171+
case odb::Direction2D::West:
1172+
case odb::Direction2D::East:
1173+
obs_index = snapToRowSite(row, check_rect.yMin());
1174+
break;
12151175
}
1216-
const odb::Rect check_rect = check_inst->getBBox()->getBox();
1217-
if (!allow_overlap && inst_rect.overlaps(check_rect)) {
1218-
logger_->error(utl::PAD,
1219-
1,
1220-
"Unable to place {} ({}) at ({:.3f}um, {:.3f}um) - "
1221-
"({:.3f}um, {:.3f}um) as it "
1222-
"overlaps with {} ({}) at ({:.3f}um, {:.3f}um) - "
1223-
"({:.3f}um, {:.3f}um)",
1224-
inst->getName(),
1225-
inst->getMaster()->getName(),
1226-
inst_rect.xMin() / dbus,
1227-
inst_rect.yMin() / dbus,
1228-
inst_rect.xMax() / dbus,
1229-
inst_rect.yMax() / dbus,
1230-
check_inst->getName(),
1231-
check_inst->getMaster()->getName(),
1232-
check_rect.xMin() / dbus,
1233-
check_rect.yMin() / dbus,
1234-
check_rect.xMax() / dbus,
1235-
check_rect.yMax() / dbus);
1176+
1177+
int next_index = std::max(index + 1, obs_index);
1178+
1179+
debugPrint(logger_,
1180+
utl::PAD,
1181+
"Place",
1182+
2,
1183+
"Shift required for {} to avoid {} ({} -> {})",
1184+
inst->getName(),
1185+
check_inst ? check_inst->getName() : "blockage",
1186+
index,
1187+
next_index);
1188+
1189+
return placeInstance(
1190+
row, next_index, inst, base_orient, allow_overlap, allow_shift);
1191+
}
1192+
if (!allow_overlap && check_obs) {
1193+
const auto& [check_inst, obs_rect] = *check_obs;
1194+
odb::Rect check_rect;
1195+
if (check_inst == nullptr) {
1196+
check_rect = obs_rect;
1197+
} else {
1198+
check_rect = check_inst->getBBox()->getBox();
12361199
}
1200+
logger_->error(utl::PAD,
1201+
1,
1202+
"Unable to place {} ({}) at ({:.3f}um, {:.3f}um) - "
1203+
"({:.3f}um, {:.3f}um) as it "
1204+
"overlaps with {} at ({:.3f}um, {:.3f}um) - "
1205+
"({:.3f}um, {:.3f}um)",
1206+
inst->getName(),
1207+
inst->getMaster()->getName(),
1208+
inst_rect.xMin() / dbus,
1209+
inst_rect.yMin() / dbus,
1210+
inst_rect.xMax() / dbus,
1211+
inst_rect.yMax() / dbus,
1212+
check_inst ? fmt::format("{} ({})",
1213+
check_inst->getName(),
1214+
check_inst->getMaster()->getName())
1215+
: "blockage",
1216+
check_rect.xMin() / dbus,
1217+
check_rect.yMin() / dbus,
1218+
check_rect.xMax() / dbus,
1219+
check_rect.yMax() / dbus);
12371220
}
12381221
inst->setPlacementStatus(odb::dbPlacementStatus::FIRM);
12391222

@@ -1973,4 +1956,95 @@ void ICeWall::routeRDLDebugNet(const char* net)
19731956
}
19741957
}
19751958

1959+
std::optional<std::pair<odb::dbInst*, odb::Rect>>
1960+
ICeWall::checkInstancePlacement(odb::dbInst* inst, odb::dbRow* row) const
1961+
{
1962+
std::set<odb::dbInst*> covers;
1963+
auto* block = getBlock();
1964+
if (block) {
1965+
const odb::Rect inst_rect = inst->getBBox()->getBox();
1966+
for (odb::dbBlockage* blockage : block->getBlockages()) {
1967+
if (blockage->getBBox()->getBox().overlaps(inst_rect)) {
1968+
return std::make_pair(
1969+
nullptr, blockage->getBBox()->getBox().intersect(inst_rect));
1970+
}
1971+
}
1972+
for (auto* check_inst : block->getInsts()) {
1973+
if (check_inst == inst) {
1974+
continue;
1975+
}
1976+
if (!check_inst->isFixed()) {
1977+
continue;
1978+
}
1979+
if (check_inst->getMaster()->isCover()) {
1980+
covers.insert(check_inst);
1981+
continue;
1982+
}
1983+
if (check_inst->getBBox()->getBox().overlaps(inst_rect)) {
1984+
return std::make_pair(
1985+
check_inst, check_inst->getBBox()->getBox().intersect(inst_rect));
1986+
}
1987+
}
1988+
}
1989+
1990+
// Check if inst overlaps with bumps
1991+
std::map<odb::dbTechLayer*, std::set<std::pair<odb::Rect, odb::dbNet*>>>
1992+
check_shapes;
1993+
if (!covers.empty()) {
1994+
// populate map as needed
1995+
const auto xform = inst->getTransform();
1996+
for (auto* obs : inst->getMaster()->getObstructions()) {
1997+
odb::Rect obs_rect = obs->getBox();
1998+
xform.apply(obs_rect);
1999+
odb::dbTechLayer* layer = obs->getTechLayer();
2000+
if (layer != nullptr) {
2001+
odb::Rect bloat;
2002+
obs_rect.bloat(layer->getSpacing(), bloat);
2003+
obs_rect = bloat;
2004+
}
2005+
check_shapes[obs->getTechLayer()].emplace(obs_rect, nullptr);
2006+
}
2007+
for (auto* iterm : inst->getITerms()) {
2008+
for (const auto& [layer, box] : iterm->getGeometries()) {
2009+
odb::Rect term_rect = box;
2010+
if (layer != nullptr) {
2011+
odb::Rect bloat;
2012+
box.bloat(layer->getSpacing(), bloat);
2013+
term_rect = bloat;
2014+
}
2015+
check_shapes[layer].emplace(term_rect, iterm->getNet());
2016+
}
2017+
}
2018+
}
2019+
2020+
for (odb::dbInst* check_inst : covers) {
2021+
const auto xform = check_inst->getTransform();
2022+
for (auto* obs : check_inst->getMaster()->getObstructions()) {
2023+
odb::Rect obs_rect = obs->getBox();
2024+
xform.apply(obs_rect);
2025+
for (const auto& [inst_rect, check_net] :
2026+
check_shapes[obs->getTechLayer()]) {
2027+
if (inst_rect.intersects(obs_rect)) {
2028+
return std::make_pair(check_inst, inst_rect.intersect(obs_rect));
2029+
}
2030+
}
2031+
}
2032+
2033+
for (auto* iterm : check_inst->getITerms()) {
2034+
for (const auto& [layer, box] : iterm->getGeometries()) {
2035+
for (const auto& [inst_rect, check_net] : check_shapes[layer]) {
2036+
const bool nets_match
2037+
= iterm->getNet() == check_net
2038+
&& (check_net != nullptr || iterm->getNet() != nullptr);
2039+
if (!nets_match && inst_rect.intersects(box)) {
2040+
return std::make_pair(check_inst, inst_rect.intersect(box));
2041+
}
2042+
}
2043+
}
2044+
}
2045+
}
2046+
2047+
return {};
2048+
}
2049+
19762050
} // namespace pad

src/pad/test/BUILD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ COMPULSORY_TESTS = [
2929
"place_pad_hv",
3030
"place_pad_no_master",
3131
"place_pad_outsideofrow",
32+
"place_pad_overblockage",
3233
"place_pad_with_bumps",
3334
"place_pad_wrong_master",
3435
"place_pads_bumps",
36+
"place_pads_bumps_bump_overlap",
3537
"place_pads_too_many",
3638
"place_pads_uniform",
39+
"place_pads_uniform_slip",
3740
"rdl_route",
3841
"rdl_route_45",
3942
"rdl_route_45_cost",

src/pad/test/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@ or_integration_tests(
2424
place_pad_hv
2525
place_pad_no_master
2626
place_pad_outsideofrow
27+
place_pad_overblockage
2728
place_pad_with_bumps
29+
place_pads_bumps_bump_overlap
2830
place_pad_wrong_master
2931
place_pads_bumps
3032
place_pads_too_many
3133
place_pads_uniform
34+
place_pads_uniform_slip
3235
rdl_route
3336
rdl_route_45
3437
rdl_route_45_cost
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[INFO ODB-0227] LEF file: Nangate45/Nangate45.lef, created 22 layers, 27 vias, 135 library cells
2+
[INFO ODB-0227] LEF file: Nangate45_io/dummy_pads.lef, created 29 library cells
3+
[INFO ODB-0128] Design: soc_bsg_black_parrot
4+
[INFO ODB-0130] Created 135 pins.
5+
[INFO ODB-0131] Created 267 components and 2277 component-terminals.
6+
[INFO ODB-0133] Created 350 nets and 390 connections.
7+
[ERROR PAD-0001] Unable to place IO_SOUTH_SIDE (PADCELL_SIG_H) at (2800.000um, 15.000um) - (2825.000um, 155.000um) as it overlaps with blockage at (2800.000um, 15.000um) - (2825.000um, 20.000um)
8+
PAD-0001
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Test for placing pads over placement blockages
2+
source "helpers.tcl"
3+
4+
# Init chip
5+
read_lef Nangate45/Nangate45.lef
6+
read_lef Nangate45_io/dummy_pads.lef
7+
8+
read_def Nangate45_blackparrot/floorplan.def
9+
10+
odb::dbBlockage_create [ord::get_db_block] \
11+
[ord::microns_to_dbu 2800] [ord::microns_to_dbu 10] \
12+
[ord::microns_to_dbu 2900] [ord::microns_to_dbu 20]
13+
14+
# Test place_pad
15+
make_io_sites -horizontal_site IOSITE -vertical_site IOSITE -corner_site IOSITE -offset 15
16+
17+
catch { place_pad -master PADCELL_SIG_H -row IO_SOUTH -location 2800 "IO_SOUTH_SIDE" } err
18+
puts $err

0 commit comments

Comments
 (0)