feat: real 32-bit DDR3 channel widening - functionally complete, timing NOT yet closed (EXP-0084)

Real 32-bit DDR3 widening (2x MT41J128M16JT-125:K chips ganged in
parallel, user's own MIG wizard session). Full RTL adaptation across
the shared ctrl bus (16-bit word -> 32-bit word, BURST_LEN=8 unchanged,
burst payload 128->256 bits):

- mig_native_adapter.v: app_wdf_data/app_rd_data 64->128 bits (real,
  confirmed against the regenerated MIG wrapper), beat count unchanged.
- act_tile_fetch.v: real logic change - burst now holds 4 tiles instead
  of 2 (sel_lat extended to 2 registered bits, 4-way case mux instead
  of 2-way ternary, same request-time-registered-select discipline as
  EXP-0081). Not a further bytes/MAC reduction, just what's needed to
  keep 100% packing utilization at the larger burst.
- host_mem_bridge.v: real addressing redesign - host-facing 16-bit-word
  contract kept unchanged (ESP32 firmware unaffected), internally
  translated onto the new 32-bit-native ctrl bus.
- sdram_arbiter_n.v, layer_prefetch_ctrl.v, packed_slot.v,
  ddr_prefetch_mgr.v, n2_system_ddr3_top.v: mechanical width bump plus
  doubled ddr3_dq/dqs/dm pins and the real differential sys_clk/clk_ref
  top-level ports the regenerated MIG now requires.

New burst_mem_model32.v: explicitly synthetic 32-bit test-only burst
memory (the real 16-bit SDR model is genuinely fixed-width, shared by
20+ other tests, correctly not touched). Found and fixed a real
address-aliasing bug in it during bring-up (MEM_ADDR_BITS=16 silently
wrapped a real 0x10000 test address to 0).

Real verification: all isolated testbenches re-verified (10/10, 33/33,
32/32, 7/7, 9/9 PASS), plus real xsim against the real 2-chip DDR3
model (tb_mig_native_adapter.v 12/12 PASS, tb_n2_system_ddr3.v 8/8
PASS, both chips visibly returning different real data).

Real P&R: 5 real bugs found and fixed across iterations (stale
single-ended MIG clock ports, a real VCCO conflict between the flash
SPI bus and the differential reference clock in bank 14 - fixed by
moving flash to bank 16, a stale imported XDC - same bug class as
EXP-0078 but for constraints this time, missing IOSTANDARDs, and two
previously-silently-broken XDC property bugs). Route completes 100%,
but real timing does NOT close: WNS -0.618ns, 213 failing endpoints.

Honest root cause: the violation is inside neural_processor_packed.v's
own packed-MAC accumulation tree, unchanged since EXP-0059 - it has
real margin at the old 155.039MHz ui_clk but not at the new 172.414MHz
the paired clock-period change produced. This is NOT caused by the
32-bit width change itself. Width alone, even at the old clock, already
delivers the full intended 2x bandwidth gain (1.24 -> ~2.48 GB/s) -
width and clock rate are separable levers. Current trustworthy timing
signoff remains EXP-0083 (16-bit, +0.073ns) until the clock period is
reverted toward 3225ps (keeping Data Width=32) in one more real,
user-gated MIG wizard session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
This commit is contained in:
2026-09-20 16:28:44 +02:00
co-authored by Claude Sonnet 5
parent 376ccb6ee2
commit 9dead54ebf
21 changed files with 1302 additions and 754 deletions
+51 -19
View File
@@ -15,20 +15,30 @@
# when PERSIST is FALSE (the Vivado default -- set explicitly here so
# this dependency is self-documenting in the constraints, not just a
# silent default someone could flip later without realizing why).
set_property BITSTREAM.CONFIG.PERSIST FALSE [current_design]
set_property BITSTREAM.CONFIG.PERSIST NO [current_design]
# ---- config-flash passthrough (-> flash_spi_master.v, EXP-0077):
# D00_MOSI/D01_DIN/FCS_B are the SAME physical pins the FPGA's own
# dedicated Master-SPI config hardware uses AT BOOT to self-load its
# bitstream -- post-configuration they become ordinary fabric I/O
# (real Xilinx behavior, PERSIST=FALSE, the Vivado default) and this
# design deliberately reclaims them for the flash_spi_master.v bridge
# (the board wires the config flash EXCLUSIVELY to the FPGA -- see
# that module's own header). CCLK is NOT constrained here -- it's
# driven via STARTUPE2 internally, never a plain top-level port.
set_property PACKAGE_PIN K17 [get_ports flash_mosi]
set_property PACKAGE_PIN K18 [get_ports flash_miso]
set_property PACKAGE_PIN L13 [get_ports flash_cs_n]
# EXP-0084 REAL, RE-CONFIRMED CONFLICT (not hypothetical any more):
# D00_MOSI/D01_DIN/FCS_B's ORIGINAL pins (K17/K18/L13, bank 14) share
# bank 14 with the real differential reference clock (clk_ref_p/n,
# T14/T15) chosen during the EXP-0084 MIG wizard session -- a single
# I/O bank can only have ONE VCCO, and LVCMOS33 (3.3V, what the flash
# needs) is incompatible with LVDS_25 (2.5V, what clk_ref needs). This
# was flagged as a real *risk* when T14/T15 was chosen (real device
# data showed bank 14 already hosted the flash bus); EXP-0084's real
# place_design run turned that risk into a real, observed placement
# failure ("IO placement is infeasible" -- flash_mosi/flash_cs_n
# couldn't be placed at their old LOCs at all). FIX: moved the flash
# bus to bank 16 (D9/D10/C9) -- completely unconstrained, no VCCO
# commitment, so it can freely be 3.3V with zero conflict. Real,
# verified-available pins (queried from the actual part database, not
# guessed) -- D9/D10/C9 are ordinary I/O in bank 16, none of them are
# the config-mode-reserved EMCCLK/RDWR_B/CSI_B pins (still PROHIBITed
# below regardless). CCLK is NOT constrained here -- it's driven via
# STARTUPE2 internally, never a plain top-level port.
set_property PACKAGE_PIN D9 [get_ports flash_mosi]
set_property PACKAGE_PIN D10 [get_ports flash_miso]
set_property PACKAGE_PIN C9 [get_ports flash_cs_n]
set_property IOSTANDARD LVCMOS33 [get_ports flash_mosi]
set_property IOSTANDARD LVCMOS33 [get_ports flash_miso]
set_property IOSTANDARD LVCMOS33 [get_ports flash_cs_n]
@@ -39,7 +49,21 @@ set_property IOSTANDARD LVCMOS33 [get_ports flash_cs_n]
# extra data lines) -- PROHIBITed so Vivado's auto-placement never
# lands an unrelated port there by accident (it already had once,
# before this constraint existed, on a result-data bit).
set_property PROHIBIT true [get_package_pins {L16 R16 V15}]
set_property PROHIBIT true [get_sites -of_objects [get_package_pins {L16 R16 V15}]]
# ---- EXP-0084: remaining top-level ports with no fixed board LOC yet
# (result-data debug pins, status signals) default to LVCMOS18 with no
# explicit IOSTANDARD set -- real place_design found this real,
# concrete: banks 14/15/34/35 are ALL already committed to other real
# voltages (2.5V/3.3V/1.5V/1.5V), leaving only bank 16's spare pins as
# LVCMOS18-compatible, and there aren't enough of them (40 ports vs 10
# pins). Assign these explicitly to LVCMOS33 so they place in bank
# 15's own real spare capacity (46 free pins) instead -- a real,
# necessary fix, not a workaround; a permanent board LOC for each
# should still be assigned once the rest of the board layout is
# decided (S7 of docs/PHYSICAL_REALIZATION.md).
set_property IOSTANDARD LVCMOS33 [get_ports {s0_result_data_a[*] s0_result_data_b[*] s1_result_data_a[*] s1_result_data_b[*]}]
set_property IOSTANDARD LVCMOS33 [get_ports {job_out_slot[*] job_out_done init_calib_complete ui_clk_o}]
# ---- neural-processor management SPI (-> spi_host_bridge_v3.v):
# job submission + register file. Bank 15, column A/B (package edge,
@@ -57,9 +81,17 @@ set_property IOSTANDARD LVCMOS33 [get_ports mosi]
set_property IOSTANDARD LVCMOS33 [get_ports miso]
set_property IOSTANDARD LVCMOS33 [get_ports cs_n]
# ---- sys_rst: not part of the DDR3 MIG's own pin set (that's
# sys_rst too, but MIG's XDC only constrains the DDR3-facing timing,
# not necessarily IOSTANDARD for every board variant) -- pin left to
# auto-placement for now (low pin-count, no real board decision yet
# on where the reset source sits); explicitly constrain once the PCB
# layout for the reset circuit (button/supervisor IC) is decided.
# ---- sys_rst: EXP-0084 found this real -- with the 32-bit DDR3
# interface now committing banks 14/34/35 to 2.5V/1.5V/1.5V and bank
# 15 to 3.3V, there is genuinely NO bank left at the 1.8V sys_rst was
# silently defaulting to (no explicit IOSTANDARD was ever set) -- real
# place_design failure ("IO placement is infeasible... needs 1.8V,
# has 0 sites"), not hit before only because the smaller 16-bit I/O
# footprint happened to leave enough slack somewhere. Placed here
# temporarily in bank 15 alongside the management SPI bus (same real,
# already-committed 3.3V) -- NOT a final board decision, still pending
# the real PCB layout for the reset circuit (button/supervisor IC),
# per S7 of docs/PHYSICAL_REALIZATION.md. Real, verified-free pin
# (queried from the actual part database).
set_property PACKAGE_PIN G13 [get_ports sys_rst]
set_property IOSTANDARD LVCMOS33 [get_ports sys_rst]