From cd1e403c0d894ff5684e250336b7ae4b788a0967 Mon Sep 17 00:00:00 2001 From: gatecat Date: Thu, 4 Sep 2025 17:17:24 +0200 Subject: [PATCH] Implement getBelValidityConflict for gatemate Signed-off-by: gatecat --- common/place/placer_heap.cc | 25 +++++++++++++++++++++++++ himbaechel/arch.h | 4 ++++ himbaechel/himbaechel_api.h | 1 + himbaechel/uarch/gatemate/gatemate.cc | 22 ++++++++++++++++++++++ himbaechel/uarch/gatemate/gatemate.h | 2 ++ 5 files changed, 54 insertions(+) diff --git a/common/place/placer_heap.cc b/common/place/placer_heap.cc index be8a670d..4c446ba7 100644 --- a/common/place/placer_heap.cc +++ b/common/place/placer_heap.cc @@ -1003,7 +1003,26 @@ class HeAPPlacer } // Provisionally bind the bel 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)) { + 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 // applicable) ctx->unbindBel(sz); @@ -1012,6 +1031,8 @@ class HeAPPlacer } else if (iter_at_radius < need_to_explore) { // It's legal, but we haven't tried enough locations yet ctx->unbindBel(sz); + if (conflict != nullptr) + ctx->bindBel(conflict_bel, conflict, STRENGTH_WEAK); if (bound != nullptr) ctx->bindBel(sz, bound, STRENGTH_WEAK); int input_len = 0; @@ -1040,6 +1061,10 @@ class HeAPPlacer remaining.emplace(chain_size[bound->name] * cfg.get_cell_legalisation_weight(ctx, bound), 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); cell_locs[ci->name].x = loc.x; cell_locs[ci->name].y = loc.y; diff --git a/himbaechel/arch.h b/himbaechel/arch.h index 8fe62afb..456bc187 100644 --- a/himbaechel/arch.h +++ b/himbaechel/arch.h @@ -688,6 +688,10 @@ struct Arch : BaseArch { return uarch->isBelLocationValid(bel, explain_invalid); } + CellInfo *getBelValidityConflict(BelId bel) const override + { + return uarch->getBelValidityConflict(bel); + } // ------------------------------------------------ diff --git a/himbaechel/himbaechel_api.h b/himbaechel/himbaechel_api.h index ab0e4a32..c4a29120 100644 --- a/himbaechel/himbaechel_api.h +++ b/himbaechel/himbaechel_api.h @@ -79,6 +79,7 @@ struct HimbaechelAPI virtual BelBucketId getBelBucketForCellType(IdString cell_type) const; virtual bool isValidBelForCellType(IdString cell_type, BelId bel) const; virtual bool isBelLocationValid(BelId bel, bool explain_invalid = false) const { return true; } + virtual CellInfo *getBelValidityConflict(BelId bel) const { return nullptr; } // --- Wire and pip functions --- // Called when a wire/pip is placed/unplaced (with net=nullptr for a unbind) diff --git a/himbaechel/uarch/gatemate/gatemate.cc b/himbaechel/uarch/gatemate/gatemate.cc index 9cb86f7b..1146a4b3 100644 --- a/himbaechel/uarch/gatemate/gatemate.cc +++ b/himbaechel/uarch/gatemate/gatemate.cc @@ -210,6 +210,28 @@ bool GateMateImpl::isBelLocationValid(BelId bel, bool explain_invalid) const 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 child_loc; diff --git a/himbaechel/uarch/gatemate/gatemate.h b/himbaechel/uarch/gatemate/gatemate.h index 371cd1f9..704d4bd0 100644 --- a/himbaechel/uarch/gatemate/gatemate.h +++ b/himbaechel/uarch/gatemate/gatemate.h @@ -50,6 +50,8 @@ struct GateMateImpl : HimbaechelAPI bool checkPipAvailForNet(PipId pip, const NetInfo *net) const override { return checkPipAvail(pip); }; 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; bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const override; TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const override;