himbaechel/xilinx: don't override driven ADDR*L15 on cascaded RAMB36E1

pack_bram unconditionally disconnected ADDRARDADDRL15/ADDRBWRADDRL15
on every RAMB36E1 and tied them to VCC. Tying high is correct for
non-cascaded modes, but in a depth-cascaded pair (RAM_EXTENSION_A/B =
LOWER/UPPER) these pins carry the address MSB that selects between
the two 32K halves, and the port multixform has already wired
ADDRARDADDR[15] onto them. Overriding that with VCC pinned both reads
and writes to the upper half: address bit 15 was simply ignored.

Keep the tie as a fallback for undriven pins only.

Hardware-verified on xc7a100t: a 128K ROM built from cascaded
RAMB36E1 pairs passes a full 32/32 content fingerprint check that
failed before this change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Joris van Zwieten 2026-07-30 15:47:34 +02:00
parent 1686fe7cb3
commit a652a752de
1 changed files with 8 additions and 3 deletions

View File

@ -754,14 +754,19 @@ void XC7Packer::pack_bram()
ci->connectPort(p, ctx->nets[ctx->id("$PACKER_VCC_NET")].get());
}
} else if (ci->type == id_RAMB36E1_RAMB36E1) {
// ADDRARDADDRL15/ADDRBWRADDRL15 must be tied high in non-cascaded
// modes, but in a depth-cascaded pair (RAM_EXTENSION_A/B = LOWER/
// UPPER) they carry the address MSB that selects the half; the
// multixform has already wired ADDRARDADDR[15] onto them, and
// overriding that with VCC pins both reads and writes to the upper
// 32K half. Only tie when not driven.
for (auto p : {id_ADDRARDADDRL15, id_ADDRBWRADDRL15}) {
if (!ci->ports.count(p)) {
ci->ports[p].name = p;
ci->ports[p].type = PORT_IN;
} else {
ci->disconnectPort(p);
}
ci->connectPort(p, ctx->nets[ctx->id("$PACKER_VCC_NET")].get());
if (ci->getPort(p) == nullptr)
ci->connectPort(p, ctx->nets[ctx->id("$PACKER_VCC_NET")].get());
}
if (int_or_default(ci->params, id_WRITE_WIDTH_A, 0) == 1) {
ci->disconnectPort(id_DIADI1);