aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/placer1.cc148
-rw-r--r--common/timing.cc21
2 files changed, 113 insertions, 56 deletions
diff --git a/common/placer1.cc b/common/placer1.cc
index ee12f7f4..efa8a674 100644
--- a/common/placer1.cc
+++ b/common/placer1.cc
@@ -119,6 +119,12 @@ class SAPlacer
region_bounds[r->name] = bb;
}
build_port_index();
+ for (auto &cell : ctx->cells) {
+ CellInfo *ci = cell.second.get();
+ if (ci->cluster == ClusterId())
+ continue;
+ cluster2cell[ci->cluster].push_back(ci);
+ }
}
~SAPlacer()
@@ -616,56 +622,95 @@ class SAPlacer
bool try_swap_chain(CellInfo *cell, BelId newBase)
{
std::vector<std::pair<CellInfo *, Loc>> cell_rel;
- pool<IdString> cells;
- std::vector<std::pair<CellInfo *, BelId>> moves_made;
+ dict<IdString, BelId> moved_cells;
std::vector<std::pair<CellInfo *, BelId>> dest_bels;
double delta = 0;
int orig_share_cost = total_net_share;
moveChange.reset(this);
-#if 0
- if (ctx->debug)
- log_info("finding cells for chain swap %s\n", cell->name.c_str(ctx));
+#if CHAIN_DEBUG
+ log_info("finding cells for chain swap %s\n", cell->name.c_str(ctx));
#endif
- if (!ctx->getClusterPlacement(cell->cluster, newBase, dest_bels))
- return false;
-
- for (const auto &db : dest_bels)
- cells.insert(db.first->name);
-
- for (const auto &db : dest_bels) {
- CellInfo *bound = ctx->getBoundBelCell(db.second);
- // We don't consider swapping chains with other chains, at least for the time being - unless it is
- // part of this chain
- if (bound != nullptr && !cells.count(bound->name) &&
- (bound->belStrength >= STRENGTH_STRONG || bound->cluster != ClusterId()))
- return false;
-
- if (bound != nullptr)
- if (!ctx->isValidBelForCellType(bound->type, db.first->bel))
- return false;
- }
-#if 0
- if (ctx->debug)
- log_info("trying chain swap %s\n", cell->name.c_str(ctx));
+ std::queue<std::pair<ClusterId, BelId>> displaced_clusters;
+ displaced_clusters.emplace(cell->cluster, newBase);
+ while (!displaced_clusters.empty()) {
+ auto cursor = displaced_clusters.front();
+ displaced_clusters.pop();
+ if (!ctx->getClusterPlacement(cursor.first, cursor.second, dest_bels))
+ goto swap_fail;
+ for (const auto &db : dest_bels) {
+ // Ensure the cluster is ripped up
+ if (db.first->bel != BelId()) {
+ moved_cells[db.first->name] = db.first->bel;
+#if CHAIN_DEBUG
+ log_info("%d unbind %s\n", __LINE__, ctx->nameOfBel(db.first->bel));
+#endif
+ ctx->unbindBel(db.first->bel);
+ }
+ }
+ for (const auto &db : dest_bels) {
+ CellInfo *bound = ctx->getBoundBelCell(db.second);
+ BelId old_bel = moved_cells.at(db.first->name);
+ if (!ctx->checkBelAvail(old_bel) && bound != nullptr) {
+ // Simple swap no longer possible
+ goto swap_fail;
+ }
+ if (bound != nullptr) {
+ if (moved_cells.count(bound->name)) {
+ // Don't move a cell multiple times in the same go
+ goto swap_fail;
+ } else if (bound->belStrength > STRENGTH_STRONG) {
+ goto swap_fail;
+ } else if (bound->cluster != ClusterId()) {
+ // Displace the entire cluster
+ Loc old_loc = ctx->getBelLocation(old_bel);
+ Loc bound_loc = ctx->getBelLocation(bound->bel);
+ Loc root_loc = ctx->getBelLocation(ctx->getClusterRootCell(bound->cluster)->bel);
+ BelId new_root = ctx->getBelByLocation(Loc(old_loc.x + (root_loc.x - bound_loc.x),
+ old_loc.y + (root_loc.y - bound_loc.y),
+ old_loc.z + (root_loc.z - bound_loc.z)));
+ if (new_root == BelId())
+ goto swap_fail;
+ for (auto cluster_cell : cluster2cell.at(bound->cluster)) {
+ moved_cells[cluster_cell->name] = cluster_cell->bel;
+#if CHAIN_DEBUG
+ log_info("%d unbind %s\n", __LINE__, ctx->nameOfBel(cluster_cell->bel));
+#endif
+ ctx->unbindBel(cluster_cell->bel);
+ }
+ displaced_clusters.emplace(bound->cluster, new_root);
+ } else {
+ // Just a single cell to move
+ moved_cells[bound->name] = bound->bel;
+#if CHAIN_DEBUG
+ log_info("%d unbind %s\n", __LINE__, ctx->nameOfBel(bound->bel));
+ log_info("%d bind %s %s\n", __LINE__, ctx->nameOfBel(old_bel), ctx->nameOf(bound));
+#endif
+ ctx->unbindBel(bound->bel);
+ ctx->bindBel(old_bel, bound, STRENGTH_WEAK);
+ }
+ } else if (!ctx->checkBelAvail(db.second)) {
+ goto swap_fail;
+ }
+ // All those shenanigans should now mean the target bel is free to use
+#if CHAIN_DEBUG
+ log_info("%d bind %s %s\n", __LINE__, ctx->nameOfBel(db.second), ctx->nameOf(db.first));
#endif
- // <cell, oldBel>
- for (const auto &db : dest_bels) {
- BelId oldBel = swap_cell_bels(db.first, db.second);
- moves_made.emplace_back(std::make_pair(db.first, oldBel));
- CellInfo *bound = ctx->getBoundBelCell(oldBel);
- add_move_cell(moveChange, db.first, oldBel);
- if (bound != nullptr)
- add_move_cell(moveChange, bound, db.second);
+ ctx->bindBel(db.second, db.first, STRENGTH_WEAK);
+ }
}
- for (const auto &mm : moves_made) {
- if (!ctx->isBelLocationValid(mm.first->bel) || !mm.first->testRegion(mm.first->bel))
- goto swap_fail;
- if (!ctx->isBelLocationValid(mm.second))
- goto swap_fail;
- CellInfo *bound = ctx->getBoundBelCell(mm.second);
- if (bound && !bound->testRegion(bound->bel))
+
+ for (const auto &mm : moved_cells) {
+ CellInfo *cell = ctx->cells.at(mm.first).get();
+ add_move_cell(moveChange, cell, moved_cells.at(cell->name));
+ if (cfg.netShareWeight > 0)
+ update_nets_by_tile(cell, ctx->getBelLocation(moved_cells.at(cell->name)),
+ ctx->getBelLocation(cell->bel));
+ if (!ctx->isBelLocationValid(cell->bel) || !cell->testRegion(cell->bel))
goto swap_fail;
}
+#if CHAIN_DEBUG
+ log_info("legal chain swap %s\n", cell->name.c_str(ctx));
+#endif
compute_cost_changes(moveChange);
delta = lambda * (moveChange.timing_delta / last_timing_cost) +
(1 - lambda) * (double(moveChange.wirelen_delta) / last_wirelen_cost);
@@ -675,11 +720,10 @@ class SAPlacer
}
n_move++;
// SA acceptance criteria
- if (delta < 0 || (temp > 1e-9 && (ctx->rng() / float(0x3fffffff)) <= std::exp(-delta / temp))) {
+ if (delta < 0 || (temp > 1e-8 && (ctx->rng() / float(0x3fffffff)) <= std::exp(-delta / temp))) {
n_accept++;
-#if 0
- if (ctx->debug)
- log_info("accepted chain swap %s\n", cell->name.c_str(ctx));
+#if CHAIN_DEBUG
+ log_info("accepted chain swap %s\n", cell->name.c_str(ctx));
#endif
} else {
goto swap_fail;
@@ -687,8 +731,15 @@ class SAPlacer
commit_cost_changes(moveChange);
return true;
swap_fail:
- for (const auto &entry : boost::adaptors::reverse(moves_made))
- swap_cell_bels(entry.first, entry.second);
+ for (auto cell_pair : moved_cells) {
+ CellInfo *cell = ctx->cells.at(cell_pair.first).get();
+ if (cell->bel != BelId())
+ ctx->unbindBel(cell->bel);
+ }
+ for (auto cell_pair : moved_cells) {
+ CellInfo *cell = ctx->cells.at(cell_pair.first).get();
+ ctx->bindBel(cell_pair.second, cell, STRENGTH_WEAK);
+ }
return false;
}
@@ -1183,6 +1234,9 @@ class SAPlacer
// Fast lookup for cell port to net user index
dict<std::pair<IdString, IdString>, size_t> fast_port_to_user;
+ // Fast lookup for cell to clusters
+ dict<ClusterId, std::vector<CellInfo *>> cluster2cell;
+
// Wirelength and timing cost at last and current iteration
wirelen_t last_wirelen_cost, curr_wirelen_cost;
double last_timing_cost, curr_timing_cost;
diff --git a/common/timing.cc b/common/timing.cc
index 161769dc..ce293f34 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -275,12 +275,13 @@ void TimingAnalyser::setup_port_domains()
if (launch_data.key.clock != capture_data.key.clock)
continue;
IdString clk = launch_data.key.clock;
- if (!ctx->nets.count(clk))
- continue;
- NetInfo *clk_net = ctx->nets.at(clk).get();
- if (!clk_net->clkconstr)
- continue;
- delay_t period = clk_net->clkconstr->period.minDelay();
+ delay_t period = ctx->getDelayFromNS(1.0e9 / ctx->setting<float>("target_freq"));
+ if (ctx->nets.count(clk)) {
+ NetInfo *clk_net = ctx->nets.at(clk).get();
+ if (clk_net->clkconstr) {
+ period = clk_net->clkconstr->period.minDelay();
+ }
+ }
if (launch_data.key.edge != capture_data.key.edge)
period /= 2;
dp.period = DelayPair(period);
@@ -426,15 +427,17 @@ void TimingAnalyser::walk_backward()
// Input port: propagate delay back through net, subtracting route delay
NetInfo *net = port_info(p).net;
if (net != nullptr && net->driver.cell != nullptr)
- set_required_time(CellPortKey(net->driver), req.first, req.second.value - pd.route_delay,
- req.second.path_length, p);
+ set_required_time(CellPortKey(net->driver), req.first,
+ req.second.value - DelayPair(pd.route_delay.maxDelay()), req.second.path_length,
+ p);
} else if (pd.type == PORT_OUT) {
// Output port : propagate delay back through cell, subtracting combinational delay
for (auto &fanin : pd.cell_arcs) {
if (fanin.type != CellArc::COMBINATIONAL)
continue;
set_required_time(CellPortKey(p.cell, fanin.other_port), req.first,
- req.second.value - fanin.value.delayPair(), req.second.path_length + 1, p);
+ req.second.value - DelayPair(fanin.value.maxDelay()), req.second.path_length + 1,
+ p);
}
}
}