aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2020-02-02 15:40:23 +0000
committerDavid Shah <dave@ds0.me>2020-02-12 10:41:27 +0000
commitd1f5cdcb93cb11c22e696e5885b5c4f576e47b28 (patch)
tree3258ab53aff59046b7c5fdd63432ab3bf943e398 /common
parent1ff060c5ad066b802db15fb4b8a2270073ec8cf5 (diff)
downloadnextpnr-d1f5cdcb93cb11c22e696e5885b5c4f576e47b28.tar.gz
nextpnr-d1f5cdcb93cb11c22e696e5885b5c4f576e47b28.tar.bz2
nextpnr-d1f5cdcb93cb11c22e696e5885b5c4f576e47b28.zip
HeAP: Improve handling of heterogeneous slice arches
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'common')
-rw-r--r--common/placer_heap.cc294
-rw-r--r--common/placer_heap.h5
2 files changed, 205 insertions, 94 deletions
diff --git a/common/placer_heap.cc b/common/placer_heap.cc
index 46b572c6..7d1f2033 100644
--- a/common/placer_heap.cc
+++ b/common/placer_heap.cc
@@ -190,6 +190,13 @@ class HeAPPlacer
break;
}
+ if (cfg.placeAllAtOnce) {
+ // Never want to deal with LUTs, FFs, MUXFxs seperately,
+ // for now disable all single-cell-type runs and only have heteregenous
+ // runs
+ heap_runs.clear();
+ }
+
heap_runs.push_back(all_celltypes);
// The main HeAP placer loop
log_info("Running main analytical placer.\n");
@@ -218,8 +225,14 @@ class HeAPPlacer
solved_hpwl = total_hpwl();
update_all_chains();
+
+ for (const auto &group : cfg.cellGroups)
+ CutSpreader(this, group).run();
+
for (auto type : sorted(run))
- CutSpreader(this, type).run();
+ if (std::all_of(cfg.cellGroups.begin(), cfg.cellGroups.end(),
+ [type](const std::unordered_set<IdString> &grp) { return !grp.count(type); }))
+ CutSpreader(this, {type}).run();
update_all_chains();
spread_hpwl = total_hpwl();
@@ -577,7 +590,9 @@ class HeAPPlacer
{
const auto &base = cell_locs[cell->name];
for (auto child : cell->constr_children) {
- chain_size[root->name]++;
+ // FIXME: Improve handling of heterogeneous chains
+ if (child->type == root->type)
+ chain_size[root->name]++;
if (child->constr_x != child->UNCONSTR)
cell_locs[child->name].x = std::min(max_x, base.x + child->constr_x);
else
@@ -1033,22 +1048,33 @@ class HeAPPlacer
{
int id;
int x0, y0, x1, y1;
- int cells, bels;
+ std::vector<int> cells, bels;
bool overused() const
{
- if (bels < 4)
- return cells > bels;
- else
- return cells > beta * bels;
+ for (size_t t = 0; t < cells.size(); t++) {
+ if (bels.at(t) < 4) {
+ if (cells.at(t) > bels.at(t))
+ return true;
+ } else {
+ if (cells.at(t) > beta * bels.at(t))
+ return true;
+ }
+ }
+ return false;
}
};
class CutSpreader
{
public:
- CutSpreader(HeAPPlacer *p, IdString beltype)
- : p(p), ctx(p->ctx), beltype(beltype), fb(p->fast_bels.at(std::get<0>(p->bel_types.at(beltype))))
+ CutSpreader(HeAPPlacer *p, const std::unordered_set<IdString> &beltype) : p(p), ctx(p->ctx), beltype(beltype)
{
+ int idx = 0;
+ for (IdString type : sorted(beltype)) {
+ type_index[type] = idx;
+ fb.emplace_back(&(p->fast_bels.at(std::get<0>(p->bel_types.at(type)))));
+ ++idx;
+ }
}
static int seq;
void run()
@@ -1076,8 +1102,11 @@ class HeAPPlacer
if (merged_regions.count(r.id))
continue;
#if 0
- log_info("%s (%d, %d) |_> (%d, %d) %d/%d\n", beltype.c_str(ctx), r.x0, r.y0, r.x1, r.y1, r.cells,
- r.bels);
+ for (auto t : sorted(beltype)) {
+ log_info("%s (%d, %d) |_> (%d, %d) %d/%d\n", t.c_str(ctx), r.x0, r.y0, r.x1, r.y1,
+ r.cells.at(type_index.at(t)), r.bels.at(type_index.at(t)));
+ }
+
#endif
workqueue.emplace(r.id, false);
// cut_region(r, false);
@@ -1086,7 +1115,7 @@ class HeAPPlacer
auto front = workqueue.front();
workqueue.pop();
auto &r = regions.at(front.first);
- if (r.cells == 0)
+ if (std::all_of(r.cells.begin(), r.cells.end(), [](int x) { return x == 0; }))
continue;
auto res = cut_region(r, front.second);
if (res) {
@@ -1128,37 +1157,41 @@ class HeAPPlacer
private:
HeAPPlacer *p;
Context *ctx;
- IdString beltype;
- std::vector<std::vector<int>> occupancy;
+ std::unordered_set<IdString> beltype;
+ std::unordered_map<IdString, int> type_index;
+ std::vector<std::vector<std::vector<int>>> occupancy;
std::vector<std::vector<int>> groups;
std::vector<std::vector<ChainExtent>> chaines;
std::map<IdString, ChainExtent> cell_extents;
- std::vector<std::vector<std::vector<BelId>>> &fb;
+ std::vector<std::vector<std::vector<std::vector<BelId>>> *> fb;
std::vector<SpreaderRegion> regions;
std::unordered_set<int> merged_regions;
// Cells at a location, sorted by real (not integer) x and y
std::vector<std::vector<std::vector<CellInfo *>>> cells_at_location;
- int occ_at(int x, int y) { return occupancy.at(x).at(y); }
+ int occ_at(int x, int y, int type) { return occupancy.at(x).at(y).at(type); }
- int bels_at(int x, int y)
+ int bels_at(int x, int y, int type)
{
- if (x >= int(fb.size()) || y >= int(fb.at(x).size()))
+ if (x >= int(fb.at(type)->size()) || y >= int(fb.at(type)->at(x).size()))
return 0;
- return int(fb.at(x).at(y).size());
+ return int(fb.at(type)->at(x).at(y).size());
}
void init()
{
- occupancy.resize(p->max_x + 1, std::vector<int>(p->max_y + 1, 0));
+ occupancy.resize(p->max_x + 1,
+ std::vector<std::vector<int>>(p->max_y + 1, std::vector<int>(beltype.size(), 0)));
groups.resize(p->max_x + 1, std::vector<int>(p->max_y + 1, -1));
chaines.resize(p->max_x + 1, std::vector<ChainExtent>(p->max_y + 1));
cells_at_location.resize(p->max_x + 1, std::vector<std::vector<CellInfo *>>(p->max_y + 1));
for (int x = 0; x <= p->max_x; x++)
for (int y = 0; y <= p->max_y; y++) {
- occupancy.at(x).at(y) = 0;
+ for (int t = 0; t < int(beltype.size()); t++) {
+ occupancy.at(x).at(y).at(t) = 0;
+ }
groups.at(x).at(y) = -1;
chaines.at(x).at(y) = {x, y, x, y};
}
@@ -1175,11 +1208,11 @@ class HeAPPlacer
};
for (auto &cell : p->cell_locs) {
- if (ctx->cells.at(cell.first)->type != beltype)
+ if (!beltype.count(ctx->cells.at(cell.first)->type))
continue;
if (ctx->cells.at(cell.first)->belStrength > STRENGTH_STRONG)
continue;
- occupancy.at(cell.second.x).at(cell.second.y)++;
+ occupancy.at(cell.second.x).at(cell.second.y).at(type_index.at(ctx->cells.at(cell.first)->type))++;
// Compute ultimate extent of each chain root
if (p->chain_root.count(cell.first)) {
set_chain_ext(p->chain_root.at(cell.first)->name, cell.second.x, cell.second.y);
@@ -1188,7 +1221,7 @@ class HeAPPlacer
}
}
for (auto &cell : p->cell_locs) {
- if (ctx->cells.at(cell.first)->type != beltype)
+ if (!beltype.count(ctx->cells.at(cell.first)->type))
continue;
// Transfer chain extents to the actual chaines structure
ChainExtent *ce = nullptr;
@@ -1205,7 +1238,7 @@ class HeAPPlacer
}
}
for (auto cell : p->solve_cells) {
- if (cell->type != beltype)
+ if (!beltype.count(cell->type))
continue;
cells_at_location.at(p->cell_locs.at(cell->name).x).at(p->cell_locs.at(cell->name).y).push_back(cell);
}
@@ -1218,8 +1251,10 @@ class HeAPPlacer
// log_info("%d %d\n", groups.at(x).at(y), mergee.id);
NPNR_ASSERT(groups.at(x).at(y) == mergee.id);
groups.at(x).at(y) = merged.id;
- merged.cells += occ_at(x, y);
- merged.bels += bels_at(x, y);
+ for (size_t t = 0; t < beltype.size(); t++) {
+ merged.cells.at(t) += occ_at(x, y, t);
+ merged.bels.at(t) += bels_at(x, y, t);
+ }
}
merged_regions.insert(mergee.id);
grow_region(merged, mergee.x0, mergee.y0, mergee.x1, mergee.y1);
@@ -1239,8 +1274,10 @@ class HeAPPlacer
auto process_location = [&](int x, int y) {
// Merge with any overlapping regions
if (groups.at(x).at(y) == -1) {
- r.bels += bels_at(x, y);
- r.cells += occ_at(x, y);
+ for (int t = 0; t < int(beltype.size()); t++) {
+ r.bels.at(t) += bels_at(x, y, t);
+ r.cells.at(t) += occ_at(x, y, t);
+ }
}
if (groups.at(x).at(y) != -1 && groups.at(x).at(y) != r.id)
merge_regions(r, regions.at(groups.at(x).at(y)));
@@ -1268,7 +1305,16 @@ class HeAPPlacer
for (int x = 0; x <= p->max_x; x++)
for (int y = 0; y <= p->max_y; y++) {
// Either already in a group, or not overutilised. Ignore
- if (groups.at(x).at(y) != -1 || (occ_at(x, y) <= bels_at(x, y)))
+ if (groups.at(x).at(y) != -1)
+ continue;
+ bool overutilised = false;
+ for (size_t t = 0; t < beltype.size(); t++) {
+ if (occ_at(x, y, t) > bels_at(x, y, t)) {
+ overutilised = true;
+ break;
+ }
+ }
+ if (!overutilised)
continue;
// log_info("%d %d %d\n", x, y, occ_at(x, y));
int id = int(regions.size());
@@ -1277,8 +1323,10 @@ class HeAPPlacer
reg.id = id;
reg.x0 = reg.x1 = x;
reg.y0 = reg.y1 = y;
- reg.bels = bels_at(x, y);
- reg.cells = occ_at(x, y);
+ for (size_t t = 0; t < beltype.size(); t++) {
+ reg.bels.push_back(bels_at(x, y, t));
+ reg.cells.push_back(occ_at(x, y, t));
+ }
// Make sure we cover carries, etc
grow_region(reg, reg.x0, reg.y0, reg.x1, reg.y1, true);
@@ -1292,11 +1340,13 @@ class HeAPPlacer
if (reg.x1 < p->max_x) {
bool over_occ_x = false;
for (int y1 = reg.y0; y1 <= reg.y1; y1++) {
- if (occ_at(reg.x1 + 1, y1) > bels_at(reg.x1 + 1, y1)) {
- // log_info("(%d, %d) occ %d bels %d\n", reg.x1+ 1, y1, occ_at(reg.x1 + 1, y1),
- // bels_at(reg.x1 + 1, y1));
- over_occ_x = true;
- break;
+ for (size_t t = 0; t < beltype.size(); t++) {
+ if (occ_at(reg.x1 + 1, y1, t) > bels_at(reg.x1 + 1, y1, t)) {
+ // log_info("(%d, %d) occ %d bels %d\n", reg.x1+ 1, y1, occ_at(reg.x1 + 1, y1),
+ // bels_at(reg.x1 + 1, y1));
+ over_occ_x = true;
+ break;
+ }
}
}
if (over_occ_x) {
@@ -1308,11 +1358,13 @@ class HeAPPlacer
if (reg.y1 < p->max_y) {
bool over_occ_y = false;
for (int x1 = reg.x0; x1 <= reg.x1; x1++) {
- if (occ_at(x1, reg.y1 + 1) > bels_at(x1, reg.y1 + 1)) {
- // log_info("(%d, %d) occ %d bels %d\n", x1, reg.y1 + 1, occ_at(x1, reg.y1 + 1),
- // bels_at(x1, reg.y1 + 1));
- over_occ_y = true;
- break;
+ for (size_t t = 0; t < beltype.size(); t++) {
+ if (occ_at(x1, reg.y1 + 1, t) > bels_at(x1, reg.y1 + 1, t)) {
+ // log_info("(%d, %d) occ %d bels %d\n", x1, reg.y1 + 1, occ_at(x1, reg.y1 + 1),
+ // bels_at(x1, reg.y1 + 1));
+ over_occ_y = true;
+ break;
+ }
}
}
if (over_occ_y) {
@@ -1340,17 +1392,20 @@ class HeAPPlacer
auto &reg = regions.at(rid);
while (reg.overused()) {
bool changed = false;
- if (reg.x0 > 0) {
- grow_region(reg, reg.x0 - 1, reg.y0, reg.x1, reg.y1);
- changed = true;
- if (!reg.overused())
- break;
- }
- if (reg.x1 < p->max_x) {
- grow_region(reg, reg.x0, reg.y0, reg.x1 + 1, reg.y1);
- changed = true;
- if (!reg.overused())
- break;
+ // 2 x units for every 1 y unit to account for INT gaps between CLBs
+ for (int j = 0; j < 2; j++) {
+ if (reg.x0 > 0) {
+ grow_region(reg, reg.x0 - 1, reg.y0, reg.x1, reg.y1);
+ changed = true;
+ if (!reg.overused())
+ break;
+ }
+ if (reg.x1 < p->max_x) {
+ grow_region(reg, reg.x0, reg.y0, reg.x1 + 1, reg.y1);
+ changed = true;
+ if (!reg.overused())
+ break;
+ }
}
if (reg.y0 > 0) {
grow_region(reg, reg.x0, reg.y0 - 1, reg.x1, reg.y1);
@@ -1365,11 +1420,12 @@ class HeAPPlacer
break;
}
if (!changed) {
- if (reg.cells > reg.bels)
- log_error("Failed to expand region (%d, %d) |_> (%d, %d) of %d %ss\n", reg.x0, reg.y0,
- reg.x1, reg.y1, reg.cells, beltype.c_str(ctx));
- else
- break;
+ for (auto bt : sorted(beltype)) {
+ if (reg.cells > reg.bels)
+ log_error("Failed to expand region (%d, %d) |_> (%d, %d) of %d %ss\n", reg.x0, reg.y0,
+ reg.x1, reg.y1, reg.cells.at(type_index.at(bt)), bt.c_str(ctx));
+ }
+ break;
}
}
}
@@ -1388,7 +1444,8 @@ class HeAPPlacer
for (int x = r.x0; x <= r.x1; x++) {
for (int y = r.y0; y <= r.y1; y++) {
std::copy(cal.at(x).at(y).begin(), cal.at(x).at(y).end(), std::back_inserter(cut_cells));
- total_bels += bels_at(x, y);
+ for (size_t t = 0; t < beltype.size(); t++)
+ total_bels += bels_at(x, y, t);
}
}
for (auto &cell : cut_cells) {
@@ -1410,9 +1467,11 @@ class HeAPPlacer
break;
pivot++;
}
- if (pivot == int(cut_cells.size()))
+ if (pivot >= int(cut_cells.size())) {
pivot = int(cut_cells.size()) - 1;
- // log_info("orig pivot %d lc %d rc %d\n", pivot, pivot_cells, r.cells - pivot_cells);
+ }
+ // log_info("orig pivot %d/%d lc %d rc %d\n", pivot, int(cut_cells.size()), pivot_cells, total_cells -
+ // pivot_cells);
// Find the clearance required either side of the pivot
int clearance_l = 0, clearance_r = 0;
@@ -1438,10 +1497,11 @@ class HeAPPlacer
while (trimmed_l < (dir ? r.y1 : r.x1)) {
bool have_bels = false;
for (int i = dir ? r.x0 : r.y0; i <= (dir ? r.x1 : r.y1); i++)
- if (bels_at(dir ? i : trimmed_l, dir ? trimmed_l : i) > 0) {
- have_bels = true;
- break;
- }
+ for (size_t t = 0; t < beltype.size(); t++)
+ if (bels_at(dir ? i : trimmed_l, dir ? trimmed_l : i, t) > 0) {
+ have_bels = true;
+ break;
+ }
if (have_bels)
break;
trimmed_l++;
@@ -1449,10 +1509,11 @@ class HeAPPlacer
while (trimmed_r > (dir ? r.y0 : r.x0)) {
bool have_bels = false;
for (int i = dir ? r.x0 : r.y0; i <= (dir ? r.x1 : r.y1); i++)
- if (bels_at(dir ? i : trimmed_r, dir ? trimmed_r : i) > 0) {
- have_bels = true;
- break;
- }
+ for (size_t t = 0; t < beltype.size(); t++)
+ if (bels_at(dir ? i : trimmed_r, dir ? trimmed_r : i, t) > 0) {
+ have_bels = true;
+ break;
+ }
if (have_bels)
break;
trimmed_r--;
@@ -1462,50 +1523,94 @@ class HeAPPlacer
return {};
// Now find the initial target cut that minimises utilisation imbalance, whilst
// meeting the clearance requirements for any large macros
- int left_cells = pivot_cells, right_cells = total_cells - pivot_cells;
- int left_bels = 0, right_bels = total_bels;
+ std::vector<int> left_cells_v(beltype.size(), 0), right_cells_v(beltype.size(), 0);
+ std::vector<int> left_bels_v(beltype.size(), 0), right_bels_v(r.bels);
+ for (int i = 0; i <= pivot; i++)
+ left_cells_v.at(type_index.at(cut_cells.at(i)->type)) +=
+ p->chain_size.count(cut_cells.at(i)->name) ? p->chain_size.at(cut_cells.at(i)->name) : 1;
+ for (int i = pivot + 1; i < int(cut_cells.size()); i++)
+ right_cells_v.at(type_index.at(cut_cells.at(i)->type)) +=
+ p->chain_size.count(cut_cells.at(i)->name) ? p->chain_size.at(cut_cells.at(i)->name) : 1;
+
int best_tgt_cut = -1;
double best_deltaU = std::numeric_limits<double>::max();
- std::pair<int, int> target_cut_bels;
+ // std::pair<int, int> target_cut_bels;
+ std::vector<int> slither_bels(beltype.size(), 0);
for (int i = trimmed_l; i <= trimmed_r; i++) {
- int slither_bels = 0;
+ for (size_t t = 0; t < beltype.size(); t++)
+ slither_bels.at(t) = 0;
for (int j = dir ? r.x0 : r.y0; j <= (dir ? r.x1 : r.y1); j++) {
- slither_bels += dir ? bels_at(j, i) : bels_at(i, j);
+ for (size_t t = 0; t < beltype.size(); t++)
+ slither_bels.at(t) += dir ? bels_at(j, i, t) : bels_at(i, j, t);
}
- left_bels += slither_bels;
- right_bels -= slither_bels;
+ for (size_t t = 0; t < beltype.size(); t++) {
+ left_bels_v.at(t) += slither_bels.at(t);
+ right_bels_v.at(t) -= slither_bels.at(t);
+ }
+
if (((i - trimmed_l) + 1) >= clearance_l && ((trimmed_r - i) + 1) >= clearance_r) {
// Solution is potentially valid
- double aU =
- std::abs(double(left_cells) / double(left_bels) - double(right_cells) / double(right_bels));
+ double aU = 0;
+ for (size_t t = 0; t < beltype.size(); t++)
+ aU += (left_cells_v.at(t) + right_cells_v.at(t)) *
+ std::abs(double(left_cells_v.at(t)) / double(std::max(left_bels_v.at(t), 1)) -
+ double(right_cells_v.at(t)) / double(std::max(right_bels_v.at(t), 1)));
if (aU < best_deltaU) {
best_deltaU = aU;
best_tgt_cut = i;
- target_cut_bels = std::make_pair(left_bels, right_bels);
}
}
}
if (best_tgt_cut == -1)
return {};
- left_bels = target_cut_bels.first;
- right_bels = target_cut_bels.second;
- // log_info("pivot %d target cut %d lc %d lb %d rc %d rb %d\n", pivot, best_tgt_cut, left_cells, left_bels,
- // right_cells, right_bels);
+ // left_bels = target_cut_bels.first;
+ // right_bels = target_cut_bels.second;
+ for (size_t t = 0; t < beltype.size(); t++) {
+ left_bels_v.at(t) = 0;
+ right_bels_v.at(t) = 0;
+ }
+ for (int x = r.x0; x <= (dir ? r.x1 : best_tgt_cut); x++)
+ for (int y = r.y0; y <= (dir ? best_tgt_cut : r.y1); y++) {
+ for (size_t t = 0; t < beltype.size(); t++) {
+ left_bels_v.at(t) += bels_at(x, y, t);
+ }
+ }
+ for (int x = dir ? r.x0 : (best_tgt_cut + 1); x <= r.x1; x++)
+ for (int y = dir ? (best_tgt_cut + 1) : r.y0; y <= r.y1; y++) {
+ for (size_t t = 0; t < beltype.size(); t++) {
+ right_bels_v.at(t) += bels_at(x, y, t);
+ }
+ }
+ if (std::accumulate(left_bels_v.begin(), left_bels_v.end(), 0) == 0 ||
+ std::accumulate(right_bels_v.begin(), right_bels_v.end(), 0) == 0)
+ return {};
+ // log_info("pivot %d target cut %d lc %d lb %d rc %d rb %d\n", pivot, best_tgt_cut,
+ // std::accumulate(left_cells_v.begin(), left_cells_v.end(), 0), std::accumulate(left_bels_v.begin(),
+ // left_bels_v.end(), 0),
+ // std::accumulate(right_cells_v.begin(), right_cells_v.end(), 0),
+ // std::accumulate(right_bels_v.begin(), right_bels_v.end(), 0));
// Peturb the source cut to eliminate overutilisation
- while (pivot > 0 && (double(left_cells) / double(left_bels) > double(right_cells) / double(right_bels))) {
+ auto is_part_overutil = [&](bool r) {
+ double delta = 0;
+ for (size_t t = 0; t < left_cells_v.size(); t++) {
+ delta += double(left_cells_v.at(t)) / double(std::max(left_bels_v.at(t), 1)) -
+ double(right_cells_v.at(t)) / double(std::max(right_bels_v.at(t), 1));
+ }
+ return r ? delta < 0 : delta > 0;
+ };
+ while (pivot > 0 && is_part_overutil(false)) {
auto &move_cell = cut_cells.at(pivot);
int size = p->chain_size.count(move_cell->name) ? p->chain_size.at(move_cell->name) : 1;
- left_cells -= size;
- right_cells += size;
+ left_cells_v.at(type_index.at(cut_cells.at(pivot)->type)) -= size;
+ right_cells_v.at(type_index.at(cut_cells.at(pivot)->type)) += size;
pivot--;
}
- while (pivot < int(cut_cells.size()) - 1 &&
- (double(left_cells) / double(left_bels) < double(right_cells) / double(right_bels))) {
+ while (pivot < int(cut_cells.size()) - 1 && is_part_overutil(true)) {
auto &move_cell = cut_cells.at(pivot + 1);
int size = p->chain_size.count(move_cell->name) ? p->chain_size.at(move_cell->name) : 1;
- left_cells += size;
- right_cells -= size;
+ left_cells_v.at(type_index.at(cut_cells.at(pivot)->type)) += size;
+ right_cells_v.at(type_index.at(cut_cells.at(pivot)->type)) -= size;
pivot++;
}
// log_info("peturbed pivot %d lc %d lb %d rc %d rb %d\n", pivot, left_cells, left_bels, right_cells,
@@ -1577,15 +1682,15 @@ class HeAPPlacer
rl.y0 = r.y0;
rl.x1 = dir ? r.x1 : best_tgt_cut;
rl.y1 = dir ? best_tgt_cut : r.y1;
- rl.cells = left_cells;
- rl.bels = left_bels;
+ rl.cells = left_cells_v;
+ rl.bels = left_bels_v;
rr.id = int(regions.size()) + 1;
rr.x0 = dir ? r.x0 : (best_tgt_cut + 1);
rr.y0 = dir ? (best_tgt_cut + 1) : r.y0;
rr.x1 = r.x1;
rr.y1 = r.y1;
- rr.cells = right_cells;
- rr.bels = right_bels;
+ rr.cells = right_cells_v;
+ rr.bels = right_bels_v;
regions.push_back(rl);
regions.push_back(rr);
for (int x = rl.x0; x <= rl.x1; x++)
@@ -1611,6 +1716,7 @@ PlacerHeapCfg::PlacerHeapCfg(Context *ctx)
timingWeight = ctx->setting<int>("placerHeap/timingWeight", 10);
timing_driven = ctx->setting<bool>("timing_driven");
solverTolerance = 1e-5;
+ placeAllAtOnce = false;
}
NEXTPNR_NAMESPACE_END
diff --git a/common/placer_heap.h b/common/placer_heap.h
index 94ac5229..4bcf71e8 100644
--- a/common/placer_heap.h
+++ b/common/placer_heap.h
@@ -40,8 +40,13 @@ struct PlacerHeapCfg
float timingWeight;
bool timing_driven;
float solverTolerance;
+ bool placeAllAtOnce;
+ // These cell types will be randomly locked to prevent singular matrices
std::unordered_set<IdString> ioBufTypes;
+ // These cell types are part of the same unit (e.g. slices split into
+ // components) so will always be spread together
+ std::vector<std::unordered_set<IdString>> cellGroups;
};
extern bool placer_heap(Context *ctx, PlacerHeapCfg cfg);