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
Found while helping verify the user's own schematic: clk_sys (the PLL-
generated 64MHz system clock) was purely internal to
fpga_neural_v2_top.v -- never reached a physical output pin. The real
external SDRAM chip cannot function without its own CLK input driven
from the board; this was missing from every prior P&R run this
session, none of which ever routed a real clock to the SDRAM interface.
Added `sdram_clk` output port (driven directly by clk_sys), assigned
to J4 (bank 6, GR_PCLK6_0 -- a real clock-capable ball, confirmed free
via Trellis iodb.json). Verified via real synthesis (0 errors) and
nextpnr-ecp5 place&route: the pad-forwarded clock merges with the
existing internal clock net (as expected, both are the same clk_sys
signal), achieving 66.61 MHz post-route -- PASS at the 64 MHz target
(the pre-route estimate of 49.73 MHz was a placement-only pessimistic
number, superseded by the real post-route result). Smoke test
re-verified (tb_fpga_neural_v2_top_smoke.v, 11/11 PASS).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
Establishes the real ESP32<->ECP5 programming architecture: flash #1
(neural-network data, existing V1 subsystem, ball reserved not yet
wired into V2) stays separate from flash #2 (boot bitstream, MSPI
auto-boot, CFG[2:0]=[0,1,0]); ESP32 talks JTAG only (bit-banged, no
hardware JTAG-master peripheral on S3/C6), updating flash #2 through
the ECP5's own internal sysCONFIG-to-SPI bridge, never driving the
flash pins directly -- zero bus contention, confirmed against the real
Lattice hardware checklist and sysCONFIG user guide.
Adds real, verified ball assignments (official Lattice CABGA381 CSV +
Project Trellis iodb.json) for JTAG, PROGRAMN/INITN/DONE, CFG[2:0],
and the MSPI dedicated pins -- all written to docs/pinouts.md.
Implements FPGA_DATA_READY as real RTL: a system-idle detector
(dependency_manager's any_pending OR neural_director's !queue_empty OR
any active slot), sticky on the busy->idle edge, self-clearing on new
work -- not a per-neuron completion pulse, which was confirmed too
fine-grained. Bit-exact regression re-verified at N_SLOTS=4 and 8
(zero cycle-count change), new explicit data_ready assertion check
added to the D-Stress testbench (PASS both configs), and a fresh
Yosys+nextpnr-ecp5 placement check (0 errors, data_ready placed at G3).
Also fixes a real, independently-found bug while editing an adjacent
file: nms_neural_multiprocessor_sdram_unified.v's own sdram_a port was
still [11:0] (12 bits), stale from before the 64MB/13-bit memory
upgrade. Not exercised by the real board-level top (which wires SDRAM
directly, bypassing this wrapper) but WAS silently truncating A12 in
every D-Stress simulation this session, including today's earlier
ERR-0029 verification runs. Assessed impact: all D-Stress test
addresses used this session decode to rows under 4096 (bit 12 never
actually needed), so no false-positive PASS is believed to have
resulted -- but the full 64MB space was never actually exercised
through this wrapper. Fixed; re-verified bit-exact with identical
cycle counts.
See decisions.log DEC-0041 for full detail.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
Replace the serial "last-match-wins" priority-scan hit-index encoder
with a flat one-hot compare + single-level priority encode, breaking
the serially-dependent PFUMX/OFX cascade real P&R showed dominating
the N_SLOTS=8 @ 64MHz critical path (55.84MHz worst, 4/8 seeds PASS).
Real nextpnr-ecp5 re-verification (32-run matrix, 4 configs x 8 seeds):
N_SLOTS=8 @ 64MHz improves to 5/8 PASS (worst 60.12MHz, up from
55.84MHz). N_SLOTS=4 @ 64MHz stays 8/8 PASS but with reduced worst-case
margin (WNS +0.605ns, down from +2.143ns) as the critical path
relocates to a different, previously-second-worst path in the same
module -- a real, disclosed trade-off, not hidden. 80MHz remains NO-GO
at both processor counts (re-confirmed on the fixed RTL).
Bit-exact, zero functional regression: isolated
tb_sdram_unified_backend.v (40/40) and full D-Stress N=4/N=8 (both
256/256 neurons bit-exact vs golden model).
See errors.log ERR-0029 and decisions.log DEC-0040 for full root-cause
writeup and MEMORY_UPGRADE_64MB_N8.md section 10 for the complete
measured data set and AS4C32M16SB-7BIN pinout tables.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
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
Real Alliance Memory AS4C4M16SA-6TIN datasheet (Rev 5.0, Table 17)
specifies tMRD as a fixed 2-tCK cycle count, not an ns value.
sdram_controller.v modeled it via ns_to_cycles(12), which rounded to
2 cycles by coincidence at every previously-tested frequency
(100/133/166MHz) but rounds to only 1 cycle at the real 64MHz board
target -- an under-provisioned one-time init sequence. Fixed by
hardcoding T_MRD=2, matching how CAS_LATENCY is already modeled.
Verified zero regression: full 9-config legacy sweep + a new
dedicated 64MHz config (461/461 PASS each), N=2/N=4 D-Stress
(identical cycle counts), board-level smoke test (11/11 PASS).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
Root-causes and fixes the real, disclosed defect left open at the end
of the previous STEP20 commit: the board-level SPI host interface
produced wrong compute results when jobs were dispatched with
realistic (widely time-separated) pacing, even though job registration
itself was already confirmed correct at the dependency_manager
handshake.
Root cause: nms_weight_packed.v and nms_activation_replicated.v both
used a REGISTERED SRAM read (rd_data_reg <= mem[addr], one full clock
of latency), but nms_memory_manager_stream_wide.v's own read-ahead
pipeline (its `rd_pending` bit) is designed around a COMBINATIONAL
read -- a request issued this cycle produces data already valid to
capture the very next cycle. A busy, multi-tile job (e.g. the STEP19
D-Stress regression, 16 tiles/neuron) never exposes the mismatch,
since its own weight/activation prefetch always runs far enough ahead
that any given tile has been sitting stable in the SRAM for many
cycles by the time it's actually consumed. An uncontested single-tile
job has zero such margin: its one tile's read fires on the exact edge
the data nominally becomes ready, landing squarely on the missing
cycle and permanently latching stale/zero data.
Fixed by making both SRAMs' reads combinational, with an explicit
same-cycle fill/read address-match bypass for the one hazard a plain
combinational read alone would still miss. No FSM, arbiter, or SDRAM
controller logic was touched.
Verified (Verilator, per this project's own standing DEC-0004
protocol):
- tb_fpga_neural_v2_top_smoke.v: 11/11 PASS -- single job, back-to-back
jobs, a realistic ~85us-gap job pair, and a parametric sweep of
inter-job gaps (100ns/5000ns/50000ns).
- STEP19 D-Stress N=2: 49788 cycles, 256/256 bit-exact -- identical
cycle count to before this fix (zero regression).
- STEP19 D-Stress N=4: 49771 cycles, 256/256 bit-exact -- identical
cycle count to before this fix (zero regression).
- tb_sdram_unified_backend.v (40/40) and tb_spi_host_bridge.v (18/18)
reconfirmed unaffected.
The physical SPI host interface is now verified correct end-to-end.
Real synthesis/P&R of the board-level top (fpga_neural_v2_top.v) is
the deliberate next step, not yet performed this round.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
STEP20 work toward the V2 hardware release gate. Adds real new RTL
implementing the three pieces the previous freeze (V2.0.0) explicitly
left open, plus real, disclosed verification findings. Does NOT
declare hardware release complete -- see below.
New RTL:
- spi_host_bridge.v: real SPI slave protocol engine (WRITE_JOB/
WRITE_MEM/READ_MEM/STATUS/RESET opcodes), replacing the 110-pin
reg_* testbench bus as the intended physical host interface.
Isolated regression 18/18 PASS (tb_spi_host_bridge.v); two real
MISO-timing bugs found and fixed during its own development (see
the module's header for the root-cause writeup).
- ecp5_pll_sys_clk.v: real, tool-generated (Project Trellis ecppll)
EHXPLLL wrapper, 16MHz oscillator -> 64MHz system clock, with a
declared (not fabricated) simulation-only PLL bypass.
- reset_sync.v: standard async-assert/sync-deassert reset bridge
gating on external POR and PLL lock.
- fpga_neural_v2_top.v: board-level top wiring the above around the
STEP19 compute+memory design's own already-frozen submodules
(zero modification to neural_processor.v, dependency_manager.v,
sdram_unified_backend.v, or any other previously-frozen file).
Real findings from this step's own re-verification (both logged in
full in hardware/v2/logs/errors.log):
- ERR-0024: the current Icarus Verilog v13.0 install (updated since
the last freeze) gives WRONG bit-exact results for the
already-committed STEP19 regression. Cross-checked against
Verilator per this project's own standing protocol (DEC-0004) --
the STEP19 baseline (single SDRAM, N=2/N=4, raw reg_* interface) IS
bit-exact correct, reconfirmed today, matching the historical cycle
counts exactly. Two provably-zero-behavior-change declaration-order
fixes were required just to get the current toolchain to elaborate
the already-shipped STEP19 files at all.
- ERR-0025: a real SPI-bridge protocol race (fixed) plus a SEPARATE,
real, UNRESOLVED defect -- two jobs dispatched through the real SPI
path with realistic pacing produce wrong compute results, even
though job registration itself is confirmed correct at the
handshake. Root cause not yet isolated. Committed as a known-failing
regression (tb_fpga_neural_v2_top_smoke.v) documenting the gap
honestly rather than hiding it.
Given ERR-0025 Part B is real and unresolved, synthesis/P&R of the new
board-level top was deliberately not attempted this round, and V2
hardware release is NOT declared complete. See decisions.log DEC-0036
and hardware/v2/docs/{CHIP_READINESS,OPEN_ITEMS}.md for the full,
itemized status.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
FASE #1 hardware freeze for FPGA-Neural V2, N4/P8, single external
SDRAM (Alliance Memory AS4C4M16SA-6TIN) serving weights, activations,
and results through one physical sdram_controller.v instance. Removes
the PSRAM dependency (hardware/v1/rtl/psram_controller.v +
memory_interface.v) from the V2 physical path entirely -- V1 itself
remains fully unmodified, the golden reference.
New RTL: sdram_unified_backend.v (2-way W/AR arbitration over one
SDRAM controller, real per-byte DQM write masking added to
sdram_controller.v for correct single-byte result writes with no
read-modify-write), nms_neural_multiprocessor_sdram_unified.v (the
frozen top-level). Two real bugs found and fixed via full-system
testing before being accepted (ERR-0023): a deadlock and an off-by-one
data-shift bug in the new arbitration logic.
Real results: N=4 and N=2 D-Stress bit-exact (256/256 neurons), 40
real AUTO REFRESH events interleaved with zero corruption, real
Yosys+nextpnr-ecp5 synthesis/P&R for LFE5U-45F-8CABGA381 (149/245
TRELLIS_IO, a real 45-pin reduction from the prior dual-memory
design). Timing is MARGINAL (1/8 P&R seeds >=80MHz), reported honestly
rather than masked by the best seed.
Real, sourced ball-level pinout for the SDRAM bus + clk/rst (39/149
signals, P&R-verified) using the official Lattice ECP5U-45 pinout CSV
found on disk during this step's own pre-commit review -- corrects an
earlier draft that wrongly assumed no real pinout data was available.
Chip readiness: NO. Real, disclosed blockers remain (no physical host
interface exists yet -- the RTL's own reg_* ports are a 110-pin raw
test-harness bus; clock source/PLL decision; power/configuration
component selection) -- see hardware/v2/docs/{HARDWARE_FREEZE,
CHIP_READINESS,OPEN_ITEMS}.md for the complete, itemized status.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v