From c39f26e93a9e3d92dcc0191b145b6013ec29a57c Mon Sep 17 00:00:00 2001 From: Joris van Zwieten Date: Thu, 30 Jul 2026 15:44:01 +0200 Subject: [PATCH] himbaechel/xilinx: don't pair FFs with SRL/LUTRAM on a different clock pack_lutffs constrains an FF into the same slice position as the LUT driving its D input. When that driver is an SRL or LUTRAM cell it has a CLK of its own: the slice write clock. A slice has a single CLK input per half, so the placement validity check (xc7_logic_tile_valid) rejects any slice where the FF clock and the memory write clock differ in net or polarity. Pairing such an FF anyway creates a relatively-constrained cluster that is invalid at every bel on the device; the placer's strict legalisation phase then spins forever trying to place it (observed as a static-placer hang on a design clocking an SRL and its capture FF from different clocks). Only pair the FF when the driving cell either has no CLK or shares the FF's clock net and IS_CLK_INVERTED polarity. Hardware-verified on xc7a100t as part of a MEGA65 core port that previously hung in placement. Co-Authored-By: Claude Fable 5 --- himbaechel/uarch/xilinx/pack.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/himbaechel/uarch/xilinx/pack.cc b/himbaechel/uarch/xilinx/pack.cc index f363716d..d5f63875 100644 --- a/himbaechel/uarch/xilinx/pack.cc +++ b/himbaechel/uarch/xilinx/pack.cc @@ -310,6 +310,17 @@ void XilinxPacker::pack_lutffs() ci->constr_z = lut->constr_z + (BEL_FF - BEL_6LUT); ++pairs; } else { + // For SRL/LUTRAM drivers the slice write clock is the slice + // CLK, which the FF must share (same net, same polarity) — + // otherwise the cluster is unplaceable (xc7_logic_tile_valid + // FF-clk-vs-wclk check rejects it at every bel and + // legalisation spins forever). + NetInfo *lut_clk = lut->getPort(id_CLK); + if (lut_clk != nullptr && + (ci->getPort(id_CK) != lut_clk || + bool_or_default(ci->params, id_IS_CLK_INVERTED, false) != + bool_or_default(lut->params, id_IS_CLK_INVERTED, false))) + continue; lut->constr_children.push_back(ci); lut->cluster = lut->name; ci->cluster = lut->name;