feat(v2): M2 Neural Processor Array, N_PROCESSORS resource sweep

Implements M2 of the V2 roadmap: neural_processor_array.v instantiates
N_PROCESSORS independent neural_processor (M1) units, each with its
own dedicated point-to-point job/operand/result interface -- no shared
bus or mux at this level (arbitration is explicitly the Neural
Director's job, M5).

Verified with Verilator (tb_neural_processor_array.v, N_PROCESSORS=4):
7/7 tests pass, including a same-cycle 4-way concurrent launch with
different tile counts and a staggered-start test where a
later-launched, shorter job completes before an earlier-launched,
longer one -- confirming genuine independent concurrent execution
(§18/§34: a blocked/busy processor must not block the others).

Real resource/timing sweep for N_PROCESSORS in {1,2,4,8} (Yosys +
nextpnr-ecp5, real place&route): Fmax stays above the 80MHz target
throughout (159.11 -> 134.70 MHz), but MULT18X18D usage scales
linearly and reaches 88% of the LFE5U-45F's 72 DSPs at N=8 while
LUT/FF stay under 6% -- DSP, not LUT/FF/routing, is the first hard
ceiling on N_PROCESSORS at P_IN=8 (decisions.log DEC-0005). Measured
via a dedicated synthesis-only timing harness after the array's wide
per-processor buses were found to exhaust the device's TRELLIS_IO pin
budget as a bare top-level module beyond N=1 (errors.log ERR-0005) --
not a logic limit, an artifact of testing the array in isolation
before the Memory Manager/Director (M4/M5) exist to consume those
ports on-chip.

Full log trail (development/experiments/errors/decisions/simulation/
synthesis/timing/benchmark.log) in hardware/v2/logs/ per the project's
logging mandate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013xXuuRUWZScuo1DeYJxs3v
This commit is contained in:
2026-09-05 14:15:11 +02:00
co-authored by Claude Sonnet 5
parent dc0b331d3e
commit 3026dcd997
41 changed files with 1076183 additions and 2 deletions
+22
View File
@@ -18,3 +18,25 @@ stall %, effective MAC/s: not yet meaningful at this milestone (single
isolated processor, no streaming benchmark harness yet -- deferred to
M2 once neural_processor_array.v exists and a real workload can be
timed end-to-end).
[2026-09-05] M2 Neural Processor Array, N_PROCESSORS sweep (P_IN=8,
ACC_WIDTH=32 each; synthesized via the timing harness, see errors.log
ERR-0005 for why)
| N_PROCESSORS | Fmax (POST-P&R) | LUT | FF | DSP (MULT18X18D) | DSP % of 72 |
|--------------|------------------|-----|------|-------------------|-------------|
| 1 | 159.11 MHz | 59 | 409 | 8 | 11% |
| 2 | 149.59 MHz | 106 | 786 | 16 | 22% |
| 4 | 151.01 MHz | 207 | 1540 | 32 | 44% |
| 8 | 134.70 MHz | 374 | 3048 | 64 | 88% |
All figures POST-P&R (real nextpnr-ecp5), all PASS at the 80MHz
target. LUT4 utilization stays under 6% of the device even at N=8;
DSP is the binding resource (see decisions.log DEC-0005), reaching 88%
at N=8 -- N_PROCESSORS=9 would already exceed the LFE5U-45F's 72
MULT18X18D budget at P_IN=8. Theoretical MAC/cycle (THEORETICAL, not
yet measured end-to-end -- no real workload/benchmark harness exists
until M9): N_PROCESSORS * P_IN MACs/cycle when all processors are
simultaneously streaming tiles (8, 16, 32, 64 for N=1/2/4/8 -- verified
achievable in principle by EXP-0003's concurrent/staggered simulation,
not yet measured as a sustained throughput number).
+47
View File
@@ -201,3 +201,50 @@ resolved by picking whichever answer looks more convenient.
STATUS:
ACCEPTED
---
DEC-0005
DATE: 2026-09-05
DECISION:
Treat DSP (MULT18X18D) budget, not LUT/FF/routing, as the primary
constraint when exploring the N_PROCESSORS x P_IN trade-off space
(§16) going forward.
WHY:
Real place&route measurement (EXP-0003) shows MULT18X18D usage
scaling linearly and reaching 88% of the LFE5U-45F-8BG381's 72 total
DSPs at N_PROCESSORS=8, P_IN=8 -- while LUT4/FF usage stays under 6%
at the SAME configuration and Fmax is still comfortably above the
80MHz target (134.70 MHz). This means the naive "just add more
processors" scaling (§8/§16) hits a hard DSP ceiling around
N_PROCESSORS=9 at P_IN=8, long before LUT/FF/routing/timing become
relevant -- the opposite of what LUT/FF utilization alone would
suggest if read in isolation.
EVIDENCE:
experiments.log EXP-0003 -- MULT18X18D 8/16/32/64 (11%/22%/44%/88% of
72) at N_PROCESSORS 1/2/4/8, LUT4 under 6% throughout, Fmax PASS at
80MHz throughout (159.11/149.59/151.01/134.70 MHz).
ALTERNATIVES:
Assume LUT/FF/routing congestion would be the limiting factor (the
naive expectation for "more parallel copies of a datapath"). Rejected
by direct measurement, not assumed -- §16 explicitly requires
choosing the final configuration "sulla base del throughput effettivo
... non dell'utilizzo massimo delle risorse", and knowing WHICH
resource binds first is a prerequisite for that.
RESULT:
Future N_PROCESSORS x P_IN sweeps (§16, deferred to a dedicated
scripts/sweep/ run per §31) should budget MULT18X18D count explicitly
(N_PROCESSORS * P_IN <= ~72, minus whatever the rest of the real
system needs once M4/PSRAM integration lands) rather than only
tracking LUT/FF. A smaller P_IN with more N_PROCESSORS (or vice versa)
is a live trade-off worth exploring precisely because of this ceiling,
not merely a stylistic choice.
STATUS:
ACCEPTED
+29
View File
@@ -59,3 +59,32 @@ errors: vedi errors.log ERR-0001, ERR-0002, ERR-0003, ERR-0004.
decision: vedi decisions.log DEC-0002, DEC-0003, DEC-0004.
next_action: M2 -- neural_processor_array.v, sweep N_PROCESSORS
(1,2,4,8), misura timing/risorse/throughput/utilization reali.
[2026-09-05T14:30:00Z] commit=dc0b331 session=v2-M2-processor-array
module: hardware/v2/rtl/neural_processor_array.v + hardware/v2/sim/
tb_neural_processor_array.v + hardware/v2/synthesis/
harness_neural_processor_array.v
action: implementato M2 -- Neural Processor Array, N_PROCESSORS
parametrico, ogni processore con interfaccia job/operand/result
dedicata (nessun bus condiviso/mux a questo livello, §7). Testato
N_PROCESSORS=4 con esecuzione concorrente reale (lancio simultaneo
di 4 job diversi, più un test a partenza sfalsata) e con lo sweep
reale N_PROCESSORS={1,2,4,8} per sintesi/place&route.
reason: roadmap M2.
result: 7/7 test PASS (Verilator), confermata esecuzione concorrente e
indipendente (un job più corto lanciato dopo completa prima di uno
più lungo lanciato prima -- non c'e' serializzazione nascosta).
Sintesi/P&R reali per N=1/2/4/8: 0 problemi CHECK, scaling lineare
delle risorse, Fmax sempre PASS a 80MHz (159.11/149.59/151.01/134.70
MHz). Scoperta reale non assunta: il DSP (MULT18X18D) e' la prima
risorsa a saturare (88% a N=8), non LUT/FF (sotto il 6% anche a
N=8) -- vedi decisions.log DEC-0005.
errors: ERR-0005 (artefatto di sintesi da pin-count, non un bug RTL --
workaround con un harness dedicato, vedi errors.log). Un primo
tentativo di harness alimentava dati identici a ogni processore/lane
MAC, e Yosys deduplicava silenziosamente tutto a 1x indipendentemente
da N -- scoperto verificando che lo scaling fosse davvero lineare
prima di fidarsi dei numeri.
decision: vedi decisions.log DEC-0005.
next_action: M3 -- activation_buffer.v / weight_buffer.v /
result_buffer.v (profondita' parametrica, valutare BRAM mapping).
+26
View File
@@ -98,3 +98,29 @@ NOTE: this session's V1 certification campaign (docs/validation/,
this V2-kickoff session (V1 is frozen, not to be touched) and was
not performed. See decisions.log DEC-0004.
STATUS: OPEN CAVEAT, not actioned in this session by design.
ERR-0005 (synthesis measurement artifact, WORKED AROUND, not an RTL bug)
DATE: 2026-09-05
MODULE: hardware/v2/rtl/neural_processor_array.v
SYMPTOM: synthesizing neural_processor_array as a bare top-level
module (every per-processor job/operand/result field exposed as a
real TRELLIS_IO pin) works at N_PROCESSORS=1 but fails place&route
at N_PROCESSORS=2 with "Unable to place cell ...$tr_io, no BELs
remaining to implement cell type 'TRELLIS_IO'".
ROOT CAUSE: not a logic/timing limit -- the LFE5U-45F-8BG381 package
has 245 TRELLIS_IO pins total; the array's wide per-processor buses
(input_data/weight_data alone are DATA_WIDTH*P_IN*N_PROCESSORS bits)
exceed that budget once N_PROCESSORS>=2, purely because these ports
have no on-chip consumer yet (the Memory Manager/M4 and Neural
Director/M5 that will drive them in the real system don't exist
yet).
WORKAROUND: hardware/v2/synthesis/harness_neural_processor_array.v --
a synthesis-only wrapper (NOT part of rtl/, not a functional
deliverable) that drives all wide buses from an internal free-
running LFSR and reduces outputs to a small checksum, keeping only
clk/rst/seed/checksum as real top-level pins. See its own header
comment and experiments.log EXP-0003 for the resulting real
resource/Fmax numbers.
STATUS: WORKED AROUND. Will become moot once M4/M5 exist and the array
is synthesized as part of a larger design with on-chip ports instead
of a bare top-level module.
+61
View File
@@ -98,3 +98,64 @@ decision: ACC_WIDTH=32 remains the M1 default (matches V1 exactly for
comparison run).
next_action: revisit ACC_WIDTH choice during M10 (Optimization) with a
real seed sweep, not before.
EXP-0003
timestamp: 2026-09-05T14:30:00Z
git_commit: dc0b331 (+ uncommitted M2 work)
session: v2-M2-processor-array
module: hardware/v2/rtl/neural_processor_array.v
configuration: N_PROCESSORS in {1,2,4,8}, P_IN=8, ACC_WIDTH=32 each
action: M2 -- functional array + real N_PROCESSORS resource/timing sweep
command (sim, Verilator): verilator --binary --timing -j 0 -Wno-fatal
--top-module tb -o /tmp/vtb_array hardware/v2/rtl/neural_processor.v
hardware/v2/rtl/neural_processor_array.v
hardware/v2/sim/tb_neural_processor_array.v && /tmp/vtb_array
command (synth/timing): see hardware/v2/synthesis/harness_n{1,2,4,8}/
(yosys.log, nextpnr.log) -- synthesized via
hardware/v2/synthesis/harness_neural_processor_array.v, a
synthesis-only timing harness (see its own header comment and
errors.log ERR-0005 for why the array cannot be synthesized as a
bare top-level module beyond N_PROCESSORS=1 without it).
result:
SIMULATED (N_PROCESSORS=4, tb_neural_processor_array.v): 7/7 tests
PASS -- single-processor sanity, 4 processors launched the SAME
cycle with different tile counts (finish at different times,
proving true concurrency), and a staggered-start test (processor 1
launched mid-way through processor 0's 6-tile job, both complete
correctly and independently, confirming §18/§34's "un processor
bloccato non deve bloccare gli altri").
SYNTHESIZED (resource scaling, harness): perfectly linear in
N_PROCESSORS, confirming no unintended resource sharing:
N=1: LUT=59 FF=409 MULT18X18D=8 CCU2C=96
N=2: LUT=106 FF=786 MULT18X18D=16 CCU2C=192
N=4: LUT=207 FF=1540 MULT18X18D=32 CCU2C=384
N=8: LUT=374 FF=3048 MULT18X18D=64 CCU2C=768
0 CHECK problems in every configuration.
POST-P&R (real nextpnr-ecp5, --45k --package CABGA381 --speed 8
--freq 80): Fmax PASS at 80MHz in every configuration:
N=1: 159.11 MHz N=2: 149.59 MHz
N=4: 151.01 MHz N=8: 134.70 MHz
Fmax decreases gently with N (routing congestion), never close to
failing the 80MHz target up to N=8.
REAL RESOURCE CEILING FOUND (not assumed, measured via nextpnr's own
device utilisation report): MULT18X18D usage is 22%/44%/88% of the
LFE5U-45F's 72 total DSPs at N=2/4/8 respectively, while LUT4/FF
usage stays under 6% even at N=8. **DSP (not LUT/FF/routing) is
the first hard ceiling as N_PROCESSORS grows at P_IN=8** --
N_PROCESSORS=9 would already exceed the device's 72 MULT18X18D
budget at P_IN=8, before accounting for any multipliers the rest
of a real system (Memory Manager, PSRAM path, etc.) might need.
See decisions.log DEC-0005 and benchmark.log.
errors: ERR-0005 (toplevel-pin-count synthesis artifact, worked around
with the timing harness -- see errors.log); a first harness attempt
fed every processor and every MAC lane identical LFSR-derived data,
which Yosys correctly (from pure logic-equivalence) collapsed via
CSE down to 1 processor's worth of multipliers regardless of N --
fixed by giving each processor AND each of its P_IN MAC lanes a
distinct bit-rotated data source, confirmed by the corrected,
properly-linear MULT18X18D counts above.
decision: see decisions.log DEC-0005 (DSP is the binding constraint,
not LUT/FF -- informs how the N_PROCESSORS x P_IN trade-off should
be explored going forward).
next_action: M3 -- activation_buffer.v / weight_buffer.v /
result_buffer.v.
+13
View File
@@ -15,3 +15,16 @@ PASS/FAIL: 7/7 PASS (ACC_WIDTH=32); 7/7 PASS (ACC_WIDTH=24, EXP-0002)
bit-exact result: V1.y === V2.result_data for every case, both widths
stall cycles / memory wait / utilization: N/A (no Memory Manager yet,
M1 operands fed directly by testbench per the roadmap)
[2026-09-05] EXP-0003 -- hardware/v2/sim/tb_neural_processor_array.v
(N_PROCESSORS=4)
test: 7 cases (single-processor sanity; 4-way same-cycle concurrent
launch with different tile counts; staggered-start 2-processor test)
simulator: Verilator 5.050 (--binary --timing)
PASS/FAIL: 7/7 PASS
bit-exact result: N/A at this milestone (hand-computed expected
values, arithmetic itself already bit-exact-certified vs V1 at M1)
concurrency: confirmed genuine -- in the staggered test, the
later-launched, shorter job (processor 1) completes BEFORE the
earlier-launched, longer job (processor 0), proving independent
progress rather than serialization.
+13
View File
@@ -14,3 +14,16 @@ CHECK: 0 problems. 36 warnings, all "multiple conflicting drivers for
LUT: 49 FF: 509 DSP(MULT18X18D): 8 BRAM: 0 CCU2C: 88
CHECK: 0 problems, same 36 benign warnings as EXP-0001.
Log: hardware/v2/synthesis/neural_processor_p8_acc24/yosys.log
[2026-09-05] EXP-0003 -- neural_processor_array via
harness_neural_processor_array.v (synthesis-only wrapper, see
errors.log ERR-0005), N_PROCESSORS in {1,2,4,8}, P_IN=8
N=1: LUT=59 FF=409 MULT18X18D=8 CCU2C=96
N=2: LUT=106 FF=786 MULT18X18D=16 CCU2C=192
N=4: LUT=207 FF=1540 MULT18X18D=32 CCU2C=384
N=8: LUT=374 FF=3048 MULT18X18D=64 CCU2C=768
CHECK: 0 problems in all 4 configurations. Perfectly linear scaling in
N confirms no unintended cross-processor resource sharing (a first,
flawed harness attempt fed identical data to every processor/lane
and Yosys silently deduplicated down to 1x regardless of N -- caught
by checking for exactly this linearity before trusting the numbers).
+11
View File
@@ -20,3 +20,14 @@ Delta vs ACC_WIDTH=32: -6.91 MHz (-3.8%) despite FEWER resources --
(no seed sweep run to confirm either way -- see experiments.log
EXP-0002 and benchmark.log). Log: hardware/v2/synthesis/
neural_processor_p8_acc24/nextpnr.log
[2026-09-05] EXP-0003 -- N_PROCESSORS sweep (P_IN=8), real nextpnr-ecp5
--45k --package CABGA381 --speed 8 --freq 80 --lpf-allow-unconstrained
N=1: Fmax=159.11 MHz PASS MULT18X18D 8/72 (11%)
N=2: Fmax=149.59 MHz PASS MULT18X18D 16/72 (22%)
N=4: Fmax=151.01 MHz PASS MULT18X18D 32/72 (44%)
N=8: Fmax=134.70 MHz PASS MULT18X18D 64/72 (88%)
TRELLIS_IO stays at 18/245 (7%) throughout (harness has only
clk/rst/seed/checksum as real pins, by design -- see ERR-0005).
See decisions.log DEC-0005: DSP, not Fmax or LUT/FF, is the resource
that will first prevent scaling N_PROCESSORS further at P_IN=8.