From ca97eb6ec2abe3b1ca047ce22bd04b67b793461e Mon Sep 17 00:00:00 2001 From: Max Aigner Date: Fri, 10 Jul 2026 12:30:09 +0200 Subject: [PATCH] gatemate: diagnose multiplier routing conflicts instead of asserting find_and_bind_downhill_pip() bound multiplier halo pips unconditionally, so two multiplier clusters placed close enough that their dedicated (locked) routing overlaps would trip the opaque bindPip assertion (base_arch.h: w2n_entry == nullptr). Make the primitive: - idempotent when the destination wire is already part of THIS net's route (a revisit of a shared start wire is a no-op, not an error); - fail with an actionable message naming the wire and both contending nets when a DIFFERENT net already holds the wire -- never silently drop the connection. This does not yet prevent the collision (that needs a placement-spacing rule so two multiplier clusters' halos cannot overlap); it converts an opaque abort into a diagnosable error and removes a latent same-net re-bind assertion. Co-Authored-By: Claude --- himbaechel/uarch/gatemate/route_mult.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/himbaechel/uarch/gatemate/route_mult.cc b/himbaechel/uarch/gatemate/route_mult.cc index 3af60c1a..17401afe 100644 --- a/himbaechel/uarch/gatemate/route_mult.cc +++ b/himbaechel/uarch/gatemate/route_mult.cc @@ -39,6 +39,22 @@ void find_and_bind_downhill_pip(Context *ctx, WireId from, WireId to, NetInfo *n { NPNR_ASSERT(from != WireId()); NPNR_ASSERT(to != WireId()); + + // Multiplier routes are hand-bound with STRENGTH_LOCKED. If this exact + // destination wire is already part of THIS net's route, re-binding it would + // trip the bindPip double-bind assertion (base_arch.h) -- it is just a + // revisit of a shared start wire, so treat it as a no-op. + if (ctx->getBoundWireNet(to) == net) + return; + // If the wire is held by a DIFFERENT net, two multiplier clusters were placed + // close enough that their dedicated (locked, hand-picked) routing overlaps. + // Fail with an actionable message instead of the opaque bindPip assertion, and + // never silently drop the connection (that would mis-route the product). + if (ctx->getBoundWireNet(to) != nullptr) + log_error("Multiplier routing conflict on wire %s: needed by net '%s' but already held by " + "net '%s' -- two multiplier clusters are placed too close.\n", + ctx->nameOfWire(to), net->name.c_str(ctx), ctx->getBoundWireNet(to)->name.c_str(ctx)); + for (auto pip : ctx->getPipsDownhill(from)) { if (ctx->getPipDstWire(pip) == to) { if (ctx->debug)