Adds result_writeback.v, one instance per packed_slot.v, writing each
completed job's result directly into DDR3 at the job's own
result_addr_a/b instead of driving literal top-level pins -- the same
architectural shape as the weight-fetch path, in reverse. job_done now
means "durably in DDR3", not "captured in a register only a pin could
see". n2_system_ddr3_top.v's own s0_result_data_a/b, s1_result_data_a/b
top-level package pins are removed (and the now-dangling XDC constraint
for them), closing the real, hard scaling blocker docs/ARCHITECTURE_
ANALYSIS.md flagged since EXP-0074/0079 (8 bits x 2 lanes x N cores ->
256 pins at N=16).
Addressing reuses the exact same JOB_ADDR_WIDTH->ctrl-bus-word
truncation x_base_a/w_base already use (verified against act_tile_
fetch.v's/layer_prefetch_ctrl.v's own real code, not guessed). The host
reads results back via the already-existing READ_MEM (0x02) SPI opcode
-- no new protocol. A real EXP-0066-class bug (issuing ctrl_req before
mem_grant) was caught and fixed before ever compiling, by re-deriving
the design against act_tile_fetch.v's own proven S_MEMWAIT/S_GAP
sequencing.
Verified two ways: tb_packed_slot.v extended with a real DDR3
read-after-write check (9/9 PASS, confirms the write actually landed,
not just that job_done pulsed); tb_n2_system_ddr3.v re-run via real
xsim to confirm correct behavior under real 2-slot shared-bus
arbitration (8/8 PASS, 0 errors, consistent timing with EXP-0087's own
baseline for this workload).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
Re-measured ddr_prefetch_mgr.v's (EXP-0083) real benefit against the
now-closed 32-bit DDR3 channel (EXP-0086), per this project's own
standing plan. Real result: the 2.86% benefit measured at the old
16-bit channel is GONE at 32-bit (WITH: 100663.1335ns vs WITHOUT:
100656.6835ns -- a 0.0064% regression, statistically a wash). The
wider channel's lower per-tile latency already absorbs the gap the
look-ahead prefetch used to hide. Kept wired in for correctness/
timing-neutrality (real P&R already signs off with it included), but
it's no longer a real performance win. Updated docs/ARCHITECTURE_
ANALYSIS.md and docs/PHYSICAL_REALIZATION.md accordingly.
Found and fixed 3 real testbench/simulation-setup bugs along the way:
- tb_n2_system_ddr3.v and tb_mig_native_adapter.v still had a stale
CLKIN_PERIOD=2900 (the FAILED EXP-0084 clock period) instead of the
current real, closed 3225ps (EXP-0086).
- tb_n2_system_ddr3.v used SystemVerilog-only $signed(8'(...)) cast
syntax, invalid for xvlog's default plain-Verilog mode -- fixed via
an intermediate 8-bit reg.
- Building a fresh sim_1 fileset needs the real MIG simulation
dependency set added explicitly (mig_7series_0_mig.v is marked
USED_IN_SIMULATION=0 in the project since testbenches bypass the
public wrapper); verilog_define is a fileset-level property, not
per-file, in this Vivado version.
New measurement-only fork (not part of the real synthesis target, per
fork-before-promote discipline): packed_slot_noprefetch.v +
tb_n2_system_ddr3_noprefetch.v, reproducing the pre-EXP-0083 direct
per-tile activation-fetch sequencing for a fair A/B baseline.
Also adds docs/BOM.md and docs/PINOUT.md: a real component list (DDR3
x2, flash, FPGA already verified; clk_ref oscillator and an ESP32-S3-
WROOM-1 module newly verified in-stock on LCSC; sys_clk oscillator
flagged as needing a custom-programmed order, no off-the-shelf SKU at
the required 310.077MHz) and a consolidated, board-layout-ready pinout
extract of PHYSICAL_REALIZATION.md's own pin tables.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
Reverting Clock Period to 3225ps (keeping Data Width=32) closes real
timing: WNS=+0.095707ns, WHS=+0.036275ns, 0 failing endpoints, all
user-specified constraints met. This is the real final signoff for the
32-bit DDR3 channel widening effort (EXP-0083 through EXP-0086),
replacing EXP-0083's 16-bit-era baseline as the project's current
trustworthy number. Confirms the EXP-0084 root-cause analysis: the
earlier -0.618ns failure was caused by a separate, stacked clock
speedup, not the width change itself.
Also found and fixed a second, wholesale real occurrence of the
stale-import bug: the MIG wizard regeneration needed to revert Clock
Period silently re-imported the entire v3 RTL tree (9 files) plus the
top XDC back to pre-EXP-0084 stale copies, not just the file(s) the
regeneration touched. CLAUDE.md's lesson extended accordingly.
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
S5.6.1: opportunistic BRAM cache for activation tiles - exploits real,
currently 0%-utilized Block RAM to catch whatever locality the workload
happens to have, without committing to a specific reuse pattern the way
the systolic direction does. No cache-invalidation problem given the
current write-once-before-job protocol.
S5.6.2: host-side (ESP32) job-queue reordering - a software-only
"DDRManager" upstream of ddr_prefetch_mgr.v, grouping jobs with nearby
DDR3 addresses before submission to reduce row-switch cost with zero
RTL and zero timing-margin risk. Both marked exploratory, not decided,
not built - same as S5.6's systolic direction.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
Brainstorming session outcome: instead of flat N=16 independent DDR3
requesters, group cores into 4 weight-stationary systolic chains of 4
PEs each - reduces independent DDR3 contenders from 16 to 4 while
preserving task-level parallelism across the 4 groups. Captured as
docs/ARCHITECTURE_ANALYSIS.md S5.6, explicitly marked exploratory/not
decided/not built - revisit after the 32-bit channel widening and real
N=2/4/8 flat-core scaling tests produce real numbers.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
New ddr_prefetch_mgr.v wraps act_tile_fetch.v with a depth-2 ping-pong
buffer, issuing the next tile's DDR3 fetch as soon as the fetch engine
is free instead of waiting for packed_slot.v to finish consuming the
current tile. Wired into packed_slot.v's tile loop (job-level start
instead of per-tile req), simplifying the S_TILEWAIT join in the process
(ddrpf_tile_valid is level-held, no separate act_seen latch needed).
Verification: new tb_ddr_prefetch_mgr.v (25/25 PASS after fixing a real
testbench polling race found via iteration-tagged tracing, not an RTL
bug), tb_packed_slot.v re-run unmodified (9/9 PASS, bit-identical
results), tb_n2_system_ddr3.v re-run via real xsim against real
ddr3_model.sv (8/8 PASS). Real P&R: WNS +0.073ns (up from EXP-0082's
+0.068ns), LUTs 5644, DSP48E1 16 unchanged, 0 failing endpoints.
Honest result: real A/B on the actual DDR3 backend (same testbench,
before/after) shows a real but modest 2.86% reduction in total
simulated time - smaller than the original hypothesis suggested, because
neural_processor_packed.v already accepts one operand per cycle, so the
per-tile dead time being removed was already small relative to real DDR3
fetch latency. Docs updated to report this honestly rather than oversell
it; the larger multi-slot DDRManager is deferred pending re-measurement
against the (still pending, user-gated) 32-bit channel widening.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
- PHYSICAL_REALIZATION.md: replace stale "1 tile = 1 burst" layout
description with the real EXP-0081/0082 "2 tiles = 1 burst" convention;
add EXP-0082 signoff row and history table.
- ARCHITECTURE_ANALYSIS.md: mark §5.1 (denser activation packing) DONE with
real re-measured numbers (bandwidth ceiling fraction 25%->50%, WNS
+0.030->+0.068ns); add §5.4, the real device-data-backed comparison of
32-bit single-channel widening vs a second independent DDR3 channel
(decided: 32-bit widening, per real DQS/bank pin-conflict analysis);
update scaling-path recommendation to reflect the user's final directive
(widen channel -> build DDRManager -> N=2/4/8/16 tests, N=8 target, N=16
documentary).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
Before building N=4/8/16 core scaling, did the requested full
analysis. Real finding: using measured DDR3 throughput (1.24 GB/s,
from the actual EXP-0079 JEDEC trace) against calculated compute-side
need (4.96 GB/s for one core at peak DSP throughput, given the
current activation memory layout's 2x byte overhead), the system is
memory-bandwidth-bound already at N=1/N=2, not DSP-bound (only 6.67%
DSP used). Scaling core count today would show no real throughput
gain.
docs/ARCHITECTURE_ANALYSIS.md: full module review + ranked
interventions -- result-writeback engine (blocker), denser activation
packing (highest-leverage bandwidth fix), then the user's own proposed
DDRManager/orchestrator-prefetch idea (design-sketched, grounded in
neural_director_packed.v's existing job queue, explicitly scoped as
complementary to denser packing, not a substitute for it), THEN
N-scaling with real per-N P&R signoff.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC