From 75c8144d42cb2f436ae0b11ab911837a990c5908 Mon Sep 17 00:00:00 2001 From: Joris van Zwieten Date: Thu, 30 Jul 2026 15:45:59 +0200 Subject: [PATCH] himbaechel/xilinx: emit BRAM36 width-1 features for RAMB36E1 A RAMB36E1 port configured with width 1 (true 32K x 1 mode) needs the RAMB36-level BRAM36_{READ,WRITE}_WIDTH_{A,B}_1 feature in addition to the per-half RAMB18_Yx width bits, which were the only ones emitted. In this mode the two 16K halves interleave even/odd bit addresses. Without the RAMB36-level feature both halves respond at addr>>1: every write hits the bit pair 2k/2k+1 and the address LSB is ignored, so half the memory aliases the other half. Verified against Vivado bitstreams for the same configuration and on xc7a100t hardware (32K x 1 and cascaded 64K x 1 inferred memories). Co-Authored-By: Claude Fable 5 --- himbaechel/uarch/xilinx/fasm.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/himbaechel/uarch/xilinx/fasm.cc b/himbaechel/uarch/xilinx/fasm.cc index dc70320c..b1611f69 100644 --- a/himbaechel/uarch/xilinx/fasm.cc +++ b/himbaechel/uarch/xilinx/fasm.cc @@ -1442,6 +1442,18 @@ struct FasmBackend write_bit("CASCOUT_ARD_ACTIVE", !used_rdaddrcasc.empty()); write_bit("CASCOUT_BWR_ACTIVE", !used_wraddrcasc.empty()); } + // A RAMB36E1 with a width-1 port needs the RAMB36-level BRAM36_*_WIDTH_*_1 + // feature in addition to the per-half RAMB18_Yx width bits. Without it the + // two 16K halves (which interleave even/odd bit addresses in true 32K x 1 + // mode) both respond at addr>>1: every write hits bit pairs 2k/2k+1 and + // the address LSB is ignored. + if (half == 0 && ci != nullptr && ci->type == id_RAMB36E1_RAMB36E1) { + push("RAMB36"); + for (const char *port : {"READ_WIDTH_A", "READ_WIDTH_B", "WRITE_WIDTH_A", "WRITE_WIDTH_B"}) + if (int_or_default(ci->params, ctx->id(port), 0) == 1) + write_bit(std::string("BRAM36_") + port + "_1"); + pop(); + } pop(); }