feat: config-flash passthrough bridge via STARTUPE2, real board-exclusive flash access (EXP-0077)

Implements the user's board architecture: config flash wired
exclusively to the FPGA, host (ESP32) reaches it only through the
FPGA. flash_spi_master.v is a plain byte-wide SPI master using
STARTUPE2 to reclaim CCLK after configuration (the real, Xilinx-
documented "indirect SPI flash programming" technique, UG470 p94-96).
New opcode 0x40 FLASH_XFER in spi_host_bridge_v3.v relays bytes
byte-for-byte between host and the physical flash bus -- the host
decides the exact SPI NOR command sequence (verified against the real
W25Q32JV datasheet), this RTL knows nothing about flash semantics.

Found and fixed two real bugs during verification: a byte-assembly
off-by-one in flash_spi_master.v, and a genuine protocol-latency bug
in the FLASH_XFER opcode's response timing (needed 2 trailing margin
bytes, not 1 -- the internal flash transfer doesn't start until the
triggering byte finishes, so 1 byte of margin isn't enough). 39/39
tests pass end to end (host SPI -> bridge -> flash_spi_master ->
behavioral flash model).

Wired into n2_system_ddr3_top.v with real pin constraints (flash_mosi
=K17/flash_miso=K18/flash_cs_n=L13, the same pins reserved-but-unused
in EXP-0075) and BITSTREAM.CONFIG.PERSIST=FALSE made explicit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
This commit is contained in:
2026-09-19 21:45:17 +02:00
co-authored by Claude Sonnet 5
parent fd6cc7a2fa
commit a4c080da83
7 changed files with 727 additions and 10 deletions
+30 -9
View File
@@ -10,15 +10,36 @@
# top_routed.dcp), not guessed from a datasheet table.
# ============================================================
# ---- reserve the dedicated Master-SPI configuration-flash pins
# (bank 14) for a FUTURE external config flash -- prevents Vivado's
# auto-placement from ever landing one of THIS design's own ports on
# them (it already had, by accident, before this constraint existed:
# job_out_done on L13/FCS_B, a result bit on R16/RDWR_B, another on
# V15/CSI_B). These pins are not driven by this design at all; they
# stay free for the flash CCLK/D00_MOSI/D01_DIN/FCS_B/EMCCLK/RDWR_B/
# CSI_B wiring described in the accompanying configuration writeup.
set_property PROHIBIT true [get_package_pins {K17 K18 L13 L16 R16 V15}]
# ---- required for flash_spi_master.v to work at all: D00_MOSI/
# D01_DIN/FCS_B only become ordinary fabric I/O post-configuration
# 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]
# ---- 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]
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]
# ---- EMCCLK/RDWR_B/CSI_B (bank 14): not used by this design at all
# (this project's Master SPI config mode never needed them -- they're
# only relevant to modes this board doesn't use, e.g. BPI or Quad-SPI
# 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}]
# ---- neural-processor management SPI (-> spi_host_bridge_v3.v):
# job submission + register file. Bank 15, column A/B (package edge,