feat: integrate flash #1 (neural-network data) RTL into V2 top-level
Closes the flash #1 RTL gap flagged in DEC-0041: real, unmodified V1 subsystem (flash_slot_manager.v/flash_copy_engine.v/spi_flash_master.v/ crc32.v) now instantiated in fpga_neural_v2_top.v, bridged to the AR memory bus via a new flash_mem_adapter.v (byte<->word, matches nms_memory_manager_stream_wide.v's own real masking convention), and commandable over SPI via a new spi_host_bridge.v opcode (OP_FLASH_CMD, 0x30) using the same byte-counting idiom as OP_WRITE_JOB. Real balls now in the LPF: flash_sclk=B2, flash_mosi=E2, flash_miso=F2, flash_cs_n=F3. New tb_flash_integration_smoke.v: real SPI-triggered OP_FLASH_READ_BLOCK verified bit-exact (64/64 bytes) against a real V1 flash_model.v instance, through the new adapter and the widened (2->3 port) host-arb arbiter; WRITE_JOB regression confirms the new 3rd port doesn't disturb existing traffic. Full existing regression re-run clean: D-Stress N=4/ N=8 (bit-exact + data_ready PASS), board-level smoke test (11/11), isolated spi_host_bridge test (18/18). Honest, disclosed finding: a full 8-seed P&R re-verification shows N_SLOTS=4 @ 64MHz regressed from 8/8 to 3/8 PASS (worst 60.18MHz). Root cause traced via the real critical-path report: the SAME pre-existing arbiter-to-sdram-backend bottleneck already documented all session, made worse by flash's added die-area placement pressure -- not a new path through the flash logic itself. N_SLOTS=8 essentially unchanged (6/8, was 5/8). See decisions.log DEC-0042 for full detail and open decision points. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
This commit is contained in:
@@ -2402,3 +2402,101 @@ STATUS: two-flash architecture and FPGA_DATA_READY CLOSED and
|
||||
verified (bit-exact + real placement). Flash #1's RTL port
|
||||
(`flash_copy_engine.v` integration into V2's top-level) remains a
|
||||
real, separate, OPEN task -- ball positions reserved, not wired.
|
||||
|
||||
DEC-0042 -- Flash #1 RTL integration completed; real timing regression
|
||||
found and disclosed (N_SLOTS=4 @ 64MHz 8/8 -> 3/8 PASS)
|
||||
|
||||
DATE: 2026-09-07
|
||||
CONTEXT: closing DEC-0041's own remaining open item -- flash #1
|
||||
(neural-network weights/graph data) had real ball reservations
|
||||
(B2/E2/F2/F3) but no RTL port. User asked for this to be completed,
|
||||
then a meticulous full-stack verification (RTL, tests, timing).
|
||||
|
||||
INTEGRATION (real, functional, verified):
|
||||
- Instantiated the real, unmodified V1 subsystem
|
||||
(`flash_slot_manager.v`, which owns `flash_copy_engine.v`, which
|
||||
owns `spi_flash_master.v`; `crc32.v` used internally) directly in
|
||||
`fpga_neural_v2_top.v` -- zero modifications to any of these four
|
||||
files, matching this project's own established "reuse, don't
|
||||
re-derive" precedent for verified V1 modules.
|
||||
- New file `hardware/v2/rtl/flash_mem_adapter.v`: bridges flash_slot_
|
||||
manager's real "Port D" (PSRAM-style byte interface: d_req/d_wr/
|
||||
d_addr/d_wdata/d_rdata/d_ready, 8-bit signed) to the AR-port
|
||||
convention (word address, 16-bit data, lb_n/ub_n byte-lane masking)
|
||||
used by `slot_mem_arbiter.v` -- byte<->word convention matches
|
||||
`nms_memory_manager_stream_wide.v`'s own real, already-verified
|
||||
result-writeback logic exactly (not invented): word_addr =
|
||||
byte_addr[ADDR_WIDTH-1:1], byte_addr[0] selects lower/upper lane,
|
||||
write data replicated to both halves with the mask picking which
|
||||
the controller actually writes.
|
||||
- `slot_mem_arbiter.v`'s host-arb instance (the "AR level 2" already
|
||||
combining compute-side traffic and the SPI host's raw memory port)
|
||||
widened from N_PORTS=2 to N_PORTS=3, flash at the new highest index
|
||||
(confirmed lowest-priority in this arbiter's real "lowest-index-
|
||||
wins" scheme -- matches V1's own "Port D, lowest priority"
|
||||
convention for this exact traffic class).
|
||||
- `spi_host_bridge.v`: new real opcode `OP_FLASH_CMD` (0x30), 19
|
||||
payload bytes (op_code/slot_id/new_offset/new_length/new_type/
|
||||
ext_psram_addr/ext_length/raw_flash_addr), built with the same
|
||||
byte-counting state-machine idiom already used by OP_WRITE_JOB
|
||||
(including the same cs_fell mid-transaction protection). STATUS
|
||||
byte (0x20) extended: bit3=flash_busy, bit4=flash_done (sticky),
|
||||
bit5=flash_err (sticky), both cleared by the next OP_FLASH_CMD.
|
||||
Catalog readback (cat_read_sel/cat_out_*) deliberately NOT wired to
|
||||
SPI in this pass -- diagnostic-only, not required for the core
|
||||
LOAD/SAVE/raw-block functionality; a real, disclosed, separate
|
||||
follow-up.
|
||||
- Real balls (already reserved in DEC-0041, now actually in the LPF):
|
||||
flash_sclk=B2, flash_mosi=E2, flash_miso=F2, flash_cs_n=F3.
|
||||
|
||||
VERIFICATION (real, not assumed):
|
||||
- New testbench `tb_flash_integration_smoke.v`: real SPI OP_FLASH_CMD
|
||||
transaction (OP_FLASH_READ_BLOCK) drives flash_slot_manager through
|
||||
the new adapter and the new 3rd arbiter port, into the real
|
||||
sdram_unified_backend/sdram_controller/AS4C32M16SB-7BIN chain,
|
||||
against a real V1 `flash_model.v` instance preloaded with a known
|
||||
64-byte pattern -- PASS, 64/64 bytes bit-exact. A WRITE_JOB
|
||||
regression check in the same file confirms the pre-existing job-
|
||||
registration path still completes without hanging with the new 3rd
|
||||
arbiter port present -- PASS.
|
||||
- Full existing regression re-run, zero functional regressions:
|
||||
D-Stress N_SLOTS=4 (49927 cycles) and N_SLOTS=8 (49909 cycles), both
|
||||
256/256 bit-exact vs golden, both `data_ready` PASS; the real board-
|
||||
level smoke test `tb_fpga_neural_v2_top_smoke.v` (11/11 PASS); the
|
||||
isolated `tb_spi_host_bridge.v` (18/18 PASS, confirming the new
|
||||
OP_FLASH_CMD opcode and widened STATUS byte did not disturb the
|
||||
existing WRITE_JOB/WRITE_MEM/READ_MEM/STATUS behavior).
|
||||
- Real synthesis (Yosys, 0 errors, 0 new warnings vs. the pre-flash
|
||||
baseline -- confirmed by exact warning-count diff) and real
|
||||
nextpnr-ecp5 placement (0 errors, all 4 new flash balls placed
|
||||
correctly at their reserved sites).
|
||||
|
||||
HONEST TIMING FINDING (disclosed, not hidden): a full, real 8-seed
|
||||
nextpnr-ecp5 P&R matrix with flash #1 now included shows a REAL
|
||||
regression at the previously rock-solid N_SLOTS=4 @ 64MHz production
|
||||
baseline:
|
||||
N_SLOTS=4 @ 64MHz: 8/8 -> **3/8 PASS** (seeds 0,2,5 PASS; worst
|
||||
60.18MHz seed3, best 67.34MHz seed2).
|
||||
N_SLOTS=8 @ 64MHz: was 5/8, now 6/8 PASS (seeds 1,3,4,5,6,7 PASS;
|
||||
worst 61.09MHz seed0, best 67.71MHz seed4) -- essentially
|
||||
unchanged/slightly better, within seed-to-seed noise.
|
||||
ROOT CAUSE (real, traced via the actual critical-path report, not
|
||||
guessed): the worst N=4 seed's critical path is the SAME pre-existing
|
||||
class already documented all session (`u_arbiter_wide.m_addr` ->
|
||||
`u_sdram_backend.state`, 84% routing-dominated) -- NOT a new path
|
||||
through the flash subsystem itself. Flash #1's real logic footprint
|
||||
(flash_slot_manager + flash_copy_engine + spi_flash_master + crc32,
|
||||
an entire secondary state-machine-heavy subsystem) measurably
|
||||
increases die utilization and placement pressure, degrading this
|
||||
SAME pre-existing bottleneck's achievable placement -- the identical
|
||||
mechanism already observed when N_SLOTS scaled from 4 to 8 earlier
|
||||
this session, now triggered by added area rather than added N_SLOTS.
|
||||
STATUS: flash #1 integration is functionally CLOSED and verified
|
||||
(bit-exact). N_SLOTS=4 @ 64MHz's own timing closure is now OPEN,
|
||||
regressed by this integration -- explicitly NOT silently declared
|
||||
still-closed. This is a real, disclosed trade-off requiring a
|
||||
decision: accept and pursue a further optimization pass (same class
|
||||
of fix as ERR-0027/ERR-0028/ERR-0029), constrain placement to isolate
|
||||
flash logic from the sensitive region, or defer/gate flash #1 behind
|
||||
a build-time option that keeps the pre-flash timing profile available.
|
||||
Not decided in this pass -- flagged for the user.
|
||||
|
||||
Reference in New Issue
Block a user