himbaechel/xilinx: fix LUTRAM initialisation (INIT_A..INIT_D)

Distributed RAM primitives (RAM32M/RAM64M etc.) carry their per-port
initialisation in parameters named INIT_A..INIT_D, but pack_dram
looked up INITA..INITD. The lookup never matched, so all LUTRAM was
configured with INIT=0 regardless of the design's initial contents.

Fixing the name exposed a second, previously unreachable bug in the
wide (dbits>1) path: the 64-bit INIT slice was converted with
as_bits(), which yields raw bool values rather than the '0'/'1'
characters a Property string requires, producing a corrupt property.
De-interleave the canonical bit string directly (bit k*2+j of the
64-bit INIT is bit j of entry k) and rebuild the Property with
update_intval().

Repro: a RAM32M with a nonzero INIT_A..D readback (WE held low /
driven by a live net); before this change the read data is all-zero.

Hardware-verified on xc7a100t (QMTech Wukong): LUTRAM-based tables in
a MEGA65 core port now read back their initial contents correctly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Joris van Zwieten 2026-07-30 15:35:36 +02:00
parent 68c1acd80a
commit 4fd89bca9a
1 changed files with 15 additions and 9 deletions

View File

@ -495,8 +495,8 @@ void XilinxPacker::pack_dram()
dout, zoffset + i);
if (base == nullptr)
base = dram;
if (ci->params.count(ctx->idf("INIT%c", 'A' + i)))
dram->params[id_INIT] = ci->params[ctx->idf("INIT%c", 'A' + i)];
if (ci->params.count(ctx->idf("INIT_%c", 'A' + i)))
dram->params[id_INIT] = ci->params[ctx->idf("INIT_%c", 'A' + i)];
} else {
for (int j = 0; j < dbits; j++) {
NetInfo *di = ci->getPort(ctx->idf("DI%c[%d]", 'A' + i, j));
@ -507,13 +507,19 @@ void XilinxPacker::pack_dram()
address, di, dout, (j == 0), zoffset + i);
if (base == nullptr)
base = dram;
if (ci->params.count(ctx->idf("INIT%c", 'A' + i))) {
auto orig_init = ci->params.at(ctx->idf("INIT%c", 'A' + i)).extract(0, 64).as_bits();
std::string init;
for (int k = 0; k < 32; k++) {
init.push_back(orig_init.at(k * 2 + j));
}
dram->params[id_INIT] = Property::from_string(init);
if (ci->params.count(ctx->idf("INIT_%c", 'A' + i))) {
// De-interleave the 64-bit INIT (bit k*2+j is bit j
// of entry k) into this RAMD32's 32 bits. Slice the
// canonical bit string ('0'/'1' chars, LSB first) -
// as_bits() gives raw bools, which are not valid
// Property string characters.
Property orig_init = ci->params.at(ctx->idf("INIT_%c", 'A' + i)).extract(0, 64);
Property init;
init.is_string = false;
for (int k = 0; k < 32; k++)
init.str.push_back(orig_init.str.at(k * 2 + j));
init.update_intval();
dram->params[id_INIT] = init;
}
}
}