Implement getBelValidityConflict for gatemate

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2025-09-04 17:17:24 +02:00
parent 9c6b106195
commit cd1e403c0d
5 changed files with 54 additions and 0 deletions

View File

@ -1003,7 +1003,26 @@ class HeAPPlacer
} }
// Provisionally bind the bel // Provisionally bind the bel
ctx->bindBel(sz, ci, STRENGTH_WEAK); ctx->bindBel(sz, ci, STRENGTH_WEAK);
// Handle legality-driven ripups
bool is_illegal = false;
CellInfo *conflict = nullptr;
BelId conflict_bel = BelId();
if (require_validity && !ctx->isBelLocationValid(sz)) { if (require_validity && !ctx->isBelLocationValid(sz)) {
conflict = ctx->getBelValidityConflict(sz);
// Only rip up conflicts without constraints
if (!conflict || conflict->cluster != ClusterId() || conflict->belStrength > STRENGTH_WEAK) {
is_illegal = true;
conflict = nullptr; // so we don't add it back to remaining later
} else {
conflict_bel = conflict->bel;
ctx->unbindBel(conflict_bel);
// This is the contract for getBelValidityConflict that the ripup has to make the location valid
NPNR_ASSERT(ctx->isBelLocationValid(sz));
}
}
if (is_illegal) {
// New location is not legal; unbind the cell (and rebind the cell we ripped up if // New location is not legal; unbind the cell (and rebind the cell we ripped up if
// applicable) // applicable)
ctx->unbindBel(sz); ctx->unbindBel(sz);
@ -1012,6 +1031,8 @@ class HeAPPlacer
} 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 // It's legal, but we haven't tried enough locations yet
ctx->unbindBel(sz); ctx->unbindBel(sz);
if (conflict != nullptr)
ctx->bindBel(conflict_bel, conflict, STRENGTH_WEAK);
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;
@ -1040,6 +1061,10 @@ class HeAPPlacer
remaining.emplace(chain_size[bound->name] * remaining.emplace(chain_size[bound->name] *
cfg.get_cell_legalisation_weight(ctx, bound), cfg.get_cell_legalisation_weight(ctx, bound),
bound->name); bound->name);
if (conflict != nullptr)
remaining.emplace(chain_size[conflict->name] *
cfg.get_cell_legalisation_weight(ctx, conflict),
conflict->name);
Loc loc = ctx->getBelLocation(sz); Loc loc = ctx->getBelLocation(sz);
cell_locs[ci->name].x = loc.x; cell_locs[ci->name].x = loc.x;
cell_locs[ci->name].y = loc.y; cell_locs[ci->name].y = loc.y;

View File

@ -688,6 +688,10 @@ struct Arch : BaseArch<ArchRanges>
{ {
return uarch->isBelLocationValid(bel, explain_invalid); return uarch->isBelLocationValid(bel, explain_invalid);
} }
CellInfo *getBelValidityConflict(BelId bel) const override
{
return uarch->getBelValidityConflict(bel);
}
// ------------------------------------------------ // ------------------------------------------------

View File

@ -79,6 +79,7 @@ struct HimbaechelAPI
virtual BelBucketId getBelBucketForCellType(IdString cell_type) const; virtual BelBucketId getBelBucketForCellType(IdString cell_type) const;
virtual bool isValidBelForCellType(IdString cell_type, BelId bel) const; virtual bool isValidBelForCellType(IdString cell_type, BelId bel) const;
virtual bool isBelLocationValid(BelId bel, bool explain_invalid = false) const { return true; } virtual bool isBelLocationValid(BelId bel, bool explain_invalid = false) const { return true; }
virtual CellInfo *getBelValidityConflict(BelId bel) const { return nullptr; }
// --- Wire and pip functions --- // --- Wire and pip functions ---
// Called when a wire/pip is placed/unplaced (with net=nullptr for a unbind) // Called when a wire/pip is placed/unplaced (with net=nullptr for a unbind)

View File

@ -210,6 +210,28 @@ bool GateMateImpl::isBelLocationValid(BelId bel, bool explain_invalid) const
return true; return true;
} }
CellInfo *GateMateImpl::getBelValidityConflict(BelId bel) const
{
if (ctx->getBelBucketForBel(bel) == id_RAM_HALF) {
CellInfo *cell = ctx->getBoundBelCell(bel);
Loc loc = ctx->getBelLocation(bel);
CellInfo *adj_half =
ctx->getBoundBelCell(ctx->getBelByLocation(Loc(loc.x, loc.z == RAM_HALF_L_Z ? loc.y - 8 : loc.y + 8,
loc.z == RAM_HALF_L_Z ? RAM_HALF_U_Z : RAM_HALF_L_Z)));
if (adj_half) {
const auto &half_data = fast_cell_info.at(cell->flat_index);
if (half_data.used) {
const auto &adj_data = fast_cell_info.at(adj_half->flat_index);
if (adj_data.used) {
if (adj_data.config != half_data.config)
return adj_half;
}
}
}
}
return nullptr;
}
Loc GateMateImpl::getRelativeConstraint(Loc &root_loc, IdString id) const Loc GateMateImpl::getRelativeConstraint(Loc &root_loc, IdString id) const
{ {
Loc child_loc; Loc child_loc;

View File

@ -50,6 +50,8 @@ struct GateMateImpl : HimbaechelAPI
bool checkPipAvailForNet(PipId pip, const NetInfo *net) const override { return checkPipAvail(pip); }; bool checkPipAvailForNet(PipId pip, const NetInfo *net) const override { return checkPipAvail(pip); };
bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override; bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override;
CellInfo *getBelValidityConflict(BelId bel) const override;
delay_t estimateDelay(WireId src, WireId dst) const override; delay_t estimateDelay(WireId src, WireId dst) const override;
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override; bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override;
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override; TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;