Commit Graph
114 Commits
Author SHA1 Message Date
micheleandClaude Sonnet 5 cbd16dd727 docs: sync physical/architecture docs with EXP-0081/0082 reality, add 32-bit vs dual-channel analysis
- 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
2026-09-20 10:07:16 +02:00
micheleandClaude Sonnet 5 e6768623d6 docs: confirm denser activation packing is real-timing-safe, margin improved (EXP-0082)
Real P&R: WNS +0.068ns (up from +0.030ns), 0 failing endpoints, 5437
LUTs, 16 DSP48E1. Confirms EXP-0081's "register the select bit at
request time" design genuinely kept the fix off the critical path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-20 10:01:58 +02:00
micheleandClaude Sonnet 5 8ad04987de feat: denser activation packing, real bandwidth ceiling doubled (EXP-0081)
Implements the highest-leverage fix from EXP-0080's bottleneck
analysis: act_tile_fetch.v now packs 2 consecutive tiles per DDR3
burst (even tile low 64 bits, odd tile high 64 bits) instead of 1
tile per burst, halving real DDR3 bytes-per-useful-byte. Timing-safe
by construction: the tile-index select bit is registered at request
time, long before the real DDR3 round-trip completes, never racing
the arriving read data (unlike the runtime part-select pattern
EXP-0079 deliberately avoided).

Re-verified at all 3 levels (isolated engine 8/8, packed_slot.v 9/9
with bit-identical results to EXP-0079, full N=2 system on real DDR3
8/8) -- the real JEDEC trace now shows no half-burst padding, direct
confirmation the fix works in practice, not just in theory.

Also: real device data gathered on this package's I/O bank layout
(only 5 banks total, 14/15/16/34/35) informing the next bandwidth step
(32-bit-wide single controller recommended over a second independent
channel, given the pin/logic cost comparison).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-20 09:55:16 +02:00
micheleandClaude Sonnet 5 27cf5f36da docs: complete architecture analysis - DDR3 bandwidth is the real ceiling, not DSP count (EXP-0080)
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
2026-09-20 09:44:10 +02:00
micheleandClaude Sonnet 5 43a12379a5 feat: MILESTONE - real activation-fetch engine, full N=2 system verified on real DDR3 (EXP-0079)
Closes the last major disclosed functional gap: packed_slot.v's
activation data was read through a combinational stand-in since
EXP-0062. New act_tile_fetch.v reads activation tiles directly from
DDR3 (no on-chip buffering needed, unlike weights -- activation data
has no reuse), sharing each slot's existing ctrl port with its own
weight-prefetch engine. Real memory layout: one full BURST_LEN=8-word
burst per tile, deliberately avoiding any runtime-indexed part-select
given this project's thin P&R timing margin (EXP-0078).

Verified at three levels: act_tile_fetch.v alone (6/6), packed_slot.v
with real preloaded activation data (9/9), and the full N=2 system
against real DDR3 via xsim (8/8, 0 errors) -- the first time this
project's compute path has been verified end-to-end with real DDR3
for both weights and activations.

Retired hardware/v3/rtl/n2_system_top.v and its testbench (pre-DDR3
SDR-placeholder era, fully superseded by n2_system_ddr3_top.v).

Also: docs/PHYSICAL_REALIZATION.md (real pinout/parts/timing/protocol
reference for the physical board) and CLAUDE.md (persistent project
instructions for future Claude Code sessions).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-20 08:13:15 +02:00
micheleandClaude Sonnet 5 78577dde59 docs: log real Vivado stale-source bug + final flash-bridge P&R signoff (EXP-0078)
Found and fixed a real Vivado project-management bug: two source
files (n2_system_ddr3_top.v, spi_host_bridge_v3.v) had stale imported
copies (plus a duplicate at a second path) that silently kept being
used in synth+impl despite live edits, making the first "flash bridge
included" P&R run silently synthesize the OLD design (STARTUPE2
Used=0/1 gave it away). Fixed by removing the stale/duplicate entries
and re-adding both files as direct (non-copied) references.

Final real P&R: STARTUPE2 Used=1/1 (confirms the flash bridge is
genuinely placed/routed), timing still closes but margin is now
thinner and real: WNS +0.013ns, WHS +0.032ns, 0 failing endpoints.
5213 LUTs, 16 DSP48E1.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-20 07:24:33 +02:00
micheleandClaude Sonnet 5 a4c080da83 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
2026-09-19 21:45:17 +02:00
micheleandClaude Sonnet 5 fd6cc7a2fa docs: log final re-verified real P&R signoff after SPI fix + reg file (EXP-0076)
Confirms EXP-0075's fixes (SPI physical-layer bug, register file,
real pin constraints) don't regress timing: WNS +0.056ns (slightly
better than EXP-0074's +0.040ns), 0 failing endpoints, 5173 LUTs,
16 DSP48E1. User confirmed board plan: both JTAG and Master SPI boot
(Winbond W25Q32JVSSIQ config flash, verified in-stock on LCSC) will
be present on the custom PCB.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-19 19:22:32 +02:00
micheleandClaude Sonnet 5 ca17765fe3 fix: real SPI MISO bit-corruption bug found+fixed; add register file + pin plan (EXP-0075)
Found a real, previously-masked bug in spi_host_bridge_v3.v's physical
layer (inherited unchanged from V1/V2): the bit_count==0 MISO bypass
corrupts the last bit of any multi-byte response whose value happens
to end in a 1 -- every prior test's response data coincidentally
ended in 0, hiding it until the new DEVICE_ID register (0x...01)
exposed it via a real bit-exact mismatch. Fixed by removing the
bypass (verified unnecessary for this protocol's actual usage).

Added REG_WRITE/REG_READ opcodes (0x30/0x31) and a register file
(DEVICE_ID/CONTROL/STATUS/N_SLOTS) for general device control beyond
job submission, per explicit user request. Full regression: 38/38
PASS, including new cases specifically targeting the bit-corruption
bug for both REG_READ and READ_MEM.

New hardware/v3/constraints/n2_system_ddr3_top.xdc: reserves the
FPGA's dedicated Master-SPI config-flash pins (found colliding with
auto-placed design ports in the real routed checkpoint) and assigns
the neural-processor management SPI to real, verified-free, edge-
adjacent pins on xc7a100tcsg324-2.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-19 18:31:51 +02:00
micheleandClaude Sonnet 5 835ae881dc feat: MILESTONE - first real in-context P&R, timing closes at 310MHz DDR3 (EXP-0074)
n2_system_ddr3_top.v: the first synthesizable top wiring the real
mig_7series_0 DDR3 controller (public wrapper, real calibration) +
mig_native_adapter.v + sdram_arbiter_n.v (3-way: 2 packed_slot + host
raw-access) + neural_director_packed.v + spi_host_bridge_v3.v.

