feat: SDRAM 8MB->64MB upgrade (AS4C32M16SB-7BIN) + N_SLOTS=8 support

Memory upgrade, at the user's own explicit request: Alliance Memory
AS4C4M16SA-6TIN (64Mbit/8MB) -> AS4C32M16SB-7BIN (512Mbit/64MB, 54-ball
TFBGA), the largest same-family SDR SDRAM Alliance Memory offers.
Real-datasheet-driven (whole AS4C4M16SA/AS4C8M16SA/AS4C16M16SA/
AS4C32M16SA family investigated): 13 row bits (was 12, one new FPGA
pin sdram_a[12]/ball F1), 10 column bits (was 8), real -7-grade AC
timing (tRCD/tRP improved to 15ns, tREFI halved to 7.8us for the
doubled row count). sdram_controller.v and sdram_model.v gained real
ROW_BITS/COL_BITS/BANK_BITS parameters (was hardcoded 12/8/2).

ADDR_WIDTH widened 23->26 bits across the live instantiation tree.
This required a real SPI protocol change (spi_host_bridge.v): a 26-bit
byte address no longer fits in 3 bytes -- every address field widened
3->4 bytes (WRITE_JOB 15->18 payload bytes, WRITE_MEM/READ_MEM header
5->6 bytes).

Found and fixed two real timing regressions via nextpnr-ecp5 P&R
(not assumed): neural_director.v's own runtime-indexed demux write
(ERR-0027, was silently synthesizing an extra MULT18X18D) and
nms_activation_fill_ctrl_v3.v's own linear N_SLOTS-wide max-scan
(ERR-0028, became dominant at N_SLOTS=8) -- both replaced with
constant-indexed/tree-based equivalents, bit-exact same behavior,
confirmed via full D-Stress N=2/4/8 regression (identical cycle
counts). N_SLOTS=4 now fully closes timing at 64MHz (8/8 seeds);
N_SLOTS=8 significantly improved but not yet fully reliable (5/8
seeds) -- honestly disclosed, not claimed complete.

Full regression re-verified: sdram_controller (461/461, 18 configs),
tb_sdram_boundary (21/21), D-Stress N=2/4/8 (bit-exact), spi_host_bridge
(18/18), board-level SPI smoke test (11/11), unified backend (40/40).

See hardware/v2/docs/MEMORY_UPGRADE_64MB_N8.md for the full
investigation, and errors.log/decisions.log (ERR-0027, ERR-0028,
DEC-0039) for the complete root-cause writeups.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
This commit is contained in:
2026-09-07 00:20:53 +02:00
co-authored by Claude Sonnet 5
parent 9b5d1055b8
commit 8d83d97bde
21 changed files with 558 additions and 295 deletions
+12 -9
View File
@@ -20,7 +20,7 @@
module tb_spi_host_bridge;
localparam ADDR_WIDTH = 23;
localparam ADDR_WIDTH = 26; // AS4C32M16SA memory upgrade: 25-bit word address + 1 byte-select bit
localparam N_NODES = 16;
localparam MAX_DEPS = 4;
localparam NODEW = $clog2(N_NODES);
@@ -135,15 +135,18 @@ module tb_spi_host_bridge;
spi_byte(8'h02, rxb); // required=2
spi_byte(8'hAB, rxb); // producer_ids[15:8]
spi_byte(8'hCD, rxb); // producer_ids[7:0]
spi_byte(8'h00, rxb); // x_base[22:16]
spi_byte(8'h00, rxb); // x_base[25:24]
spi_byte(8'h00, rxb); // x_base[23:16]
spi_byte(8'h10, rxb); // x_base[15:8]
spi_byte(8'h00, rxb); // x_base[7:0] -> x_base=0x001000
spi_byte(8'h00, rxb); // w_base[22:16]
spi_byte(8'h00, rxb); // w_base[25:24]
spi_byte(8'h00, rxb); // w_base[23:16]
spi_byte(8'h20, rxb); // w_base[15:8]
spi_byte(8'h00, rxb); // w_base[7:0] -> w_base=0x002000
spi_byte(8'h00, rxb); // n_tiles[15:8]
spi_byte(8'h04, rxb); // n_tiles[7:0] -> n_tiles=4
spi_byte(8'h00, rxb); // result_addr[22:16]
spi_byte(8'h00, rxb); // result_addr[25:24]
spi_byte(8'h00, rxb); // result_addr[23:16]
spi_byte(8'h30, rxb); // result_addr[15:8]
spi_byte(8'h00, rxb); // result_addr[7:0] -> result_addr=0x003000
@@ -154,10 +157,10 @@ module tb_spi_host_bridge;
check(reg_node_id == 5, "A: reg_node_id");
check(reg_required == 2, "A: reg_required");
check(reg_producer_ids == 16'hABCD, "A: reg_producer_ids");
check(reg_x_base == 23'h001000, "A: reg_x_base");
check(reg_w_base == 23'h002000, "A: reg_w_base");
check(reg_x_base == 26'h001000, "A: reg_x_base");
check(reg_w_base == 26'h002000, "A: reg_w_base");
check(reg_n_tiles == 16'h0004, "A: reg_n_tiles");
check(reg_result_addr == 23'h003000, "A: reg_result_addr");
check(reg_result_addr == 26'h003000, "A: reg_result_addr");
repeat (3) begin
@(posedge clk);
@@ -182,7 +185,7 @@ module tb_spi_host_bridge;
// ================= Test C: WRITE_MEM, single word ===========
cs_n = 0; #20;
spi_byte(8'h01, rxb); // opcode WRITE_MEM
spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); spi_byte(8'h55, rxb); // addr=0x000055
spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); spi_byte(8'h55, rxb); // addr=0x000055
spi_byte(8'h00, rxb); spi_byte(8'h01, rxb); // len_words=1
spi_byte(8'h12, rxb); spi_byte(8'h34, rxb); // data=0x1234
// hold CS low, idle SCLK, while the memory model latency elapses
@@ -193,7 +196,7 @@ module tb_spi_host_bridge;
// ================= Test D: READ_MEM, single word =============
cs_n = 0; #20;
spi_byte(8'h02, rxb); // opcode READ_MEM
spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); spi_byte(8'h55, rxb); // addr=0x000055
spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); spi_byte(8'h00, rxb); spi_byte(8'h55, rxb); // addr=0x000055
spi_byte(8'h00, rxb); spi_byte(8'h01, rxb); // len_words=1
#200; // idle SCLK while the read latency elapses
spi_byte(8'h00, rxb); exp_addr = rxb; // MSB