Merge pull request #594 from YosysHQ/gatecat/heap-tidying
Tidying up HeAP
This commit is contained in:
commit
85af066d4f
@ -223,6 +223,28 @@ void CellInfo::unsetParam(IdString name) { params.erase(name); }
|
|||||||
void CellInfo::setAttr(IdString name, Property value) { attrs[name] = value; }
|
void CellInfo::setAttr(IdString name, Property value) { attrs[name] = value; }
|
||||||
void CellInfo::unsetAttr(IdString name) { attrs.erase(name); }
|
void CellInfo::unsetAttr(IdString name) { attrs.erase(name); }
|
||||||
|
|
||||||
|
bool CellInfo::isConstrained(bool include_abs_z_constr) const
|
||||||
|
{
|
||||||
|
return constr_parent != nullptr || !constr_children.empty() || (include_abs_z_constr && constr_abs_z);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CellInfo::testRegion(BelId bel) const
|
||||||
|
{
|
||||||
|
return region == nullptr || !region->constr_bels || region->bels.count(bel);
|
||||||
|
}
|
||||||
|
Loc CellInfo::getConstrainedLoc(Loc parent_loc) const
|
||||||
|
{
|
||||||
|
NPNR_ASSERT(constr_parent != nullptr);
|
||||||
|
Loc cloc = parent_loc;
|
||||||
|
if (constr_x != UNCONSTR)
|
||||||
|
cloc.x += constr_x;
|
||||||
|
if (constr_y != UNCONSTR)
|
||||||
|
cloc.y += constr_y;
|
||||||
|
if (constr_z != UNCONSTR)
|
||||||
|
cloc.z = constr_abs_z ? constr_z : (parent_loc.z + constr_z);
|
||||||
|
return cloc;
|
||||||
|
}
|
||||||
|
|
||||||
std::string Property::to_string() const
|
std::string Property::to_string() const
|
||||||
{
|
{
|
||||||
if (is_string) {
|
if (is_string) {
|
||||||
|
@ -664,6 +664,14 @@ struct CellInfo : ArchCellInfo
|
|||||||
void unsetParam(IdString name);
|
void unsetParam(IdString name);
|
||||||
void setAttr(IdString name, Property value);
|
void setAttr(IdString name, Property value);
|
||||||
void unsetAttr(IdString name);
|
void unsetAttr(IdString name);
|
||||||
|
|
||||||
|
// return true if the cell has placement constraints (optionally excluding the case where the only case is an
|
||||||
|
// absolute z constraint)
|
||||||
|
bool isConstrained(bool include_abs_z_constr = true) const;
|
||||||
|
// check whether a bel complies with the cell's region constraint
|
||||||
|
bool testRegion(BelId bel) const;
|
||||||
|
// get the constrained location for this cell given a provisional location for its parent
|
||||||
|
Loc getConstrainedLoc(Loc parent_loc) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TimingPortClass
|
enum TimingPortClass
|
||||||
|
@ -536,12 +536,4 @@ int get_constraints_distance(const Context *ctx, const CellInfo *cell)
|
|||||||
return dist;
|
return dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_cell_bel_region(const CellInfo *cell, BelId bel)
|
|
||||||
{
|
|
||||||
if (cell->region != nullptr && cell->region->constr_bels && !cell->region->bels.count(bel))
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -50,9 +50,6 @@ bool legalise_relative_constraints(Context *ctx);
|
|||||||
// Get the total distance from satisfied constraints for a cell
|
// Get the total distance from satisfied constraints for a cell
|
||||||
int get_constraints_distance(const Context *ctx, const CellInfo *cell);
|
int get_constraints_distance(const Context *ctx, const CellInfo *cell);
|
||||||
|
|
||||||
// Check that a Bel is within the region for a cell
|
|
||||||
bool check_cell_bel_region(const CellInfo *cell, BelId bel);
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -504,12 +504,12 @@ class SAPlacer
|
|||||||
{
|
{
|
||||||
static const double epsilon = 1e-20;
|
static const double epsilon = 1e-20;
|
||||||
moveChange.reset(this);
|
moveChange.reset(this);
|
||||||
if (!require_legal && is_constrained(cell))
|
if (!require_legal && cell->isConstrained(false))
|
||||||
return false;
|
return false;
|
||||||
BelId oldBel = cell->bel;
|
BelId oldBel = cell->bel;
|
||||||
CellInfo *other_cell = ctx->getBoundBelCell(newBel);
|
CellInfo *other_cell = ctx->getBoundBelCell(newBel);
|
||||||
if (!require_legal && other_cell != nullptr &&
|
if (!require_legal && other_cell != nullptr &&
|
||||||
(is_constrained(other_cell) || other_cell->belStrength > STRENGTH_WEAK)) {
|
(other_cell->isConstrained(false) || other_cell->belStrength > STRENGTH_WEAK)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int old_dist = get_constraints_distance(ctx, cell);
|
int old_dist = get_constraints_distance(ctx, cell);
|
||||||
@ -589,11 +589,6 @@ class SAPlacer
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_constrained(CellInfo *cell)
|
|
||||||
{
|
|
||||||
return cell->constr_parent != nullptr || !cell->constr_children.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap the Bel of a cell with another, return the original location
|
// Swap the Bel of a cell with another, return the original location
|
||||||
BelId swap_cell_bels(CellInfo *cell, BelId newBel)
|
BelId swap_cell_bels(CellInfo *cell, BelId newBel)
|
||||||
{
|
{
|
||||||
@ -605,9 +600,9 @@ class SAPlacer
|
|||||||
if (bound != nullptr)
|
if (bound != nullptr)
|
||||||
ctx->unbindBel(newBel);
|
ctx->unbindBel(newBel);
|
||||||
ctx->unbindBel(oldBel);
|
ctx->unbindBel(oldBel);
|
||||||
ctx->bindBel(newBel, cell, is_constrained(cell) ? STRENGTH_STRONG : STRENGTH_WEAK);
|
ctx->bindBel(newBel, cell, cell->isConstrained(false) ? STRENGTH_STRONG : STRENGTH_WEAK);
|
||||||
if (bound != nullptr) {
|
if (bound != nullptr) {
|
||||||
ctx->bindBel(oldBel, bound, is_constrained(bound) ? STRENGTH_STRONG : STRENGTH_WEAK);
|
ctx->bindBel(oldBel, bound, bound->isConstrained(false) ? STRENGTH_STRONG : STRENGTH_WEAK);
|
||||||
if (cfg.netShareWeight > 0)
|
if (cfg.netShareWeight > 0)
|
||||||
update_nets_by_tile(bound, ctx->getBelLocation(newBel), ctx->getBelLocation(oldBel));
|
update_nets_by_tile(bound, ctx->getBelLocation(newBel), ctx->getBelLocation(oldBel));
|
||||||
}
|
}
|
||||||
@ -658,7 +653,7 @@ class SAPlacer
|
|||||||
// We don't consider swapping chains with other chains, at least for the time being - unless it is
|
// We don't consider swapping chains with other chains, at least for the time being - unless it is
|
||||||
// part of this chain
|
// part of this chain
|
||||||
if (bound != nullptr && !cells.count(bound->name) &&
|
if (bound != nullptr && !cells.count(bound->name) &&
|
||||||
(bound->belStrength >= STRENGTH_STRONG || is_constrained(bound)))
|
(bound->belStrength >= STRENGTH_STRONG || bound->isConstrained(false)))
|
||||||
return false;
|
return false;
|
||||||
dest_bels.emplace_back(std::make_pair(cr.first, targetBel));
|
dest_bels.emplace_back(std::make_pair(cr.first, targetBel));
|
||||||
}
|
}
|
||||||
@ -676,12 +671,12 @@ class SAPlacer
|
|||||||
add_move_cell(moveChange, bound, db.second);
|
add_move_cell(moveChange, bound, db.second);
|
||||||
}
|
}
|
||||||
for (const auto &mm : moves_made) {
|
for (const auto &mm : moves_made) {
|
||||||
if (!ctx->isBelLocationValid(mm.first->bel) || !check_cell_bel_region(mm.first, mm.first->bel))
|
if (!ctx->isBelLocationValid(mm.first->bel) || !mm.first->testRegion(mm.first->bel))
|
||||||
goto swap_fail;
|
goto swap_fail;
|
||||||
if (!ctx->isBelLocationValid(mm.second))
|
if (!ctx->isBelLocationValid(mm.second))
|
||||||
goto swap_fail;
|
goto swap_fail;
|
||||||
CellInfo *bound = ctx->getBoundBelCell(mm.second);
|
CellInfo *bound = ctx->getBoundBelCell(mm.second);
|
||||||
if (bound && !check_cell_bel_region(bound, bound->bel))
|
if (bound && !bound->testRegion(bound->bel))
|
||||||
goto swap_fail;
|
goto swap_fail;
|
||||||
}
|
}
|
||||||
compute_cost_changes(moveChange);
|
compute_cost_changes(moveChange);
|
||||||
@ -752,7 +747,7 @@ class SAPlacer
|
|||||||
if (loc.z != force_z)
|
if (loc.z != force_z)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!check_cell_bel_region(cell, bel))
|
if (!cell->testRegion(bel))
|
||||||
continue;
|
continue;
|
||||||
if (locked_bels.find(bel) != locked_bels.end())
|
if (locked_bels.find(bel) != locked_bels.end())
|
||||||
continue;
|
continue;
|
||||||
|
@ -222,6 +222,7 @@ class HeAPPlacer
|
|||||||
// Heuristic: don't bother with threading below a certain size
|
// Heuristic: don't bother with threading below a certain size
|
||||||
auto solve_startt = std::chrono::high_resolution_clock::now();
|
auto solve_startt = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
// Build the connectivity matrix and run the solver; multithreaded between x and y axes if applicable
|
||||||
#ifndef NPNR_DISABLE_THREADS
|
#ifndef NPNR_DISABLE_THREADS
|
||||||
if (solve_cells.size() >= 500) {
|
if (solve_cells.size() >= 500) {
|
||||||
boost::thread xaxis([&]() { build_solve_direction(false, (iter == 0) ? -1 : iter); });
|
boost::thread xaxis([&]() { build_solve_direction(false, (iter == 0) ? -1 : iter); });
|
||||||
@ -240,6 +241,7 @@ class HeAPPlacer
|
|||||||
|
|
||||||
update_all_chains();
|
update_all_chains();
|
||||||
|
|
||||||
|
// Run the spreader
|
||||||
for (const auto &group : cfg.cellGroups)
|
for (const auto &group : cfg.cellGroups)
|
||||||
CutSpreader(this, group).run();
|
CutSpreader(this, group).run();
|
||||||
|
|
||||||
@ -248,6 +250,7 @@ class HeAPPlacer
|
|||||||
[type](const std::unordered_set<BelBucketId> &grp) { return !grp.count(type); }))
|
[type](const std::unordered_set<BelBucketId> &grp) { return !grp.count(type); }))
|
||||||
CutSpreader(this, {type}).run();
|
CutSpreader(this, {type}).run();
|
||||||
|
|
||||||
|
// Run strict legalisation to find a valid bel for all cells
|
||||||
update_all_chains();
|
update_all_chains();
|
||||||
spread_hpwl = total_hpwl();
|
spread_hpwl = total_hpwl();
|
||||||
legalise_placement_strict(true);
|
legalise_placement_strict(true);
|
||||||
@ -263,6 +266,7 @@ class HeAPPlacer
|
|||||||
std::chrono::duration<double>(run_stopt - run_startt).count());
|
std::chrono::duration<double>(run_stopt - run_startt).count());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update timing weights
|
||||||
if (cfg.timing_driven)
|
if (cfg.timing_driven)
|
||||||
get_criticalities(ctx, &net_crit);
|
get_criticalities(ctx, &net_crit);
|
||||||
|
|
||||||
@ -851,6 +855,8 @@ class HeAPPlacer
|
|||||||
log_error("Unable to find legal placement for cell '%s', check constraints and utilisation.\n",
|
log_error("Unable to find legal placement for cell '%s', check constraints and utilisation.\n",
|
||||||
ctx->nameOf(ci));
|
ctx->nameOf(ci));
|
||||||
|
|
||||||
|
// Determine a search radius around the solver location (which increases over time) that is clamped to
|
||||||
|
// the region constraint for the cell (if applicable)
|
||||||
int rx = radius, ry = radius;
|
int rx = radius, ry = radius;
|
||||||
|
|
||||||
if (ci->region != nullptr) {
|
if (ci->region != nullptr) {
|
||||||
@ -864,14 +870,18 @@ class HeAPPlacer
|
|||||||
1);
|
1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pick a random X and Y location within our search radius
|
||||||
int nx = ctx->rng(2 * rx + 1) + std::max(cell_locs.at(ci->name).x - rx, 0);
|
int nx = ctx->rng(2 * rx + 1) + std::max(cell_locs.at(ci->name).x - rx, 0);
|
||||||
int ny = ctx->rng(2 * ry + 1) + std::max(cell_locs.at(ci->name).y - ry, 0);
|
int ny = ctx->rng(2 * ry + 1) + std::max(cell_locs.at(ci->name).y - ry, 0);
|
||||||
|
|
||||||
iter++;
|
iter++;
|
||||||
iter_at_radius++;
|
iter_at_radius++;
|
||||||
if (iter >= (10 * (radius + 1))) {
|
if (iter >= (10 * (radius + 1))) {
|
||||||
|
// No luck yet, increase radius
|
||||||
radius = std::min(std::max(max_x, max_y), radius + 1);
|
radius = std::min(std::max(max_x, max_y), radius + 1);
|
||||||
while (radius < std::max(max_x, max_y)) {
|
while (radius < std::max(max_x, max_y)) {
|
||||||
|
// Keep increasing the radius until it will actually increase the number of cells we are
|
||||||
|
// checking (e.g. BRAM and DSP will not be in all cols/rows), so we don't waste effort
|
||||||
for (int x = std::max(0, cell_locs.at(ci->name).x - radius);
|
for (int x = std::max(0, cell_locs.at(ci->name).x - radius);
|
||||||
x <= std::min(max_x, cell_locs.at(ci->name).x + radius); x++) {
|
x <= std::min(max_x, cell_locs.at(ci->name).x + radius); x++) {
|
||||||
if (x >= int(fb->size()))
|
if (x >= int(fb->size()))
|
||||||
@ -890,6 +900,8 @@ class HeAPPlacer
|
|||||||
iter_at_radius = 0;
|
iter_at_radius = 0;
|
||||||
iter = 0;
|
iter = 0;
|
||||||
}
|
}
|
||||||
|
// If our randomly chosen cooridnate is out of bounds; or points to a tile with no relevant bels; ignore
|
||||||
|
// it
|
||||||
if (nx < 0 || nx > max_x)
|
if (nx < 0 || nx > max_x)
|
||||||
continue;
|
continue;
|
||||||
if (ny < 0 || ny > max_y)
|
if (ny < 0 || ny > max_y)
|
||||||
@ -902,8 +914,11 @@ class HeAPPlacer
|
|||||||
if (fb->at(nx).at(ny).empty())
|
if (fb->at(nx).at(ny).empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// The number of attempts to find a location to try
|
||||||
int need_to_explore = 2 * radius;
|
int need_to_explore = 2 * radius;
|
||||||
|
|
||||||
|
// If we have found at least one legal location; and made enough attempts; assume it's good enough and
|
||||||
|
// finish
|
||||||
if (iter_at_radius >= need_to_explore && bestBel != BelId()) {
|
if (iter_at_radius >= need_to_explore && bestBel != BelId()) {
|
||||||
CellInfo *bound = ctx->getBoundBelCell(bestBel);
|
CellInfo *bound = ctx->getBoundBelCell(bestBel);
|
||||||
if (bound != nullptr) {
|
if (bound != nullptr) {
|
||||||
@ -919,27 +934,37 @@ class HeAPPlacer
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ci->constr_children.empty() && !ci->constr_abs_z) {
|
if (ci->constr_children.empty() && !ci->constr_abs_z) {
|
||||||
|
// The case where we have no relative constraints
|
||||||
for (auto sz : fb->at(nx).at(ny)) {
|
for (auto sz : fb->at(nx).at(ny)) {
|
||||||
if (ci->region != nullptr && ci->region->constr_bels && !ci->region->bels.count(sz))
|
// Look through all bels in this tile; checking region constraint if applicable
|
||||||
|
if (!ci->testRegion(sz))
|
||||||
continue;
|
continue;
|
||||||
|
// Prefer available bels; unless we are dealing with a wide radius (e.g. difficult control sets)
|
||||||
|
// or occasionally trigger a tiebreaker
|
||||||
if (ctx->checkBelAvail(sz) || (radius > ripup_radius || ctx->rng(20000) < 10)) {
|
if (ctx->checkBelAvail(sz) || (radius > ripup_radius || ctx->rng(20000) < 10)) {
|
||||||
CellInfo *bound = ctx->getBoundBelCell(sz);
|
CellInfo *bound = ctx->getBoundBelCell(sz);
|
||||||
if (bound != nullptr) {
|
if (bound != nullptr) {
|
||||||
if (bound->constr_parent != nullptr || !bound->constr_children.empty() ||
|
// Only rip up cells without constraints
|
||||||
bound->constr_abs_z)
|
if (bound->isConstrained())
|
||||||
continue;
|
continue;
|
||||||
ctx->unbindBel(bound->bel);
|
ctx->unbindBel(bound->bel);
|
||||||
}
|
}
|
||||||
|
// Provisionally bind the bel
|
||||||
ctx->bindBel(sz, ci, STRENGTH_WEAK);
|
ctx->bindBel(sz, ci, STRENGTH_WEAK);
|
||||||
if (require_validity && !ctx->isBelLocationValid(sz)) {
|
if (require_validity && !ctx->isBelLocationValid(sz)) {
|
||||||
|
// New location is not legal; unbind the cell (and rebind the cell we ripped up if
|
||||||
|
// applicable)
|
||||||
ctx->unbindBel(sz);
|
ctx->unbindBel(sz);
|
||||||
if (bound != nullptr)
|
if (bound != nullptr)
|
||||||
ctx->bindBel(sz, bound, STRENGTH_WEAK);
|
ctx->bindBel(sz, bound, STRENGTH_WEAK);
|
||||||
} else if (iter_at_radius < need_to_explore) {
|
} else if (iter_at_radius < need_to_explore) {
|
||||||
|
// It's legal, but we haven't tried enough locations yet
|
||||||
ctx->unbindBel(sz);
|
ctx->unbindBel(sz);
|
||||||
if (bound != nullptr)
|
if (bound != nullptr)
|
||||||
ctx->bindBel(sz, bound, STRENGTH_WEAK);
|
ctx->bindBel(sz, bound, STRENGTH_WEAK);
|
||||||
int input_len = 0;
|
int input_len = 0;
|
||||||
|
// Compute a fast input wirelength metric at this bel; and save if better than our last
|
||||||
|
// try
|
||||||
for (auto &port : ci->ports) {
|
for (auto &port : ci->ports) {
|
||||||
auto &p = port.second;
|
auto &p = port.second;
|
||||||
if (p.type != PORT_IN || p.net == nullptr || p.net->driver.cell == nullptr)
|
if (p.type != PORT_IN || p.net == nullptr || p.net->driver.cell == nullptr)
|
||||||
@ -958,6 +983,7 @@ class HeAPPlacer
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
// It's legal, and we've tried enough. Finish.
|
||||||
if (bound != nullptr)
|
if (bound != nullptr)
|
||||||
remaining.emplace(chain_size[bound->name], bound->name);
|
remaining.emplace(chain_size[bound->name], bound->name);
|
||||||
Loc loc = ctx->getBelLocation(sz);
|
Loc loc = ctx->getBelLocation(sz);
|
||||||
@ -969,44 +995,49 @@ class HeAPPlacer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// We do have relative constraints
|
||||||
for (auto sz : fb->at(nx).at(ny)) {
|
for (auto sz : fb->at(nx).at(ny)) {
|
||||||
Loc loc = ctx->getBelLocation(sz);
|
Loc loc = ctx->getBelLocation(sz);
|
||||||
|
// Check that the absolute-z constraint is satisfied if applicable
|
||||||
if (ci->constr_abs_z && loc.z != ci->constr_z)
|
if (ci->constr_abs_z && loc.z != ci->constr_z)
|
||||||
continue;
|
continue;
|
||||||
|
// List of cells and their destination
|
||||||
std::vector<std::pair<CellInfo *, BelId>> targets;
|
std::vector<std::pair<CellInfo *, BelId>> targets;
|
||||||
|
// List of bels we placed things at; and the cell that was there before if applicable
|
||||||
std::vector<std::pair<BelId, CellInfo *>> swaps_made;
|
std::vector<std::pair<BelId, CellInfo *>> swaps_made;
|
||||||
|
// List of (cell, new location) pairs to check
|
||||||
std::queue<std::pair<CellInfo *, Loc>> visit;
|
std::queue<std::pair<CellInfo *, Loc>> visit;
|
||||||
|
// FIXME: this approach of having a visit queue is designed to deal with recursively chained
|
||||||
|
// cells. But is this a case we really want to care about given the complexity it adds? Start by
|
||||||
|
// considering the root cell at the root location
|
||||||
visit.emplace(ci, loc);
|
visit.emplace(ci, loc);
|
||||||
while (!visit.empty()) {
|
while (!visit.empty()) {
|
||||||
CellInfo *vc = visit.front().first;
|
CellInfo *vc = visit.front().first;
|
||||||
NPNR_ASSERT(vc->bel == BelId());
|
NPNR_ASSERT(vc->bel == BelId());
|
||||||
Loc ploc = visit.front().second;
|
Loc ploc = visit.front().second;
|
||||||
visit.pop();
|
visit.pop();
|
||||||
|
// Get the bel we're going to place this cell at
|
||||||
BelId target = ctx->getBelByLocation(ploc);
|
BelId target = ctx->getBelByLocation(ploc);
|
||||||
if (vc->region != nullptr && vc->region->constr_bels && !vc->region->bels.count(target))
|
// Check it satisfies the region constraint if applicable
|
||||||
|
if (!vc->testRegion(target))
|
||||||
goto fail;
|
goto fail;
|
||||||
CellInfo *bound;
|
CellInfo *bound;
|
||||||
|
// Check that the target bel exists and is of a suitable type
|
||||||
if (target == BelId() || !ctx->isValidBelForCellType(vc->type, target))
|
if (target == BelId() || !ctx->isValidBelForCellType(vc->type, target))
|
||||||
goto fail;
|
goto fail;
|
||||||
bound = ctx->getBoundBelCell(target);
|
bound = ctx->getBoundBelCell(target);
|
||||||
// Chains cannot overlap
|
// Chains cannot overlap; so if we have to ripup a cell make sure it isn't part of a chain
|
||||||
if (bound != nullptr)
|
if (bound != nullptr)
|
||||||
if (bound->constr_z != bound->UNCONSTR || bound->constr_parent != nullptr ||
|
if (bound->isConstrained() || bound->belStrength > STRENGTH_WEAK)
|
||||||
!bound->constr_children.empty() || bound->belStrength > STRENGTH_WEAK)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
targets.emplace_back(vc, target);
|
targets.emplace_back(vc, target);
|
||||||
for (auto child : vc->constr_children) {
|
for (auto child : vc->constr_children) {
|
||||||
Loc cloc = ploc;
|
// For all the constrained children; compute the location we need to place them at and
|
||||||
if (child->constr_x != child->UNCONSTR)
|
// add them to the queue
|
||||||
cloc.x += child->constr_x;
|
visit.emplace(child, child->getConstrainedLoc(ploc));
|
||||||
if (child->constr_y != child->UNCONSTR)
|
|
||||||
cloc.y += child->constr_y;
|
|
||||||
if (child->constr_z != child->UNCONSTR)
|
|
||||||
cloc.z = child->constr_abs_z ? child->constr_z : (ploc.z + child->constr_z);
|
|
||||||
visit.emplace(child, cloc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Actually perform the move; keeping track of the moves we make so we can revert them if needed
|
||||||
for (auto &target : targets) {
|
for (auto &target : targets) {
|
||||||
CellInfo *bound = ctx->getBoundBelCell(target.second);
|
CellInfo *bound = ctx->getBoundBelCell(target.second);
|
||||||
if (bound != nullptr)
|
if (bound != nullptr)
|
||||||
@ -1014,7 +1045,7 @@ class HeAPPlacer
|
|||||||
ctx->bindBel(target.second, target.first, STRENGTH_STRONG);
|
ctx->bindBel(target.second, target.first, STRENGTH_STRONG);
|
||||||
swaps_made.emplace_back(target.second, bound);
|
swaps_made.emplace_back(target.second, bound);
|
||||||
}
|
}
|
||||||
|
// Check that the move we have made is legal
|
||||||
for (auto &sm : swaps_made) {
|
for (auto &sm : swaps_made) {
|
||||||
if (!ctx->isBelLocationValid(sm.first))
|
if (!ctx->isBelLocationValid(sm.first))
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1022,6 +1053,7 @@ class HeAPPlacer
|
|||||||
|
|
||||||
if (false) {
|
if (false) {
|
||||||
fail:
|
fail:
|
||||||
|
// If the move turned out to be illegal; revert all the moves we made
|
||||||
for (auto &swap : swaps_made) {
|
for (auto &swap : swaps_made) {
|
||||||
ctx->unbindBel(swap.first);
|
ctx->unbindBel(swap.first);
|
||||||
if (swap.second != nullptr)
|
if (swap.second != nullptr)
|
||||||
@ -1036,6 +1068,7 @@ class HeAPPlacer
|
|||||||
// log_info("%s %d %d %d\n", target.first->name.c_str(ctx), loc.x, loc.y, loc.z);
|
// log_info("%s %d %d %d\n", target.first->name.c_str(ctx), loc.x, loc.y, loc.z);
|
||||||
}
|
}
|
||||||
for (auto &swap : swaps_made) {
|
for (auto &swap : swaps_made) {
|
||||||
|
// Where we have ripped up cells; add them to the queue
|
||||||
if (swap.second != nullptr)
|
if (swap.second != nullptr)
|
||||||
remaining.emplace(chain_size[swap.second->name], swap.second->name);
|
remaining.emplace(chain_size[swap.second->name], swap.second->name);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user