Real Vivado in-context synth+impl against the actual MIG-generated
XDC (pin locations, DDR3 timing exceptions) on xc7a100tcsg324-2:
route_design 100%, all timing constraints met (WNS +0.040ns, WHS
+0.048ns, 0 failing endpoints), 310.078MHz DDR3 PHY clock / 155.039MHz
compute domain, 5140 LUTs / 5952 regs / 16 DSP48E1 / 0 BRAM.

Fixed three real issues found getting here: a SystemVerilog literal
synth_design can't parse, MIG stub port mismatch (calib_tap_* isn't
exposed in this IP config), and a genuine design mistake -- exposing
packed_slot.v's activation-fetch stand-in ports as literal top-level
pins demanded ~360 I/O against the package's 324 total. Made that
interface internal (stub-driven) instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-19 17:47:40 +02:00
micheleandClaude Sonnet 5 6caea54b8e fix: neural_director_packed.v SV literal for synth; exonerate it from a testbench race (EXP-0073)
Replaced three uses of the SystemVerilog '0 self-sizing literal with
explicit-width zero-fill so the file synthesizes under Vivado's
synth_design (which has no -sv equivalent in this flow), needed while
adding this module to the real in-context P&R project.

Re-running its isolated regression after that edit surfaced 3/8
failures. Root-caused via git stash (reproduces on the untouched
committed file, not caused by this edit) and a DUT-internal $display:
tb_neural_director_packed.v's own submit_job task drove DUT inputs
with blocking assignment across two separate @(posedge clk) waits,
racing the DUT's own always block under Icarus and causing a spurious
duplicate enqueue. Fixed by switching to nonblocking assignment
(race-free by construction). neural_director_packed.v itself was
correct all along - 8/8 tests pass after the testbench fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-19 13:37:25 +02:00
micheleandClaude Sonnet 5 562cf91f1e feat: spi_host_bridge_v3.v, SPI opcode re-audit against real V3 RTL (EXP-0072)
Forked from V2's spi_host_bridge.v after finding two real protocol
mismatches: WRITE_JOB carried dependency-manager fields (required/
producer_ids) that neural_director_packed.v's job_in_* port doesn't
have (no dependency manager exists in V3 -- dropped, disclosed, not
silently ignored), and WRITE_MEM/READ_MEM assumed a word-granularity
host-arb port V3 never had (now wired through host_mem_bridge.v,
EXP-0071). Physical SPI layer carried over unchanged.

Verified standalone: 18/18 tests, 0 errors, including a case
exercising the narrower 25-bit MEM_ADDR_WIDTH's own top bit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-17 08:56:15 +02:00
micheleandClaude Sonnet 5 786464ee21 feat: host_mem_bridge.v, word<->burst translator for host DDR3 access (EXP-0071)
Closes part of the gap found re-auditing spi_host_bridge.v against V3:
V3 had no host raw-memory-access path into DDR3 at all. This module
translates single-16-bit-word req/wr/addr/wdata/lb_n/ub_n transactions
(spi_host_bridge.v's own WRITE_MEM/READ_MEM shape) into BURST_LEN=8
transactions on the shared arbiter, using the project's existing
DQM-style partial-burst masking technique.

Verified standalone against the SDR SDRAM placeholder: 16/16 tests,
0 errors, including cross-word-corruption checks on every burst
offset. Not yet wired into the N=2 system or driven by real SPI
opcode decode.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-17 08:53:23 +02:00
micheleandClaude Sonnet 5 598feb975b feat: first genuine N=2 multi-core system verified against real DDR3 (EXP-0070)
Swapped mig_native_adapter.v + sdram_arbiter_n.v into the full N=2
system (neural_director_packed.v + 2x packed_slot.v), replacing the
SDR SDRAM placeholder used since EXP-0057. Verified against the real
Vivado-generated ddr3_model.sv end-to-end: 8/8 positions bit-exact
against golden model, 0 errors, real JEDEC command traffic observed.

This is the first fully real V3 system-level correctness result:
real packed DSP cores + real weight-reuse scheduling + real N-way
arbitration + real DDR3 timing, all verified together.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-17 08:51:43 +02:00
micheleandClaude Sonnet 5 afff0c4f02 test: fix tb_sdram_arbiter_n.v hang, root-caused as testbench bug (EXP-0069)
TEST2 fired all 3 simulated requesters' one-shot req pulse
unconditionally, not waiting for each one's own grant -- an
unrealistic stimulus that doesn't match packed_slot.v's real
S_MEMWAIT usage (wait for grant, then fire). Rewrote with parallel
fork branches, each waiting for its own req_grant first, still
exercising the real simultaneous-activation contention case.

7/7 PASS, 0 errors. sdram_arbiter_n.v is now genuinely verified, not
just written.

Full writeup in hardware/v2/logs/experiments.log EXP-0069.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-17 08:44:46 +02:00
micheleandClaude Sonnet 5 e25e4a1506 feat: real DDR3 memory path verified against MIG's own ddr3_model.sv (EXP-0068)
New hardware/v3/rtl/mig_native_adapter.v: adapts this project's
established req/wr/addr/wdata/wmask->rdata/ready/busy contract to the
real MIG 7-series native app interface (app_addr/app_cmd/app_en,
app_wdf_data/app_wdf_mask/app_wdf_wren/app_wdf_end, app_rd_data/
app_rd_data_valid/app_rd_data_end), derived from this project's own
real generated mig_7series_0.v port widths, not assumed. Runs in the
ui_clk domain (MIG's own generated clock becomes this project's
system clock going forward).

Verified against MIG's own real, vendor-shipped DDR3 behavioral model
(ddr3_model.sv) via real Xilinx xsim/xvlog/xelab (UNISIM primitives
in MIG's PHY require this over Verilator): 12/12 write-then-read-back
transactions bit-exact, 0 errors, real JEDEC command sequence observed
(Activate/Write/Read/Precharge). Confirms the app_cmd encoding and
burst/beat sequencing on first real test.

Also adds hardware/v3/rtl/sdram_arbiter_n.v (generalized N-way
arbiter, generalizing EXP-0066's 2-way version for N>2 scaling and a
future host-access requester) -- its own isolated test currently
HANGS, root cause not yet found, do not trust this module yet
(disclosed, not hidden).

Full writeup in hardware/v2/logs/experiments.log EXP-0068.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-17 08:43:22 +02:00
micheleandClaude Sonnet 5 0589620b58 exp: real P&R of the N=2 multi-core system, first genuine system Fmax (EXP-0067)
New hardware/v3/rtl/n2_system_top.v: synthesis wrapper around the
EXP-0066-verified system (neural_director_packed.v + arbiter + real
SDRAM controller + 2 real packed_slot.v instances).

Real Vivado post-route: 16/240 DSP48E1, WNS -2.570ns @ 200MHz ->
Fmax ~132.1MHz -- only -2.1% vs the isolated single core (134.9MHz,
EXP-0059). Unlike V2/ECP5 (where the real full-system Fmax was
measurably lower than the isolated-core number), this Director+
arbiter architecture shows no comparable penalty at N=2, real
confirmation (not projection) that the earlier ~55-85x-over-ESP32-S3
estimate's key assumption holds at this scale.

Full writeup in hardware/v2/logs/experiments.log EXP-0067.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-17 00:21:01 +02:00
micheleandClaude Sonnet 5 09fbf01ea5 feat: first genuine N=2 multi-core system, two real bugs found+fixed (EXP-0066)
New sdram_slot_arbiter2.v + tb_np_director_n2_system.v: real
neural_director_packed.v dispatching to 2 real packed_slot.v
instances sharing one real SDRAM controller. Jobs submitted one at a
time through the Director's own producer interface -- the Director's
own scheduling decisions determine slot assignment here, unlike every
prior V3 test.

Bug 1 (real, structural): the arbiter's first design registered its
grant one cycle late; layer_prefetch_ctrl.v's ctrl_req is a one-shot
pulse with no retry (every prior use wired it directly to a
controller, never behind arbitration), so a slot's first request
could be silently lost, hanging it forever. Fixed with a new
S_MEMWAIT state in packed_slot.v (wait for a combinational mem_grant
before ever pulsing layer_prefetch_ctrl's start) and a combinational-
first grant in the arbiter.

Bug 2 (testbench): node_id used a stray bit-slice (li[15:8]) instead
of a real multiply, making every layer produce the same node_ids and
silently checking results against the wrong layer's golden value.
Fixed.

Result: 12/12 PASS, 0 errors, real concurrent execution across both
slots (slot 0: positions {0,1,4,5,8,9}, slot 1: {2,3,6,7,10,11}).

Also noted (user correction): the SDR SDRAM controller used
throughout this memory path is a declared placeholder -- the real
target is DDR3 on a custom XC7A100T board, not yet built.

Full writeup in hardware/v2/logs/experiments.log EXP-0066.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-17 00:16:47 +02:00
micheleandClaude Sonnet 5 124a0dbca0 feat: packed_slot.v, real per-slot sequencer FSM (EXP-0065)
Promotes EXP-0062's own procedural testbench sequence (prefetch ->
buffer swap -> per-tile gather -> operand streaming -> result
capture) into real synthesizable RTL, wrapping layer_prefetch_ctrl.v
-> layer_weight_buffer.v -> weight_tile_gather.v ->
neural_processor_packed.v behind a 9-state FSM matching
neural_director_packed.v's own per-slot contract.

First run: 4/9 failed, deterministic. Root-caused (not a sequencer
bug): the testbench's own w_base computation wrongly treated it as a
byte address needing *2 conversion; layer_prefetch_ctrl.v expects a
word address directly, and packed_slot.v already passes it through
unconverted to match. Fixed the testbench.

Re-verified: 9/9 PASS, 0 errors, bit-exact results and correct
node_id/result_addr passthrough, entirely self-sequenced (no
testbench-side procedural driving of the sub-modules).

Full writeup in hardware/v2/logs/experiments.log EXP-0065.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-17 00:02:35 +02:00
micheleandClaude Sonnet 5 71600096f9 feat: neural_director_packed.v, job-pairing scheduler for packed cores (EXP-0064)
Forked from neural_director.v (M5): dispatches PAIRS of queued jobs
(sharing w_base+n_tiles) to packed-core slots instead of one job per
slot, matching neural_processor_packed.v's A/B job structure. If the
two oldest queue entries don't share w_base/n_tiles, the Director
stalls (never mis-pairs) -- a disclosed scope limitation, not hidden.

Isolated testbench with behavioral per-slot stubs (same DEC-0007 scope
decision as tb_neural_director.v). First run: 3/7 tests failed --
investigated each, root-caused as testbench timing bugs (checking
dispatch state before the Director's own FSM had caught up, and a
held-too-long job_in_valid making push counts ambiguous), not Director
bugs. Fixed the testbench, re-verified: 8/8 PASS, 0 errors.

Full writeup in hardware/v2/logs/experiments.log EXP-0064.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 23:52:19 +02:00
micheleandClaude Sonnet 5 5afa6a7477 exp: real P&R of verified weight-reuse memory path + packed core (EXP-0063)
New hardware/v3/rtl/np_packed_weight_reuse_top.v: flat structural
synthesis wrapper around the EXP-0062-verified module chain (real SDR
SDRAM controller -> layer_prefetch_ctrl.v -> layer_weight_buffer.v ->
weight_tile_gather.v -> neural_processor_packed.v).

Real Vivado post-route: 8/240 DSP48E1 (unchanged, memory path uses
zero DSPs), WNS -2.502ns @ 200MHz -> Fmax ~133.3MHz, only -1.2% vs
the isolated single core (134.9MHz, EXP-0059). Real memory-path
control logic adds negligible Fmax cost at this scale.

Full writeup in hardware/v2/logs/experiments.log EXP-0063.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 23:44:24 +02:00
micheleandClaude Sonnet 5 9ca180a787 test: first real end-to-end weight-reuse -> packed-core integration, bug found+fixed (EXP-0062)
New hardware/v3/sim/tb_np_packed_layer_reuse.v: real SDR SDRAM ->
layer_prefetch_ctrl.v -> layer_weight_buffer.v -> weight_tile_gather.v
-> neural_processor_packed.v, ALL real synthesizable RTL (unlike
EXP-0058, which still had a testbench-only gather step).

First run: 15/16 PASS, 1 FAIL. Root-caused (not re-run away): a
testbench handshake bug, not a DUT bug -- operand_valid was held one
extra clock edge after each accepted tile, double-consuming stale
data every tile on every pair. 15 of 16 "passed" only because this
test's saturating outputs happened to clamp to the same value whether
or not the accumulator was inflated -- disclosed as a real methodology
risk, not swept under the rug. Fixed by dropping operand_valid the
same delta the handshake is observed.

Re-verified after the fix: 16/16 PASS, 0 errors, bit-exact against an
independent golden model, through the complete real RTL path.

Full writeup in hardware/v2/logs/experiments.log EXP-0062.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 23:41:35 +02:00
micheleandClaude Sonnet 5 5c127fb069 feat: weight_tile_gather.v, real synthesizable byte-to-tile adapter (EXP-0061)
Closes the gap EXP-0058 left testbench-only: assembling P_IN
sequential layer_weight_buffer.v byte reads into one weight_data
tile bus, as real RTL instead of a testbench driver task. Avoids the
runtime-indexed-part-select anti-pattern already found and fixed once
in neural_director.v (ERR-0027-class Fmax collapse) by using a fixed
shift-concat instead.

Verified in isolation against a real, unmodified layer_weight_buffer.v:
37/37 tests, 0 errors, bit-exact across sequential, back-to-back, and
non-sequential/repeated (real reuse-position-style) access patterns.

Full writeup in hardware/v2/logs/experiments.log EXP-0061.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 23:34:09 +02:00
micheleandClaude Sonnet 5 94b63705be exp: N=8 packed-core array real P&R, isolates placement density from interconnect (EXP-0060)
New hardware/v3/rtl/np_packed_array.v: flat array of 8 unmodified
neural_processor_packed.v instances, fully independent I/O, zero
shared arbiter/Director logic -- isolates exactly one variable
(DSP/placement density) from EXP-0059's single-core baseline.

Real Vivado post-route: 64/240 DSP48E1 (26.67%), WNS -2.592ns @
200MHz -> Fmax ~131.7MHz, only -2.4% vs the single-core 134.9MHz.
Placement density alone is NOT the main driver of the ECP5-era gap
between isolated-core and full-system Fmax -- narrows the question
for the still-unbuilt real Director/arbiter/memory integration.

Full writeup in hardware/v2/logs/experiments.log EXP-0060.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 23:29:54 +02:00
micheleandClaude Sonnet 5 34b15cc0a7 exp: first real Vivado synthesis+P&R on XC7A100T for V3 DSP-packed core (EXP-0059)
Real Vivado 2026.1 run (not estimated) confirms the DSP48 packing
survives actual Xilinx synthesis: mac2_dsp_packed.v uses exactly 1
DSP48E1, and the full neural_processor_packed.v pipeline uses 8
DSP48E1/240 for 2 jobs -- half the DSP of two separate V2 cores for
the same work.

Post-route (real place_design+route_design, not synthesis-only):
WNS -2.414ns @ 200MHz -> Fmax ~134.9MHz, within 0.5% of the
post-synthesis-only estimate. This is the isolated compute core,
out-of-context -- not yet a real N-core system number, flagged as
such in the log entry.

Full writeup, including the two real toolchain fixes needed to get
Vivado running on this machine (CRLF line endings in installLibs.sh,
missing libncurses.so.5 on Ubuntu 26.04), in
hardware/v2/logs/experiments.log EXP-0059.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 23:18:18 +02:00
michele 9851930613 docs: extract V2 datasheet into submodule 2026-09-16 23:03:43 +02:00
micheleandClaude Sonnet 5 1cbe7b85d5 v3: real Artix-7 compute core -- DSP48 packing verified, 2 real bugs found and fixed
New hardware/v3/ (Artix-7 port, branch v3-artix7): the compute engine
that makes the 100x-vs-ESP32 target theoretically reachable on
XC7A100T's 240 DSP48E1 budget.

mac2_dsp_packed.v: packs 2 INT8 MACs sharing one resident weight into
a single DSP48-shaped 25x18 multiply, exploiting this project's own
weight-stationary reuse pattern (layer_weight_buffer.v, EXP-0057/0058)
where one weight is genuinely multiplied against many different
activations. Verified exhaustively: 16,777,216/16,777,216
(weight,x0,x1) combinations, 0 errors.

Two real bugs found and fixed during that verification (both purely
arithmetic/RTL, not toolchain-related):
1. An off-by-one in a declared wire width caused Verilog's part-select
   unsigned-by-default rule to corrupt sign extension on the upper
   product field -- ~50% of vectors failed.
2. After fixing (1), still ~50% failed: concatenating two independently
   sign-extended fields ({sext(x1,9), sext(x0,16)}) is NOT equivalent
   to the real arithmetic sum x1*2^16+x0 whenever the lower field is
   negative (its own two's-complement encoding "bleeds" an extra 2^16
   into the concatenated value). Fixed by building the packed operand
   with an explicit arithmetic shift-and-add instead of concatenation.

neural_processor_packed.v: full port of hardware/v2/rtl/
neural_processor.v's pipeline (same stage count/structure), doubled on
the accumulator/bias/activation/saturation side to process two
weight-reuse positions per weight-tile stream. Verified against TWO
real hardware/v2/rtl/neural_processor.v instances (job A / job B, same
shared weight, independent activations) -- 18/18 PASS, 0 errors,
covering the functional sweep, INT8 extremes, and back-to-back jobs.

A third real bug found in the process (in the new testbench, not the
RTL): clearing operand_valid/tile_last in the same simulation delta as
the handshake edge that should register tile_last=1 races against the
DUTs' own FSM evaluation of that same edge -- the same pulse-clearing
race class found three times already today in hardware/v2/sim (EXP-0058
and its follow-up commits). Fixed the same way: hold the pulse past the
edge with a real time delay (#1) before clearing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 19:48:46 +02:00
micheleandClaude Sonnet 5 ff5908f25f docs: log DEC-0009 -- project v22 paused, hard DSP resource ceiling on ECP5
Real nextpnr-ecp5 resource data shows the ECP5 family (45F: 72
MULT18X18D, 85F: 156) cannot reach the 20x-1000x speedup targets
discussed today with this or any redesigned architecture -- N=16 was
already near the 85F's absolute physical ceiling of 19 cores. User
made an informed decision to pause the project rather than chase a
target this hardware family cannot physically deliver.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
v22-final
2026-09-16 15:38:39 +02:00
micheleandClaude Sonnet 5 3416b8d3cf exp: fix pulse-race hang in tb_layer_reuse_vs_zero_reuse.v (EXP-0058 follow-up); real remaining bug still open, 7.16x NOT yet re-verified
Same class of testbench-vs-DUT scheduling race documented in EXP-0058
(tb_layer_prefetch_ctrl.v, tb_neural_processor_layer_reuse.v) was also
present here on ctrl_req/fill_done/consume_done: clearing a one-cycle
pulse on the very next @(posedge clk) let the clear land in the same
active-region pass as the edge the DUT needed to sample it at, so the
pulse could be silently missed. Confirmed via direct state tracing:
sdram_controller_openrow.v sat in S_IDLE with busy=0 forever after the
first burst, never latching req_pending for the second -- this is why
the file hung indefinitely rather than completing. Fixed with the same
#1-before-clear hardening as the other files.

Honesty note: fixing this hang exposed a SECOND, still-unfixed bug in
prefetch_layer's own fill_addr sequencing (real data-correctness
failures once the run actually completes, not just a hang) -- so
EXP-0057's own headline "7.16x real measured speedup" number is NOT
re-verified by this commit and should not be treated as confirmed. Not
pursued further -- see decisions.log for why (project paused).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 15:38:12 +02:00
micheleandClaude Sonnet 5 80c89fa10d exp: real end-to-end weight-reuse integration with neural_processor.v (EXP-0058)
New tb_neural_processor_layer_reuse.v wires the real SDRAM controller,
layer_prefetch_ctrl.v and layer_weight_buffer.v into a real
neural_processor.v compute engine: one resident filter is fetched once
and reused across 8 independent jobs per layer, verified bit-exact
against an independent golden dot-product model (32/32 PASS).

Also found and fixed a real testbench-vs-DUT scheduling race present in
tb_layer_prefetch_ctrl.v (and hardened in the new file): clearing a
one-cycle control pulse on the very next clock edge lands the clear in
the same active-region pass as the edge a receiving module's own
synchronous logic reads it at, so the pulse can be silently missed
depending on implementation-defined process ordering. This had been
silently preventing tb_layer_prefetch_ctrl.v's own claimed 8192/8192
result from ever actually being observed; fixed by holding the pulse
past the edge with a real time delay before clearing, and the
8192/8192 result is now genuinely reproducible (5/5 consecutive runs).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 14:26:09 +02:00
micheleandClaude Sonnet 5 ca94083366 prod: promote EXP-0056 fixes into production RTL (dependency_manager.v, nms_activation_fill_ctrl_v3.v)
Per explicit instruction: when a bug/fix found in an experimental fork
also applies to the production file it was forked from, apply it
there too, not just in the fork.

dependency_manager.v: swaps in priority_encoder_lsb.v for the
first_ready_idx scan (was: serial O(N_NODES) for-loop). Bit-exact
equivalent, correctness-neutral by construction.

nms_activation_fill_ctrl_v3.v: adds the missing N_SLOTS==16 balanced
max-tree case (was: silently falling back to the slow flat scan for
any N_SLOTS not in {1,2,4,8}) -- this was the real cause of N_SLOTS=16
failing timing closure (23-24MHz vs 64MHz target), fixed to 71.01MHz
PASS in the experimental fork.

Verified on the REAL, unmodified production top (fpga_neural_v2_top.v,
N_SLOTS=4 default): tb_dependency_manager.v 4/4 PASS, board smoke test
11/11 PASS, D-Stress N=4 total_cycles=49927 (bit-exact, IDENTICAL to
the pre-fix baseline -- zero functional regression, as expected from a
pure combinational-depth change). Real nextpnr-ecp5 P&R (LFE5U-45F,
seed 1): 97.36MHz, PASS at 64MHz -- BETTER margin than the pre-fix
baseline's own 76.80-88.25MHz seed range, not just neutral.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 12:29:52 +02:00
micheleandClaude Sonnet 5 49b25f6eb6 exp: layer_prefetch_ctrl.v, real synthesizable RTL for layer-weight-reuse prefetch, fixes a real address-truncation bug (EXP-0057b)
Built the real FSM version of EXP-0057's own task-based prefetch
pattern (bulk-sequential layer fetch via sdram_controller_openrow.v
into layer_weight_buffer.v), so it's an actual instantiable module,
not just a simulation convenience.

Found and fixed a real bug in the process: cur_fill_addr's own address
arithmetic bit-sliced BYTES_PER_BURST down to too few bits
(BYTES_PER_BURST[BIDXW-1:0]), silently truncating 16 to 0 -- every
burst's bytes landed at fill offset 0-15 instead of their real
position, overwriting each other (only each layer's last burst
survived). Root cause: misapplied a widening idiom used safely
elsewhere in this codebase to a case where the target width was
actually too small. Found via a standalone control-flow debug test
first, then tracing data once control-flow was cleared.

Verified: 8192/8192 bit-exact, 0 errors (was 512/8192 before the fix)
through the real controller + SDRAM model, 16 layers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 12:25:32 +02:00
micheleandClaude Sonnet 5 1ce78dff6e exp: N=16 timing closure fixed (EXP-0056), weight-reuse gives real 7.16x memory speedup without DDR3 (EXP-0057)
EXP-0056: N_SLOTS=16 failed timing on LFE5U-85F (23-24MHz vs 64MHz
target). First hypothesis (dependency_manager.v's serial ready-scan)
was wrong but real -- built and verified priority_encoder_lsb.v (a
generic recursive tree encoder) and dependency_manager_fast.v, bit-
exact equivalent to the original, but integrated it made no real
difference (24.26MHz). The real cause, found from nextpnr's own
critical-path report: nms_activation_fill_ctrl_v3.v's balanced max-
tree was only ever extended to N_SLOTS in {1,2,4,8}, silently falling
back to the original slow scan for 16. Added the missing case
(nms_activation_fill_ctrl_v3_n16.v), verified isolated (10017/10017)
and functionally (D-Stress N=16 still 256/256 bit-exact). Real result:
71.01MHz, PASS at 64MHz (single seed so far).

EXP-0057: built layer_weight_buffer.v, a double-buffered per-layer
weight scratchpad (fill one buffer in the background from SDRAM while
compute reads many times from the other -- weight-stationary reuse,
as opposed to D-Stress's own deliberately zero-reuse pattern). Wired
to the real sdram_controller_openrow.v + sdram_model.v, no new
hardware. For the same 32768 bytes of useful data: zero-reuse costs
27048 real cycles, reuse costs 3777 -- 7.16x real measured speedup on
the SAME SDR SDRAM, no DDR3, no clock change. This is the answer to
whether DDR3 is necessary for a workload class that actually has
reuse (e.g. conv-style face recognition, unlike D-Stress) -- it isn't,
at least not for this reason.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 12:01:11 +02:00
micheleandClaude Sonnet 5 fce8ff2d66 exp: fork real board top (fpga_neural_v2_top_openrow.v) with open-row SDRAM backend, verified functionally identical
SPI+board-level smoke test: 11/11 PASS, matching the unmodified
production top exactly. 8-seed nextpnr-ecp5 P&R sweep (N=4, real
v2_board_top.lpf pins, 64MHz target): 8/8 PASS on both, open-row
variant has BETTER margin than baseline (worst 83.34 vs 76.80 MHz,
mean 90.40 vs 82.53 MHz) -- not just no regression, a real improvement.
Not yet promoted over the production fpga_neural_v2_top.v (that swap
is still pending an explicit go-ahead); this commit only adds the
verified fork + its own smoke test, additive only.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 08:02:14 +02:00
micheleandClaude Sonnet 5 ee5a68f6e6 exp: SDRAM CDC bridge + open-row policy (EXP-0053/54/55) -- open-row is a real ~5% D-Stress win, CDC bridge measured net-negative once integrated
EXP-0053: sdram_cdc_bridge.v decouples the SDRAM clock (115.2MHz, real
value derived from the board's own existing PLL VCO=576MHz, verified
via ecppll) from the 64MHz compute domain. Isolated: 137/137 tests, 0
errors, but real measured speedup is only 1.095x (not the naive 1.8x
clock-ratio estimate) -- the CDC handshake's own synchronizer
round-trip is a fixed per-transaction tax.

EXP-0054: sdram_controller_openrow.v implements the page-hit/
keep-row-open optimization sdram_controller.v's own header had always
deferred. weight_prefetch_engine_wide.v's real production traffic is
strictly sequential per job and mostly stays within one SDRAM row --
closing/reopening it every tile (today's fixed auto-precharge policy)
wastes tRP+tRCD for no reason. Isolated: 154/154 tests, 0 errors, 0
protocol violations (including the new refresh-while-row-open hazard,
fixed via an explicit precharge-before-refresh path). Real measured
speedup on the actual sequential access pattern: 1.141x.

EXP-0055: composed both, then integrated into the real D-Stress
benchmark (N=4/N=8, 256/256 bit-exact in every config). Result:
open-row ALONE gives a real, consistent ~5% cycle-count improvement
(47445/47468 vs baseline 49927/49909). CDC alone is a real ~8%
REGRESSION. Combined is still a ~4% regression -- the CDC's fixed tax
is paid on every transaction regardless of row-hit, and real D-Stress
traffic interleaves weight-fetch/activation-result access far more
than the isolated same-row test exercised, so open-row's real saving
doesn't offset it. Decision: do not adopt the CDC approach; open-row
alone is the disclosed, real win worth considering for production
next, pending an explicit go-ahead (not applied to the real board top
in this commit -- all additive, existing production RTL untouched).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
2026-09-16 07:07:57 +02:00
micheleandClaude Sonnet 5 03b5cbc25b exp: bank-interleaved SDRAM pipelining works in isolation, ~0.3% gain integrated (EXP-0052)
Follow-up to EXP-0051: built sdram_controller_pipelined.v, remapping
addr->bank to low-order bits (today's weight region always maps to bank
0) and adding a shadow-slot ACTIVATE lookahead so a different-bank
request can start its tRCD wait during the current transaction's tail.

Phase A (isolated tb_sdram_controller_pipelined.v, 38/38 bit-exact,
independently re-verified this session): mechanism works, saves exactly
2 cycles (tRCD) per different-bank back-to-back pair, matching the
theoretical ceiling derived before measuring (CAS_LATENCY+BURST_LEN are
serial on the shared data bus regardless of bank, so more than tRCD/tRP
was never on the table).

Phase B (integration, tb_nms_dstress_sdram_pipelined.v, independently
rebuilt/rerun): N=4 49760 cycles (-0.33% vs baseline), N=8 49755
(-0.31%) -- both 256/256 bit-exact. Root cause of the gap: the W port's
request/ready protocol is one-at-a-time, so a second, different-bank
request is essentially never already pending while the first is still
in flight, so the mechanism rarely triggers in the real system even
though it's correct when directly stimulated. Not integrated into
production; kept as additive reference for a possible future
arbiter/backend pipelined-dispatch rewrite (out of scope here, larger
and riskier).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHENedK76onD2Vtc2CMjej
2026-09-16 02:56:51 +02:00
micheleandClaude Sonnet 5 cc5db09f61 exp: dual-bank SDRAM sim shows W/AR split gives only ~9% cycle gain, not thrashing removal (EXP-0051)
Forked nms_neural_multiprocessor_sdram_unified.v + its D-Stress testbench
into a dual-bank variant (two independent sdram_unified_backend.v
instances, one for weight-fetch, one for activation+result) to test the
Fase-3 memory-bound hypothesis ahead of Phase 2. Simulation-only: the
real board (v2_board_top.lpf) still wires exactly one physical chip,
per STEP19's governing single-SDRAM mandate.

Result is honest but not the hoped-for one: splitting by traffic class
only cuts D-Stress cycles ~8-10% (N=4: 49927->45724, N=8: 49909->44980),
because the AR (activation+result) path was already lightly loaded
(~12% busy) even alone. The real ceiling is the weight-fetch channel
itself, which stays ~77-78% busy even with its own dedicated bank and
zero cross-traffic. Full writeup in experiments.log EXP-0051, including
the refined next-step options this suggests instead of a straight
2-bank board revision.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHENedK76onD2Vtc2CMjej
2026-09-16 02:18:57 +02:00
micheleandClaude Sonnet 5 19ef54aea8 docs+synth: Phase 0 complete - N=8 baseline + toolchain discrepancy closed
N=8 baseline (EXP-0050, real fpga_neural_v2_top + v2_board_top.lpf, fresh
8-seed sweep): 8/8 PASS at 64MHz, worst 80.97MHz, mean 84.62MHz. DSP
64/72 (88.9%) confirms real N_SLOTS=8. This directly contradicts the
brief's own premise (N8 expected to collapse to ~31MHz) and the project's
historical numbers (3-5/8 pass, worst ~55-67MHz) despite bit-identical
RTL.

Investigated and closed the same discrepancy already flagged for N=4:
logs/experiments.log:2563 explicitly tags historical Fmax numbers as
measured on "Yosys 0.68+"; this session's toolchain is Yosys 0.69+59, a
nightly dated the same day as the session -- a confirmed ~59-commit
version gap. Critical-path inspection on both N=4 and N=8 confirms the
underlying RTL congestion the project diagnosed is real and still
present (same bottleneck locations as previously documented) -- the
newer toolchain just places it well enough to still clear 64MHz.

Decision: this session's numbers are adopted as the operative baseline
for Phase 1+ (see timing.log for the full writeup). Also found, not yet
applied: slot_mem_arbiter.v/slot_mem_arbiter_wide.v both still have the
runtime-indexed-crossbar anti-pattern already fixed in neural_director.v,
sitting right on the arbiter<->backend boundary the brief names -- a
concrete Phase 1 candidate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 21:44:10 +00:00
micheleandClaude Sonnet 5 685a4d6cfe docs+synth: Phase 0 baseline (N_SLOTS=4, real board top), fix stale LPF freq
New brief (N=8 timing closure, LFE5U-85F retarget, 4/8/16 x 1/2-bank SDRAM
sweep). Phase 0: no RTL changes, only measure the current baseline.

ERR-0030: constraints/v2_unified.lpf's FREQUENCY PORT "clk" was still 80MHz,
a leftover from the STEP19 freeze, never updated to the project's real
64MHz target -- fixed (LPF only, zero RTL/datapath effect).

ERR-0031 (bigger one): the first two synthesis attempts targeted
nms_neural_multiprocessor_sdram_unified.v, which is NOT the real
board-level top -- it's an obsolete wrapper only exercised by one
testbench now. The real target is fpga_neural_v2_top.v (adds the real
PLL, reset_sync, spi_host_bridge, and a second arbitration level), which
is what actually goes through synthesis+P&R for hardware. Re-targeted
correctly, matched against constraints/v2_board_top.lpf (all 17 ports
real-ball-assigned).

An N_SLOTS=8 P&R attempt against the WRONG (wrapper) target ran for 2h42m
without converging on a single seed; discarded rather than trusted.
N_SLOTS=8 baseline deferred by explicit user request until N_SLOTS=4 is
fully understood -- re-attempt against the correct fpga_neural_v2_top
target with an agreed time budget.

Result (EXP-0049, fresh 8-seed nextpnr-ecp5 P&R, real pins): N_SLOTS=4
8/8 PASS at 64MHz, worst-seed 81.20MHz, mean 91.05MHz. Higher than
DEC-0042's historical worst/best (64.55/77.21MHz) despite identical RTL --
disclosed, unresolved (leading hypothesis: nextpnr-ecp5 build/version
difference), adopted as the operative baseline for this session's
toolchain going forward. Full writeup in errors.log/timing.log/
experiments.log (EXP-0049).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 20:28:16 +00:00
micheleandClaude Sonnet 5 8b8ca239ca docs: consolidate all V2 datasheets into one current, complete document
The repository had accumulated multiple, contradictory "current state"
documents for V2 hardware: an old V1 IT/EN datasheet copy nested inside
hardware/v2/docs/datasheet/, a stray untracked duplicate at repo root
(docs/DatasheetLatex/), and a second, much older documentation track
(hardware/v2/docs/*.md: PRE_PCB_VERIFICATION.md, PRE_PCB_CLOSURE_4POINT.md,
MEMORY_UPGRADE_64MB_N8.md, and 10 more) describing an earlier PSRAM/
N_SLOTS<=2 milestone alongside the real, current SDRAM/N_SLOTS=4 board.
The LaTeX datasheet's own front matter (features/pinout cover pages) and
chapter 9 (benchmarks) were themselves still describing that obsolete
architecture, contradicting the real, current chapters 5/7/10 elsewhere
in the same document.

This commit:
- Flattens hardware/v2/docs/datasheet/files/docs/datasheet/v2-en/* up to
  hardware/v2/docs/datasheet/ (was 4 levels of redundant nesting).
- Removes the old V1 IT/EN LaTeX copies and the stray root-level
  duplicate entirely (recoverable from git history, not from disk).
- Preserves the real component reference PDFs (ECP5 eval board, ISSI
  PSRAM, programming cables) under datasheet/references/.
- Removes 13 superseded hardware/v2/docs/*.md status documents after
  folding every real, unique fact they contained into the datasheet:
  SPI max verified clock (12MHz, exact 12.8MHz CDC edge), SDRAM directed
  boundary test (21/21 PASS), 16MHz oscillator MPN (ECS-3225MV-160-BN-TR),
  and the real FPGA<->SDRAM ball mapping cross-check.
- Rewrites the datasheet's own front matter, ch.4 (parameters), ch.8
  (top-level module -- was documenting the wrong, non-physical top
  entirely), and ch.9 (benchmarks) to describe the current, real SDRAM/
  N_SLOTS=4 production board, while keeping the real PSRAM-era chapters
  as clearly-labeled history rather than deleting correctly-measured
  work.
- Fixes a title-page tikzpicture that was clipped off the page edge
  (pre-existing, unrelated to this change) by scaling it to fit.

Net: 85 files changed, -8814/+498 lines. hardware/v2/docs/ now contains
exactly one current datasheet plus FIRST_POWER_ON.md (a bring-up
runbook, not a duplicate spec).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-09 00:41:06 +02:00
micheleandClaude Sonnet 5 1efd63912f docs: polish V2 datasheet to professional third-person English
Removed session-log/conversational register leftover from the
interactive drafting process ("the user's own suggestion", "user
confirmed", "user-authored schematic", "user-requested optimizations",
etc.) and replaced with neutral, factual engineering-document
phrasing. No technical content changed -- attribution language only.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-07 20:17:09 +02:00
micheleandClaude Sonnet 5 d4792beed7 docs: embed real KiCad schematic export in V2 datasheet, verify BOM from source
Exported the schematic (kicad-cli sch export pdf) and BOM (kicad-cli sch
export bom) directly from the real KiCad source instead of relying on
pasted screenshots/CSVs, then updated ch.10 accordingly:

- New "Real KiCad schematic capture" section embeds the two live sheets
  (FPGA, UnusedBank) as vector figures pulled straight from the project
  file, plus a note on the three sheet files not reachable from the
  root hierarchy.
- Boot-flash net-name mismatch finding confirmed resolved: FPGA_SPI_*
  labels now match exactly on both the flash chip and the ECP5's
  dedicated MSPI pins.
- FPGA grade fix (8BG381I -> 8BG381C) now verified directly in the
  source file's Value field, not just as a stated intent. Real package
  geometry added: 0.8mm pitch, 20x20 array, 17x17x1.76mm body.
- New minor finding: U2's footprint library folder is still named
  ..._8BG381I even though the Value field is corrected -- not
  board-affecting (identical physical footprint across grades), but
  flagged for a future rename.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-07 20:03:57 +02:00
micheleandClaude Sonnet 5 7eb02ba4bd docs: resolve FPGA grade to commercial (8BG381C), correct temp range data
User confirmed LFE5U-45F-8BG381C (commercial) is the intended part,
matching every other reference in this project. Also corrects this
chapter's own earlier temperature figures: commercial grade is real
TJ 0 to +85C, industrial is TJ -40 to +100C (an earlier draft of this
section had the industrial range wrong at -40/+85C). Same "-8" speed
grade in both -- the letter suffix only changes the characterized
temperature range. KiCad library still needs the part number itself
corrected from ...381I to ...381C.

Compiled clean (47 pages, 0 errors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-07 19:46:14 +02:00
micheleandClaude Sonnet 5 22e226a087 docs: resolve the +1V1 label mystery and close remaining schematic open items
User confirmed TLV62568 (U1) outputs 1.1V, explaining the +1V1 label
found near the VCCAUX ferrite (L2) during the schematic review: it
belongs to U1's own real output net, merely nearby on the page layout,
not routed through the ferrite. VCCAUX remains 2.5V as required by the
real Lattice datasheet.

All three schematic "open items" from the earlier review are now
resolved: TLV62568 EN (R3=499k, confirmed via BOM), the +1V1 label
(false alarm, explained above), and the JTAG pull-up array (confirmed
8 discrete 0402 parts via BOM, not a bussed package -- no polarity
limitation). Only the boot-flash net-name typo (FGPA/FPGA + SCLK/CLK)
remains as a real, open schematic fix, and the FPGA grade discrepancy
(8BG381I vs 8BG381C) remains to be confirmed.

Compiled clean (47 pages, 0 errors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-07 19:42:46 +02:00
micheleandClaude Sonnet 5 1e36853072 docs: clear CAS#/WE# false alarm, resolve TLV73325 EN wiring
User confirmed the real schematic has SDRAM CAS#=F7/WE#=F9 -- matches
this chapter exactly. The earlier review's "appear swapped" finding
was a misread of the schematic image, not a real error; moved from
"real findings" to a cleared checked-item note.

TLV73325's EN pin resolved: direct wire to +3.3V (VIN), always-enabled
-- no soft-start timing requirement like TLV62568's own R3 pull-up (a
plain LDO, no sequencing note in TI's own datasheet), and no dynamic
enable/disable control exists elsewhere in this design.

Remaining real, open finding: the boot-flash net-name mismatch
(FGPA/FPGA typo + SCLK/CLK) still needs a schematic fix.

Compiled clean (47 pages, 0 errors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-07 19:38:48 +02:00
micheleandClaude Sonnet 5 e2956d0377 docs: add real BOM, flag FPGA grade discrepancy (8BG381I vs 8BG381C)
Real KiCad-exported BOM added to the hardware chapter, cross-checked
against every component value this chapter already specifies -- most
match exactly (R1/R2 feedback divider, L1/L2, ferrite part number, all
three real ICs). One real discrepancy found: U2 is captured as
LFE5U-45F-8BG381I (industrial grade) while every other reference in
this project uses the C (commercial) grade part -- flagged, not
resolved, needs explicit confirmation.

Also resolves three earlier open items from the schematic review:
R3=499k confirms TLV62568's EN is populated; R5-R12 being 8 discrete
0402 resistors (not a multi-resistor array) confirms the JTAG
pull-up/down polarity concern doesn't apply; U5 confirms the
previously-missing 16MHz oscillator is now present.

Compiled clean (47 pages, 0 errors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-07 19:36:51 +02:00
micheleandClaude Sonnet 5 4cbbe5a29d docs: real KiCad schematic review + reserved PCB module section
Adds a dated review section recording today's actual schematic check
against every real ball assignment in this chapter: confirmed-correct
items, two real findings needing correction (boot-flash net-name
mismatch FGPA/FPGA typo + SCLK/CLK label mismatch that would leave the
flash electrically disconnected from the ECP5's config engine; SDRAM
CAS#/WE# appearing swapped vs. the verified F7/F9 assignment), and
open items not resolvable from the schematic image alone (regulator EN
pins, a stray +1V1 label near the VCCAUX ferrite, JTAG pull-up/down
array polarity).

Also reserves a "PCB module form factor" section (castellated-edge SMD
module, ~50x25mm) for the future physical layout.

Compiled clean (46 pages, 0 errors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-07 19:35:03 +02:00
micheleandClaude Sonnet 5 44be4a7d81 docs: reflect flash #1 removal and the N=4 8/8 timing recovery
Datasheet and pinouts.md updated to the current, real state after
today's session: flash #1 was implemented then removed (user's own
MHz-over-persistence priority call), the clock-closure table now
shows the post-revert, post-DEC-0042 numbers (N_SLOTS=4 @ 64MHz 8/8,
worst 64.55MHz/best 72.37MHz; N_SLOTS=8 deferred by explicit user
request), and the FPGA_DATA_READY any_pending formula is updated to
the real counter-based implementation (credited to the user's own
diagnosis) that fixed the last failing N=4 seed.

Compiled clean (45 pages, 0 errors).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-07 19:20:57 +02:00
micheleandClaude Sonnet 5 481b5d223f perf: fix N=4@64MHz 7/8->8/8 by removing any_pending fan-out (user's idea)
Real critical-path trace after the flash #1 revert showed a NEW
bottleneck (neural_director.job_out_slot -> dependency_manager.
node_resolved/node_state, 76-84% routing) distinct from every prior
fix this session -- already a flat, parallel 64-way compare, not a
serial chain, so the established restructuring fix class doesn't
apply. Root cause: any_pending (added for FPGA_DATA_READY) reads
node_state[0:N_NODES-1] combinationally every cycle, adding real
fan-out onto the same congested signal.

User's own suggestion: replace the combinational scan with a
synchronous up/down counter. pending_count +1 on registration
acceptance, -1 on dispatch acceptance; any_pending = (pending_count
!= 0) -- mathematically identical (DEC-0008: nodes never reclaimed
mid-run) but reads one small register instead of scanning a 16-wide
array every cycle.

Verified: D-Stress N=4 bit-exact (49927 cycles, data_ready PASS).
Fresh 8-seed P&R: N_SLOTS=4 @ 64MHz now 8/8 PASS (was 7/8 after the
flash revert), worst seed1 64.55MHz, best seed0 72.37MHz.

See decisions.log DEC-0042.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
2026-09-07 19:16:01 +02:00
michele ee708775c7 Revert "feat: integrate flash #1 (neural-network data) RTL into V2 top-level"
This reverts commit 59901a4905.
2026-09-07 19:02:44 +02:00